@fishwithcat/dsh-tui-app 0.0.0-stage → 0.2.2-alpha.2
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.i18n.yaml +79 -0
- package/README.md +245 -2
- package/README.zh.md +246 -0
- package/cordis.patch.yml +67 -0
- package/lib/index.js +7021 -0
- package/lib/startup.js +54 -0
- package/lib/types/ansi.d.ts +109 -0
- package/lib/types/app.d.ts +480 -0
- package/lib/types/clipboard.d.ts +61 -0
- package/lib/types/commands.d.ts +101 -0
- package/lib/types/config.d.ts +35 -0
- package/lib/types/diagnostics.d.ts +23 -0
- package/lib/types/diff.d.ts +37 -0
- package/lib/types/images.d.ts +37 -0
- package/lib/types/index.d.ts +28 -0
- package/lib/types/interactions.d.ts +132 -0
- package/lib/types/measurement.d.ts +18 -0
- package/lib/types/session.d.ts +151 -0
- package/lib/types/shell.d.ts +111 -0
- package/lib/types/startup.d.ts +34 -0
- package/lib/types/subagents.d.ts +75 -0
- package/lib/types/tool-view.d.ts +39 -0
- package/lib/types/transcript.d.ts +216 -0
- package/lib/types/views.d.ts +572 -0
- package/lib/types/watch/client.d.ts +70 -0
- package/lib/types/watch/history.d.ts +25 -0
- package/lib/types/watch/protocol.d.ts +146 -0
- package/lib/types/watch/record.d.ts +50 -0
- package/lib/types/watch/server.d.ts +172 -0
- package/lib/types/watch/viewer.d.ts +128 -0
- package/locale/de.json +6 -0
- package/locale/en.json +6 -0
- package/locale/es.json +6 -0
- package/locale/fr.json +6 -0
- package/locale/ja.json +6 -0
- package/locale/pt.json +6 -0
- package/locale/ru.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +110 -4
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native clipboard text writes and raster image reads.
|
|
3
|
+
*
|
|
4
|
+
* A terminal delivers pasted text through bracketed paste, but no terminal
|
|
5
|
+
* protocol carries image bytes to a full-screen application, so the app asks
|
|
6
|
+
* the platform's own clipboard reader and stages the result in a temporary
|
|
7
|
+
* file. Each reader is a documented external program: `osascript` running the
|
|
8
|
+
* JavaScript automation runtime reads `NSPasteboard` directly on macOS,
|
|
9
|
+
* `System.Windows.Forms.Clipboard` through PowerShell on Windows and WSL,
|
|
10
|
+
* `wl-paste` on Wayland, and `xclip` on X11. The declared media type is the
|
|
11
|
+
* reader's, verified against the decoded bytes by the attachment service, so a
|
|
12
|
+
* mislabeled payload is refused rather than stored.
|
|
13
|
+
* @module @deepseek-ai/dsh-tui-app/clipboard
|
|
14
|
+
*/
|
|
15
|
+
import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
16
|
+
/** One raster image read from the system clipboard, before attachment admission. */
|
|
17
|
+
export interface ClipboardImage {
|
|
18
|
+
/** Encoded image bytes exactly as the platform reader produced them. */
|
|
19
|
+
data: Uint8Array;
|
|
20
|
+
/** Media type the reader declared; admission verifies it against the bytes. */
|
|
21
|
+
mediaType: ImageMediaType;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run one clipboard reader.
|
|
25
|
+
* @param command - the reader program.
|
|
26
|
+
* @param args - its arguments.
|
|
27
|
+
* @param timeoutMs - how long the program may run.
|
|
28
|
+
* @param input - optional UTF-8 text supplied on stdin.
|
|
29
|
+
* @returns the program's stdout, or undefined when it is absent, fails, or times out.
|
|
30
|
+
*/
|
|
31
|
+
export type ClipboardCommandRunner = (command: string, args: readonly string[], timeoutMs: number, input?: string) => Promise<Buffer | undefined>;
|
|
32
|
+
/** Process facts and readers a clipboard read may substitute. */
|
|
33
|
+
export interface ClipboardReadOptions {
|
|
34
|
+
/** Platform to read from. */
|
|
35
|
+
platform?: NodeJS.Platform;
|
|
36
|
+
/** Environment consulted for the display session. */
|
|
37
|
+
env?: NodeJS.ProcessEnv;
|
|
38
|
+
/** Command runner. */
|
|
39
|
+
run?: ClipboardCommandRunner;
|
|
40
|
+
/** Create the path a staging reader writes. */
|
|
41
|
+
stagePath?: () => string;
|
|
42
|
+
/** Read and delete one staged file; undefined when the reader wrote no bytes. */
|
|
43
|
+
readStaged?: (path: string) => Promise<Uint8Array | undefined>;
|
|
44
|
+
}
|
|
45
|
+
/** This process's readers, used for every field a caller substitutes nothing for. */
|
|
46
|
+
export declare const systemClipboard: Required<ClipboardReadOptions>;
|
|
47
|
+
/**
|
|
48
|
+
* Read one image from the system clipboard.
|
|
49
|
+
* @param options - substituted process facts and readers; omitted fields read this process's clipboard.
|
|
50
|
+
* @returns the clipboard image, or undefined when the clipboard holds no accepted image or no reader is available.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readClipboardImage(options?: ClipboardReadOptions): Promise<ClipboardImage | undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* Copy a selection using the local macOS pasteboard, or the terminal elsewhere.
|
|
55
|
+
* @param text - exact selected text, supplied to pbcopy through stdin.
|
|
56
|
+
* @param write - terminal output for the OSC 52 path.
|
|
57
|
+
* @param options - process facts and command runner; defaults to this process.
|
|
58
|
+
* @returns native command success, or true after an unacknowledged OSC 52 write.
|
|
59
|
+
*/
|
|
60
|
+
export declare function copyClipboardText(text: string, write: (data: string) => void, options?: Pick<ClipboardReadOptions, 'platform' | 'env' | 'run'>): Promise<boolean>;
|
|
61
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composer's slash-command surface: the app's own commands, the registry's
|
|
3
|
+
* catalog, and dispatch through `ctx.commands`. A registry command runs against
|
|
4
|
+
* the Agent without creating a model message; the app renders its settled text.
|
|
5
|
+
* @module @deepseek-ai/dsh-tui-app/commands
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import type { AutocompleteProvider, SelectItem } from '@earendil-works/pi-tui';
|
|
9
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
10
|
+
import type { CommandExecution } from '@deepseek-ai/dsh-commands';
|
|
11
|
+
import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
12
|
+
/** One local command the composer handles without the registry. */
|
|
13
|
+
export interface LocalCommand {
|
|
14
|
+
/** Command name without the leading slash. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Discovery description. */
|
|
17
|
+
description: string;
|
|
18
|
+
/** Whether the command takes trailing input. */
|
|
19
|
+
takesInput: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** App-owned commands take precedence over registry commands and skill gestures. */
|
|
22
|
+
export declare const LOCAL_COMMANDS: readonly LocalCommand[];
|
|
23
|
+
/**
|
|
24
|
+
* Parse one slash line.
|
|
25
|
+
* @param line - the composer's submitted text.
|
|
26
|
+
* @returns the command name and the remainder, or undefined when the line is not a command.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseCommand(line: string): {
|
|
29
|
+
name: string;
|
|
30
|
+
input: string;
|
|
31
|
+
} | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Build the completion catalog: the app's commands followed by the registry's
|
|
34
|
+
* effective commands for this Agent.
|
|
35
|
+
* @param ctx - context carrying the command registry.
|
|
36
|
+
* @param agent - the Agent whose scoped commands apply.
|
|
37
|
+
* @returns selectable entries carrying the slash value.
|
|
38
|
+
*/
|
|
39
|
+
export declare function commandCatalog(ctx: Context, agent: Agent): SelectItem[];
|
|
40
|
+
/**
|
|
41
|
+
* Complete leading slash names with commands taking precedence over user-invocable skills.
|
|
42
|
+
* @param ctx - context carrying the optional command and skill registries.
|
|
43
|
+
* @param agent - the Agent whose scoped catalogs apply.
|
|
44
|
+
* @param cwd - workspace used for skill discovery.
|
|
45
|
+
* @returns the editor provider; each request reads the current catalogs and
|
|
46
|
+
* honors cancellation, and completion preserves the token the user typed.
|
|
47
|
+
*/
|
|
48
|
+
export declare function slashAutocomplete(ctx: Context, agent: Agent, cwd: string): AutocompleteProvider;
|
|
49
|
+
/**
|
|
50
|
+
* Execute one registry command against the owning Agent.
|
|
51
|
+
* @param ctx - context carrying the command registry.
|
|
52
|
+
* @param agent - the Agent the command targets.
|
|
53
|
+
* @param line - the full command line, including the leading slash.
|
|
54
|
+
* @param signal - cancellation lifetime of the dispatch.
|
|
55
|
+
* @returns the settled execution, or undefined when the name is unknown.
|
|
56
|
+
*/
|
|
57
|
+
export declare function executeCommand(ctx: Context, agent: Agent, line: string, signal: AbortSignal): Promise<CommandExecution | undefined>;
|
|
58
|
+
/** One selectable model route. */
|
|
59
|
+
export interface ModelChoice {
|
|
60
|
+
/** Registered provider route. */
|
|
61
|
+
provider: string;
|
|
62
|
+
/** Provider-owned model id. */
|
|
63
|
+
model: string;
|
|
64
|
+
/** Label shown in the picker. */
|
|
65
|
+
label: string;
|
|
66
|
+
/** Supporting detail shown beside the label. */
|
|
67
|
+
description: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* List the model routes the live LLM registry advertises.
|
|
71
|
+
* @param ctx - context carrying the LLM registry.
|
|
72
|
+
* @returns one choice per reachable provider model, in registry order; providers that fail discovery are omitted.
|
|
73
|
+
*/
|
|
74
|
+
export declare function listModelChoices(ctx: Context): Promise<ModelChoice[]>;
|
|
75
|
+
/** One selectable reasoning effort, or the routed model's provider default. */
|
|
76
|
+
export interface EffortChoice {
|
|
77
|
+
/** Opaque effort id the adapter accepts, or undefined to send no effort. */
|
|
78
|
+
effort: ReasoningEffortId | undefined;
|
|
79
|
+
/** Label shown in the picker. */
|
|
80
|
+
label: string;
|
|
81
|
+
/** Supporting detail shown beside the label. */
|
|
82
|
+
description: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* List the reasoning efforts one routed model declares.
|
|
86
|
+
*
|
|
87
|
+
* A route whose adapter declares no efforts has no effort control at all. A
|
|
88
|
+
* route that declares efforts without a default also accepts the provider's own
|
|
89
|
+
* behavior, which the first choice clears back to; when the adapter does
|
|
90
|
+
* declare a default, selecting that effort is the same request, so no separate
|
|
91
|
+
* clear is offered.
|
|
92
|
+
* @param ctx - context carrying the LLM registry.
|
|
93
|
+
* @param route - the routed provider and model.
|
|
94
|
+
* @returns the selectable efforts in adapter order, or undefined when the route declares none.
|
|
95
|
+
* @throws when the route has no registered adapter or its metadata is invalid.
|
|
96
|
+
*/
|
|
97
|
+
export declare function listEffortChoices(ctx: Context, route: {
|
|
98
|
+
provider: string;
|
|
99
|
+
model: string;
|
|
100
|
+
}): Promise<EffortChoice[] | undefined>;
|
|
101
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terminal application's deployment-varying settings.
|
|
3
|
+
* @module @deepseek-ai/dsh-tui-app/config
|
|
4
|
+
*/
|
|
5
|
+
import z from '@deepseek-ai/schemastery';
|
|
6
|
+
/**
|
|
7
|
+
* Where the TUI draws:
|
|
8
|
+
*
|
|
9
|
+
* - `'alternate'` — the alternate screen buffer with the app's own scroll
|
|
10
|
+
* window. The composer and status bar stay pinned and PageUp/PageDown scroll
|
|
11
|
+
* the transcript; the terminal's own scrollback is untouched.
|
|
12
|
+
* - `'inline'` — the terminal's normal screen. The transcript grows past the
|
|
13
|
+
* viewport and the terminal's native scrollback keeps the history, while the
|
|
14
|
+
* composer stays at the bottom.
|
|
15
|
+
*/
|
|
16
|
+
export type TuiScreen = 'alternate' | 'inline';
|
|
17
|
+
/**
|
|
18
|
+
* Which palette the surface renders with:
|
|
19
|
+
*
|
|
20
|
+
* - `'auto'` — follow the terminal background signal when the host exports one,
|
|
21
|
+
* otherwise the dark palette.
|
|
22
|
+
* - `'dark'` / `'light'` — pin the palette, for a host that gives no signal or
|
|
23
|
+
* one the user disagrees with.
|
|
24
|
+
*/
|
|
25
|
+
export type TuiColorScheme = 'auto' | 'dark' | 'light';
|
|
26
|
+
/** The terminal application's settings. */
|
|
27
|
+
export interface Config {
|
|
28
|
+
/** Screen strategy; see {@link TuiScreen}. */
|
|
29
|
+
screen: TuiScreen;
|
|
30
|
+
/** Palette selection; see {@link TuiColorScheme}. */
|
|
31
|
+
colorScheme: TuiColorScheme;
|
|
32
|
+
}
|
|
33
|
+
/** Validated settings for the `tui-app` row. */
|
|
34
|
+
export declare const Config: z<Config>;
|
|
35
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console capture for a surface that owns the terminal.
|
|
3
|
+
*
|
|
4
|
+
* A full-screen TUI writes its frame through the terminal object, so a
|
|
5
|
+
* `console` call reaches the same device outside the renderer. The text lands on
|
|
6
|
+
* whatever row the cursor occupies, and the differential renderer leaves it
|
|
7
|
+
* there until that row's own content changes. The capture replaces the console
|
|
8
|
+
* methods for the lifetime of the surface and hands each formatted write to a
|
|
9
|
+
* sink that puts it where the renderer controls it.
|
|
10
|
+
* @module @deepseek-ai/dsh-tui-app/diagnostics
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Replace the process console methods until the returned function restores them.
|
|
14
|
+
*
|
|
15
|
+
* The wrapper formats arguments the way the console would have printed them and
|
|
16
|
+
* never writes to the terminal itself. It is installed before the renderer
|
|
17
|
+
* starts and removed after the renderer has restored the screen, so its sink
|
|
18
|
+
* runs only while the surface owns the terminal.
|
|
19
|
+
* @param sink - receives each plain-text message; an empty message reports nothing.
|
|
20
|
+
* @returns the idempotent restore function.
|
|
21
|
+
*/
|
|
22
|
+
export declare function captureConsole(sink: (text: string) => void): () => void;
|
|
23
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure file-diff model for the transcript: turns the `FileDiff` hunks a
|
|
3
|
+
* mutation Tool declared into the row list the terminal draws, recovering the
|
|
4
|
+
* context/added/removed role of each line from the hunk's two sides.
|
|
5
|
+
* @module @deepseek-ai/dsh-tui-app/diff
|
|
6
|
+
*/
|
|
7
|
+
import type { FileDiff } from '@deepseek-ai/dsh-tools';
|
|
8
|
+
/** Role of one rendered diff row. */
|
|
9
|
+
export type DiffRowKind = 'path' | 'gap' | 'context' | 'added' | 'removed';
|
|
10
|
+
/** One rendered diff row: its role and its verbatim text. */
|
|
11
|
+
export interface DiffRow {
|
|
12
|
+
kind: DiffRowKind;
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
/** A file diff's complete body plus the heading figures. */
|
|
16
|
+
export interface DiffCard {
|
|
17
|
+
/** Every body row, in file order, before any height fold. */
|
|
18
|
+
rows: DiffRow[];
|
|
19
|
+
/** Added lines across every hunk. */
|
|
20
|
+
added: number;
|
|
21
|
+
/** Removed lines across every hunk. */
|
|
22
|
+
removed: number;
|
|
23
|
+
/** Distinct paths the hunks touch. */
|
|
24
|
+
files: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the body rows and heading figures for a list of declared hunks.
|
|
28
|
+
*
|
|
29
|
+
* A single-file card omits the path row because its heading already names the
|
|
30
|
+
* file; a card spanning several files opens each file with its path, and a
|
|
31
|
+
* later hunk of the same file opens with a gap marker, since the two hunks are
|
|
32
|
+
* not adjacent lines.
|
|
33
|
+
* @param diffs - the hunks a mutation Tool declared, in tool order.
|
|
34
|
+
* @returns the rows, the +/- totals, and the distinct-file count.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildDiffCard(diffs: readonly FileDiff[]): DiffCard;
|
|
37
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composer image markers: the text token that stands for one held clipboard
|
|
3
|
+
* image, and the fold that turns a submitted line back into its model-visible
|
|
4
|
+
* text and its ordered images.
|
|
5
|
+
*
|
|
6
|
+
* The composer is a text editor, so an image it holds needs a text
|
|
7
|
+
* representation that survives editing: a marker the user can delete like any
|
|
8
|
+
* other character, and that a submission reads back to decide which images the
|
|
9
|
+
* prompt still cites.
|
|
10
|
+
* @module @deepseek-ai/dsh-tui-app/images
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The marker text the composer holds for the image numbered `index`.
|
|
14
|
+
* @param index - the image's marker number, counted from one within the draft.
|
|
15
|
+
* @returns the marker the composer inserts and a submission reads back.
|
|
16
|
+
*/
|
|
17
|
+
export declare function imageMarker(index: number): string;
|
|
18
|
+
/** One submitted composer line split into its text and the images it cites. */
|
|
19
|
+
export interface MarkedPrompt {
|
|
20
|
+
/** The submitted line without the markers of images it still cites. */
|
|
21
|
+
text: string;
|
|
22
|
+
/** Cited image numbers, in first-appearance order and without duplicates. */
|
|
23
|
+
indices: number[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Read a submitted line's image markers.
|
|
27
|
+
*
|
|
28
|
+
* A marker whose image the composer no longer holds is literal user text and
|
|
29
|
+
* stays in the prompt; a marker the composer still holds is removed, because the
|
|
30
|
+
* image travels as its own content block exactly as it does on the other
|
|
31
|
+
* surfaces.
|
|
32
|
+
* @param line - the submitted composer text.
|
|
33
|
+
* @param pending - image numbers the composer currently holds.
|
|
34
|
+
* @returns the model-visible text and the cited images in content order.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseImageMarkers(line: string, pending: ReadonlySet<number>): MarkedPrompt;
|
|
37
|
+
//# sourceMappingURL=images.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deepseek-ai/dsh-tui-app — the interactive terminal application over
|
|
3
|
+
* `dsh-base`. The bundle patch mounts this row together with its command-line
|
|
4
|
+
* provider; this module requires the launcher's exit request and the provider's
|
|
5
|
+
* parsed invocation, then boots the pi-tui surface against one in-process Agent
|
|
6
|
+
* and leaves process lifetime to the app's own exit request.
|
|
7
|
+
*
|
|
8
|
+
* @module @deepseek-ai/dsh-tui-app
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import { Config } from './config.ts';
|
|
12
|
+
export { Config };
|
|
13
|
+
export type { TuiColorScheme, TuiScreen } from './config.ts';
|
|
14
|
+
export { internals, TuiApp } from './app.ts';
|
|
15
|
+
export type { TuiAppOptions } from './app.ts';
|
|
16
|
+
export { TUI_STARTUP_SERVICE } from './startup.ts';
|
|
17
|
+
export type { TuiStartupValues } from './startup.ts';
|
|
18
|
+
/** Stable Cordis plugin name. */
|
|
19
|
+
export declare const name = "tui-app";
|
|
20
|
+
/** Services required before the terminal UI can be built, including remembered tool approvals. */
|
|
21
|
+
export declare const inject: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Mount the interactive terminal application.
|
|
24
|
+
* @param ctx - plugin context carrying the session, agent, and launcher services.
|
|
25
|
+
* @param config - validated app settings.
|
|
26
|
+
*/
|
|
27
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal answerers for the two interaction seams the Agent pauses on: tool
|
|
3
|
+
* approvals and structured user questions. Approvals are answered for the
|
|
4
|
+
* app's own Agent and its live subagent descendants; every other Agent's
|
|
5
|
+
* request is delegated, so a composition that also mounts another surface
|
|
6
|
+
* keeps its own answerers authoritative. Always allow records a per-tool grant
|
|
7
|
+
* on the app's own root Agent, covering every live descendant. Questions stay
|
|
8
|
+
* restricted to the app's own Agent because a delegated child cannot ask them.
|
|
9
|
+
* A timed question is claimed through the user-questions service so this
|
|
10
|
+
* surface owns the countdown; a window that closes without an answer settles
|
|
11
|
+
* the call as pending, leaving it answerable as a late reply. A question's
|
|
12
|
+
* options end in a free-text `Other…` row, Escape skips the question, and
|
|
13
|
+
* Ctrl+C cancels the whole ask.
|
|
14
|
+
* @module @deepseek-ai/dsh-tui-app/interactions
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
import type { SelectItem } from '@earendil-works/pi-tui';
|
|
18
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
19
|
+
import type { AskUserQuestionAnswerItem, AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions';
|
|
20
|
+
import type { PromptTitle } from './views.ts';
|
|
21
|
+
/** A heading that is a fixed value, or a provider the surface re-evaluates as it repaints. */
|
|
22
|
+
export type InteractionTitle = PromptTitle;
|
|
23
|
+
/**
|
|
24
|
+
* How one modal prompt settled.
|
|
25
|
+
*
|
|
26
|
+
* `skip` is Escape's own outcome, distinct from `cancel` only because a question
|
|
27
|
+
* batch advances past a skipped question while a cancelled one is abandoned;
|
|
28
|
+
* every other caller treats the two alike.
|
|
29
|
+
*/
|
|
30
|
+
export type PromptOutcome<T> = {
|
|
31
|
+
readonly kind: 'answer';
|
|
32
|
+
readonly value: T;
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: 'skip';
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: 'cancel';
|
|
37
|
+
};
|
|
38
|
+
/** The terminal surfaces the answerers drive. */
|
|
39
|
+
export interface InteractionHost {
|
|
40
|
+
/**
|
|
41
|
+
* Ask the user to choose one item.
|
|
42
|
+
* @param title - the question shown above the list; a provider is re-evaluated on every repaint.
|
|
43
|
+
* @param items - the selectable items.
|
|
44
|
+
* @param signal - cancellation lifetime; aborting cancels the prompt.
|
|
45
|
+
* @param detail - markdown shown above the list, scrollable with Up/Down, PageUp/PageDown, and the wheel.
|
|
46
|
+
* @returns how the prompt settled: the chosen item, Escape's skip, or Ctrl+C's cancel.
|
|
47
|
+
*/
|
|
48
|
+
choose(title: InteractionTitle, items: readonly SelectItem[], signal?: AbortSignal, detail?: string): Promise<PromptOutcome<SelectItem>>;
|
|
49
|
+
/**
|
|
50
|
+
* Ask the user to check any number of items.
|
|
51
|
+
* @param title - the question shown above the list; a provider is re-evaluated on every repaint.
|
|
52
|
+
* @param items - the selectable items.
|
|
53
|
+
* @param signal - cancellation lifetime; aborting cancels the prompt.
|
|
54
|
+
* @param detail - markdown shown above the list, scrollable with Up/Down, PageUp/PageDown, and the wheel.
|
|
55
|
+
* @returns how the prompt settled: the checked items in list order, Escape's skip, or Ctrl+C's cancel.
|
|
56
|
+
*/
|
|
57
|
+
chooseMany(title: InteractionTitle, items: readonly SelectItem[], signal?: AbortSignal, detail?: string): Promise<PromptOutcome<SelectItem[]>>;
|
|
58
|
+
/**
|
|
59
|
+
* Ask the user for one line of text.
|
|
60
|
+
* @param title - the question shown above the input; a provider is re-evaluated on every repaint.
|
|
61
|
+
* @param signal - cancellation lifetime; aborting cancels the prompt.
|
|
62
|
+
* @param detail - markdown shown above the input, scrollable with Up/Down, PageUp/PageDown, and the wheel.
|
|
63
|
+
* @returns how the prompt settled: the entered text, Escape's skip, or Ctrl+C's cancel.
|
|
64
|
+
*/
|
|
65
|
+
ask(title: InteractionTitle, signal?: AbortSignal, detail?: string): Promise<PromptOutcome<string>>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Answer approvals for the app's Agent and its live subagent descendants, one
|
|
69
|
+
* request at a time. Any other Agent's request is delegated so a composition
|
|
70
|
+
* that also mounts other surfaces keeps their answerers authoritative. A
|
|
71
|
+
* request withdrawn while the prompt settles is answered `cancelled` and
|
|
72
|
+
* records no grant.
|
|
73
|
+
* @param ctx - the plugin context whose waterfall carries approval requests.
|
|
74
|
+
* @param host - the terminal prompt surface.
|
|
75
|
+
* @param owned - the Agent this app answers for.
|
|
76
|
+
* @returns a disposer removing the listener.
|
|
77
|
+
*/
|
|
78
|
+
export declare function installApprovalAnswerer(ctx: Context, host: InteractionHost, owned: Agent): () => void;
|
|
79
|
+
/** One question's place in the batch it arrived with. */
|
|
80
|
+
export interface QuestionPosition {
|
|
81
|
+
/** Zero-based index of the question. */
|
|
82
|
+
readonly index: number;
|
|
83
|
+
/** Number of questions the batch carries. */
|
|
84
|
+
readonly total: number;
|
|
85
|
+
}
|
|
86
|
+
/** How one question is presented: its cancellation lifetime, timed window, and batch place. */
|
|
87
|
+
export interface AnswerQuestionOptions {
|
|
88
|
+
/** Cancellation lifetime of the whole request; aborting cancels the ask. */
|
|
89
|
+
readonly signal?: AbortSignal | undefined;
|
|
90
|
+
/** Absolute epoch milliseconds a timed window ends at; the heading counts down to it. */
|
|
91
|
+
readonly deadline?: number | undefined;
|
|
92
|
+
/** The question's place in a multi-question batch; a lone question shows none. */
|
|
93
|
+
readonly position?: QuestionPosition | undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Answer one structured question.
|
|
97
|
+
*
|
|
98
|
+
* A question with options opens a picker whose last row is `Other…`: choosing it
|
|
99
|
+
* collects a free-form answer, which replaces a single selection and
|
|
100
|
+
* accompanies a multi-selection. Escape skips the question with an empty
|
|
101
|
+
* selection so the batch advances; Ctrl+C cancels the whole request.
|
|
102
|
+
*
|
|
103
|
+
* A plan review is special: its non-approve choice is not an answer to send
|
|
104
|
+
* back. The terminal has no separate "talk it over" action, so choosing Keep
|
|
105
|
+
* planning means the user kept planning to speak instead — leaving the question
|
|
106
|
+
* unanswered hands the turn back so the agent stays in plan mode and waits for
|
|
107
|
+
* their adjustment rather than revising immediately. Every unanswered path
|
|
108
|
+
* there hands the turn back the same way, while `Other…` carries the user's own
|
|
109
|
+
* feedback to the waiting model.
|
|
110
|
+
* @param host - the terminal prompt surface.
|
|
111
|
+
* @param question - the question to present.
|
|
112
|
+
* @param options - cancellation lifetime, timed window, and batch place.
|
|
113
|
+
* @returns the answer item, or undefined when the user cancelled the prompt or
|
|
114
|
+
* chose to keep planning instead of answering.
|
|
115
|
+
*/
|
|
116
|
+
export declare function answerQuestion(host: InteractionHost, question: AskUserQuestionItem, options?: AnswerQuestionOptions): Promise<AskUserQuestionAnswerItem | undefined>;
|
|
117
|
+
/**
|
|
118
|
+
* Answer structured user questions for one owned Agent. A dismissed prompt
|
|
119
|
+
* fails the asking Tool with the seam's aborted code instead of leaving the
|
|
120
|
+
* request unanswered; a plan review the user keeps planning fails it with the
|
|
121
|
+
* cancelled code, the one plan mode reads as "the user took the turn back".
|
|
122
|
+
*
|
|
123
|
+
* A timed request is claimed and counted down by this surface: an unanswered or
|
|
124
|
+
* dismissed window resolves the Tool's pending result rather than failing it,
|
|
125
|
+
* so the question stays answerable through `/questions`.
|
|
126
|
+
* @param ctx - the plugin context whose waterfall carries question requests.
|
|
127
|
+
* @param host - the terminal prompt surface.
|
|
128
|
+
* @param owned - the Agent this app answers for.
|
|
129
|
+
* @returns a disposer removing the listener.
|
|
130
|
+
*/
|
|
131
|
+
export declare function installQuestionAnswerer(ctx: Context, host: InteractionHost, owned: Agent): () => void;
|
|
132
|
+
//# sourceMappingURL=interactions.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Shared projection-to-footer measurements for interactive and watched sessions. */
|
|
2
|
+
import type { ProjectionSnapshot } from '@deepseek-ai/dsh-session-projection';
|
|
3
|
+
import type { TuiContextStatus, TuiSessionStats } from './views.ts';
|
|
4
|
+
/** Footer facts derived from one projection snapshot. */
|
|
5
|
+
export interface TuiMeasurement {
|
|
6
|
+
/** Context occupancy, absent until the meter reports both a pressure and a capacity. */
|
|
7
|
+
context: TuiContextStatus | undefined;
|
|
8
|
+
/** Whole-log throughput and token totals; zero counts render nothing. */
|
|
9
|
+
stats: TuiSessionStats;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Convert registered usage projections to terminal footer facts.
|
|
13
|
+
* @param values - projection values at one committed log position, if available.
|
|
14
|
+
* @param automatic - whether the owning engine compacts automatically.
|
|
15
|
+
* @returns available context occupancy and whole-log token figures.
|
|
16
|
+
*/
|
|
17
|
+
export declare function measureUsage(values: ProjectionSnapshot['values'] | undefined, automatic: boolean): TuiMeasurement;
|
|
18
|
+
//# sourceMappingURL=measurement.d.ts.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One interactive session: create or resume the single Agent this TUI drives,
|
|
3
|
+
* submit prompts, switch the model route, and tear the Agent down. The registry
|
|
4
|
+
* handle is the app's ownership capability, so no other consumer can dispose
|
|
5
|
+
* this Agent.
|
|
6
|
+
* @module @deepseek-ai/dsh-tui-app/session
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import type { Agent, ModelSelection } from '@deepseek-ai/dsh-agent';
|
|
10
|
+
import type { ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
11
|
+
import type { Session, SessionEvent, SessionId } from '@deepseek-ai/dsh-session';
|
|
12
|
+
/** One delegated child as the `/subagents` listing reports it. */
|
|
13
|
+
export interface TuiSubagent {
|
|
14
|
+
/** Durable child session id, also the argument `dsh watch` takes. */
|
|
15
|
+
readonly id: SessionId;
|
|
16
|
+
/** Catalog mode recorded by the parent when the child was created. */
|
|
17
|
+
readonly mode: 'one-shot' | 'continuable' | 'external' | 'unknown';
|
|
18
|
+
/** Durable creation label; absent for an unlabeled one-shot or external child. */
|
|
19
|
+
readonly label?: string;
|
|
20
|
+
/** Edge distance from this session; direct children are 1. */
|
|
21
|
+
readonly depth: number;
|
|
22
|
+
/** Whether the child's current local activation is still running. */
|
|
23
|
+
readonly running: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Invocation facts and route overrides for a session this app opens. */
|
|
26
|
+
export interface TuiSessionOptions {
|
|
27
|
+
/** Working directory recorded on the session and used as the tool workspace root. */
|
|
28
|
+
cwd: string;
|
|
29
|
+
/** Provider override from the command line, absent when the deployment default applies. */
|
|
30
|
+
provider?: string | undefined;
|
|
31
|
+
/** Model override from the command line, absent when the deployment default applies. */
|
|
32
|
+
model?: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** One live interactive session and the Agent behind it. */
|
|
35
|
+
export declare class TuiSession {
|
|
36
|
+
private readonly ctx;
|
|
37
|
+
private readonly handle;
|
|
38
|
+
/** Child session ids whose current local activation has not settled yet. */
|
|
39
|
+
private readonly runningSubagents;
|
|
40
|
+
/** Cached descendants, refreshed through the mounted subagent service. */
|
|
41
|
+
private readonly subagentRows;
|
|
42
|
+
/** Failure from the last descendant read; `/subagents` reports it. */
|
|
43
|
+
private subagentError;
|
|
44
|
+
/** In-flight descendant refresh shared by concurrent callers. */
|
|
45
|
+
private subagentRefresh;
|
|
46
|
+
/** A refresh was requested while one was already running. */
|
|
47
|
+
private subagentRefreshQueued;
|
|
48
|
+
/** Retires this session's subagent lifecycle subscriptions. */
|
|
49
|
+
private readonly subagentSubscriptions;
|
|
50
|
+
private constructor();
|
|
51
|
+
/**
|
|
52
|
+
* Create a fresh Agent and its session.
|
|
53
|
+
* @param ctx - context carrying the agent registry and default-model service.
|
|
54
|
+
* @param options - invocation facts and route overrides.
|
|
55
|
+
* @returns the live session.
|
|
56
|
+
*/
|
|
57
|
+
static create(ctx: Context, options: TuiSessionOptions): Promise<TuiSession>;
|
|
58
|
+
/**
|
|
59
|
+
* Resume a stored session under a live Agent.
|
|
60
|
+
* @param ctx - context carrying the agent registry, session store, and persistence.
|
|
61
|
+
* @param sessionId - the stored session to resume.
|
|
62
|
+
* @param options - invocation facts and route overrides.
|
|
63
|
+
* @returns the live session.
|
|
64
|
+
*/
|
|
65
|
+
static resume(ctx: Context, sessionId: string, options: TuiSessionOptions): Promise<TuiSession>;
|
|
66
|
+
/** The Agent this session owns. */
|
|
67
|
+
get agent(): Agent;
|
|
68
|
+
/** The Agent's live session log. */
|
|
69
|
+
get session(): Session;
|
|
70
|
+
/** The route in force for the next step. */
|
|
71
|
+
get route(): ModelSelection;
|
|
72
|
+
/**
|
|
73
|
+
* The stored events that seeded this session at resume, oldest first. The
|
|
74
|
+
* read stops at the Session's first live sequence, so events appended after
|
|
75
|
+
* resume stay with the live `session/event` stream instead of being folded
|
|
76
|
+
* twice.
|
|
77
|
+
* @returns the seed events in sequence order; empty when the deployment mounts no persistence backend.
|
|
78
|
+
* @throws when the backend refuses to open or read the stored session.
|
|
79
|
+
*/
|
|
80
|
+
history(): Promise<readonly SessionEvent[]>;
|
|
81
|
+
/** Whether the Agent currently has work in flight. */
|
|
82
|
+
get running(): boolean;
|
|
83
|
+
/** Whether the Agent or any live subagent descendant has work in flight. */
|
|
84
|
+
get busy(): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Whether any local subagent activation of this session is still running.
|
|
87
|
+
* @returns true while at least one `subagent/start` lacks its `subagent/end`.
|
|
88
|
+
*/
|
|
89
|
+
hasRunningSubagents(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* The delegated children last read through the subagent service, in catalog
|
|
92
|
+
* pre-order. The panel and the footer read this cache; {@link refreshSubagents}
|
|
93
|
+
* updates it without blocking a render.
|
|
94
|
+
* @returns the cached rows; empty until the first refresh settles.
|
|
95
|
+
*/
|
|
96
|
+
subagents(): readonly TuiSubagent[];
|
|
97
|
+
/**
|
|
98
|
+
* The last descendant read's failure, for the panel to report instead of an
|
|
99
|
+
* empty list.
|
|
100
|
+
* @returns the failure message, or undefined after a successful read.
|
|
101
|
+
*/
|
|
102
|
+
subagentsFailure(): string | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Read this session's delegated descendants through `ctx.subagents`, which
|
|
105
|
+
* owns catalog observation, cold-Session reads, and branch diagnostics.
|
|
106
|
+
* Concurrent callers share one refresh; a request that arrives mid-read runs
|
|
107
|
+
* again after it so the cache never settles on a stale catalog.
|
|
108
|
+
* @returns after the cache reflects the latest completed read.
|
|
109
|
+
*/
|
|
110
|
+
refreshSubagents(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Take one pending refresh request.
|
|
113
|
+
* @returns whether another refresh was requested while the last read ran.
|
|
114
|
+
*/
|
|
115
|
+
private consumeRefreshRequest;
|
|
116
|
+
/**
|
|
117
|
+
* Read the service's descendant rows and project them for the terminal.
|
|
118
|
+
* @returns the rows in catalog pre-order.
|
|
119
|
+
* @throws when the composition mounts no subagent service.
|
|
120
|
+
*/
|
|
121
|
+
private readSubagents;
|
|
122
|
+
/**
|
|
123
|
+
* Queue one human prompt as its own turn.
|
|
124
|
+
* @param content - the prompt's content blocks in message order.
|
|
125
|
+
*/
|
|
126
|
+
submit(content: readonly ContentBlock[]): void;
|
|
127
|
+
/**
|
|
128
|
+
* Submit steering that the running turn consumes at its next step, or that
|
|
129
|
+
* starts a turn when the Agent is idle.
|
|
130
|
+
* @param content - the steering content blocks in message order.
|
|
131
|
+
*/
|
|
132
|
+
steer(content: readonly ContentBlock[]): void;
|
|
133
|
+
/**
|
|
134
|
+
* Abort the active turn, drop pending input, and interrupt every running
|
|
135
|
+
* subagent descendant under this Agent's ancestor authority; a user interrupt
|
|
136
|
+
* owns the cause. A composition without the subagent service stops only this
|
|
137
|
+
* Agent, and one child whose interrupt is rejected is logged without keeping
|
|
138
|
+
* its siblings running.
|
|
139
|
+
*/
|
|
140
|
+
cancel(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Switch the route used by later steps.
|
|
143
|
+
* @param route - the new provider and model.
|
|
144
|
+
*/
|
|
145
|
+
selectModel(route: ModelSelection): void;
|
|
146
|
+
/** Drain this session's durable events to storage. */
|
|
147
|
+
flush(): Promise<void>;
|
|
148
|
+
/** Stop the Agent, unregister it, and unwind its scoped world. */
|
|
149
|
+
dispose(): Promise<void>;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=session.d.ts.map
|