dsh-ssh-tui 0.1.8 → 0.3.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.
@@ -12,10 +12,13 @@ export type SessionPickerResult = {
12
12
  kind: 'new';
13
13
  } | null;
14
14
  /**
15
- * Show the picker and wait for one digit, Enter (new session), or Esc/Ctrl+C
16
- * (cancel). Restores the terminal before resolving.
15
+ * Show the picker and wait for one digit, Enter (new session), or a lone
16
+ * Esc/Ctrl+C (cancel). Incomplete CSI/SS3 sequences are buffered briefly so
17
+ * arrow keys are ignored instead of cancelling. Restores the terminal before
18
+ * resolving; an AbortSignal cancels and restores as well.
17
19
  * @param ctx - boot context supplying sessionPersistence.
18
20
  * @param color - whether to apply ANSI colors.
21
+ * @param signal - optional abort signal (fiber dispose) to cancel the picker.
19
22
  * @returns the selection, or null when cancelled.
20
23
  */
21
- export declare function showSessionPicker(ctx: Context, color: boolean): Promise<SessionPickerResult>;
24
+ export declare function showSessionPicker(ctx: Context, color: boolean, signal?: AbortSignal): Promise<SessionPickerResult>;
@@ -11,7 +11,11 @@
11
11
  */
12
12
  import type { Agent, ModelSelection, ModelSelectionRef } from '@deepseek-ai/dsh-agent';
13
13
  import type { Context } from '@deepseek-ai/cordis';
14
+ import { type LlmCallConfig } from '@deepseek-ai/dsh-llm';
15
+ import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
16
+ import type { SubagentRunEndInfo, SubagentRunInfo } from '@deepseek-ai/dsh-subagent';
14
17
  import { type SubagentSelectionRef } from './subagent-model.js';
18
+ import { type AskUserQuestionAnswer, type AskUserQuestionRequest } from '@deepseek-ai/dsh-user-questions';
15
19
  /** Presentation configuration for the terminal channel. */
