dsh-code 1.3.0 → 1.4.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 +2 -2
- package/README.md +2 -2
- package/lib/index.mjs +5115 -4390
- package/lib/types/app.d.ts +18 -51
- package/lib/types/completion.d.ts +29 -0
- package/lib/types/composer.d.ts +150 -0
- package/lib/types/git-workflow.d.ts +6 -0
- package/lib/types/index.d.ts +6 -188
- package/lib/types/locales/en.d.ts +16 -4
- package/lib/types/{authorization-panel.d.ts → panels/authorization-panel.d.ts} +6 -1
- package/lib/types/panels/completion-panel.d.ts +13 -0
- package/lib/types/panels/interaction-bars.d.ts +38 -0
- package/lib/types/{kernel-panels.d.ts → panels/kernel-panels.d.ts} +16 -37
- package/lib/types/{language-panel.d.ts → panels/language-panel.d.ts} +1 -1
- package/lib/types/panels/model-panels.d.ts +86 -0
- package/lib/types/{theme-panel.d.ts → panels/theme-panel.d.ts} +1 -1
- package/lib/types/{update-panel.d.ts → panels/update-panel.d.ts} +1 -1
- package/lib/types/provider-settings.d.ts +11 -0
- package/lib/types/render/inspector.d.ts +8 -0
- package/lib/types/render/text.d.ts +4 -0
- package/lib/types/runner/harness-gate.d.ts +83 -0
- package/lib/types/runner/input-history.d.ts +31 -0
- package/lib/types/runner/mode-cycle.d.ts +44 -0
- package/lib/types/runner/preferences.d.ts +40 -0
- package/lib/types/runner/quit.d.ts +27 -0
- package/lib/types/runner/search-rows.d.ts +38 -0
- package/lib/types/runner/session-io.d.ts +46 -0
- package/lib/types/runner/session-target.d.ts +42 -0
- package/lib/types/runner/startup-config.d.ts +33 -0
- package/lib/types/runner/submissions.d.ts +87 -0
- package/lib/types/session/attach.d.ts +39 -0
- package/lib/types/{store.d.ts → session/store.d.ts} +1 -1
- package/lib/types/{subagents.d.ts → session/subagents.d.ts} +8 -1
- package/lib/types/settings-file.d.ts +10 -0
- package/lib/types/{panel-accent.d.ts → ui/panel-accent.d.ts} +1 -1
- package/lib/types/ui/panel-gap.d.ts +6 -0
- package/lib/types/ui/query-editor.d.ts +10 -0
- package/lib/types/ui/styled-rows.d.ts +8 -0
- package/lib/types/{terminal-title.d.ts → ui/terminal-title.d.ts} +1 -1
- package/lib/types/ui/ui-contract.d.ts +12 -0
- package/lib/types/ui/use-frames.d.ts +6 -0
- package/lib/types/ui/use-stable-input.d.ts +7 -0
- package/package.json +1 -1
- package/src/app.ts +543 -4066
- package/src/completion.ts +117 -0
- package/src/composer.ts +1956 -0
- package/src/git-workflow.ts +18 -0
- package/src/index.ts +113 -633
- package/src/internals.ts +1 -1
- package/src/locales/en.ts +16 -4
- package/src/locales/zh.ts +16 -4
- package/src/{authorization-panel.ts → panels/authorization-panel.ts} +25 -6
- package/src/panels/completion-panel.ts +79 -0
- package/src/panels/interaction-bars.ts +567 -0
- package/src/{kernel-panels.ts → panels/kernel-panels.ts} +84 -65
- package/src/{language-panel.ts → panels/language-panel.ts} +4 -4
- package/src/panels/model-panels.ts +1021 -0
- package/src/{theme-panel.ts → panels/theme-panel.ts} +5 -5
- package/src/{update-panel.ts → panels/update-panel.ts} +6 -6
- package/src/provider-settings.ts +38 -0
- package/src/render/inspector.ts +23 -0
- package/src/render/text.ts +8 -0
- package/src/runner/harness-gate.ts +168 -0
- package/src/runner/input-history.ts +77 -0
- package/src/runner/mode-cycle.ts +49 -0
- package/src/runner/preferences.ts +67 -0
- package/src/runner/quit.ts +53 -0
- package/src/runner/search-rows.ts +55 -0
- package/src/runner/session-io.ts +206 -0
- package/src/runner/session-target.ts +81 -0
- package/src/runner/startup-config.ts +54 -0
- package/src/runner/submissions.ts +157 -0
- package/src/session/attach.ts +87 -0
- package/src/{session-directory.ts → session/session-directory.ts} +1 -1
- package/src/{store.ts → session/store.ts} +1 -1
- package/src/{subagents.ts → session/subagents.ts} +12 -1
- package/src/settings-file.ts +19 -1
- package/src/{panel-accent.ts → ui/panel-accent.ts} +1 -1
- package/src/ui/panel-gap.ts +9 -0
- package/src/ui/query-editor.ts +16 -0
- package/src/ui/styled-rows.ts +124 -0
- package/src/{terminal-title.ts → ui/terminal-title.ts} +1 -1
- package/src/ui/ui-contract.ts +10 -0
- package/src/ui/use-frames.ts +23 -0
- package/src/ui/use-stable-input.ts +17 -0
- /package/lib/types/{fork.d.ts → session/fork.d.ts} +0 -0
- /package/lib/types/{history.d.ts → session/history.d.ts} +0 -0
- /package/lib/types/{session-directory.d.ts → session/session-directory.d.ts} +0 -0
- /package/lib/types/{session-switch.d.ts → session/session-switch.d.ts} +0 -0
- /package/src/{fork.ts → session/fork.ts} +0 -0
- /package/src/{history.ts → session/history.ts} +0 -0
- /package/src/{session-switch.ts → session/session-switch.ts} +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Submission vocabulary and the startup input gate for the terminal runner.
|
|
2
|
+
*
|
|
3
|
+
* Pure over the handles they are given: the queue mutations and the session
|
|
4
|
+
* guard are decisions the runner applies, and the gate only orders deliveries,
|
|
5
|
+
* so every branch is testable without composing an Agent.
|
|
6
|
+
*
|
|
7
|
+
* @module @deepseek-ai/dsh-code/submissions
|
|
8
|
+
*/
|
|
9
|
+
import { type ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
10
|
+
import type { Agent, AgentStatus, Inbox } from '@deepseek-ai/dsh-agent';
|
|
11
|
+
import type { UserMessage } from '@deepseek-ai/dsh-session';
|
|
12
|
+
import type { QueueMutation } from '../ui/ui-contract.ts';
|
|
13
|
+
/** One composer submission waiting behind the startup delivery. */
|
|
14
|
+
export interface QueuedSubmission {
|
|
15
|
+
readonly text: string;
|
|
16
|
+
/** `steer` inserts into the running turn; `followup` waits for the next one. */
|
|
17
|
+
readonly mode: 'followup' | 'steer';
|
|
18
|
+
readonly images: readonly ContentBlock[];
|
|
19
|
+
}
|
|
20
|
+
/** What one requested queue mutation did; the runner maps it to one notice. */
|
|
21
|
+
export type QueueMutationOutcome = 'removed' | 'edited' | 'steered' | 'unavailable' | 'empty' | 'steerUnavailable';
|
|
22
|
+
/**
|
|
23
|
+
* Replace one queued message's text while keeping its attachments. A queue
|
|
24
|
+
* edit rewrites what the user typed, not what they attached: image and file
|
|
25
|
+
* blocks ride through in delivery order (text first, then attachments, the
|
|
26
|
+
* shape {@link deliverLine} submits). Dropping them here would silently strip
|
|
27
|
+
* an attachment the user already confirmed, so this is the edit's single
|
|
28
|
+
* definition and the panel's read-only marker only mirrors it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function queueEditContent(content: readonly ContentBlock[], text: string): ContentBlock[];
|
|
31
|
+
/**
|
|
32
|
+
* Apply one terminal queue mutation to the live inbox. The decision and the
|
|
33
|
+
* inbox change are pure over the supplied handles so every branch is testable
|
|
34
|
+
* without an agent; steering itself is injected because it wakes the driver
|
|
35
|
+
* rather than mutating the inbox. The durable inbox splices remain the UI's
|
|
36
|
+
* single source of truth — this helper never reports a state the inbox did not
|
|
37
|
+
* actually reach.
|
|
38
|
+
* @param inbox - the live agent inbox (pending lists plus its mutators).
|
|
39
|
+
* @param status - the agent's lifecycle status; steering needs `running`.
|
|
40
|
+
* @param messageId - identity of the queued message to mutate.
|
|
41
|
+
* @param action - the requested mutation.
|
|
42
|
+
* @param steer - submits the removed message as next-step steering.
|
|
43
|
+
* @returns the outcome the caller reports.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyQueueMutation(inbox: Pick<Inbox, 'nextTurn' | 'append' | 'remove' | 'replace'>, status: AgentStatus, messageId: string, action: QueueMutation, steer: (message: UserMessage) => void): QueueMutationOutcome;
|
|
46
|
+
/**
|
|
47
|
+
* Cancel the active turn while keeping the next-turn queue, then wake the
|
|
48
|
+
* driver again so the preserved messages actually run. `cancel` clears
|
|
49
|
+
* pending work by default and never wakes the driver on its own, so the queue
|
|
50
|
+
* is captured first and re-submitted afterwards: a waking submission latches
|
|
51
|
+
* the wake while the aborted activity converges to idle, which is what turns
|
|
52
|
+
* "preserved" into "sent next" instead of "parked forever". Next-step
|
|
53
|
+
* steering is deliberately dropped — it belonged to the cancelled turn.
|
|
54
|
+
* @param agent - the live agent handle.
|
|
55
|
+
* @returns how many queued messages were preserved across the abort.
|
|
56
|
+
*/
|
|
57
|
+
export declare function cancelPreservingQueue(agent: Pick<Agent, 'inbox' | 'cancel' | 'followup'>): number;
|
|
58
|
+
/**
|
|
59
|
+
* Whether a tagged submission still belongs to the active session. Attachment
|
|
60
|
+
* prepares resolve on the microtask timeline, while a queued session switch
|
|
61
|
+
* remounts the app asynchronously — the composing instance's unmount cleanup
|
|
62
|
+
* runs too late to abort, so the delivery itself carries the composing
|
|
63
|
+
* session's full id and the runner drops it here when the world moved on.
|
|
64
|
+
* An untagged (synchronous) or pending-session ('') submission always passes.
|
|
65
|
+
*/
|
|
66
|
+
export declare function submissionBelongsToSession(origin: string | undefined, activeSessionId: string | undefined): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Order-preserving gate for composer input while the startup prompt/images
|
|
69
|
+
* are still preparing. Anything submitted before the startup delivery settles
|
|
70
|
+
* queues and flushes afterwards in submit order, so the initial request can
|
|
71
|
+
* never be overtaken by typing that raced a slow image preparation. The flush
|
|
72
|
+
* also runs when the startup delivery fails: user input is never stranded.
|
|
73
|
+
*/
|
|
74
|
+
export declare class StartupInputGate {
|
|
75
|
+
private readonly deliver;
|
|
76
|
+
private readonly queued;
|
|
77
|
+
private pending;
|
|
78
|
+
constructor(deliver: (submission: QueuedSubmission) => void);
|
|
79
|
+
/** Submit one line: delivered now while idle, queued behind the startup delivery otherwise. */
|
|
80
|
+
submit(submission: QueuedSubmission): void;
|
|
81
|
+
/**
|
|
82
|
+
* Run the startup delivery — the callback receives the direct-delivery sink
|
|
83
|
+
* for the startup prompt itself — then flush everything that queued behind
|
|
84
|
+
* it, in order, even when the callback rejects.
|
|
85
|
+
*/
|
|
86
|
+
run(startup: (deliver: (submission: QueuedSubmission) => void) => Promise<void>): Promise<void>;
|
|
87
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One live attachment to a subagent conversation: a transcript store seeded
|
|
3
|
+
* from the child's durable log and then fed by the process-local event and
|
|
4
|
+
* stream buses in real time. The parent's own store is never touched.
|
|
5
|
+
*
|
|
6
|
+
* @module @deepseek-ai/dsh-code/session/attach
|
|
7
|
+
*/
|
|
8
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
9
|
+
import { type TranscriptStore } from './store.ts';
|
|
10
|
+
/** The bus surfaces one attachment reads; the runner wires these to ctx. */
|
|
11
|
+
export interface SubagentAttachmentServices {
|
|
12
|
+
/** Seed: the child's full durable event log, oldest first. */
|
|
13
|
+
load(id: string, signal?: AbortSignal): Promise<readonly SessionEvent[]>;
|
|
14
|
+
/** Durable events for exactly this child session, live. */
|
|
15
|
+
subscribeEvents(id: string, onEvent: (event: SessionEvent) => void): () => void;
|
|
16
|
+
/** Token stream frames for exactly this child agent, live. */
|
|
17
|
+
subscribeStream(id: string, onFrame: (frame: Parameters<TranscriptStore['applyStreamFrame']>[0]) => void): () => void;
|
|
18
|
+
}
|
|
19
|
+
/** A live child view handed to the App while attached. */
|
|
20
|
+
export interface SubagentAttachment {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly label: string;
|
|
23
|
+
readonly store: TranscriptStore;
|
|
24
|
+
/** Whether the durable seed has landed (frames are held back until then). */
|
|
25
|
+
seeded(): boolean;
|
|
26
|
+
/** Drop the bus subscriptions; the store freezes at its last state. */
|
|
27
|
+
dispose(): void;
|
|
28
|
+
}
|
|
29
|
+
/** An inert empty store keeps the App's external-store hook unconditional. */
|
|
30
|
+
export declare const EMPTY_ATTACH_STORE: TranscriptStore;
|
|
31
|
+
/**
|
|
32
|
+
* Attach to one subagent conversation.
|
|
33
|
+
*
|
|
34
|
+
* Ordering contract: durable events carry a per-session sequence, so the seed
|
|
35
|
+
* sets a watermark and live events at or below it are dropped as duplicates;
|
|
36
|
+
* stream frames are held until the seed lands so a frame whose settlement
|
|
37
|
+
* already arrived cannot resurrect a stale tail.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createSubagentAttachment(services: SubagentAttachmentServices, id: string, label: string): SubagentAttachment;
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
import type { AssistantStreamFrame } from '@deepseek-ai/dsh-agent';
|
|
33
33
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
34
|
-
import { type TranscriptView } from '
|
|
34
|
+
import { type TranscriptView } from '../render/projection.ts';
|
|
35
35
|
/** The externally readable, event-fed transcript store for one session. */
|
|
36
36
|
export interface TranscriptStore {
|
|
37
37
|
/** The current view; the same object identity until an event changes it. */
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* microtask notify chained SyncLane rerenders past React's nested update
|
|
19
19
|
* limit; a bare macrotask merge repaints a whole turn's bursts at once).
|
|
20
20
|
*
|
|
21
|
-
* @module @deepseek-ai/dsh-code/subagents
|
|
21
|
+
* @module @deepseek-ai/dsh-code/session/subagents
|
|
22
22
|
*/
|
|
23
23
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
24
24
|
/** Hard row cap: overflow evicts the oldest settled row; a fully busy feed waits. */
|
|
@@ -68,3 +68,10 @@ export declare function createSubagentFeed(): SubagentFeedView & {
|
|
|
68
68
|
apply(sessionId: string, event: SessionEvent): void;
|
|
69
69
|
reset(): void;
|
|
70
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Root-log catalog facts a resumed session must replay into the subagent
|
|
73
|
+
* feed: constructor seeds never fire on the live bus, so without this the
|
|
74
|
+
* children of a resumed session vanish behind a restart. The empty-child
|
|
75
|
+
* placeholder row (childId '') is a placeholder, not a child, and stays out.
|
|
76
|
+
*/
|
|
77
|
+
export declare function subagentCatalogSeed(events: readonly SessionEvent[]): readonly SessionEvent<'subagent/catalog'>[];
|
|
@@ -39,3 +39,13 @@ export interface UserSettingsPersistence {
|
|
|
39
39
|
* @returns the persistence handle.
|
|
40
40
|
*/
|
|
41
41
|
export declare function createUserSettingsPersistence(): UserSettingsPersistence;
|
|
42
|
+
/**
|
|
43
|
+
* Read one user-level settings file as a plain object. The callers all treat a
|
|
44
|
+
* missing file as "unset" and a corrupt one as "warn and fall back", so this
|
|
45
|
+
* helper owns the one distinction they share: readable JSON that is not an
|
|
46
|
+
* object is corruption, not an absent preference, and must not surface as a
|
|
47
|
+
* cryptic property access on `null`.
|
|
48
|
+
* @param path - absolute path of the settings file.
|
|
49
|
+
* @returns the parsed object; the caller narrows each field itself.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readSettingsObject(path: string): Record<string, unknown>;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module @deepseek-ai/dsh-tui/panel-accent
|
|
12
12
|
*/
|
|
13
|
-
import { type RgbTriple } from '
|
|
13
|
+
import { type RgbTriple } from '../theme.ts';
|
|
14
14
|
/** One panel's resolved accent pair (border and title share the ring color in prismatic). */
|
|
15
15
|
export interface PanelAccent {
|
|
16
16
|
readonly border: RgbTriple;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Shared optional spacer row used by bounded panel layouts. */
|
|
2
|
+
import { type ReactElement } from 'react';
|
|
3
|
+
/** Codex-style panel rhythm that still participates in the row budget. */
|
|
4
|
+
export declare function PanelGap({ visible }: {
|
|
5
|
+
visible: boolean;
|
|
6
|
+
}): ReactElement | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Shared one-line query editor for keyboard-owned filtering panels. */
|
|
2
|
+
/**
|
|
3
|
+
* Apply one keystroke to a panel search query. IME commits arrive as one
|
|
4
|
+
* multi-character chunk, so the whole printable run is appended; paste
|
|
5
|
+
* markers are stripped and control-laden chunks are ignored.
|
|
6
|
+
*/
|
|
7
|
+
export declare function editQuery(query: string, input: string, key: {
|
|
8
|
+
backspace?: boolean;
|
|
9
|
+
delete?: boolean;
|
|
10
|
+
}): string | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Ink renderer for width-safe styled terminal rows. */
|
|
2
|
+
import { type ReactElement } from 'react';
|
|
3
|
+
import type { StyledLine } from '../render/lines.ts';
|
|
4
|
+
/** Render width-safe rows; every child is exactly one terminal row. */
|
|
5
|
+
export declare function StyledRows({ lines }: {
|
|
6
|
+
lines: readonly StyledLine[];
|
|
7
|
+
}): ReactElement;
|
|
8
|
+
/** File-oriented, color-coded unified diff viewport. */
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* an empty OSC payload and the terminal falls back to its own default; the
|
|
11
11
|
* previously set title is not portable to read back and is never restored.
|
|
12
12
|
*
|
|
13
|
-
* @module @deepseek-ai/dsh-code/terminal-title
|
|
13
|
+
* @module @deepseek-ai/dsh-code/ui/terminal-title
|
|
14
14
|
*/
|
|
15
15
|
/** Tab label before a session carries a name. */
|
|
16
16
|
export declare const DEFAULT_TERMINAL_TITLE = "deepseek";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Shared terminal UI contracts used by the runner, App, and composer. */
|
|
2
|
+
/** Visual priority for one bounded local notice. */
|
|
3
|
+
export type NoticeTone = 'info' | 'warning' | 'error';
|
|
4
|
+
/** One mutation the terminal may request for a pending next-turn inbox item. */
|
|
5
|
+
export type QueueMutation = {
|
|
6
|
+
readonly kind: 'remove';
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'edit';
|
|
9
|
+
readonly text: string;
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: 'steer';
|
|
12
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Wall-clock animation frame hook shared by independent terminal leaves. */
|
|
2
|
+
/**
|
|
3
|
+
* Derive ticks from elapsed wall time so a stretched interval skips ahead
|
|
4
|
+
* instead of slowing the animation under a busy event loop or remote shell.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useFrames(intervalMs: number, active?: boolean): number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Stable Ink input subscription for stateful keyboard-owned surfaces. */
|
|
2
|
+
import { type Key } from 'ink';
|
|
3
|
+
/**
|
|
4
|
+
* Ink re-subscribes its input effect whenever the handler identity changes.
|
|
5
|
+
* Keep ownership stable while a surface updates cursor, scroll, or draft state.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useStableInput(handler: (input: string, key: Key) => void, active: boolean): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-code",
|
|
3
3
|
"description": "DeepSeek Harness CLI core bundle: interactive coding terminal, durable sessions, and model management for dsh --profile cli",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"packageManager": "pnpm@12.4.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|