dsh-code 0.7.0 → 0.9.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 +30 -7
- package/README.md +30 -7
- package/lib/index.mjs +3791 -853
- package/lib/types/app.d.ts +90 -1
- package/lib/types/approval.d.ts +3 -1
- package/lib/types/history.d.ts +15 -4
- package/lib/types/index.d.ts +48 -0
- package/lib/types/kernel-panels.d.ts +65 -8
- package/lib/types/models.d.ts +15 -1
- 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 +8 -6
- 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 +97 -3
- package/lib/types/render/status.d.ts +26 -36
- 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 +14 -1
- package/lib/types/session-directory.d.ts +61 -2
- package/lib/types/store.d.ts +13 -2
- package/lib/types/subagents.d.ts +60 -0
- package/lib/types/version.d.ts +5 -0
- package/package.json +1 -1
- package/src/app.ts +1200 -219
- package/src/approval.ts +161 -126
- package/src/history.ts +20 -5
- package/src/index.ts +577 -167
- package/src/kernel-panels.ts +354 -37
- package/src/models.ts +26 -0
- 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 +32 -18
- package/src/render/lines.ts +236 -218
- package/src/render/markdown.ts +302 -4
- package/src/render/projection.ts +670 -11
- package/src/render/status.ts +68 -162
- package/src/render/text.ts +28 -9
- package/src/render/tool-detail.ts +81 -40
- package/src/render/tool-preview.ts +77 -34
- package/src/session-directory.ts +171 -10
- package/src/skills.ts +8 -4
- package/src/store.ts +26 -8
- package/src/subagents.ts +165 -0
- package/src/version.ts +16 -0
package/lib/types/app.d.ts
CHANGED
|
@@ -17,13 +17,17 @@ import { type ReactElement } from 'react';
|
|
|
17
17
|
import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
|
|
18
18
|
import { type ThemeName } from './theme.ts';
|
|
19
19
|
import type { TranscriptStore } from './store.ts';
|
|
20
|
+
import { type TranscriptEntry } from './render/projection.ts';
|
|
20
21
|
import type { ApprovalStore } from './approval.ts';
|
|
21
22
|
import type { CommandsView } from './commands.ts';
|
|
22
23
|
import type { ModelDirectory, ModelRow } from './models.ts';
|
|
24
|
+
import type { ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
23
25
|
import type { QuestionStore } from './questions.ts';
|
|
24
26
|
import type { SkillsView, SkillRow } from './skills.ts';
|
|
25
27
|
import type { MentionCandidate } from './mentions.ts';
|
|
28
|
+
import type { SubagentFeedView } from './subagents.ts';
|
|
26
29
|
import type { PresetRow } from './presets.ts';
|
|
30
|
+
import type { PermissionRow } from './permissions.ts';
|
|
27
31
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
28
32
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
29
33
|
/** Visual priority for one bounded local notice. */
|
|
@@ -36,6 +40,8 @@ export interface AppProps {
|
|
|
36
40
|
approval: ApprovalStore;
|
|
37
41
|
/** ask_user_question store fed by the single UI provider. */
|
|
38
42
|
questions: QuestionStore;
|
|
43
|
+
/** Live subagent activity feed (child sessions of the current root). */
|
|
44
|
+
subagents: SubagentFeedView;
|
|
39
45
|
/** Live slash-command descriptor list (completion candidates). */
|
|
40
46
|
commands: CommandsView;
|
|
41
47
|
/** Live user-invocable skill catalog (completion candidates). */
|
|
@@ -54,8 +60,10 @@ export interface AppProps {
|
|
|
54
60
|
sessionId: string;
|
|
55
61
|
/** Whether this session was resumed from persistence. */
|
|
56
62
|
resumed: boolean;
|
|
57
|
-
/** Agent preset
|
|
63
|
+
/** Agent preset selected for the current or pending first session. */
|
|
58
64
|
mode: string;
|
|
65
|
+
/** Permission preset selected for the current or pending first session. */
|
|
66
|
+
permission: string;
|
|
59
67
|
/** Submit one line: slash commands to the registry, other text to the agent. */
|
|
60
68
|
dispatch(text: string): void;
|
|
61
69
|
/** Submit steering: consumed at the running turn's next step boundary. */
|
|
@@ -70,8 +78,28 @@ export interface AppProps {
|
|
|
70
78
|
loadMentions(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
|
|
71
79
|
/** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
|
|
72
80
|
selectModel(row: ModelRow, effortId?: string): string;
|
|
81
|
+
/** The /subagent override label, '' when delegated agents follow the current model. */
|
|
82
|
+
subagentModel: string;
|
|
83
|
+
/** Apply one /subagent model pick; returns the override label. */
|
|
84
|
+
setSubagentModel(row: ModelRow, effortId?: string): string;
|
|
85
|
+
/** Drop the /subagent override (delegated agents follow the current model). */
|
|
86
|
+
clearSubagentModel(): void;
|
|
87
|
+
/** Delete one session subtree; resolves with the outcome line. */
|
|
88
|
+
deleteSession(id: string): Promise<string>;
|
|
89
|
+
/** Load provider/settings/credential facts for the optional /model provider stage. */
|
|
90
|
+
loadModelProviders?(): Promise<ProviderSettingsDirectory>;
|
|
91
|
+
/** Subscribe to Harness credential/settings/adapter invalidations while /model is open. */
|
|
92
|
+
subscribeModelProviders?(listener: () => void): () => void;
|
|
93
|
+
/** Store or rotate one provider credential through the Harness credential service. */
|
|
94
|
+
saveModelProviderCredential?(target: ProviderTargetView, key: string): Promise<void>;
|
|
95
|
+
/** Remove one writable provider credential without removing its settings profile. */
|
|
96
|
+
unsetModelProviderCredential?(target: ProviderTargetView): Promise<void>;
|
|
97
|
+
/** Remove one user-owned provider profile and its page-managed credential. */
|
|
98
|
+
removeModelProvider?(target: ProviderTargetView): Promise<void>;
|
|
73
99
|
/** Cycle to the next permission preset (Shift+Tab); returns the new label. */
|
|
74
100
|
cyclePermission(): string;
|
|
101
|
+
/** Select or inspect a permission preset without requiring a pre-existing session. */
|
|
102
|
+
setPermission(id: string): string;
|
|
75
103
|
/** Export the transcript to a markdown file (/export [path]); reports via notices. */
|
|
76
104
|
exportTranscript(argument: string): Promise<void>;
|
|
77
105
|
/** Rename the session (/title <text>); returns the outcome line for the notice. */
|
|
@@ -79,9 +107,13 @@ export interface AppProps {
|
|
|
79
107
|
/** Preset/session/plugin kernel operations. */
|
|
80
108
|
loadPresets(): Promise<readonly PresetRow[]>;
|
|
81
109
|
switchMode(id: string): Promise<string>;
|
|
110
|
+
/** Load the switchable permission presets for the /permission panel. */
|
|
111
|
+
loadPermissions(): Promise<readonly PermissionRow[]>;
|
|
82
112
|
createSession(mode?: string): void;
|
|
83
113
|
loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
84
114
|
loadSessionTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
115
|
+
/** Load this session's subagent conversations (children by lineage). */
|
|
116
|
+
loadSubagents(): Promise<readonly SessionRow[]>;
|
|
85
117
|
switchSession(row: SessionRow): void;
|
|
86
118
|
cancelSessionSwitch(): boolean;
|
|
87
119
|
loadPlugins(): readonly PluginRow[];
|
|
@@ -123,6 +155,63 @@ interface CompletionCandidate {
|
|
|
123
155
|
* selection window bounds the visible rows, so no slice cap is needed.
|
|
124
156
|
*/
|
|
125
157
|
export declare function completionCandidates(value: string, descriptors: readonly CommandDescriptor[], skills: readonly SkillRow[]): readonly CompletionCandidate[];
|
|
158
|
+
/** One cached settled row: the row Box plus its roomy-prompt spacers. */
|
|
159
|
+
interface SettledRowRecord {
|
|
160
|
+
/** The row Box element (keyed by the entry's settled index). */
|
|
161
|
+
box: ReactElement;
|
|
162
|
+
/** The roomy-prompt spacer BEFORE the row, or undefined. */
|
|
163
|
+
before: ReactElement | undefined;
|
|
164
|
+
/** The roomy-prompt spacer AFTER the row, or undefined. */
|
|
165
|
+
after: ReactElement | undefined;
|
|
166
|
+
/** Whether the row's text depends on the reasoning toggle (Ctrl+R). */
|
|
167
|
+
reasonSensitive: boolean;
|
|
168
|
+
/** The toggle state the row was built with. */
|
|
169
|
+
showReasoning: boolean;
|
|
170
|
+
}
|
|
171
|
+
/** The incremental settled-history cache (see `computeSettledRows`). */
|
|
172
|
+
interface SettledRowsCache {
|
|
173
|
+
/** The exact settled entries the cache covers (`view.entries[0..entries.length)`). */
|
|
174
|
+
entries: TranscriptEntry[];
|
|
175
|
+
/** Records keyed by entry identity; mutated in place so the append path
|
|
176
|
+
* never copies the whole map. */
|
|
177
|
+
records: Map<TranscriptEntry, SettledRowRecord>;
|
|
178
|
+
/** The header element (depends only on `resumed`). */
|
|
179
|
+
header: ReactElement;
|
|
180
|
+
/** The `resumed` the header was built with. */
|
|
181
|
+
resumed: boolean;
|
|
182
|
+
/** The toggle state the rows were built with. */
|
|
183
|
+
showReasoning: boolean;
|
|
184
|
+
/** The refreshEpoch the rows were built for; a bump forces a full rebuild. */
|
|
185
|
+
epoch: number;
|
|
186
|
+
/** The flat row list (header + per-entry before/box/after). */
|
|
187
|
+
flat: ReactElement[];
|
|
188
|
+
}
|
|
189
|
+
/** One step of `computeSettledRows`. */
|
|
190
|
+
interface SettledRowsResult {
|
|
191
|
+
cache: SettledRowsCache;
|
|
192
|
+
/** How many rows had to be BUILT by this step (0 = pure reuse). */
|
|
193
|
+
built: number;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The settled `<Static>` row set as a PURE incremental state machine (App
|
|
197
|
+
* drives it from the memo; tests drive it directly and read `built`).
|
|
198
|
+
*
|
|
199
|
+
* The settled prefix is permanently final: the projection only APPENDS below
|
|
200
|
+
* the flush boundary, removes pending rows at or beyond it, and replaces
|
|
201
|
+
* running tool/retry/command rows there too. So extending the cache never
|
|
202
|
+
* rescans the old prefix — a grown boundary builds ONLY the newly settled
|
|
203
|
+
* suffix and reuses every cached element, letting React bail out of unchanged
|
|
204
|
+
* rows and keeping long histories out of the per-durable-event path (no O(N)
|
|
205
|
+
* rebuild of rows, Map, or MarkdownBody parses). `records` is mutated in place
|
|
206
|
+
* on the append/toggle paths to stay O(delta).
|
|
207
|
+
*
|
|
208
|
+
* Full rebuilds run only on the rare, deliberate paths: no cache yet, a
|
|
209
|
+
* source-backed replay (`epoch` bump: resize / Ctrl+L / Ctrl+R remounts
|
|
210
|
+
* `<Static>` and must re-flush the CURRENT rows), a `resumed` change, or a shrink
|
|
211
|
+
* (`store.reset`). A reasoning toggle rebuilds only the rows whose text
|
|
212
|
+
* depends on it, preserving the other rows' element identity.
|
|
213
|
+
*/
|
|
214
|
+
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number): SettledRowsResult;
|
|
126
215
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
127
216
|
export declare function App(props: AppProps): ReactElement;
|
|
128
217
|
export {};
|
package/lib/types/approval.d.ts
CHANGED
|
@@ -29,10 +29,12 @@ export interface PendingApproval {
|
|
|
29
29
|
}
|
|
30
30
|
/** The pending-question snapshot the renderer subscribes to. */
|
|
31
31
|
export interface ApprovalSnapshot {
|
|
32
|
-
/** The
|
|
32
|
+
/** The question on screen (queue head), or undefined when none is asked. */
|
|
33
33
|
pending: PendingApproval | undefined;
|
|
34
34
|
/** Presentational: an answer was submitted, the ask has not settled yet. */
|
|
35
35
|
answered: boolean;
|
|
36
|
+
/** Further asks waiting behind the on-screen one (FIFO, Codex-style). */
|
|
37
|
+
queued: number;
|
|
36
38
|
}
|
|
37
39
|
/** Store the pending question lands in; the renderer reads, the answerer writes. */
|
|
38
40
|
export interface ApprovalStore {
|
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. */
|
|
@@ -25,9 +27,55 @@ export interface Config {
|
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
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>;
|
|
28
75
|
/**
|
|
29
76
|
* Mount the interactive terminal driver.
|
|
30
77
|
* @param ctx - plugin context carrying core services and the launcher-provided exit request.
|
|
31
78
|
* @param config - validated startup config resolved from the tuiStartup provider.
|
|
32
79
|
*/
|
|
33
80
|
export declare function apply(ctx: Context, config: Config): void;
|
|
81
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
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';
|
|
3
|
+
import type { ModelDirectory, ModelRow } from './models.ts';
|
|
4
|
+
import type { SubagentRow } from './subagents.ts';
|
|
5
|
+
import type { PermissionRow } from './permissions.ts';
|
|
4
6
|
import type { PresetRow } from './presets.ts';
|
|
5
7
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
6
8
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
@@ -11,16 +13,30 @@ export declare function ModePanel({ current, load, select, close }: {
|
|
|
11
13
|
select(id: string): void;
|
|
12
14
|
close(): void;
|
|
13
15
|
}): ReactElement;
|
|
16
|
+
export declare function PermissionPanel({ current, load, select, close }: {
|
|
17
|
+
current: string;
|
|
18
|
+
load(): Promise<readonly PermissionRow[]>;
|
|
19
|
+
select(id: string): void;
|
|
20
|
+
close(): void;
|
|
21
|
+
}): ReactElement;
|
|
14
22
|
export declare function PluginPanel({ load, close, initialQuery }: {
|
|
15
23
|
load(): readonly PluginRow[];
|
|
16
24
|
close(): void;
|
|
17
25
|
initialQuery?: string;
|
|
18
26
|
}): ReactElement;
|
|
19
|
-
export declare function ResumePanel({ currentCwd, load, readTranscript, select, close }: {
|
|
27
|
+
export declare function ResumePanel({ currentCwd, load, readTranscript, select, requestDelete, deleteConfirmId, reloadToken, deleteMode, close }: {
|
|
20
28
|
currentCwd: string;
|
|
21
29
|
load(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
22
30
|
readTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
23
31
|
select(row: SessionRow): void;
|
|
32
|
+
/** Arm the composer-based delete confirm for one row (App owns the keys). */
|
|
33
|
+
requestDelete?(row: SessionRow): void;
|
|
34
|
+
/** The row id awaiting y/n in the composer, when any (App-owned). */
|
|
35
|
+
deleteConfirmId?: string;
|
|
36
|
+
/** Bump to reload the listing (e.g. after a deletion). */
|
|
37
|
+
reloadToken?: number;
|
|
38
|
+
/** Opened via /delete: hint-first delete mode. */
|
|
39
|
+
deleteMode?: boolean;
|
|
24
40
|
close(): void;
|
|
25
41
|
}): ReactElement;
|
|
26
42
|
/**
|
|
@@ -50,12 +66,15 @@ export declare function StatuslinePanel({ enabled, change, close }: {
|
|
|
50
66
|
/**
|
|
51
67
|
* The `/model` reasoning-effort stage (the Codex model → reasoning popup
|
|
52
68
|
* contract): one bounded list over the selected model's adapter-advertised
|
|
53
|
-
* effort levels
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* model
|
|
69
|
+
* effort levels — in the adapter's own display order, ids verbatim (the
|
|
70
|
+
* kernel treats them as opaque and rejects anything else) — with the
|
|
71
|
+
* effective effort and the model default marked. A model WITHOUT an
|
|
72
|
+
* adapter-declared default leads with a "Default" (provider-default) row —
|
|
73
|
+
* the web effort pane's first entry — so the user can clear a picked level
|
|
74
|
+
* back to provider behavior. A model advertising no levels opens the same
|
|
75
|
+
* stage with an explicit empty state (the web pane's "no levels" copy)
|
|
76
|
+
* instead of a bare failure notice. Enter applies one level; Esc returns to
|
|
77
|
+
* the model list without applying.
|
|
59
78
|
*/
|
|
60
79
|
export declare function EffortPanel({ row, current, select, back }: {
|
|
61
80
|
/** The model row whose advertised levels this stage lists. */
|
|
@@ -67,3 +86,41 @@ export declare function EffortPanel({ row, current, select, back }: {
|
|
|
67
86
|
/** Return to the model list without applying. */
|
|
68
87
|
back(): void;
|
|
69
88
|
}): ReactElement;
|
|
89
|
+
/**
|
|
90
|
+
* The /agents panel (the Codex agent-picker contract, read-only): this
|
|
91
|
+
* conversation's subagent conversations — live rows from the activity feed
|
|
92
|
+
* first, persisted children the feed has not seen this process after — with
|
|
93
|
+
* Enter/t opening the child's full transcript in the shared read-only
|
|
94
|
+
* document view (the same projection the exporter uses).
|
|
95
|
+
*/
|
|
96
|
+
export declare function AgentsPanel({ live, load, readTranscript, close }: {
|
|
97
|
+
/** Live feed rows (child sessions observed this process). */
|
|
98
|
+
live: readonly SubagentRow[];
|
|
99
|
+
/** Load this session's persisted child sessions by lineage. */
|
|
100
|
+
load(): Promise<readonly SessionRow[]>;
|
|
101
|
+
/** Read one child session's full transcript as markdown. */
|
|
102
|
+
readTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
103
|
+
close(): void;
|
|
104
|
+
}): ReactElement;
|
|
105
|
+
/**
|
|
106
|
+
* The /subagent model panel: which model configuration delegated subagents
|
|
107
|
+
* run on. The kernel seeds child agents from the parent's CREATE-TIME
|
|
108
|
+
* AgentOptions, so a mid-session /model switch would otherwise leave them on
|
|
109
|
+
* the launch-time route; the TUI mirrors the selection onto subagent-origin
|
|
110
|
+
* requests (or an explicit override picked here) via an agent/request
|
|
111
|
+
* listener. The leading "inherit" row restores follow-the-current-model
|
|
112
|
+
* behavior; picking a model with several advertised efforts opens the same
|
|
113
|
+
* effort stage /model uses. Effort overrides are not offered separately —
|
|
114
|
+
* the kernel's AgentOptions has no effort channel for children, so the level
|
|
115
|
+
* rides the selected model exactly as /model applies it.
|
|
116
|
+
*/
|
|
117
|
+
export declare function SubagentPanel({ current, load, pick, inherit, close }: {
|
|
118
|
+
/** Display label of the override in force, '' when following the current model. */
|
|
119
|
+
current: string;
|
|
120
|
+
load(): Promise<ModelDirectory>;
|
|
121
|
+
/** Apply one model (with an advertised effort, when picked) as the override. */
|
|
122
|
+
pick(row: ModelRow, effortId?: string): void;
|
|
123
|
+
/** Drop the override: subagents follow the current model again. */
|
|
124
|
+
inherit(): void;
|
|
125
|
+
close(): void;
|
|
126
|
+
}): ReactElement;
|
package/lib/types/models.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { Context } from '@deepseek-ai/cordis';
|
|
11
11
|
import type { ModelSelection } from '@deepseek-ai/dsh-agent';
|
|
12
|
-
import { type LlmModelReasoningInfo } from '@deepseek-ai/dsh-llm';
|
|
12
|
+
import { type LlmCallConfig, type LlmModelReasoningInfo } from '@deepseek-ai/dsh-llm';
|
|
13
13
|
/** Display metadata for one adapter-owned reasoning effort (mirrors `LlmReasoningEffortInfo`). */
|
|
14
14
|
export interface ModelReasoningEffort {
|
|
15
15
|
/** Opaque value accepted by the model's `GenerateOptions.reasoningEffort`. */
|
|
@@ -87,6 +87,20 @@ export declare function resolveEffectiveSelection(picked: ModelSelection | undef
|
|
|
87
87
|
export declare function buildModelSelection(row: ModelRow, effortId?: string): ModelSelection;
|
|
88
88
|
/** Display label for one applied selection: `provider/model` or `provider/model@effort`. */
|
|
89
89
|
export declare function modelSelectionLabel(selection: ModelSelection): string;
|
|
90
|
+
/**
|
|
91
|
+
* Apply one model selection onto a resolved request config — the exact
|
|
92
|
+
* semantics of the kernel's `installModelSelection` request listener,
|
|
93
|
+
* extracted so the TUI can mirror it for subagent-origin requests: children
|
|
94
|
+
* spawned by the subagent tool inherit the parent's CREATE-TIME AgentOptions,
|
|
95
|
+
* which a mid-session /model switch never touches, so delegated work would
|
|
96
|
+
* otherwise keep running on the launch-time route. An absent effort strips
|
|
97
|
+
* any inherited effort (restoring the selected model's provider default),
|
|
98
|
+
* matching the kernel listener field-for-field.
|
|
99
|
+
* @param resolved - the config the inner chain produced.
|
|
100
|
+
* @param selection - the selection to enforce.
|
|
101
|
+
* @returns the overridden config.
|
|
102
|
+
*/
|
|
103
|
+
export declare function applyModelSelectionToConfig(resolved: LlmCallConfig, selection: ModelSelection): LlmCallConfig;
|
|
90
104
|
/**
|
|
91
105
|
* Load the selectable model directory from the live `ctx.llm` registry.
|
|
92
106
|
* Providers are listed synchronously; each provider's models are discovered
|
|
@@ -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. */
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider settings adapter for the TUI `/model` provider-management panel:
|
|
3
|
+
* the same-process equivalent of the web host's Models page join
|
|
4
|
+
* (`packages/client/ui-settings-models`), reading the advisory `ctx.llm`
|
|
5
|
+
* registry, the redacted `ctx.settings` descriptors, and the value-free
|
|
6
|
+
* `ctx.credentials` facts directly. Secrets never cross this module: settings
|
|
7
|
+
* are read with `redactSecrets: true`, credentials are only ever described
|
|
8
|
+
* (never resolved), and every message is single-line without embedding key
|
|
9
|
+
* data.
|
|
10
|
+
*
|
|
11
|
+
* @module @deepseek-ai/dsh-tui/provider-settings
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
/**
|
|
15
|
+
* The conventional credential reference for a provider route: `<ROUTE>_API_KEY`
|
|
16
|
+
* with the route uppercased and every non-alphanumeric run collapsed to one
|
|
17
|
+
* underscore — the exact derivation the official Models page uses
|
|
18
|
+
* (`deriveKeyRef` in `ui-settings-models`), so a key saved here is found there.
|
|
19
|
+
* @param provider - provider route id (e.g. `pi-ai`, `minimax-cn`).
|
|
20
|
+
* @returns the derived reference name (e.g. `PI_AI_API_KEY`).
|
|
21
|
+
*/
|
|
22
|
+
export declare function deriveCredentialRef(provider: string): string;
|
|
23
|
+
/** Value-free facts about one credential reference — never the value. */
|
|
24
|
+
export interface ProviderCredentialFacts {
|
|
25
|
+
/** Whether the reference currently resolves to a stored value. */
|
|
26
|
+
readonly configured: boolean;
|
|
27
|
+
/** Source layer supplying the value; absent while unconfigured. */
|
|
28
|
+
readonly source?: string;
|
|
29
|
+
/** Whether a write through this panel would currently succeed. */
|
|
30
|
+
readonly writable: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One row's credential state: value-free facts once the reference was
|
|
34
|
+
* described, a bounded error when that describe failed (the row itself is
|
|
35
|
+
* never dropped), or `undefined` when the row names no reference to describe —
|
|
36
|
+
* an unmanaged active provider, a dormant route, or a profile authenticating
|
|
37
|
+
* through the provider's own path.
|
|
38
|
+
*/
|
|
39
|
+
export type ProviderCredentialView = ({
|
|
40
|
+
readonly kind: 'facts';
|
|
41
|
+
} & ProviderCredentialFacts) | {
|
|
42
|
+
readonly kind: 'error';
|
|
43
|
+
readonly message: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* One provider row in the TUI provider-management panel: the configurable
|
|
47
|
+
* directory entry joined with its settings profile and credential facts.
|
|
48
|
+
* Every mutation below addresses this row, and the caller passes the row back
|
|
49
|
+
* after re-loading so the revision/ref facts are current.
|
|
50
|
+
*/
|
|
51
|
+
export interface ProviderTargetView {
|
|
52
|
+
/** Provider route id (`GenerateOptions.provider`). */
|
|
53
|
+
readonly provider: string;
|
|
54
|
+
/** Human-readable provider name. */
|
|
55
|
+
readonly displayName: string;
|
|
56
|
+
/** Whether an adapter currently serves this route. */
|
|
57
|
+
readonly active: boolean;
|
|
58
|
+
/** User-settings namespace whose section configures this provider; '' when unmanaged. */
|
|
59
|
+
readonly settingsNs: string;
|
|
60
|
+
/** Path from that section's root to this provider's profile; [] when the whole section is the profile. */
|
|
61
|
+
readonly settingsPath: readonly string[];
|
|
62
|
+
/** Revision of the owning settings section at load (0 when no namespace resolved). */
|
|
63
|
+
readonly settingsRevision: number;
|
|
64
|
+
/** Whether the resolved profile exists (the whole section, or at `settingsPath`). */
|
|
65
|
+
readonly configured: boolean;
|
|
66
|
+
/** Whether only the user settings layer carries the profile, so removal restores the base. */
|
|
67
|
+
readonly removable: boolean;
|
|
68
|
+
/** The credential reference the resolved profile names, when one does. */
|
|
69
|
+
readonly credentialRef?: string;
|
|
70
|
+
/** The conventional reference a save uses for a dormant or ref-less profile. */
|
|
71
|
+
readonly suggestedRef: string;
|
|
72
|
+
/** Credential facts, a bounded describe error, or undefined when there is no ref to describe. */
|
|
73
|
+
readonly credential: ProviderCredentialView | undefined;
|
|
74
|
+
/** The owning adapter reports this route as hand-declared (absent when it draws no distinction). */
|
|
75
|
+
readonly declared?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** The resolved provider/settings/credential join. */
|
|
78
|
+
export interface ProviderSettingsDirectory {
|
|
79
|
+
/** Provider rows: configurable-directory order first, active-unmanaged rows after. */
|
|
80
|
+
readonly rows: readonly ProviderTargetView[];
|
|
81
|
+
/** Whether the settings provider accepts writes (mirrors the web page's flag). */
|
|
82
|
+
readonly writable: boolean;
|
|
83
|
+
/** Non-fatal join failures (settings/directory reads), for a degradation notice. */
|
|
84
|
+
readonly failures: readonly string[];
|
|
85
|
+
}
|
|
86
|
+
/** Subscribe to the same provider-directory invalidations as the official Web Models page. */
|
|
87
|
+
export declare function subscribeProviderSettings(ctx: Context, listener: () => void): () => void;
|
|
88
|
+
/** A single-line, bounded error from the provider-management adapter. */
|
|
89
|
+
export declare class ProviderSettingsError extends Error {
|
|
90
|
+
constructor(message: string);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Join the configurable-provider directory, the redacted settings
|
|
94
|
+
* namespaces, and the referenced credentials into panel rows, web-parity:
|
|
95
|
+
* - directory entries merge with `listProviders()` to mark each live or
|
|
96
|
+
* dormant, and routes registered without a directory declaration appear as
|
|
97
|
+
* read-only/unmanaged rows (no settings address);
|
|
98
|
+
* - a whole-section entry is configured whenever its namespace resolves;
|
|
99
|
+
* a path-addressed one only when the profile resolves there;
|
|
100
|
+
* - a row is removable when the user layer alone carries its profile;
|
|
101
|
+
* - only refs named by resolved profiles are described, and a per-ref failure
|
|
102
|
+
* degrades to that row's bounded error instead of losing it.
|
|
103
|
+
* Absent `settings`/`credentials` services are tolerated the same way.
|
|
104
|
+
* @param ctx - context carrying the `llm` service (settings/credentials optional).
|
|
105
|
+
* @returns the resolved directory; empty rows when `llm` is unavailable.
|
|
106
|
+
*/
|
|
107
|
+
export declare function loadProviderSettings(ctx: Context): Promise<ProviderSettingsDirectory>;
|
|
108
|
+
/**
|
|
109
|
+
* Store a provider API key, web-parity: validate with `normalizeApiKey`
|
|
110
|
+
* (single-line, actionable errors that never echo the key), materialize the
|
|
111
|
+
* profile/`apiKeyEnv` through `settings.mutate` first when the resolved
|
|
112
|
+
* profile names no reference (dormant route or ref-less profile), then store
|
|
113
|
+
* under the trusted named ref or the derived conventional ref. An existing
|
|
114
|
+
* whole-section DeepSeek whose resolved profile already names
|
|
115
|
+
* `DEEPSEEK_API_KEY` needs no settings mutation. Env-supplied read-only keys
|
|
116
|
+
* are refused before any service call.
|
|
117
|
+
* @param ctx - context carrying `settings` (when materializing) and `credentials`.
|
|
118
|
+
* @param target - the joined row to write through.
|
|
119
|
+
* @param rawKey - the key exactly as typed; surrounding whitespace is trimmed.
|
|
120
|
+
* @throws {@link ProviderSettingsError} with a single-line, key-free message.
|
|
121
|
+
*/
|
|
122
|
+
export declare function saveProviderCredential(ctx: Context, target: ProviderTargetView, rawKey: string): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Remove the currently named credential without touching the provider
|
|
125
|
+
* profile. Only the resolved profile's own reference is unset; a dormant or
|
|
126
|
+
* ref-less row (nothing to remove), an already-absent key, and an
|
|
127
|
+
* env-supplied read-only key are rejected safely before any service call.
|
|
128
|
+
* @param ctx - context carrying the `credentials` service.
|
|
129
|
+
* @param target - the joined row whose named credential to unset.
|
|
130
|
+
* @throws {@link ProviderSettingsError} with a single-line, key-free message.
|
|
131
|
+
*/
|
|
132
|
+
export declare function unsetProviderCredential(ctx: Context, target: ProviderTargetView): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Remove a user-added provider profile, web-parity: only `removable` rows may
|
|
135
|
+
* be removed; a page-managed credential — the derived ref, configured and
|
|
136
|
+
* writable — is unset first (so a second-step failure leaves the row visible
|
|
137
|
+
* and the operation retryable), then `settings.mutate` unsets
|
|
138
|
+
* `target.settingsPath`. Both steps are idempotent. A hand-named credential
|
|
139
|
+
* ref may be shared elsewhere and is left alone.
|
|
140
|
+
* @param ctx - context carrying `credentials` and `settings`.
|
|
141
|
+
* @param target - the joined row to remove.
|
|
142
|
+
* @throws {@link ProviderSettingsError} with a single-line, key-free message.
|
|
143
|
+
*/
|
|
144
|
+
export declare function removeProviderSettings(ctx: Context, target: ProviderTargetView): Promise<void>;
|
package/lib/types/questions.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface PendingQuestion {
|
|
|
22
22
|
resolve(answers: AskUserQuestionAnswer): void;
|
|
23
23
|
/** Reject the provider promise as aborted (also used for Esc cancel). */
|
|
24
24
|
reject(error: Error): void;
|
|
25
|
+
/** Detach the request's abort listener once the question settles (internal). */
|
|
26
|
+
detachAbort?(): void;
|
|
25
27
|
}
|
|
26
28
|
/** The pending-question snapshot the renderer subscribes to. */
|
|
27
29
|
export interface QuestionSnapshot {
|
|
@@ -73,9 +73,11 @@ export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"];
|
|
|
73
73
|
*/
|
|
74
74
|
export type DeepseekWaveBand = readonly [number, number, number];
|
|
75
75
|
export declare const DEEPSEEK_WAVE_BANDS: Readonly<Record<DeepseekWaveStyle, Readonly<Record<DeepseekWaveTier, readonly DeepseekWaveBand[]>>>>;
|
|
76
|
+
/** Extra display time applied to every Codex ignition style. */
|
|
77
|
+
export declare const DEEPSEEK_WAVE_DURATION_EXTENSION_MS = 200;
|
|
76
78
|
/**
|
|
77
|
-
* Total
|
|
78
|
-
*
|
|
79
|
+
* Total visible duration: the Codex ignition duration plus 200ms so its motion
|
|
80
|
+
* remains readable in a busy terminal.
|
|
79
81
|
* @param tier - the active wave tier.
|
|
80
82
|
* @param style - the active ignition style.
|
|
81
83
|
* @returns the duration in milliseconds.
|
|
@@ -150,11 +152,11 @@ export declare function envelope(elapsed: number, total: number, fadeIn: number,
|
|
|
150
152
|
*/
|
|
151
153
|
export declare function deepseekWaveColumnBg(tick: number, column: number, width: number, tier: DeepseekWaveTier, style: DeepseekWaveStyle, hues: readonly [RgbTriple, RgbTriple, RgbTriple], base: RgbTriple): RgbTriple | null;
|
|
152
154
|
/**
|
|
153
|
-
* The sparkle glyph for a tick — Codex `spark_frame
|
|
154
|
-
*
|
|
155
|
-
*
|
|
155
|
+
* The sparkle glyph for a tick — Codex `spark_frame`, sampled on the same
|
|
156
|
+
* proportionally slowed DeepSeek Wave timeline as the composer background.
|
|
157
|
+
* The Ink layer still must skip occupied cells.
|
|
156
158
|
* @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
|
|
157
|
-
* @returns the sparkle glyph, or null outside the
|
|
159
|
+
* @returns the sparkle glyph, or null outside the stretched tail window.
|
|
158
160
|
*/
|
|
159
161
|
export declare function deepseekWaveSpark(tick: number): string | null;
|
|
160
162
|
/**
|
|
@@ -24,6 +24,12 @@ export declare function styledLines(segments: readonly StyledSegment[], columns:
|
|
|
24
24
|
export declare function textLines(text: string, columns: number, style?: LineStyle): readonly StyledLine[];
|
|
25
25
|
/** Markdown rows re-hardened so a single long word cannot escape the budget. */
|
|
26
26
|
export declare function markdownLines(text: string, columns: number): readonly StyledLine[];
|
|
27
|
+
/**
|
|
28
|
+
* Codex-style reasoning rows: the marker occupies the reply gutter and every
|
|
29
|
+
* wrapped or explicit continuation starts with the same two-column indent, so
|
|
30
|
+
* reasoning content and assistant Markdown share one left edge.
|
|
31
|
+
*/
|
|
32
|
+
export declare function reasoningLines(text: string, columns: number): readonly StyledLine[];
|
|
27
33
|
/**
|
|
28
34
|
* Convert one durable transcript entry to its complete scrollable row model.
|
|
29
35
|
* The source entry stays intact; only the caller's visible slice is rendered.
|