dsh-code 0.6.1 → 0.8.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 +20 -6
- package/README.md +20 -6
- package/lib/index.mjs +3952 -1315
- package/lib/startup.mjs +21 -9
- package/lib/theme-BEi4i_aN.mjs +624 -0
- package/lib/types/app.d.ts +108 -4
- package/lib/types/history.d.ts +15 -4
- package/lib/types/index.d.ts +49 -0
- package/lib/types/kernel-panels.d.ts +28 -0
- package/lib/types/mentions.d.ts +29 -12
- package/lib/types/models.d.ts +66 -0
- package/lib/types/permissions.d.ts +37 -0
- package/lib/types/presets.d.ts +2 -0
- package/lib/types/provider-settings.d.ts +144 -0
- package/lib/types/questions.d.ts +2 -0
- package/lib/types/render/animations.d.ts +177 -2
- package/lib/types/render/lines.d.ts +6 -0
- package/lib/types/render/markdown.d.ts +3 -3
- package/lib/types/render/projection.d.ts +123 -3
- package/lib/types/render/status.d.ts +35 -24
- package/lib/types/render/text.d.ts +14 -7
- package/lib/types/render/tool-detail.d.ts +3 -1
- package/lib/types/render/tool-preview.d.ts +4 -1
- package/lib/types/session-directory.d.ts +15 -0
- package/lib/types/startup.d.ts +12 -4
- package/lib/types/store.d.ts +13 -2
- package/lib/types/theme-panel.d.ts +24 -0
- package/lib/types/theme.d.ts +158 -2
- package/lib/types/version.d.ts +5 -0
- package/package.json +1 -1
- package/src/app.ts +1283 -206
- package/src/approval.ts +11 -2
- package/src/history.ts +20 -5
- package/src/index.ts +1207 -905
- package/src/kernel-panels.ts +518 -419
- package/src/mentions.ts +57 -27
- package/src/models.ts +200 -66
- package/src/permissions.ts +85 -0
- package/src/presets.ts +12 -0
- package/src/provider-settings.ts +520 -0
- package/src/questions.ts +15 -5
- package/src/render/animations.ts +373 -2
- package/src/render/lines.ts +21 -6
- package/src/render/markdown.ts +302 -4
- package/src/render/projection.ts +1419 -659
- package/src/render/status.ts +650 -603
- package/src/render/text.ts +28 -9
- package/src/render/tool-detail.ts +81 -40
- package/src/render/tool-preview.ts +18 -2
- package/src/session-directory.ts +44 -5
- package/src/skills.ts +8 -4
- package/src/startup.ts +119 -109
- package/src/store.ts +26 -8
- package/src/theme-panel.ts +72 -0
- package/src/theme.ts +206 -70
- package/src/version.ts +16 -0
package/lib/types/app.d.ts
CHANGED
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
* @module @deepseek-ai/dsh-code/app
|
|
15
15
|
*/
|
|
16
16
|
import { type ReactElement } from 'react';
|
|
17
|
+
import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
|
|
18
|
+
import { type ThemeName } from './theme.ts';
|
|
17
19
|
import type { TranscriptStore } from './store.ts';
|
|
20
|
+
import { type TranscriptEntry } from './render/projection.ts';
|
|
18
21
|
import type { ApprovalStore } from './approval.ts';
|
|
19
22
|
import type { CommandsView } from './commands.ts';
|
|
20
23
|
import type { ModelDirectory, ModelRow } from './models.ts';
|
|
24
|
+
import type { ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
21
25
|
import type { QuestionStore } from './questions.ts';
|
|
22
|
-
import type { SkillsView } from './skills.ts';
|
|
26
|
+
import type { SkillsView, SkillRow } from './skills.ts';
|
|
23
27
|
import type { MentionCandidate } from './mentions.ts';
|
|
24
28
|
import type { PresetRow } from './presets.ts';
|
|
29
|
+
import type { PermissionRow } from './permissions.ts';
|
|
25
30
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
26
31
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
27
32
|
/** Visual priority for one bounded local notice. */
|
|
@@ -40,6 +45,8 @@ export interface AppProps {
|
|
|
40
45
|
skills: SkillsView;
|
|
41
46
|
/** `provider/model` selection serving this session (updated on /model). */
|
|
42
47
|
model: string;
|
|
48
|
+
/** Effective reasoning effort in force ('' when none), for the /model picker mark. */
|
|
49
|
+
effort?: string;
|
|
43
50
|
/** Working-directory basename the session serves. */
|
|
44
51
|
cwd: string;
|
|
45
52
|
/** Absolute working directory used by session filters and references. */
|
|
@@ -50,8 +57,10 @@ export interface AppProps {
|
|
|
50
57
|
sessionId: string;
|
|
51
58
|
/** Whether this session was resumed from persistence. */
|
|
52
59
|
resumed: boolean;
|
|
53
|
-
/** Agent preset
|
|
60
|
+
/** Agent preset selected for the current or pending first session. */
|
|
54
61
|
mode: string;
|
|
62
|
+
/** Permission preset selected for the current or pending first session. */
|
|
63
|
+
permission: string;
|
|
55
64
|
/** Submit one line: slash commands to the registry, other text to the agent. */
|
|
56
65
|
dispatch(text: string): void;
|
|
57
66
|
/** Submit steering: consumed at the running turn's next step boundary. */
|
|
@@ -64,10 +73,22 @@ export interface AppProps {
|
|
|
64
73
|
loadModels(): Promise<ModelDirectory>;
|
|
65
74
|
/** Load @mention candidates for the typed query (files + sessions). */
|
|
66
75
|
loadMentions(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
|
|
67
|
-
/** Apply one /model selection; returns the display label. */
|
|
68
|
-
selectModel(row: ModelRow): string;
|
|
76
|
+
/** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
|
|
77
|
+
selectModel(row: ModelRow, effortId?: string): string;
|
|
78
|
+
/** Load provider/settings/credential facts for the optional /model provider stage. */
|
|
79
|
+
loadModelProviders?(): Promise<ProviderSettingsDirectory>;
|
|
80
|
+
/** Subscribe to Harness credential/settings/adapter invalidations while /model is open. */
|
|
81
|
+
subscribeModelProviders?(listener: () => void): () => void;
|
|
82
|
+
/** Store or rotate one provider credential through the Harness credential service. */
|
|
83
|
+
saveModelProviderCredential?(target: ProviderTargetView, key: string): Promise<void>;
|
|
84
|
+
/** Remove one writable provider credential without removing its settings profile. */
|
|
85
|
+
unsetModelProviderCredential?(target: ProviderTargetView): Promise<void>;
|
|
86
|
+
/** Remove one user-owned provider profile and its page-managed credential. */
|
|
87
|
+
removeModelProvider?(target: ProviderTargetView): Promise<void>;
|
|
69
88
|
/** Cycle to the next permission preset (Shift+Tab); returns the new label. */
|
|
70
89
|
cyclePermission(): string;
|
|
90
|
+
/** Select or inspect a permission preset without requiring a pre-existing session. */
|
|
91
|
+
setPermission(id: string): string;
|
|
71
92
|
/** Export the transcript to a markdown file (/export [path]); reports via notices. */
|
|
72
93
|
exportTranscript(argument: string): Promise<void>;
|
|
73
94
|
/** Rename the session (/title <text>); returns the outcome line for the notice. */
|
|
@@ -75,6 +96,8 @@ export interface AppProps {
|
|
|
75
96
|
/** Preset/session/plugin kernel operations. */
|
|
76
97
|
loadPresets(): Promise<readonly PresetRow[]>;
|
|
77
98
|
switchMode(id: string): Promise<string>;
|
|
99
|
+
/** Load the switchable permission presets for the /permission panel. */
|
|
100
|
+
loadPermissions(): Promise<readonly PermissionRow[]>;
|
|
78
101
|
createSession(mode?: string): void;
|
|
79
102
|
loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
80
103
|
loadSessionTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
@@ -89,6 +112,8 @@ export interface AppProps {
|
|
|
89
112
|
statusline: readonly string[];
|
|
90
113
|
/** Persist a new statusline item set; the runner surfaces IO failures as notices. */
|
|
91
114
|
saveStatusline(items: readonly string[]): void;
|
|
115
|
+
/** Apply and persist one /theme selection; the runner owns the theme.json file. */
|
|
116
|
+
saveTheme?(name: ThemeName): void;
|
|
92
117
|
/** Persistent cross-session input history (oldest first); the runner owns the file. */
|
|
93
118
|
history: readonly string[];
|
|
94
119
|
/** Persist one submitted prompt to the global history file. */
|
|
@@ -96,5 +121,84 @@ export interface AppProps {
|
|
|
96
121
|
/** Cancel one queued inbox message by identity (Delete on the empty composer). */
|
|
97
122
|
cancelQueued(messageId: string): void;
|
|
98
123
|
}
|
|
124
|
+
/** One completion candidate row. */
|
|
125
|
+
interface CompletionCandidate {
|
|
126
|
+
/** Insertion text for the command name (with leading slash). */
|
|
127
|
+
label: string;
|
|
128
|
+
/** Human-readable description shown beside the label. */
|
|
129
|
+
description: string;
|
|
130
|
+
/** Candidate origin; skills land the same literal text but route through the prompt. */
|
|
131
|
+
origin: 'command' | 'skill' | 'mention' | 'path';
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve completion candidates for the current input: TUI-local commands,
|
|
135
|
+
* the live registry descriptors, and user-invocable skills, filtered by the
|
|
136
|
+
* typed prefix. Command names win collisions (the dispatch tries the
|
|
137
|
+
* registry first and only then falls through to the skill gesture), and a
|
|
138
|
+
* later duplicate name never renders twice.
|
|
139
|
+
*
|
|
140
|
+
* A bare `/` returns the FULL merged list — Codex's command popup shows every
|
|
141
|
+
* command inside a scroll window on an empty filter, and the menu's own
|
|
142
|
+
* selection window bounds the visible rows, so no slice cap is needed.
|
|
143
|
+
*/
|
|
144
|
+
export declare function completionCandidates(value: string, descriptors: readonly CommandDescriptor[], skills: readonly SkillRow[]): readonly CompletionCandidate[];
|
|
145
|
+
/** One cached settled row: the row Box plus its roomy-prompt spacers. */
|
|
146
|
+
interface SettledRowRecord {
|
|
147
|
+
/** The row Box element (keyed by the entry's settled index). */
|
|
148
|
+
box: ReactElement;
|
|
149
|
+
/** The roomy-prompt spacer BEFORE the row, or undefined. */
|
|
150
|
+
before: ReactElement | undefined;
|
|
151
|
+
/** The roomy-prompt spacer AFTER the row, or undefined. */
|
|
152
|
+
after: ReactElement | undefined;
|
|
153
|
+
/** Whether the row's text depends on the reasoning toggle (Ctrl+R). */
|
|
154
|
+
reasonSensitive: boolean;
|
|
155
|
+
/** The toggle state the row was built with. */
|
|
156
|
+
showReasoning: boolean;
|
|
157
|
+
}
|
|
158
|
+
/** The incremental settled-history cache (see `computeSettledRows`). */
|
|
159
|
+
interface SettledRowsCache {
|
|
160
|
+
/** The exact settled entries the cache covers (`view.entries[0..entries.length)`). */
|
|
161
|
+
entries: TranscriptEntry[];
|
|
162
|
+
/** Records keyed by entry identity; mutated in place so the append path
|
|
163
|
+
* never copies the whole map. */
|
|
164
|
+
records: Map<TranscriptEntry, SettledRowRecord>;
|
|
165
|
+
/** The header element (depends only on `resumed`). */
|
|
166
|
+
header: ReactElement;
|
|
167
|
+
/** The `resumed` the header was built with. */
|
|
168
|
+
resumed: boolean;
|
|
169
|
+
/** The toggle state the rows were built with. */
|
|
170
|
+
showReasoning: boolean;
|
|
171
|
+
/** The refreshEpoch the rows were built for; a bump forces a full rebuild. */
|
|
172
|
+
epoch: number;
|
|
173
|
+
/** The flat row list (header + per-entry before/box/after). */
|
|
174
|
+
flat: ReactElement[];
|
|
175
|
+
}
|
|
176
|
+
/** One step of `computeSettledRows`. */
|
|
177
|
+
interface SettledRowsResult {
|
|
178
|
+
cache: SettledRowsCache;
|
|
179
|
+
/** How many rows had to be BUILT by this step (0 = pure reuse). */
|
|
180
|
+
built: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The settled `<Static>` row set as a PURE incremental state machine (App
|
|
184
|
+
* drives it from the memo; tests drive it directly and read `built`).
|
|
185
|
+
*
|
|
186
|
+
* The settled prefix is permanently final: the projection only APPENDS below
|
|
187
|
+
* the flush boundary, removes pending rows at or beyond it, and replaces
|
|
188
|
+
* running tool/retry/command rows there too. So extending the cache never
|
|
189
|
+
* rescans the old prefix — a grown boundary builds ONLY the newly settled
|
|
190
|
+
* suffix and reuses every cached element, letting React bail out of unchanged
|
|
191
|
+
* rows and keeping long histories out of the per-durable-event path (no O(N)
|
|
192
|
+
* rebuild of rows, Map, or MarkdownBody parses). `records` is mutated in place
|
|
193
|
+
* on the append/toggle paths to stay O(delta).
|
|
194
|
+
*
|
|
195
|
+
* Full rebuilds run only on the rare, deliberate paths: no cache yet, a
|
|
196
|
+
* source-backed replay (`epoch` bump: resize / Ctrl+L / Ctrl+R remounts
|
|
197
|
+
* `<Static>` and must re-flush the CURRENT rows), a `resumed` change, or a shrink
|
|
198
|
+
* (`store.reset`). A reasoning toggle rebuilds only the rows whose text
|
|
199
|
+
* depends on it, preserving the other rows' element identity.
|
|
200
|
+
*/
|
|
201
|
+
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number): SettledRowsResult;
|
|
99
202
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
100
203
|
export declare function App(props: AppProps): ReactElement;
|
|
204
|
+
export {};
|
package/lib/types/history.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module @deepseek-ai/dsh-tui/history
|
|
9
9
|
*/
|
|
10
|
-
/** Maximum entries retained in the persistent history file. */
|
|
11
|
-
export declare const HISTORY_MAX_ENTRIES =
|
|
10
|
+
/** Maximum entries retained in the persistent history file and the local recall pool. */
|
|
11
|
+
export declare const HISTORY_MAX_ENTRIES = 100;
|
|
12
12
|
/** Encode one entry for the history file (JSON keeps multi-line drafts intact). */
|
|
13
13
|
export declare function serializeHistoryEntry(text: string): string;
|
|
14
14
|
/**
|
|
@@ -31,12 +31,23 @@ export declare function parseHistoryFile(raw: string, max?: number): readonly st
|
|
|
31
31
|
export declare function appendHistoryContent(current: string, text: string, max?: number): string;
|
|
32
32
|
/**
|
|
33
33
|
* Record one in-session submission: empty text is ignored and an adjacent
|
|
34
|
-
* duplicate collapses (Codex `record_local_submission` semantics).
|
|
34
|
+
* duplicate collapses (Codex `record_local_submission` semantics). The local
|
|
35
|
+
* pool shares the persistent pool's cap so the recall space stays bounded.
|
|
35
36
|
* @param local - current in-session entries, oldest first.
|
|
36
37
|
* @param text - the submitted prompt.
|
|
38
|
+
* @param max - the local pool cap.
|
|
37
39
|
* @returns the updated local list.
|
|
38
40
|
*/
|
|
39
|
-
export declare function recordLocalEntry(local: readonly string[], text: string): readonly string[];
|
|
41
|
+
export declare function recordLocalEntry(local: readonly string[], text: string, max?: number): readonly string[];
|
|
42
|
+
/**
|
|
43
|
+
* Serialize a capped entry list to the history file format (one JSON line per
|
|
44
|
+
* entry, trailing newline). The runner writes the in-memory list as the whole
|
|
45
|
+
* file, so rapid same-process submissions cannot lose entries to a
|
|
46
|
+
* read-modify-write race (the file is never read back before writing).
|
|
47
|
+
* @param entries - the entries to persist, oldest first.
|
|
48
|
+
* @returns the file content, '' for an empty list.
|
|
49
|
+
*/
|
|
50
|
+
export declare function serializeHistoryList(entries: readonly string[]): string;
|
|
40
51
|
/**
|
|
41
52
|
* Build the recall space, newest first: local entries, then persistent
|
|
42
53
|
* entries whose text is not duplicated locally (the local copy wins and the
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
12
|
import z from '@deepseek-ai/schemastery';
|
|
13
|
+
import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
|
|
14
|
+
import type { TuiStartup } from './startup.ts';
|
|
13
15
|
/** Stable Cordis plugin name. */
|
|
14
16
|
export declare const name = "tui-runner";
|
|
15
17
|
/** Core services required before the interactive session can start. */
|
|
@@ -21,12 +23,59 @@ export interface Config {
|
|
|
21
23
|
kind: string;
|
|
22
24
|
sessionId?: string;
|
|
23
25
|
mode?: string;
|
|
26
|
+
theme?: string;
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
export declare const Config: z<Config>;
|
|
30
|
+
/** The session identity this invocation will run, plus whether it is resumed. */
|
|
31
|
+
interface Target {
|
|
32
|
+
sessionId: string;
|
|
33
|
+
resume: boolean;
|
|
34
|
+
mode?: string;
|
|
35
|
+
cwd?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reduce a session id to a filename-safe /export default-name suffix. Session
|
|
39
|
+
* ids are normally minted `session-<uuid>`, but `--session` accepts arbitrary
|
|
40
|
+
* user text: path separators must never leak into the default export filename
|
|
41
|
+
* (which would escape the session cwd).
|
|
42
|
+
* @param id - the session id.
|
|
43
|
+
* @returns at most the last 8 filename-safe characters.
|
|
44
|
+
*/
|
|
45
|
+
export declare function exportSessionIdSuffix(id: string): string;
|
|
46
|
+
/** One ordered step of the terminal quit cleanup. */
|
|
47
|
+
export interface QuitCleanupStep {
|
|
48
|
+
/** Step label used in diagnostics and tests. */
|
|
49
|
+
readonly name: string;
|
|
50
|
+
/** The step's async work; a rejection is contained by the sequence. */
|
|
51
|
+
readonly run: () => Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Run the ordered quit cleanup, then request exit. Every step rejection is
|
|
55
|
+
* contained (reported through `onError`) so a failed flush or dispose never
|
|
56
|
+
* skips the remaining cleanup; the exit request is always reached exactly
|
|
57
|
+
* once.
|
|
58
|
+
* @param steps - the cleanup steps in dependency order (settle the visible
|
|
59
|
+
* session, await the final in-flight composition, await durable recall).
|
|
60
|
+
* @param exit - the terminal exit request (code 0).
|
|
61
|
+
* @param onError - optional failure sink; called once per failing step and
|
|
62
|
+
* itself contained, so a throwing sink cannot abort the sequence.
|
|
63
|
+
* @returns the names of the steps that started, in order (for tests).
|
|
64
|
+
*/
|
|
65
|
+
export declare function runQuitSequence(steps: readonly QuitCleanupStep[], exit: (code: number) => void, onError?: (name: string, error: unknown) => void): Promise<readonly string[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the invocation's target session against the persisted headers.
|
|
68
|
+
* @param startup - the parsed startup flags.
|
|
69
|
+
* @param persistence - the persistence service; required for resume/latest.
|
|
70
|
+
* @param cwd - the working directory `--continue` filters by.
|
|
71
|
+
* @returns the target identity.
|
|
72
|
+
* @throws with a user-facing message when the flags name nothing resolvable.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveTarget(startup: TuiStartup, persistence: SessionPersistence | undefined, cwd: string): Promise<Target>;
|
|
27
75
|
/**
|
|
28
76
|
* Mount the interactive terminal driver.
|
|
29
77
|
* @param ctx - plugin context carrying core services and the launcher-provided exit request.
|
|
30
78
|
* @param config - validated startup config resolved from the tuiStartup provider.
|
|
31
79
|
*/
|
|
32
80
|
export declare function apply(ctx: Context, config: Config): void;
|
|
81
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Bounded, composer-safe panels for preset, session, and plugin kernel views. */
|
|
2
2
|
import { type ReactElement } from 'react';
|
|
3
|
+
import type { ModelRow } from './models.ts';
|
|
4
|
+
import type { PermissionRow } from './permissions.ts';
|
|
3
5
|
import type { PresetRow } from './presets.ts';
|
|
4
6
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
5
7
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
@@ -10,6 +12,12 @@ export declare function ModePanel({ current, load, select, close }: {
|
|
|
10
12
|
select(id: string): void;
|
|
11
13
|
close(): void;
|
|
12
14
|
}): ReactElement;
|
|
15
|
+
export declare function PermissionPanel({ current, load, select, close }: {
|
|
16
|
+
current: string;
|
|
17
|
+
load(): Promise<readonly PermissionRow[]>;
|
|
18
|
+
select(id: string): void;
|
|
19
|
+
close(): void;
|
|
20
|
+
}): ReactElement;
|
|
13
21
|
export declare function PluginPanel({ load, close, initialQuery }: {
|
|
14
22
|
load(): readonly PluginRow[];
|
|
15
23
|
close(): void;
|
|
@@ -46,3 +54,23 @@ export declare function StatuslinePanel({ enabled, change, close }: {
|
|
|
46
54
|
change(items: readonly StatusItemId[]): void;
|
|
47
55
|
close(): void;
|
|
48
56
|
}): ReactElement;
|
|
57
|
+
/**
|
|
58
|
+
* The `/model` reasoning-effort stage (the Codex model → reasoning popup
|
|
59
|
+
* contract): one bounded list over the selected model's adapter-advertised
|
|
60
|
+
* effort levels, with the effective effort and the model default marked.
|
|
61
|
+
* A model WITHOUT an adapter-declared default leads with a "Default"
|
|
62
|
+
* (provider-default) row — the web effort pane's first entry — so the user
|
|
63
|
+
* can clear a picked level back to provider behavior instead of being forced
|
|
64
|
+
* to choose an advertised one. Enter applies one level; Esc returns to the
|
|
65
|
+
* model list without applying.
|
|
66
|
+
*/
|
|
67
|
+
export declare function EffortPanel({ row, current, select, back }: {
|
|
68
|
+
/** The model row whose advertised levels this stage lists. */
|
|
69
|
+
row: ModelRow;
|
|
70
|
+
/** Effective effort currently in force ('' when none), for the ● mark. */
|
|
71
|
+
current: string | undefined;
|
|
72
|
+
/** Accept one advertised effort id, or '' for the provider default. */
|
|
73
|
+
select(effortId: string): void;
|
|
74
|
+
/** Return to the model list without applying. */
|
|
75
|
+
back(): void;
|
|
76
|
+
}): ReactElement;
|
package/lib/types/mentions.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workspace @mention support: file candidates from a bounded
|
|
3
|
-
* the session cwd, session candidates from the opt-in
|
|
4
|
-
* service, and submission preparation through its
|
|
5
|
-
* session mentions land as canonical
|
|
6
|
-
* submit the text is parsed back into
|
|
7
|
-
* references, snapshots are injected
|
|
8
|
-
*
|
|
9
|
-
* upstream README's wiring.
|
|
2
|
+
* Workspace @mention support: file and directory candidates from a bounded
|
|
3
|
+
* async scan of the session cwd, session candidates from the opt-in
|
|
4
|
+
* `sessionReferenceResolver` service, and submission preparation through its
|
|
5
|
+
* `prepare()` API. Picked session mentions land as canonical
|
|
6
|
+
* `@[label](dsh-session:…)` tokens; on submit the text is parsed back into
|
|
7
|
+
* readable `@label` text plus structured references, snapshots are injected
|
|
8
|
+
* via `agent.inject()` before the readable message wakes the driver
|
|
9
|
+
* (`followup` idle, `steer` running) — exactly the upstream README's wiring.
|
|
10
|
+
*
|
|
11
|
+
* Harness exposes no workspace-file mention service (only session references
|
|
12
|
+
* plus a post-hoc produced-file linker), so the file index is the lightweight
|
|
13
|
+
* bounded scan below, kept deliberately smaller than Codex's streaming
|
|
14
|
+
* gitignore-aware walker.
|
|
10
15
|
*
|
|
11
16
|
* @module @deepseek-ai/dsh-code/mentions
|
|
12
17
|
*/
|
|
@@ -40,11 +45,17 @@ export interface PreparedMention {
|
|
|
40
45
|
/** Aggregated snapshot for `agent.inject()`, undefined without references. */
|
|
41
46
|
additionalContext?: import('@deepseek-ai/dsh-session').UserMessage;
|
|
42
47
|
}
|
|
43
|
-
/**
|
|
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
|
+
*/
|
|
44
55
|
export declare function scanWorkspaceFiles(root: string, signal?: AbortSignal): Promise<readonly FileCandidate[]>;
|
|
45
56
|
/** The mention API the input editor and the runner share. */
|
|
46
57
|
export interface MentionsApi {
|
|
47
|
-
/** Scanned workspace files, cached across one session. */
|
|
58
|
+
/** Scanned workspace files and directories, cached across one session. */
|
|
48
59
|
files(): Promise<readonly FileCandidate[]>;
|
|
49
60
|
/** Ranked menu candidates for the typed `@` query. */
|
|
50
61
|
candidates(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
|
|
@@ -61,10 +72,16 @@ export interface MentionsApi {
|
|
|
61
72
|
/**
|
|
62
73
|
* Create the mention API for one agent's workspace. A missing
|
|
63
74
|
* session-reference service degrades to file mentions only (the scan still
|
|
64
|
-
* works); `prepare` then passes text through untouched.
|
|
75
|
+
* works); `prepare` then passes text through untouched. An undefined agent
|
|
76
|
+
* (a bare launch before any session exists) also degrades to file-only
|
|
77
|
+
* mentions, so `@` file completion works before the first message.
|
|
78
|
+
*
|
|
79
|
+
* `files` is hoisted into the closure so `candidates` never reaches for
|
|
80
|
+
* `this` — the runner hands `mentions.candidates` to the input editor as a
|
|
81
|
+
* detached callback, and a `this`-bound method would throw on every `@` key.
|
|
65
82
|
* @param ctx - context carrying the optional `sessionReferenceResolver`.
|
|
66
83
|
* @param agent - the session owner; excluded from its own candidates.
|
|
67
84
|
* @param cwd - workspace root to scan.
|
|
68
85
|
*/
|
|
69
|
-
export declare function createMentions(ctx: Context, agent: Agent, cwd: string): MentionsApi;
|
|
86
|
+
export declare function createMentions(ctx: Context, agent: Agent | undefined, cwd: string): MentionsApi;
|
|
70
87
|
export {};
|
package/lib/types/models.d.ts
CHANGED
|
@@ -8,6 +8,24 @@
|
|
|
8
8
|
* @module @deepseek-ai/dsh-tui/models
|
|
9
9
|
*/
|
|
10
10
|
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { ModelSelection } from '@deepseek-ai/dsh-agent';
|
|
12
|
+
import { type LlmModelReasoningInfo } from '@deepseek-ai/dsh-llm';
|
|
13
|
+
/** Display metadata for one adapter-owned reasoning effort (mirrors `LlmReasoningEffortInfo`). */
|
|
14
|
+
export interface ModelReasoningEffort {
|
|
15
|
+
/** Opaque value accepted by the model's `GenerateOptions.reasoningEffort`. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Human-readable effort name for selectors. */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Optional user-facing distinction from otherwise similar efforts. */
|
|
20
|
+
description?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Selectable reasoning efforts for one model (mirrors `LlmModelReasoningInfo`). */
|
|
23
|
+
export interface ModelReasoning {
|
|
24
|
+
/** Supported efforts in adapter-preferred display order. */
|
|
25
|
+
efforts: readonly ModelReasoningEffort[];
|
|
26
|
+
/** Adapter-configured default materialized when callers omit an effort. */
|
|
27
|
+
defaultEffort?: string;
|
|
28
|
+
}
|
|
11
29
|
/** One selectable row in the `/model` panel. */
|
|
12
30
|
export interface ModelRow {
|
|
13
31
|
/** Registered provider route. */
|
|
@@ -18,6 +36,8 @@ export interface ModelRow {
|
|
|
18
36
|
model: string;
|
|
19
37
|
/** Human-readable model name. */
|
|
20
38
|
modelName: string;
|
|
39
|
+
/** Adapter-owned selectable reasoning levels when the model exposes any. */
|
|
40
|
+
reasoning?: ModelReasoning;
|
|
21
41
|
}
|
|
22
42
|
/** The resolved directory: rows plus per-provider discovery failures. */
|
|
23
43
|
export interface ModelDirectory {
|
|
@@ -25,12 +45,58 @@ export interface ModelDirectory {
|
|
|
25
45
|
rows: readonly ModelRow[];
|
|
26
46
|
/** Provider ids whose model listing failed; those providers contribute no rows. */
|
|
27
47
|
failures: readonly string[];
|
|
48
|
+
/**
|
|
49
|
+
* `provider/model` labels whose per-model capability lookup failed. Those
|
|
50
|
+
* rows still appear (advisory degrade, mirroring the web catalog), but
|
|
51
|
+
* without an effort picker — a picker caller must not misread the absence
|
|
52
|
+
* as "this model exposes no reasoning" (e.g. deepseek-v4-flash always
|
|
53
|
+
* advertises off/high/max unless thinking is disabled). Optional for
|
|
54
|
+
* callers that shape a directory by hand; {@link loadModelDirectory}
|
|
55
|
+
* always populates it (empty when nothing failed).
|
|
56
|
+
*/
|
|
57
|
+
reasoningFailures?: readonly string[];
|
|
28
58
|
}
|
|
59
|
+
/** Map an adapter's reasoning capability onto the panel's plain-id shape. */
|
|
60
|
+
export declare function mapReasoning(reasoning: LlmModelReasoningInfo): ModelReasoning;
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the effective model selection for one live session, in the
|
|
63
|
+
* documented precedence: the in-process explicit pick, then the session's
|
|
64
|
+
* last `request/header` config, then the deployment default.
|
|
65
|
+
* @param picked - the explicit selection made in this process, when any.
|
|
66
|
+
* @param logged - the last logged request header config, when any.
|
|
67
|
+
* @param defaults - the deployment default selection.
|
|
68
|
+
* @returns the effective selection, carrying a reasoning effort when one is in force.
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveEffectiveSelection(picked: ModelSelection | undefined, logged: {
|
|
71
|
+
provider: string;
|
|
72
|
+
model: string;
|
|
73
|
+
reasoningEffort?: string;
|
|
74
|
+
} | undefined, defaults: ModelSelection): ModelSelection;
|
|
75
|
+
/**
|
|
76
|
+
* Build the selection one `/model` pick applies, rejecting an effort the
|
|
77
|
+
* row does not advertise. The row is the picker's source of truth, so a
|
|
78
|
+
* stale directory cannot smuggle an unsupported effort into the next step
|
|
79
|
+
* (the request pipeline would reject it before network I/O regardless). The
|
|
80
|
+
* empty string is the picker's "provider default" sentinel — an explicit
|
|
81
|
+
* choice to leave the effort to the model's own default, exactly like an
|
|
82
|
+
* absent effort.
|
|
83
|
+
* @param row - the picked model row.
|
|
84
|
+
* @param effortId - the chosen advertised effort, '' or undefined for the model default.
|
|
85
|
+
* @returns the selection the runner records for the next assembled step.
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildModelSelection(row: ModelRow, effortId?: string): ModelSelection;
|
|
88
|
+
/** Display label for one applied selection: `provider/model` or `provider/model@effort`. */
|
|
89
|
+
export declare function modelSelectionLabel(selection: ModelSelection): string;
|
|
29
90
|
/**
|
|
30
91
|
* Load the selectable model directory from the live `ctx.llm` registry.
|
|
31
92
|
* Providers are listed synchronously; each provider's models are discovered
|
|
32
93
|
* with a bounded parallel fan-out whose failures degrade to that provider
|
|
33
94
|
* contributing no rows (mirrors the web catalog's per-provider failures).
|
|
95
|
+
* Each row's reasoning levels are resolved per exact model like the web
|
|
96
|
+
* catalog (`buildModelCatalog`); a single model's capability lookup failure
|
|
97
|
+
* degrades to that row having no effort picker rather than hiding the model,
|
|
98
|
+
* and the failure rides `reasoningFailures` so the caller can tell "no
|
|
99
|
+
* advertised reasoning" from "capability lookup failed".
|
|
34
100
|
* @param ctx - context carrying the `llm` service.
|
|
35
101
|
* @returns the resolved directory; empty rows when `llm` is unavailable.
|
|
36
102
|
*/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Permission-preset policy for pending and active TUI sessions. */
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
4
|
+
/** One selectable permission preset row for the /permission panel. */
|
|
5
|
+
export interface PermissionRow {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly description?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Structural boundary over Harness permission presets; values stay service-owned. */
|
|
10
|
+
export interface PermissionPresetsService {
|
|
11
|
+
readonly names: readonly string[];
|
|
12
|
+
readonly defaultPreset: string;
|
|
13
|
+
resolve(name: string): unknown;
|
|
14
|
+
current(events: readonly SessionEvent[]): string;
|
|
15
|
+
set(session: Session, preset: string): void;
|
|
16
|
+
/** Client presentation metadata for one preset; may reject unknown names. */
|
|
17
|
+
optionOf?(name: string): {
|
|
18
|
+
name: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
} | undefined;
|
|
21
|
+
}
|
|
22
|
+
/** Read the optional Harness service without importing its runtime package. */
|
|
23
|
+
export declare function permissionPresetsFrom(ctx: Context): PermissionPresetsService | undefined;
|
|
24
|
+
/** Effective label for either an active session or the not-yet-created first one. */
|
|
25
|
+
export declare function effectivePermission(service: PermissionPresetsService, session: Session | undefined, pending: string | undefined): string;
|
|
26
|
+
/** Validate a preset and write it only when a durable session already exists. */
|
|
27
|
+
export declare function selectPermission(service: PermissionPresetsService, session: Session | undefined, preset: string): string;
|
|
28
|
+
/** Cycle table order from the active, pending, or configured-default value. */
|
|
29
|
+
export declare function cyclePermission(service: PermissionPresetsService, session: Session | undefined, pending: string | undefined): string;
|
|
30
|
+
/** Materialize a pre-session choice after Harness creates the first session. */
|
|
31
|
+
export declare function applyPendingPermission(service: PermissionPresetsService, session: Session, pending: string | undefined): void;
|
|
32
|
+
/**
|
|
33
|
+
* List every switchable preset for the /permission panel, table order kept.
|
|
34
|
+
* Description lookup failures degrade to an undocumented row, never a failed
|
|
35
|
+
* panel load — `optionOf` rejects names its table no longer knows.
|
|
36
|
+
*/
|
|
37
|
+
export declare function listPermissionRows(service: PermissionPresetsService): readonly PermissionRow[];
|
package/lib/types/presets.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare function agentPresetsFrom(ctx: Context): AgentPresetsService | un
|
|
|
26
26
|
export declare function isBlankSession(events: readonly SessionEvent[]): boolean;
|
|
27
27
|
/** Latest logged selection wins; legacy sessions deliberately fall back to standard. */
|
|
28
28
|
export declare function resolvePreset(session: Pick<Session, 'header' | 'events'>): string;
|
|
29
|
+
/** Resolve a pre-session choice, or recompose an active blank Agent. */
|
|
30
|
+
export declare function selectPreset(service: AgentPresetsService, agent: Agent | undefined, presetId: string): Promise<PresetRow>;
|
|
29
31
|
/** Recompose atomically from the caller's perspective, logging only success. */
|
|
30
32
|
export declare function switchPreset(service: AgentPresetsService, agent: Agent, presetId: string): Promise<PresetRow>;
|
|
31
33
|
/** Minimal handle shape used by lifecycle tests without exposing Agent internals. */
|