16
20
  export interface TuiConfig {
17
21
  /** Exact shared agent/session identity driven by this terminal. */
@@ -47,6 +51,17 @@ export interface TuiConfig {
47
51
  /** Open the history-session picker immediately after mounting (--resume). */
48
52
  resumePicker?: boolean;
49
53
  }
54
+ type SubagentLogKind = 'user' | 'assistant' | 'tool' | 'result' | 'turn' | 'approval' | 'team' | 'system';
55
+ /** One child-session event folded into a parent-side subagent card. */
56
+ export interface SubagentLogEntry {
57
+ kind: SubagentLogKind;
58
+ text: string;
59
+ }
60
+ /** One todo-list item as the plan card renders it. */
61
+ export interface PlanTodoItem {
62
+ content: string;
63
+ status: 'pending' | 'in_progress' | 'completed';
64
+ }
50
65
  type Row = {
51
66
  kind: 'user';
52
67
  text: string;
@@ -77,6 +92,42 @@ type Row = {
77
92
  exitCode?: number;
78
93
  signal?: string;
79
94
  expanded: boolean;
95
+ } | {
96
+ kind: 'subagent';
97
+ sessionId: string;
98
+ runId: string;
99
+ provider: string;
100
+ local: boolean;
101
+ label: string;
102
+ status: 'running' | 'ok' | 'error' | 'aborted';
103
+ startedAt: number;
104
+ endedAt?: number;
105
+ stopReason?: string;
106
+ lastActivity: string;
107
+ logs: SubagentLogEntry[];
108
+ expanded: boolean;
109
+ } | {
110
+ kind: 'plan';
111
+ active: boolean;
112
+ pending: boolean;
113
+ todos: PlanTodoItem[];
114
+ expanded: boolean;
115
+ } | {
116
+ kind: 'question';
117
+ questionId: string;
118
+ title: string;
119
+ header?: string;
120
+ detail?: string;
121
+ intent: 'ask' | 'plan-review';
122
+ status: 'waiting' | 'answered' | 'cancelled';
123
+ summary: string;
124
+ expanded: boolean;
125
+ } | {
126
+ kind: 'goal';
127
+ objective: string;
128
+ phase: 'active' | 'paused' | 'blocked' | 'complete' | 'cleared';
129
+ blockedReason?: string;
130
+ expanded: boolean;
80
131
  } | {
81
132
  kind: 'system';
82
133
  text: string;
@@ -95,6 +146,13 @@ interface ToolDiffHunk {
95
146
  export interface TuiController {
96
147
  dispose(): Promise<void>;
97
148
  }
149
+ /** Human-facing kind for a live LLM route. */
150
+ export declare function describeProviderRoute(provider: string): {
151
+ kind: string;
152
+ short: string;
153
+ };
154
+ /** Routes that authenticate without a harness API-key credential. */
155
+ export declare function providerUsesLocalOAuth(provider: string): boolean;
98
156
  /**
99
157
  * Render workspace markdown into width-bounded terminal rows. Assistant
100
158
  * replies get a bold-white base; code blocks, headings, quotes, lists, rules,
@@ -132,6 +190,18 @@ export interface OpenCodeSource {
132
190
  export declare function openCodeSourceFor(provider: string, llmPiAiSection: unknown): OpenCodeSource | null;
133
191
  /** Render the OpenCode Go quota payload as a transcript block. */
134
192
  export declare function formatOpenCodeGoUsage(payload: unknown, source: OpenCodeSource): string;
193
+ /** Whether `text` could still grow into a recognized escape sequence. */
194
+ export declare function isEscapePrefix(text: string): boolean;
195
+ /** Parse a todo_write payload into displayable plan items. */
196
+ export declare function parsePlanTodos(value: unknown): PlanTodoItem[];
197
+ /** Compact todo-list summary: done/total plus the first in-progress task. */
198
+ export declare function todoSummary(value: unknown): string;
199
+ /** Compact ask_user_question summary from tool arguments. */
200
+ export declare function askSummary(value: unknown): string;
201
+ /** One-line subagent card header used while collapsed. */
202
+ export declare function subagentHeaderText(row: Extract<Row, {
203
+ kind: 'subagent';
204
+ }>, now?: number): string;
135
205
  /** One-line friendly tool-call presentation (command / path / arg summary). */
136
206
  export declare function presentToolCall(name: string, args: string): {
137
207
  title: string;
@@ -263,6 +333,11 @@ export declare class SshTui {
263
333
  private pushRow;
264
334
  /** The transcript rows that support per-row expand/collapse. */
265
335
  private collapsibleRows;
336
+ private spinnerFrame;
337
+ private findSubagentRow;
338
+ private findLivePlanRow;
339
+ private upsertPlanRow;
340
+ private paintCollapsibleHeader;
266
341
  /** Move the expand/collapse focus among reasoning and tool rows. */
267
342
  private moveCollapsibleFocus;
268
343
  /** Toggle the focused block; without focus, toggle the most recent one. */
@@ -272,6 +347,7 @@ export declare class SshTui {
272
347
  private paint;
273
348
  private buildSuggestions;
274
349
  private suggestionsVisible;
350
+ private currentProviderId;
275
351
  private currentSelectionLabel;
276
352
  /** Replace one step's usage sample so a repeated report never double counts. */
277
353
  private recordUsage;
@@ -289,19 +365,27 @@ export declare class SshTui {
289
365
  * owns the route); direct children created by tool-subagent inherit the
290
366
  * parent provider unless `/submodel` stored an explicit subagent provider.
291
367
  */
292
- private readonly handleAgentRequest;
293
- private readonly handleSessionEvent;
368
+ readonly handleAgentRequest: ({ agent }: {
369
+ agent: Agent;
370
+ }, next: () => Promise<LlmCallConfig>) => Promise<LlmCallConfig>;
371
+ readonly handleSessionEvent: (session: {
372
+ id: SessionId;
373
+ }, event: SessionEvent) => void;
294
374
  private readonly handleStatus;
295
375
  private readonly handleError;
296
376
  private readonly handleInboxClaimed;
297
377
  private readonly handleInboxDiscarded;
298
378
  private readonly handleDisposed;
299
- /** Render a live subagent's own session events so its progress is visible. */
300
- private readonly handleSubagentSessionEvent;
301
- private readonly handleSubagentStart;
302
- private readonly handleSubagentEnd;
379
+ /** Plan-mode / command / team events that plugins merge into SessionEventMap. */
380
+ private handleExtensionEvent;
381
+ private handleGoalChange;
382
+ private handleSubagentExtensionEvent;
383
+ /** Fold a live subagent's own session events into that child's card. */
384
+ readonly handleSubagentSessionEvent: (sessionId: SessionId, event: SessionEvent) => void;
385
+ readonly handleSubagentStart: (info: SubagentRunInfo) => void;
386
+ readonly handleSubagentEnd: (info: SubagentRunEndInfo) => void;
303
387
  private readonly handleApproval;
304
- private readonly handleUserQuestions;
388
+ readonly handleUserQuestions: (request: AskUserQuestionRequest) => Promise<AskUserQuestionAnswer>;
305
389
  /** Queue one dialog behind an already-open one instead of overwriting it. */
306
390
  private openDialog;
307
391
  private showNextDialog;
@@ -336,7 +420,9 @@ export declare class SshTui {
336
420
  * dialog so an endpoint with dozens of models stays selectable.
337
421
  */
338
422
  private pickModelOption;
339
- /** /model: pick a model and reasoning effort for the current provider. */
423
+ /** Live adapter routes the TUI can switch to, plus the current selection. */
424
+ private listSelectableProviders;
425
+ /** /model: pick a provider, then a model and reasoning effort on that route. */
340
426
  private runModelCommand;
341
427
  /** Provider route the next subagent request should use. */
342
428
  private effectiveSubagentProvider;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ssh-tui",
3
- "version": "0.1.8",
3
+ "version": "0.3.0",
4
4
  "description": "SSH-friendly interactive terminal TUI plugin for DeepSeek Harness",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -72,19 +72,20 @@
72
72
  },
73
73
  "peerDependencies": {
74
74
  "@deepseek-ai/cordis": "^4.0.1",
75
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
76
- "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.6",
77
- "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.6",
78
- "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6",
79
- "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.6",
80
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6",
81
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
82
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
83
- "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
84
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
85
- "@deepseek-ai/dsh-subagent": "^0.1.0-rc.6",
86
- "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6",
87
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6"
75
+ "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
76
+ "@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.2",
77
+ "@deepseek-ai/dsh-agent-loop": "^0.1.1-rc.2",
78
+ "@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.2",
79
+ "@deepseek-ai/dsh-cmdline": "^0.1.1-rc.2",
80
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
81
+ "@deepseek-ai/dsh-credentials": "^0.1.1-rc.2",
82
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
83
+ "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
84
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
85
+ "@deepseek-ai/dsh-subagent": "^0.1.1-rc.2",
86
+ "@deepseek-ai/dsh-user-approval": "^0.1.1-rc.2",
87
+ "@deepseek-ai/dsh-user-questions": "^0.1.1-rc.2",
88
+ "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.2"
88
89
  },
89
90
  "peerDependenciesMeta": {
90
91
  "@deepseek-ai/dsh-user-approval": {
@@ -102,20 +103,21 @@
102
103
  },
103
104
  "devDependencies": {
104
105
  "@deepseek-ai/cordis": "^4.0.1",
105
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
106
- "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.6",
107
- "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.6",
108
- "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.6",
109
- "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.6",
110
- "@deepseek-ai/dsh-commands": "^0.1.0-rc.6",
111
- "@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
112
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
113
- "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
114
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
115
- "@deepseek-ai/dsh-subagent": "^0.1.0-rc.6",
116
- "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6",
117
- "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.6",
106
+ "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
107
+ "@deepseek-ai/dsh-agent-default-model": "^0.1.1-rc.2",
108
+ "@deepseek-ai/dsh-agent-loop": "^0.1.1-rc.2",
109
+ "@deepseek-ai/dsh-agent-presets": "^0.1.1-rc.2",
110
+ "@deepseek-ai/dsh-cmdline": "^0.1.1-rc.2",
111
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
112
+ "@deepseek-ai/dsh-credentials": "^0.1.1-rc.2",
113
+ "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
114
+ "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
115
+ "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
116
+ "@deepseek-ai/dsh-subagent": "^0.1.1-rc.2",
117
+ "@deepseek-ai/dsh-user-approval": "^0.1.1-rc.2",
118
+ "@deepseek-ai/dsh-user-questions": "^0.1.1-rc.2",
118
119
  "@types/node": "^24.0.0",
119
- "typescript": "^5.9.0"
120
+ "typescript": "^5.9.0",
121
+ "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.2"
120
122
  }
121
123
  }