dsh-code 1.0.4 → 1.0.6
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 +287 -286
- package/README.md +16 -13
- package/bin/deepseek.mjs +336 -11
- package/cordis.patch.yml +26 -18
- package/lib/index.mjs +1310 -439
- package/lib/types/app.d.ts +25 -6
- package/lib/types/attachments.d.ts +36 -4
- package/lib/types/git-workflow.d.ts +7 -2
- package/lib/types/history.d.ts +18 -11
- package/lib/types/index.d.ts +11 -2
- package/lib/types/presets.d.ts +4 -1
- package/lib/types/provider-settings.d.ts +6 -11
- package/lib/types/questions.d.ts +16 -12
- package/lib/types/render/animations.d.ts +74 -7
- package/lib/types/render/export.d.ts +0 -6
- package/lib/types/render/fuzzy.d.ts +21 -0
- package/lib/types/render/projection.d.ts +47 -5
- package/lib/types/session-directory.d.ts +48 -13
- package/lib/types/settings-file.d.ts +8 -0
- package/lib/types/store.d.ts +3 -0
- package/package.json +168 -159
- package/src/app.ts +480 -199
- package/src/attachments.ts +110 -11
- package/src/commands.ts +35 -5
- package/src/git-workflow.ts +29 -10
- package/src/history.ts +22 -13
- package/src/index.ts +1868 -1752
- package/src/internals.ts +61 -40
- package/src/permissions.ts +1 -1
- package/src/presets.ts +19 -6
- package/src/provider-settings.ts +12 -12
- package/src/questions.ts +57 -74
- package/src/render/animations.ts +606 -403
- package/src/render/export.ts +20 -10
- package/src/render/fuzzy.ts +83 -0
- package/src/render/projection.ts +1833 -1620
- package/src/session-directory.ts +94 -16
- package/src/settings-file.ts +38 -6
- package/src/skills.ts +23 -9
- package/src/store.ts +39 -1
- package/src/subagents.ts +26 -3
package/lib/types/app.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { type ReactElement } from 'react';
|
|
17
17
|
import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
|
|
18
|
-
import type { ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
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
21
|
import type { TranscriptStore } from './store.ts';
|
|
@@ -35,7 +35,7 @@ import type { PluginRow } from './plugin-inventory.ts';
|
|
|
35
35
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
36
36
|
import type { GitDiffView } from './git-workflow.ts';
|
|
37
37
|
import { type ProviderAuthorizationDirectory, type ProviderAuthorizationRow } from './authorization.ts';
|
|
38
|
-
import { type ImagePathInspection } from './attachments.ts';
|
|
38
|
+
import { type FilePathInspection, type ImagePathInspection } from './attachments.ts';
|
|
39
39
|
/** Visual priority for one bounded local notice. */
|
|
40
40
|
export type NoticeTone = 'info' | 'warning' | 'error';
|
|
41
41
|
/** Props the runner hands the app; callbacks stay owned by the runner. */
|
|
@@ -70,10 +70,20 @@ export interface AppProps {
|
|
|
70
70
|
mode: string;
|
|
71
71
|
/** Permission preset selected for the current or pending first session. */
|
|
72
72
|
permission: string;
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Submit one line: slash commands to the registry, other text to the agent.
|
|
75
|
+
* The optional origin names the session the submission was composed for —
|
|
76
|
+
* an attachment prepare resolves after the app remounted onto another
|
|
77
|
+
* session, and the runner drops the stale delivery then.
|
|
78
|
+
*/
|
|
79
|
+
dispatch(text: string, attachments?: readonly ContentBlock[], origin?: string): void;
|
|
80
|
+
/** Submit steering, with the same stale-delivery guard as {@link dispatch}. */
|
|
81
|
+
steer(text: string, attachments?: readonly ContentBlock[], origin?: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* The FULL current session identity ('' while the first session is pending)
|
|
84
|
+
* — the stale-delivery origin above. Distinct from the short display id.
|
|
85
|
+
*/
|
|
86
|
+
sessionKey: string;
|
|
77
87
|
/** Interrupt the running turn (Esc); true when a turn was cancelled. */
|
|
78
88
|
interrupt(): boolean;
|
|
79
89
|
/** Quit: unmount, flush, and request process exit. */
|
|
@@ -86,6 +96,10 @@ export interface AppProps {
|
|
|
86
96
|
inspectImages(paths: readonly string[]): Promise<readonly ImagePathInspection[]>;
|
|
87
97
|
/** Validate, normalize and persist images immediately before submission. */
|
|
88
98
|
prepareImages(paths: readonly string[], signal?: AbortSignal): Promise<readonly ImageBlock[]>;
|
|
99
|
+
/** Validate draft non-image file paths without committing attachment objects. */
|
|
100
|
+
inspectFiles(paths: readonly string[]): Promise<readonly FilePathInspection[]>;
|
|
101
|
+
/** Persist non-image files immediately before submission as durable file blocks. */
|
|
102
|
+
prepareFiles(paths: readonly string[], signal?: AbortSignal): Promise<readonly FileBlock[]>;
|
|
89
103
|
/** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
|
|
90
104
|
selectModel(row: ModelRow, effortId?: string): string;
|
|
91
105
|
/** The /subagent override label, '' when delegated agents follow the current model. */
|
|
@@ -166,6 +180,11 @@ export interface AppProps {
|
|
|
166
180
|
saveStatusline(items: readonly string[]): void;
|
|
167
181
|
/** Apply and persist one /theme selection; the runner owns the theme.json file. */
|
|
168
182
|
saveTheme?(name: ThemeName): void;
|
|
183
|
+
/** Whether timed animations run at startup (animations.json; on by default
|
|
184
|
+
* — like parseAnimationsPref, only an explicit false disables them). */
|
|
185
|
+
animations?: boolean;
|
|
186
|
+
/** Apply and persist one /animation toggle; the runner owns the file. */
|
|
187
|
+
saveAnimations?(enabled: boolean): void;
|
|
169
188
|
/** Persistent cross-session input history (oldest first); the runner owns the file. */
|
|
170
189
|
history: readonly string[];
|
|
171
190
|
/** Persist one submitted prompt to the global history file. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/** Terminal image-file adapter over the Harness durable attachment service. */
|
|
1
|
+
/** Terminal image- and file-attachment adapter over the Harness durable attachment service. */
|
|
2
2
|
import type { AttachmentStore, ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
3
|
-
import type { ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import type { FileBlock, ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
4
4
|
/** A validated path retained in the editor until submission persists it. */
|
|
5
5
|
export interface ImagePathInspection {
|
|
6
6
|
readonly path: string;
|
|
@@ -8,13 +8,45 @@ export interface ImagePathInspection {
|
|
|
8
8
|
readonly mediaType: ImageMediaType;
|
|
9
9
|
readonly bytes: number;
|
|
10
10
|
}
|
|
11
|
+
/** A validated non-image file path retained the same way (0.1.5 file blocks). */
|
|
12
|
+
export interface FilePathInspection {
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly bytes: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Terminal-side file admission bounds. Upstream exposes image limits through
|
|
19
|
+
* the attachment service but no file limits (files ride verbatim storage);
|
|
20
|
+
* these keep a dragged file from silently ingesting a disk-sized blob and
|
|
21
|
+
* bound one message the way the image batch is bounded.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MAX_FILE_BYTES: number;
|
|
24
|
+
export declare const MAX_FILES_PER_MESSAGE = 8;
|
|
11
25
|
/** Detect the supported encoded raster formats from bytes, never from a path suffix. */
|
|
12
26
|
export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
|
|
13
27
|
/** Whether a path-like token is worth probing as an image attachment. */
|
|
14
28
|
export declare function looksLikeImagePath(path: string): boolean;
|
|
15
|
-
/**
|
|
16
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Parse a paste/drop into its image and file paths: image-suffixed tokens
|
|
31
|
+
* stay images, other path-shaped tokens ride as file attachments (0.1.5
|
|
32
|
+
* file blocks), and anything that is neither leaves both empty — the caller
|
|
33
|
+
* then treats the paste as plain text.
|
|
34
|
+
*
|
|
35
|
+
* File tokens are held to an absolute-path-with-shape bar (drive/backslash
|
|
36
|
+
* or a dot-suffixed leaf after a separator): a dropped terminal path always
|
|
37
|
+
* carries one of those, while prose, slash commands, and option flags never
|
|
38
|
+
* do. A POSIX absolute path without any dot-suffixed leaf falls through as
|
|
39
|
+
* text — the @ mention route still attaches such files deliberately.
|
|
40
|
+
*/
|
|
41
|
+
export declare function parsePastedAttachmentPaths(input: string): {
|
|
42
|
+
readonly images: readonly string[];
|
|
43
|
+
readonly files: readonly string[];
|
|
44
|
+
};
|
|
17
45
|
/** Validate path, byte size and encoded signature without writing an attachment object. */
|
|
18
46
|
export declare function inspectImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined, cwd?: string): Promise<readonly ImagePathInspection[]>;
|
|
19
47
|
/** Read, validate, and persist an ordered image path list as model content blocks. */
|
|
20
48
|
export declare function saveImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined, signal?: AbortSignal): Promise<readonly ImageBlock[]>;
|
|
49
|
+
/** Validate path and byte size for non-image file attachments without writing. */
|
|
50
|
+
export declare function inspectFilePaths(paths: readonly string[], attachments: AttachmentStore | undefined, cwd?: string): Promise<readonly FilePathInspection[]>;
|
|
51
|
+
/** Read and persist an ordered non-image file path list as model file blocks. */
|
|
52
|
+
export declare function saveFilePaths(paths: readonly string[], attachments: AttachmentStore | undefined, signal?: AbortSignal): Promise<readonly FileBlock[]>;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Read-only Git inspection used by /diff and /review. Every diff
|
|
3
|
+
* invocation carries --no-ext-diff and --no-textconv, so configured
|
|
4
|
+
* external diff drivers and text converters can never execute as a
|
|
5
|
+
* side effect of reading a diff.
|
|
6
|
+
*/
|
|
2
7
|
export interface GitDiffSpec {
|
|
3
8
|
readonly label: string;
|
|
4
9
|
readonly args: readonly string[];
|
|
@@ -18,7 +23,7 @@ export declare function parseGitDiffFiles(text: string): readonly GitDiffFile[];
|
|
|
18
23
|
/** Parse the intentionally small, option-safe /diff argument vocabulary. */
|
|
19
24
|
export declare function parseGitDiffSpec(argument: string): GitDiffSpec;
|
|
20
25
|
/**
|
|
21
|
-
* Load one complete textual diff without invoking external
|
|
26
|
+
* Load one complete textual diff without invoking external programs.
|
|
22
27
|
* @param signal - aborted by the caller on session switches/quit, killing the
|
|
23
28
|
* git subprocess instead of letting a stale repository's diff land later.
|
|
24
29
|
*/
|
package/lib/types/history.d.ts
CHANGED
|
@@ -21,14 +21,21 @@ export declare function serializeHistoryEntry(text: string): string;
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function parseHistoryFile(raw: string, max?: number): readonly string[];
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
24
|
+
* The append unit for the persistent file: one JSON line, so a multi-line
|
|
25
|
+
* draft still occupies exactly one physical line. Each submission appends
|
|
26
|
+
* this unit at the end of the file, so concurrent terminals add entries
|
|
27
|
+
* after each other. Node chunks one append at 512 KiB: a pasted entry
|
|
28
|
+
* beyond that size could interleave mid-line with another writer's
|
|
29
|
+
* chunks, and the damaged line then drops out at the next parse —
|
|
30
|
+
* recall tolerates the loss by design.
|
|
31
|
+
*/
|
|
32
|
+
export declare function historyLine(text: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the file on disk differs from its canonical form (deduped and
|
|
35
|
+
* capped). True means stale lines have accumulated and the next boot
|
|
36
|
+
* should rewrite it once, atomically.
|
|
30
37
|
*/
|
|
31
|
-
export declare function
|
|
38
|
+
export declare function needsCompaction(raw: string, max?: number): boolean;
|
|
32
39
|
/**
|
|
33
40
|
* Record one in-session submission: empty text is ignored and an adjacent
|
|
34
41
|
* duplicate collapses (Codex `record_local_submission` semantics). The local
|
|
@@ -40,10 +47,10 @@ export declare function appendHistoryContent(current: string, text: string, max?
|
|
|
40
47
|
*/
|
|
41
48
|
export declare function recordLocalEntry(local: readonly string[], text: string, max?: number): readonly string[];
|
|
42
49
|
/**
|
|
43
|
-
* Serialize a capped entry list to the history file format (one JSON line
|
|
44
|
-
* entry, trailing newline). The
|
|
45
|
-
*
|
|
46
|
-
*
|
|
50
|
+
* Serialize a capped entry list to the history file format (one JSON line
|
|
51
|
+
* per entry, trailing newline). The boot-time compaction writes this
|
|
52
|
+
* canonical form once when stale lines have accumulated; submissions
|
|
53
|
+
* themselves only ever append a single line.
|
|
47
54
|
* @param entries - the entries to persist, oldest first.
|
|
48
55
|
* @returns the file content, '' for an empty list.
|
|
49
56
|
*/
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
12
|
import z from '@deepseek-ai/schemastery';
|
|
13
|
-
import { type
|
|
13
|
+
import { type ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
14
14
|
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
15
15
|
import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
|
|
16
16
|
import type { TuiStartup } from './startup.ts';
|
|
@@ -74,8 +74,17 @@ export declare function runQuitSequence(steps: readonly QuitCleanupStep[], exit:
|
|
|
74
74
|
export interface QueuedSubmission {
|
|
75
75
|
readonly text: string;
|
|
76
76
|
readonly mode: 'followup' | 'steer';
|
|
77
|
-
readonly images: readonly
|
|
77
|
+
readonly images: readonly ContentBlock[];
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Whether a tagged submission still belongs to the active session. Attachment
|
|
81
|
+
* prepares resolve on the microtask timeline, while a queued session switch
|
|
82
|
+
* remounts the app asynchronously — the composing instance's unmount cleanup
|
|
83
|
+
* runs too late to abort, so the delivery itself carries the composing
|
|
84
|
+
* session's full id and the runner drops it here when the world moved on.
|
|
85
|
+
* An untagged (synchronous) or pending-session ('') submission always passes.
|
|
86
|
+
*/
|
|
87
|
+
export declare function submissionBelongsToSession(origin: string | undefined, activeSessionId: string | undefined): boolean;
|
|
79
88
|
/**
|
|
80
89
|
* Order-preserving gate for composer input while the startup prompt/images
|
|
81
90
|
* are still preparing. Anything submitted before the startup delivery settles
|
package/lib/types/presets.d.ts
CHANGED
|
@@ -11,8 +11,11 @@ export type AgentPresetsService = AgentPresets;
|
|
|
11
11
|
export declare function agentPresetsFrom(ctx: Context): AgentPresetsService | undefined;
|
|
12
12
|
/** A preset may change only before the first durable turn begins. */
|
|
13
13
|
export declare function isBlankSession(events: readonly SessionEvent[]): boolean;
|
|
14
|
+
/** Translate a preset id recorded before an upstream rename to its current id. */
|
|
15
|
+
export declare function normalizePresetId(id: string): string;
|
|
16
|
+
export declare function normalizePresetId(id: string | undefined): string | undefined;
|
|
14
17
|
/** Latest logged selection wins; legacy sessions deliberately fall back to standard. */
|
|
15
|
-
export declare function resolvePreset(session: Pick<Session, 'header' | '
|
|
18
|
+
export declare function resolvePreset(session: Pick<Session, 'header' | 'snapshotEvents'>): string;
|
|
16
19
|
/** Resolve a pre-session choice, or recompose an active blank Agent. */
|
|
17
20
|
export declare function selectPreset(service: AgentPresetsService, agent: Agent | undefined, presetId: string): Promise<PresetRow>;
|
|
18
21
|
/** Recompose atomically from the caller's perspective, logging only success. */
|
|
@@ -78,17 +78,6 @@ export interface DiscoveredModelView {
|
|
|
78
78
|
/** Output cap when disclosed. */
|
|
79
79
|
readonly maxTokens?: number;
|
|
80
80
|
}
|
|
81
|
-
/** One model an endpoint reported about itself (mirrors LlmDiscoveredModel). */
|
|
82
|
-
export interface DiscoveredModelView {
|
|
83
|
-
/** Model id the endpoint accepts. */
|
|
84
|
-
readonly id: string;
|
|
85
|
-
/** Human-readable name when the endpoint supplies one. */
|
|
86
|
-
readonly name?: string;
|
|
87
|
-
/** Context window when disclosed; adoption still owes it if absent. */
|
|
88
|
-
readonly contextWindow?: number;
|
|
89
|
-
/** Output cap when disclosed. */
|
|
90
|
-
readonly maxTokens?: number;
|
|
91
|
-
}
|
|
92
81
|
/**
|
|
93
82
|
* The seven canonical reasoning levels a reasoningEfforts key may name -
|
|
94
83
|
* pi-ai's THINKING_LEVELS. A pi-ai upgrade that adds or removes one fails
|
|
@@ -153,6 +142,12 @@ export interface ProviderTargetView {
|
|
|
153
142
|
readonly configuration: ProviderConfiguration;
|
|
154
143
|
/** The owning adapter reports this route as hand-declared (absent when it draws no distinction). */
|
|
155
144
|
readonly declared?: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Configuration diagnostic the adapter reported for this route (catalog or
|
|
147
|
+
* profile damage): the row stays listed and repairable instead of the whole
|
|
148
|
+
* provider vanishing; absent when the route reads clean.
|
|
149
|
+
*/
|
|
150
|
+
readonly diagnostic?: string;
|
|
156
151
|
}
|
|
157
152
|
/** The resolved provider/settings/credential join. */
|
|
158
153
|
export interface ProviderSettingsDirectory {
|
package/lib/types/questions.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The terminal ask_user_question
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* The terminal ask_user_question answerer: one `user-questions/request`
|
|
3
|
+
* waterfall listener that drives a FIFO queue — one question request on
|
|
4
|
+
* screen at a time, everything else waiting — then resolves the collected
|
|
5
|
+
* answers back into the waterfall. Mirrors the approval answerer's claim/
|
|
6
|
+
* defer split: only agents this TUI owns are answered, every other request
|
|
7
|
+
* falls through to the next answerer.
|
|
8
8
|
*
|
|
9
|
-
* Plan reviews (`exit_plan_mode`) arrive through the same
|
|
9
|
+
* Plan reviews (`exit_plan_mode`) arrive through the same waterfall with an
|
|
10
10
|
* `intent: { kind: 'plan-review' }` — the renderer highlights the approve
|
|
11
11
|
* option; the answer encoding is identical either way.
|
|
12
12
|
*
|
|
13
13
|
* @module @deepseek-ai/dsh-code/questions
|
|
14
14
|
*/
|
|
15
15
|
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
16
17
|
import { type AskUserQuestionAnswer, type AskUserQuestionRequest } from '@deepseek-ai/dsh-user-questions';
|
|
17
18
|
/** One question request waiting on the human, with its settle channels. */
|
|
18
19
|
export interface PendingQuestion {
|
|
@@ -42,9 +43,12 @@ export interface QuestionStore {
|
|
|
42
43
|
cancel(pending: PendingQuestion): void;
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
45
|
-
* Mount the
|
|
46
|
-
* @param ctx - context
|
|
47
|
-
* @
|
|
48
|
-
*
|
|
46
|
+
* Mount the `user-questions/request` answerer over a FIFO queue.
|
|
47
|
+
* @param ctx - plugin context whose event bus carries the waterfall.
|
|
48
|
+
* @param owns - agents this terminal answers for; every other request is
|
|
49
|
+
* deferred back into the waterfall (`next()`), so sibling answerers stay
|
|
50
|
+
* usable. Agent-less asks are claimed: this TUI is the only human surface
|
|
51
|
+
* in the process.
|
|
52
|
+
* @returns the store the renderer subscribes to.
|
|
49
53
|
*/
|
|
50
|
-
export declare function mountQuestionProvider(ctx: Context): QuestionStore;
|
|
54
|
+
export declare function mountQuestionProvider(ctx: Context, owns: (agent: Agent) => boolean): QuestionStore;
|
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
* marker keeps the tier accent afterwards (persistent, like Codex's prompt
|
|
14
14
|
* charge). Pure functions only — the Ink layer owns timers and colors.
|
|
15
15
|
*
|
|
16
|
+
* Wave and Pulse deliberately extend the Codex port after in-terminal
|
|
17
|
+
* testing: the per-row phase cascade was removed (Codex tints each column
|
|
18
|
+
* across the whole band), Wave became a WATER SURFACE — one continuous sine
|
|
19
|
+
* swell spanning the band, mirror-symmetric about the center column, its
|
|
20
|
+
* crests flowing outward from the center with a symmetric fade envelope
|
|
21
|
+
* (the deepseek tier adds one faster harmonic crossing it), painted with
|
|
22
|
+
* Aurora's recipe: wide soft gradients, mirrored second-hue mixing, and a
|
|
23
|
+
* low alpha cap — no hard core line — while Pulse became true
|
|
24
|
+
* two-dimensional, cell-aspect-corrected detonations: soft wide rings whose
|
|
25
|
+
* color grades across their width, expanding outward through a symmetric
|
|
26
|
+
* fade envelope and each trailing an echo ripple in the next blue. Aurora
|
|
27
|
+
* keeps Codex's geometry verbatim.
|
|
28
|
+
*
|
|
16
29
|
* @module @deepseek-ai/dsh-code/render/animations
|
|
17
30
|
*/
|
|
18
31
|
import type { RgbTriple } from '../theme.ts';
|
|
@@ -41,6 +54,8 @@ export declare function deepDivingGradientColor(index: number, tick: number, gra
|
|
|
41
54
|
export declare function deepDivingSparkIntensity(tick: number): number;
|
|
42
55
|
/** Blue RGB color for the breathing Deep diving sparkle. */
|
|
43
56
|
export declare function deepDivingSparkColor(tick: number, base: RgbTriple, highlight: RgbTriple): RgbTriple;
|
|
57
|
+
/** Caret blink cadence: one blink step (on or off) per tick. */
|
|
58
|
+
export declare const CARET_BLINK_TICK_MS = 530;
|
|
44
59
|
/** Caret visibility: half the ticks on, half off (530ms blink). */
|
|
45
60
|
export declare function caretVisible(tick: number): boolean;
|
|
46
61
|
/**
|
|
@@ -71,8 +86,34 @@ export type DeepseekWaveTier = 'flash' | 'deepseek' | 'unknown';
|
|
|
71
86
|
* One style is picked at random per trigger and never repeats the previous.
|
|
72
87
|
*/
|
|
73
88
|
export type DeepseekWaveStyle = 'wave' | 'aurora' | 'pulse';
|
|
74
|
-
/**
|
|
75
|
-
|
|
89
|
+
/**
|
|
90
|
+
* The water surface: ONE continuous sine line spanning the whole band,
|
|
91
|
+
* mirror-symmetric about the center column, its crests flowing OUTWARD from
|
|
92
|
+
* the center (phase k·|x − center| − ω·t). No sweep window, no return trip —
|
|
93
|
+
* the surface fades in, flows, and fades out, symmetric in both space and
|
|
94
|
+
* time. The deepseek tier adds one faster, finer HARMONIC line whose crests
|
|
95
|
+
* cross the fundamental's: interleaved richness with both lines still
|
|
96
|
+
* symmetric and still only ever flowing outward.
|
|
97
|
+
*/
|
|
98
|
+
export declare const WAVE_SURFACE_AMPLITUDE = 0.8;
|
|
99
|
+
export declare const WAVE_SURFACE_HARMONIC = 0.45;
|
|
100
|
+
export declare const WAVE_SURFACE_WAVELENGTH = 40;
|
|
101
|
+
export declare const WAVE_SURFACE_OMEGA = 9;
|
|
102
|
+
/** Vertical thickness in lane units — Aurora-wide: soft gradients, no hard edges. */
|
|
103
|
+
export declare const WAVE_SURFACE_THICKNESS = 1.2;
|
|
104
|
+
/**
|
|
105
|
+
* The mirrored second-hue profile: the space BELOW the surface carries a
|
|
106
|
+
* second blue at this strength, so color (not just brightness) varies
|
|
107
|
+
* continuously across the wave — Aurora-style hue mixing instead of a
|
|
108
|
+
* single flat tint.
|
|
109
|
+
*/
|
|
110
|
+
export declare const WAVE_SURFACE_MIRROR = 0.6;
|
|
111
|
+
/** Aurora-style soft alpha: low gain, capped well under the pulse ring's. */
|
|
112
|
+
export declare const WAVE_SURFACE_ALPHA_GAIN = 0.45;
|
|
113
|
+
export declare const WAVE_SURFACE_ALPHA_CAP = 0.68;
|
|
114
|
+
/** Aurora-grade soft alpha for the detonation — a notch above the swell. */
|
|
115
|
+
export declare const PULSE_ALPHA_GAIN = 0.45;
|
|
116
|
+
export declare const PULSE_ALPHA_CAP = 0.72;
|
|
76
117
|
/** Sparkle glyphs in frame order — Codex SPARK_GLYPHS (`· ✦ ✧`). */
|
|
77
118
|
export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"];
|
|
78
119
|
/**
|
|
@@ -98,9 +139,11 @@ export declare function deepseekWaveDuration(tier: DeepseekWaveTier, style?: Dee
|
|
|
98
139
|
*/
|
|
99
140
|
export declare function deepseekWaveStyleRandom(previous: DeepseekWaveStyle | undefined): DeepseekWaveStyle;
|
|
100
141
|
/**
|
|
101
|
-
* Tier for a `provider/model` label: a
|
|
142
|
+
* Tier for a `provider/model` label: a MODEL ID containing `flash` runs the
|
|
102
143
|
* single-band flash tier; everything else (pro/reasoner/chat) runs the
|
|
103
|
-
* dual-band deepseek tier. Mirrors Codex's Max→Ultra mapping.
|
|
144
|
+
* dual-band deepseek tier. Mirrors Codex's Max→Ultra mapping. Only the model
|
|
145
|
+
* segment (after the `/`) is matched, so a provider whose name contains
|
|
146
|
+
* `flash` cannot flip an unrelated model onto the flash tier.
|
|
104
147
|
* @param model - the `provider/model` label of the applied model.
|
|
105
148
|
* @returns the wave tier for that model.
|
|
106
149
|
*/
|
|
@@ -139,9 +182,13 @@ export declare function envelope(elapsed: number, total: number, fadeIn: number,
|
|
|
139
182
|
* blends the mixed hue toward the blank-cell base at the style's alpha cap,
|
|
140
183
|
* and Aurora applies its own fade envelope. Returns `null` when the column
|
|
141
184
|
* should stay transparent, so the row returns to no `backgroundColor` on
|
|
142
|
-
* both ends. With `rows > 1
|
|
143
|
-
*
|
|
144
|
-
*
|
|
185
|
+
* both ends. With `rows > 1`: Wave is a water surface — every column
|
|
186
|
+
* lights the row nearest the surface's current height, so the light reads
|
|
187
|
+
* as ONE continuous wavy line spanning the band, symmetric about the center
|
|
188
|
+
* column and flowing outward (a single-row band falls back to a flat glow);
|
|
189
|
+
* Pulse rings in two dimensions around the band's center cell with trailing
|
|
190
|
+
* echo ripples; only Aurora samples the timeline shifted by a per-row phase
|
|
191
|
+
* offset.
|
|
145
192
|
* @param tick - wave frame (0, 1, … at DEEPSEEK_WAVE_TICK_MS).
|
|
146
193
|
* @param column - column index in the content row (0..width-1).
|
|
147
194
|
* @param width - content-row width in columns.
|
|
@@ -196,3 +243,23 @@ export declare function isOfficialDeepSeekLabel(label: string): boolean;
|
|
|
196
243
|
* @returns whether the effort ranks above high.
|
|
197
244
|
*/
|
|
198
245
|
export declare function effortAboveHigh(effort: string | undefined): boolean;
|
|
246
|
+
/**
|
|
247
|
+
* Parse a persisted animations preference (`animations.json`): timed
|
|
248
|
+
* animations are on by default and only an explicit `false` disables them —
|
|
249
|
+
* a missing key, corrupt value, or absent file all mean enabled, so the
|
|
250
|
+
* /animation toggle degrades exactly like every other user preference.
|
|
251
|
+
* @param value - the raw parsed JSON value (expected boolean).
|
|
252
|
+
* @returns whether timed animations should run.
|
|
253
|
+
*/
|
|
254
|
+
export declare function parseAnimationsPref(value: unknown): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* One parsed `/animation` argument: '' toggles, `on|true|1` enables,
|
|
257
|
+
* `off|false|0` disables (case-insensitive, surrounding whitespace ignored),
|
|
258
|
+
* and anything else is a usage error the caller surfaces. Kept pure so the
|
|
259
|
+
* command's entire decision table is unit-testable.
|
|
260
|
+
* @param argument - the raw text after `/animation`.
|
|
261
|
+
* @returns `{ enabled }`, `'toggle'`, or `'usage'`.
|
|
262
|
+
*/
|
|
263
|
+
export declare function parseAnimationsArgument(argument: string): {
|
|
264
|
+
enabled: boolean;
|
|
265
|
+
} | 'toggle' | 'usage';
|
|
@@ -6,10 +6,4 @@
|
|
|
6
6
|
* @module @deepseek-ai/dsh-code/render/export
|
|
7
7
|
*/
|
|
8
8
|
import { type TranscriptView } from './projection.ts';
|
|
9
|
-
/**
|
|
10
|
-
* Render the transcript as a standalone markdown document.
|
|
11
|
-
* @param view - the folded transcript view to export.
|
|
12
|
-
* @param sessionId - the full session identity for the header.
|
|
13
|
-
* @returns the complete markdown text.
|
|
14
|
-
*/
|
|
15
9
|
export declare function buildExportMarkdown(view: TranscriptView, sessionId: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared fuzzy ranking for `/` and `@` menu candidates: the query must be a
|
|
3
|
+
* case-insensitive ordered subsequence of the candidate name. Prefix hits
|
|
4
|
+
* rank first, then the strongest alignment score, then the source order of
|
|
5
|
+
* the input. Ported from the upstream web client's ui-primitives
|
|
6
|
+
* (rank-by-name.ts) so the terminal matches the web menu's discovery feel;
|
|
7
|
+
* the algorithm is unchanged, only the module's home moved.
|
|
8
|
+
*
|
|
9
|
+
* @module @deepseek-ai/dsh-code/render/fuzzy
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Rank named items by a menu query.
|
|
13
|
+
* @param items - candidates in source order (the caller's composition order
|
|
14
|
+
* is the final tie-breaker, e.g. local commands before registry entries).
|
|
15
|
+
* @param rawQuery - the text typed after the trigger, matched case-insensitively.
|
|
16
|
+
* @returns the matching items: prefix hits first, then by alignment score,
|
|
17
|
+
* then in source order. The input list itself for an empty query.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rankByName<T extends {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
}>(items: readonly T[], rawQuery: string): readonly T[];
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module @deepseek-ai/dsh-tui/render/projection
|
|
8
8
|
*/
|
|
9
|
-
import { type ImageBlock, type MessageId } from '@deepseek-ai/dsh-llm';
|
|
10
|
-
import type {
|
|
9
|
+
import { type ImageBlock, type MessageId, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
10
|
+
import type { FileAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
11
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
12
|
+
import type { TodoItem } from '@deepseek-ai/dsh-tool-todo';
|
|
11
13
|
import { type ToolDetail } from './tool-detail.ts';
|
|
12
14
|
/** One user prompt line. */
|
|
13
15
|
export interface UserEntry {
|
|
@@ -19,6 +21,8 @@ export interface UserEntry {
|
|
|
19
21
|
notice: boolean;
|
|
20
22
|
/** Durable image references carried by this prompt. */
|
|
21
23
|
images?: readonly ImageBlock['attachment'][];
|
|
24
|
+
/** Durable file references carried by this prompt (0.1.5 file blocks). */
|
|
25
|
+
files?: readonly FileAttachmentRef[];
|
|
22
26
|
}
|
|
23
27
|
/** One user message waiting in the agent inbox (the web's queued-message row). */
|
|
24
28
|
export interface PendingEntry {
|
|
@@ -31,6 +35,8 @@ export interface PendingEntry {
|
|
|
31
35
|
text: string;
|
|
32
36
|
/** Durable image references queued with this prompt. */
|
|
33
37
|
images?: readonly ImageBlock['attachment'][];
|
|
38
|
+
/** Durable file references queued with this prompt (0.1.5 file blocks). */
|
|
39
|
+
files?: readonly FileAttachmentRef[];
|
|
34
40
|
}
|
|
35
41
|
/** One authoritative assembled assistant reply. */
|
|
36
42
|
export interface AssistantEntry {
|
|
@@ -217,7 +223,7 @@ export interface TranscriptStats {
|
|
|
217
223
|
export interface TranscriptView {
|
|
218
224
|
/** Settled entries in log order. */
|
|
219
225
|
entries: readonly TranscriptEntry[];
|
|
220
|
-
/** Bounded text tail accumulated from
|
|
226
|
+
/** Bounded text tail accumulated from live stream frames since the last settlement. */
|
|
221
227
|
streaming: string;
|
|
222
228
|
/** Bounded thinking tail accumulated from reasoning deltas since the last flush. */
|
|
223
229
|
streamingReasoning: string;
|
|
@@ -248,6 +254,13 @@ export interface TranscriptView {
|
|
|
248
254
|
permission: string;
|
|
249
255
|
/** Latest session title folded from the last `session/title` event, empty before one. */
|
|
250
256
|
title: string;
|
|
257
|
+
/**
|
|
258
|
+
* Effective system prompt assembled from `system/message` surface nodes
|
|
259
|
+
* (v3): the head node's text joined with every later non-empty node, blank
|
|
260
|
+
* lines between. Empty before the first system node or when every node is
|
|
261
|
+
* empty ("no system prompt").
|
|
262
|
+
*/
|
|
263
|
+
systemPrompt: string;
|
|
251
264
|
/** Sandbox-mode override folded from the last `sandbox/mode` event, empty when never switched. */
|
|
252
265
|
sandbox: string;
|
|
253
266
|
/** Current long-running goal folded from the last `goal/change`, undefined when cleared. */
|
|
@@ -278,12 +291,16 @@ export interface TranscriptView {
|
|
|
278
291
|
turnFiles: Map<number, Set<string>>;
|
|
279
292
|
turnSteps: Map<number, string>;
|
|
280
293
|
turnTools: Map<number, Set<string>>;
|
|
294
|
+
/** Live `system/message` surface nodes by event seq (empty string = an empty node). */
|
|
295
|
+
systemNodes: Map<number, string>;
|
|
281
296
|
};
|
|
282
297
|
}
|
|
283
298
|
/** Human-readable bounded image labels for transcript, inspector, and export surfaces. */
|
|
284
299
|
export declare function imageLabels(images: readonly ImageBlock['attachment'][] | undefined): string;
|
|
285
|
-
/**
|
|
286
|
-
export declare function
|
|
300
|
+
/** Human-readable bounded file labels for the same surfaces (0.1.5 file blocks). */
|
|
301
|
+
export declare function fileLabels(files: readonly FileAttachmentRef[] | undefined): string;
|
|
302
|
+
/** Prompt text with its durable image and file labels, without exposing local paths or bytes. */
|
|
303
|
+
export declare function promptDisplayText(entry: Pick<UserEntry | PendingEntry, 'text' | 'images' | 'files'>): string;
|
|
287
304
|
/** A fresh, empty transcript view. */
|
|
288
305
|
export declare function createTranscriptView(): TranscriptView;
|
|
289
306
|
/**
|
|
@@ -340,6 +357,7 @@ export interface ReplayAccumulator {
|
|
|
340
357
|
plan: boolean;
|
|
341
358
|
permission: string;
|
|
342
359
|
title: string;
|
|
360
|
+
systemPrompt: string;
|
|
343
361
|
sandbox: string;
|
|
344
362
|
goal: GoalFold | undefined;
|
|
345
363
|
stats: TranscriptStats;
|
|
@@ -351,6 +369,8 @@ export interface ReplayAccumulator {
|
|
|
351
369
|
turnFiles: Map<number, Set<string>>;
|
|
352
370
|
turnSteps: Map<number, string>;
|
|
353
371
|
turnTools: Map<number, Set<string>>;
|
|
372
|
+
/** Live `system/message` surface nodes by event seq (empty string = an empty node). */
|
|
373
|
+
systemNodes: Map<number, string>;
|
|
354
374
|
/** Entry-level container operations performed so far (test instrumentation). */
|
|
355
375
|
ops: number;
|
|
356
376
|
}
|
|
@@ -399,6 +419,28 @@ export declare function snapshotReplayView(acc: ReplayAccumulator): TranscriptVi
|
|
|
399
419
|
* @returns the folded view.
|
|
400
420
|
*/
|
|
401
421
|
export declare function projectEvents(events: readonly SessionEvent[]): TranscriptView;
|
|
422
|
+
/**
|
|
423
|
+
* Fold one process-local assistant-stream chunk frame (session-log v2+ keeps
|
|
424
|
+
* durable logs settlement-only; live typing rides the `agent/assistant-stream`
|
|
425
|
+
* agent event). Same first-token anchoring the durable `assistant/chunk` event
|
|
426
|
+
* used to carry: the first non-empty delta anchors the TTFT and empty
|
|
427
|
+
* keep-alive deltas do not count. The caller maps the frame's attempt to the
|
|
428
|
+
* `turn:step` key (the start frame owns turn/step; chunk frames do not).
|
|
429
|
+
* @param acc - the live replay accumulator.
|
|
430
|
+
* @param key - the `turn:step` key the attempt's start frame declared.
|
|
431
|
+
* @param time - the frame's safe-integer timestamp.
|
|
432
|
+
* @param chunk - the model chunk the frame carries.
|
|
433
|
+
* @returns whether the accumulator changed (the store stays silent otherwise).
|
|
434
|
+
*/
|
|
435
|
+
export declare function applyAssistantStreamChunk(acc: ReplayAccumulator, key: string, time: number, chunk: StreamChunk): boolean;
|
|
436
|
+
/**
|
|
437
|
+
* Drop the live streaming tails without a settlement (an `agent/assistant-stream`
|
|
438
|
+
* end frame with an `abandoned` outcome, or a session switch). The next start
|
|
439
|
+
* frame rebuilds from scratch.
|
|
440
|
+
* @param acc - the live replay accumulator.
|
|
441
|
+
* @returns whether any tail text was discarded.
|
|
442
|
+
*/
|
|
443
|
+
export declare function clearAssistantStream(acc: ReplayAccumulator): boolean;
|
|
402
444
|
/**
|
|
403
445
|
* The append-only flush boundary for a transcript view: the count of entries
|
|
404
446
|
* no later event can remove. Entries at or beyond this index are mutable and
|