@toddzheng024/dscode-bundle 0.1.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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/THIRD_PARTY_NOTICES.md +11 -0
  4. package/bin/apply_patch +4 -0
  5. package/bootstrap.mjs +21 -0
  6. package/cordis.patch.yml +756 -0
  7. package/package.json +327 -0
  8. package/plugins/auto-review/audit.mjs +20 -0
  9. package/plugins/auto-review/index.mjs +181 -0
  10. package/plugins/auto-review/policy.mjs +59 -0
  11. package/plugins/dscode/index.mjs +35 -0
  12. package/plugins/session-metrics/index.mjs +44 -0
  13. package/plugins/session-metrics/pricing.mjs +18 -0
  14. package/plugins/session-metrics/store.mjs +24 -0
  15. package/plugins/session-metrics/view.mjs +58 -0
  16. package/plugins/tui-tools/hooks.mjs +23 -0
  17. package/plugins/tui-tools/index.mjs +164 -0
  18. package/plugins/ultra/policy.mjs +11 -0
  19. package/presets/dscode/agent.cordis.yml +288 -0
  20. package/presets/dscode/preset.yml +3 -0
  21. package/vendor/bash/LICENSE +21 -0
  22. package/vendor/bash/index.js +449 -0
  23. package/vendor/bash/types/background.d.ts +19 -0
  24. package/vendor/bash/types/index.d.ts +22 -0
  25. package/vendor/bash/types/render.d.ts +38 -0
  26. package/vendor/deepseek/LICENSE +21 -0
  27. package/vendor/deepseek/index.js +2102 -0
  28. package/vendor/deepseek/types/adapter.d.ts +163 -0
  29. package/vendor/deepseek/types/file-id.d.ts +19 -0
  30. package/vendor/deepseek/types/file-store.d.ts +83 -0
  31. package/vendor/deepseek/types/files-api.d.ts +103 -0
  32. package/vendor/deepseek/types/image-tokens.d.ts +19 -0
  33. package/vendor/deepseek/types/index.d.ts +106 -0
  34. package/vendor/deepseek/types/request-pricing.d.ts +48 -0
  35. package/vendor/deepseek/types/serialize.d.ts +85 -0
  36. package/vendor/deepseek/types/sse.d.ts +24 -0
  37. package/vendor/deepseek/types/translate.d.ts +37 -0
  38. package/vendor/deepseek/types/types.d.ts +178 -0
  39. package/vendor/deepseek/types/upload-index.d.ts +68 -0
  40. package/vendor/persistent/LICENSE +21 -0
  41. package/vendor/persistent/index.js +386 -0
  42. package/vendor/persistent/types/index.d.ts +24 -0
  43. package/vendor/tui/LICENSE +21 -0
  44. package/vendor/tui/devtools-CdTl3MNy.mjs +3643 -0
  45. package/vendor/tui/index.mjs +39105 -0
  46. package/vendor/tui/invariant.mjs +21 -0
  47. package/vendor/tui/rolldown-runtime-CMFfr-1z.mjs +26 -0
  48. package/vendor/tui/startup.mjs +109 -0
  49. package/vendor/tui/theme-DCT8Y2xf.mjs +628 -0
  50. package/vendor/tui/types/app.d.ts +304 -0
  51. package/vendor/tui/types/approval.d.ts +59 -0
  52. package/vendor/tui/types/attachments.d.ts +52 -0
  53. package/vendor/tui/types/authorization-panel.d.ts +22 -0
  54. package/vendor/tui/types/authorization.d.ts +36 -0
  55. package/vendor/tui/types/commands.d.ts +52 -0
  56. package/vendor/tui/types/editor-keys.d.ts +105 -0
  57. package/vendor/tui/types/editor.d.ts +6 -0
  58. package/vendor/tui/types/fork.d.ts +8 -0
  59. package/vendor/tui/types/git-workflow.d.ts +32 -0
  60. package/vendor/tui/types/history.d.ts +97 -0
  61. package/vendor/tui/types/index.d.ts +124 -0
  62. package/vendor/tui/types/input-split.d.ts +54 -0
  63. package/vendor/tui/types/internals.d.ts +26 -0
  64. package/vendor/tui/types/invariant.d.ts +15 -0
  65. package/vendor/tui/types/kernel-panels.d.ts +167 -0
  66. package/vendor/tui/types/keyboard.d.ts +80 -0
  67. package/vendor/tui/types/mentions.d.ts +81 -0
  68. package/vendor/tui/types/model-capabilities.d.ts +82 -0
  69. package/vendor/tui/types/models.d.ts +119 -0
  70. package/vendor/tui/types/permissions.d.ts +27 -0
  71. package/vendor/tui/types/plugin-inventory.d.ts +11 -0
  72. package/vendor/tui/types/presets.d.ts +22 -0
  73. package/vendor/tui/types/provider-settings.d.ts +239 -0
  74. package/vendor/tui/types/questions.d.ts +54 -0
  75. package/vendor/tui/types/render/animations.d.ts +265 -0
  76. package/vendor/tui/types/render/editor.d.ts +162 -0
  77. package/vendor/tui/types/render/export.d.ts +9 -0
  78. package/vendor/tui/types/render/fuzzy.d.ts +21 -0
  79. package/vendor/tui/types/render/inspector.d.ts +36 -0
  80. package/vendor/tui/types/render/lines.d.ts +66 -0
  81. package/vendor/tui/types/render/markdown.d.ts +29 -0
  82. package/vendor/tui/types/render/projection.d.ts +461 -0
  83. package/vendor/tui/types/render/status.d.ts +196 -0
  84. package/vendor/tui/types/render/text.d.ts +58 -0
  85. package/vendor/tui/types/render/tool-detail.d.ts +94 -0
  86. package/vendor/tui/types/render/tool-preview.d.ts +28 -0
  87. package/vendor/tui/types/render/width.d.ts +29 -0
  88. package/vendor/tui/types/session-directory.d.ts +173 -0
  89. package/vendor/tui/types/session-switch.d.ts +17 -0
  90. package/vendor/tui/types/settings-file.d.ts +41 -0
  91. package/vendor/tui/types/skills.d.ts +47 -0
  92. package/vendor/tui/types/startup.d.ts +65 -0
  93. package/vendor/tui/types/store.d.ts +58 -0
  94. package/vendor/tui/types/subagents.d.ts +70 -0
  95. package/vendor/tui/types/theme-panel.d.ts +24 -0
  96. package/vendor/tui/types/theme.d.ts +215 -0
  97. package/vendor/tui/types/version.d.ts +18 -0
  98. package/vendor/tui/types/whale-glyph.d.ts +6 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * The Ink terminal app: whale-and-wordmark header in DeepSeek blue, the live
3
+ * transcript, the todo panel, the streaming line, the approval bar, the model
4
+ * panel, local notices, and the input box with history and slash-command
5
+ * completion. All state arrives through the transcript store (derived from
6
+ * the durable session log) plus local input state; the app owns no session
7
+ * mutation of its own.
8
+ *
9
+ * Element construction uses `createElement` (not JSX): the `dsh` source launch
10
+ * compiles this file through tsx's ESM-only hook, which does not adopt this
11
+ * package's `jsx: react-jsx` compiler option, and the classic JSX runtime
12
+ * would demand a React global.
13
+ *
14
+ * @module @deepseek-ai/dsh-code/app
15
+ */
16
+ import { type ReactElement } from 'react';
17
+ import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
18
+ import type { ContentBlock, FileBlock, ImageBlock } from '@deepseek-ai/dsh-llm';
19
+ import type { AuthorizationInteraction, AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
20
+ import { type ThemeName } from './theme.ts';
21
+ import type { TranscriptStore } from './store.ts';
22
+ import { type TranscriptEntry } from './render/projection.ts';
23
+ import type { ApprovalStore } from './approval.ts';
24
+ import { type CommandsView } from './commands.ts';
25
+ import type { ModelDirectory, ModelRow } from './models.ts';
26
+ import { type DiscoveredModelView, type ProviderConfiguration, type ProviderSettingsDirectory, type ProviderTargetView } from './provider-settings.ts';
27
+ import type { QuestionStore } from './questions.ts';
28
+ import type { SkillsView, SkillRow } from './skills.ts';
29
+ import { type MentionCandidate } from './mentions.ts';
30
+ import type { SubagentFeedView } from './subagents.ts';
31
+ import { type JobRow } from './kernel-panels.ts';
32
+ import type { PresetRow } from './presets.ts';
33
+ import type { PermissionRow } from './permissions.ts';
34
+ import type { PluginRow } from './plugin-inventory.ts';
35
+ import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
36
+ import type { GitDiffView } from './git-workflow.ts';
37
+ import { type ProviderAuthorizationDirectory, type ProviderAuthorizationRow } from './authorization.ts';
38
+ import { type FilePathInspection, type ImagePathInspection } from './attachments.ts';
39
+ /** Visual priority for one bounded local notice. */
40
+ export type NoticeTone = 'info' | 'warning' | 'error';
41
+ /** Props the runner hands the app; callbacks stay owned by the runner. */
42
+ export interface AppProps {
43
+ /** Event-fed transcript store for the live session. */
44
+ store: TranscriptStore;
45
+ /** Approval-question store fed by the answerer listener. */
46
+ approval: ApprovalStore;
47
+ /** ask_user_question store fed by the single UI provider. */
48
+ questions: QuestionStore;
49
+ /** Live subagent activity feed (child sessions of the current root). */
50
+ subagents: SubagentFeedView;
51
+ /** Live slash-command descriptor list (completion candidates). */
52
+ commands: CommandsView;
53
+ /** Live user-invocable skill catalog (completion candidates). */
54
+ skills: SkillsView;
55
+ /** `provider/model` selection serving this session (updated on /model). */
56
+ model: string;
57
+ /** Effective reasoning effort in force ('' when none), for the /model picker mark. */
58
+ effort?: string;
59
+ /** Working-directory basename the session serves. */
60
+ cwd: string;
61
+ /** Absolute working directory used by session filters and references. */
62
+ workspaceRoot: string;
63
+ /** Git branch name, empty outside a repository. */
64
+ branch: string;
65
+ /** Short session identifier. */
66
+ sessionId: string;
67
+ /** Whether this session was resumed from persistence. */
68
+ resumed: boolean;
69
+ /** Agent preset selected for the current or pending first session. */
70
+ mode: string;
71
+ /** Permission preset selected for the current or pending first session. */
72
+ permission: string;
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;
87
+ /** Interrupt the running turn (Esc); true when a turn was cancelled. */
88
+ interrupt(): boolean;
89
+ /** Quit: unmount, flush, and request process exit. */
90
+ quit(): void;
91
+ /** Load the selectable model directory (called when /model opens). */
92
+ loadModels(): Promise<ModelDirectory>;
93
+ /** Load @mention candidates for the typed query (files + sessions). */
94
+ loadMentions(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
95
+ /** Validate draft image paths without committing attachment objects. */
96
+ inspectImages(paths: readonly string[]): Promise<readonly ImagePathInspection[]>;
97
+ /** Validate, normalize and persist images immediately before submission. */
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[]>;
103
+ /** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
104
+ selectModel(row: ModelRow, effortId?: string): string;
105
+ /** The /subagent override label, '' when delegated agents follow the current model. */
106
+ subagentModel: string;
107
+ /** Apply one /subagent model pick; returns the override label. */
108
+ setSubagentModel(row: ModelRow, effortId?: string): string;
109
+ /** Drop the /subagent override (delegated agents follow the current model). */
110
+ clearSubagentModel(): void;
111
+ /** Delete one session subtree; resolves with the outcome line. */
112
+ deleteSession(id: string): Promise<string>;
113
+ /** Load provider/settings/credential facts for the optional /model provider stage. */
114
+ loadModelProviders?(): Promise<ProviderSettingsDirectory>;
115
+ /** Subscribe to Harness credential/settings/adapter invalidations while /model is open. */
116
+ subscribeModelProviders?(listener: () => void): () => void;
117
+ /** Store or rotate one provider credential through the Harness credential service. */
118
+ saveModelProviderCredential?(target: ProviderTargetView, key: string): Promise<void>;
119
+ /** Remove one writable provider credential without removing its settings profile. */
120
+ unsetModelProviderCredential?(target: ProviderTargetView): Promise<void>;
121
+ /** Remove one user-owned provider profile and its page-managed credential. */
122
+ removeModelProvider?(target: ProviderTargetView): Promise<void>;
123
+ /** Save endpoint and explicit model capacities through the provider profile. */
124
+ saveModelProviderConfiguration?(target: ProviderTargetView, configuration: ProviderConfiguration): Promise<void>;
125
+ /**
126
+ * Interrogate the provider's real endpoint (typed key wins over the stored
127
+ * credential) for the models it actually serves — the discovery stage of
128
+ * the provider setup page.
129
+ */
130
+ discoverModelProvider?(target: ProviderTargetView, request: {
131
+ readonly apiKey?: string;
132
+ readonly baseURL?: string;
133
+ }, signal?: AbortSignal): Promise<readonly DiscoveredModelView[]>;
134
+ /** Provider authorization flows and value-free stored-record facts. */
135
+ loadProviderAuthorizations?(): Promise<ProviderAuthorizationDirectory>;
136
+ subscribeProviderAuthorizations?(listener: () => void): () => void;
137
+ beginProviderAuthorization?(row: ProviderAuthorizationRow, method: string, interaction: AuthorizationInteraction, signal: AbortSignal): Promise<AuthorizationStatus>;
138
+ cancelProviderAuthorization?(row: ProviderAuthorizationRow): void;
139
+ logoutProviderAuthorization?(row: ProviderAuthorizationRow): Promise<void>;
140
+ openAuthorizationUrl?(url: string): boolean;
141
+ copyTextValue?(text: string): Promise<void>;
142
+ /** Cycle to the next permission preset (Shift+Tab); returns the new label. */
143
+ cyclePermission(): string;
144
+ /** Select or inspect a permission preset without requiring a pre-existing session. */
145
+ setPermission(id: string): string;
146
+ /** Export the transcript to a markdown file (/export [path]); reports via notices. */
147
+ exportTranscript(argument: string): Promise<void>;
148
+ /** Rename the session (/title <text>); returns the outcome line for the notice. */
149
+ renameTitle(argument: string): string;
150
+ /** Copy the latest complete assistant response; resolves to notice text. */
151
+ copyLastResponse(): Promise<string>;
152
+ /** Load a complete read-only Git diff for the file-oriented viewport. */
153
+ loadGitDiff(argument: string): Promise<GitDiffView>;
154
+ /** Start a model review after applying the read-only permission preset. */
155
+ reviewChanges(argument: string): void;
156
+ /** Preset/session/plugin kernel operations. */
157
+ loadPresets(): Promise<readonly PresetRow[]>;
158
+ switchMode(id: string): Promise<string>;
159
+ /** Load the switchable permission presets for the /permission panel. */
160
+ loadPermissions(): Promise<readonly PermissionRow[]>;
161
+ createSession(mode?: string): void;
162
+ /** Fork the active session at a completed-turn boundary. */
163
+ forkSession(argument: string): void;
164
+ loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
165
+ loadSessionTranscript(id: string, signal?: AbortSignal): Promise<string>;
166
+ /** Load this session's subagent conversations (children by lineage). */
167
+ loadSubagents(): Promise<readonly SessionRow[]>;
168
+ switchSession(row: SessionRow): void;
169
+ cancelSessionSwitch(): boolean;
170
+ loadPlugins(): readonly PluginRow[];
171
+ /** Caller-visible background jobs (the host jobs registry, read-only). */
172
+ loadJobs(): readonly JobRow[];
173
+ /** Registers the app's notice channel with the runner (called once on mount). */
174
+ onBridgeReady(bridge: {
175
+ notify(text: string, tone?: NoticeTone): void;
176
+ }): void;
177
+ /** Ordered enabled status items (/statusline config); the runner owns persistence. */
178
+ statusline: readonly string[];
179
+ /** Persist a new statusline item set; the runner surfaces IO failures as notices. */
180
+ saveStatusline(items: readonly string[]): void;
181
+ /** Apply and persist one /theme selection; the runner owns the theme.json file. */
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;
188
+ /** Persistent cross-session input history (oldest first); the runner owns the file. */
189
+ history: readonly string[];
190
+ /** Persist one submitted prompt to the global history file. */
191
+ recordHistory(text: string): void;
192
+ /** Cancel one queued inbox message by identity (Delete on the empty composer). */
193
+ cancelQueued(messageId: string): void;
194
+ /** Apply the Ctrl+R terminal passthrough to the detected editor (/vscode-keys); resolves to a one-line summary. */
195
+ applyEditorKeys(): Promise<string>;
196
+ }
197
+ /** One completion candidate row. */
198
+ interface CompletionCandidate {
199
+ /** Insertion text for the command name (with leading slash). */
200
+ label: string;
201
+ /** Human-readable description shown beside the label. */
202
+ description: string;
203
+ /** Candidate origin; skills land the same literal text but route through the prompt. */
204
+ origin: 'command' | 'skill' | 'mention';
205
+ }
206
+ /**
207
+ * Resolve completion candidates for the current input: TUI-local commands,
208
+ * the live registry descriptors, and user-invocable skills, filtered by the
209
+ * typed prefix. Command names win collisions (the dispatch tries the
210
+ * registry first and only then falls through to the skill gesture), and a
211
+ * later duplicate name never renders twice.
212
+ *
213
+ * A bare `/` returns the FULL merged list — Codex's command popup shows every
214
+ * command inside a scroll window on an empty filter, and the menu's own
215
+ * selection window bounds the visible rows, so no slice cap is needed.
216
+ */
217
+ export declare function completionCandidates(value: string, descriptors: readonly CommandDescriptor[], skills: readonly SkillRow[]): readonly CompletionCandidate[];
218
+ /** One cached settled row: the row Box plus its roomy-prompt spacers. */
219
+ interface SettledRowRecord {
220
+ /** The row Box element (keyed by the entry's settled index). */
221
+ box: ReactElement;
222
+ /** The roomy-prompt spacer BEFORE the row, or undefined. */
223
+ before: ReactElement | undefined;
224
+ /** The roomy-prompt spacer AFTER the row, or undefined. */
225
+ after: ReactElement | undefined;
226
+ /** Physical rows this record contributes (row body plus spacers) — the
227
+ * unit of the rendered-history cap. */
228
+ rows: number;
229
+ }
230
+ /** The incremental settled-history cache (see `computeSettledRows`). */
231
+ interface SettledRowsCache {
232
+ /** The exact settled entries the cache covers (the WINDOW: the newest
233
+ * `entries.length` settled entries, oldest dropped entries excluded). */
234
+ entries: TranscriptEntry[];
235
+ /** Records keyed by entry identity; mutated in place so the append path
236
+ * never copies the whole map. */
237
+ records: Map<TranscriptEntry, SettledRowRecord>;
238
+ /** The header element (depends only on `resumed`). */
239
+ header: ReactElement;
240
+ /** The `resumed` the header was built with. */
241
+ resumed: boolean;
242
+ /** The toggle state the rows were built with. */
243
+ showReasoning: boolean;
244
+ /** The refreshEpoch the rows was built for; a bump forces a full rebuild. */
245
+ epoch: number;
246
+ /** The terminal width the rows were wrapped for; a change forces a rebuild. */
247
+ columns: number;
248
+ /** The flat row list (header + optional hint + per-entry before/box/after). */
249
+ flat: ReactElement[];
250
+ /** Settled entries dropped from the window's head (rendering only — the
251
+ * event log keeps everything; Ctrl+O and /export read it directly). */
252
+ droppedEntries: number;
253
+ /** Physical rows the window's entries contribute (excludes header/hint). */
254
+ totalRows: number;
255
+ /** The window overflowed the trim hysteresis; one source-backed replay
256
+ * (epoch bump) will re-window the cache. The append path never mutates
257
+ * flat's head, so <Static> only ever sees tail appends between remounts. */
258
+ needsTrim: boolean;
259
+ }
260
+ /** One step of `computeSettledRows`. */
261
+ interface SettledRowsResult {
262
+ cache: SettledRowsCache;
263
+ /** How many rows had to be BUILT by this step (0 = pure reuse). */
264
+ built: number;
265
+ }
266
+ /**
267
+ * The settled `<Static>` row set as a PURE incremental state machine (App
268
+ * drives it from the memo; tests drive it directly and read `built`).
269
+ *
270
+ * The settled prefix is permanently final: the projection only APPENDS below
271
+ * the flush boundary, removes pending rows at or beyond it, and replaces
272
+ * running tool/retry/command rows there too. So extending the cache never
273
+ * rescans the old prefix — a grown boundary builds ONLY the newly settled
274
+ * suffix and reuses every cached element, letting React bail out of unchanged
275
+ * rows and keeping long histories out of the per-durable-event path (no O(N)
276
+ * rebuild of rows, Map, or MarkdownBody parses). `records` is mutated in place
277
+ * on the append/toggle paths to stay O(delta).
278
+ *
279
+ * RENDERED-HISTORY CAP: the window holds at most `rowCap` physical rows of
280
+ * settled transcript (header and hint reserved on top). The cap exists only
281
+ * here — the event log, the store projection, /export, Ctrl+O, and /resume
282
+ * keep the full history. Ink 5's <Static> is a consumption counter
283
+ * (items.slice(index) keyed on length): deleting head items mid-stream while
284
+ * appending tail items can permanently swallow new rows, so the append branch
285
+ * NEVER drops the head — it only accounts rows and flags `needsTrim` once the
286
+ * window overflows cap + margin. The flag fires one source-backed replay
287
+ * (epoch bump = the existing clear + <Static> remount), whose rebuild branch
288
+ * walks the settled entries BACKWARD from the newest, keeps whole entries
289
+ * until the cap, and counts everything older as `droppedEntries` (those
290
+ * entries never even reach settledEntryLines). Hysteresis bounds replays to
291
+ * at most one per 25% growth; resize / Ctrl+L / idle Ctrl+R replays re-window
292
+ * for free on the same path.
293
+ *
294
+ * Full rebuilds run only on the rare, deliberate paths: no cache yet, a
295
+ * source-backed replay (`epoch` bump: resize / Ctrl+L / an idle Ctrl+R fold
296
+ * toggle / a cap trim remounts `<Static>` and must re-flush the CURRENT rows
297
+ * at the CURRENT fold state), a `resumed` change, or a shrink (`store.reset`).
298
+ * While a turn is busy or streaming, Ctrl+R only flips the live region; rows
299
+ * already emitted to native scrollback change exclusively through rebuilds.
300
+ */
301
+ export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number, columns?: number, rowCap?: number): SettledRowsResult;
302
+ /** The whole terminal app; state arrives via the store, output via Ink. */
303
+ export declare function App(props: AppProps): ReactElement;
304
+ export {};
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The terminal approval answerer: one `approval/request` waterfall listener
3
+ * that renders the pending question as a y/n bar and resolves the decision
4
+ * back into the waterfall. Mirrors the web host's composer takeover — the
5
+ * service (audit pair, policy gate, fail-closed defaults) all live in
6
+ * dsh-base; this module only answers for agents this TUI owns.
7
+ *
8
+ * Vocabulary note: a client answerer may only ever resolve `'allowed-once'`
9
+ * or `'rejected'`; `'cancelled'` belongs to the request signal and
10
+ * `'unavailable'` to the fail-closed waterfall default.
11
+ *
12
+ * @module @deepseek-ai/dsh-code/approval
13
+ */
14
+ import type { Context } from '@deepseek-ai/cordis';
15
+ import type { Agent } from '@deepseek-ai/dsh-agent';
16
+ import type { ApprovalRequest } from '@deepseek-ai/dsh-user-approval';
17
+ /** The answer values a client answerer may resolve with. */
18
+ export type ApprovalAnswer = 'allowed-once' | 'rejected';
19
+ /** One pending approval question, derived from the request for rendering. */
20
+ export interface PendingApproval {
21
+ /** The asker's human-readable explanation, or a generic fallback. */
22
+ headline: string;
23
+ /** The tool the question is about. */
24
+ toolName: string;
25
+ /** Command-line preview resolved from the paired streaming tool call. */
26
+ command: string;
27
+ /** Resolve the ask; calling twice is inert (one-shot latch). */
28
+ answer(outcome: ApprovalAnswer): void;
29
+ }
30
+ /** The pending-question snapshot the renderer subscribes to. */
31
+ export interface ApprovalSnapshot {
32
+ /** The question on screen (queue head), or undefined when none is asked. */
33
+ pending: PendingApproval | undefined;
34
+ /** Presentational: an answer was submitted, the ask has not settled yet. */
35
+ answered: boolean;
36
+ /** Further asks waiting behind the on-screen one (FIFO, Codex-style). */
37
+ queued: number;
38
+ }
39
+ /** Store the pending question lands in; the renderer reads, the answerer writes. */
40
+ export interface ApprovalStore {
41
+ /** Subscribe to pending-state changes; returns the unsubscribe function. */
42
+ subscribe(listener: () => void): () => void;
43
+ /** Read the current snapshot (identity-stable between changes). */
44
+ getSnapshot(): ApprovalSnapshot;
45
+ }
46
+ /**
47
+ * Create the approval store and mount the answerer listener on the context.
48
+ * The listener claims only requests for `owns`-owned agents and defers every
49
+ * other request back into the waterfall (`next()`), so sibling answerers stay
50
+ * usable. An aborted ask never reaches the human. Plugin teardown removes the
51
+ * listener; the service then fails its own question closed.
52
+ * @param ctx - plugin context whose event bus carries `approval/request`.
53
+ * @param owns - agents this terminal answers for.
54
+ * @param preview - resolves a tool-call preview for a pending request (the
55
+ * request contract carries no arguments; the UI self-serves from the
56
+ * transcript projection via `callId`).
57
+ * @returns the store the renderer subscribes to.
58
+ */
59
+ export declare function mountApprovalAnswerer(ctx: Context, owns: (agent: Agent) => boolean, preview: (request: ApprovalRequest) => string): ApprovalStore;
@@ -0,0 +1,52 @@
1
+ /** Terminal image- and file-attachment adapter over the Harness durable attachment service. */
2
+ import type { AttachmentStore, ImageMediaType } from '@deepseek-ai/dsh-attachment';
3
+ import type { FileBlock, ImageBlock } from '@deepseek-ai/dsh-llm';
4
+ /** A validated path retained in the editor until submission persists it. */
5
+ export interface ImagePathInspection {
6
+ readonly path: string;
7
+ readonly name: string;
8
+ readonly mediaType: ImageMediaType;
9
+ readonly bytes: number;
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;
25
+ /** Detect the supported encoded raster formats from bytes, never from a path suffix. */
26
+ export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
27
+ /** Whether a path-like token is worth probing as an image attachment. */
28
+ export declare function looksLikeImagePath(path: string): boolean;
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
+ };
45
+ /** Validate path, byte size and encoded signature without writing an attachment object. */
46
+ export declare function inspectImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined, cwd?: string): Promise<readonly ImagePathInspection[]>;
47
+ /** Read, validate, and persist an ordered image path list as model content blocks. */
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[]>;
@@ -0,0 +1,22 @@
1
+ /** Bounded Ink surfaces for provider login and logout. */
2
+ import { type ReactElement } from 'react';
3
+ import { type AuthorizationInteraction, type AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
4
+ import type { CredentialKey } from '@deepseek-ai/dsh-credentials';
5
+ import type { ProviderAuthorizationRow } from './authorization.ts';
6
+ export interface ProviderAuthorizationPanelProps {
7
+ readonly row: ProviderAuthorizationRow;
8
+ begin(row: ProviderAuthorizationRow, method: string, interaction: AuthorizationInteraction, signal: AbortSignal): Promise<AuthorizationStatus>;
9
+ cancel(key: CredentialKey): void;
10
+ openUrl(url: string): boolean;
11
+ copy(text: string): Promise<void>;
12
+ done(): void;
13
+ back(): void;
14
+ }
15
+ /** Run one upstream authorization flow without letting notices or prompts exceed the panel budget. */
16
+ export declare function ProviderAuthorizationPanel(props: ProviderAuthorizationPanelProps): ReactElement;
17
+ export declare function ProviderAuthorizationLogoutPanel({ row, confirm, done, back }: {
18
+ row: ProviderAuthorizationRow;
19
+ confirm(row: ProviderAuthorizationRow): Promise<void>;
20
+ done(): void;
21
+ back(): void;
22
+ }): ReactElement;
@@ -0,0 +1,36 @@
1
+ /** Terminal adapter over the Harness provider-authorization and credential-record seams. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import type { AuthorizationEntry, AuthorizationInteraction, AuthorizationMethod, AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
4
+ import { type CredentialKey, type CredentialRecordInfo } from '@deepseek-ai/dsh-credentials';
5
+ /** One provider login flow joined with its value-free stored-record facts. */
6
+ export interface ProviderAuthorizationRow {
7
+ readonly key: CredentialKey;
8
+ readonly provider: string;
9
+ readonly label: string;
10
+ readonly methods: readonly AuthorizationMethod[];
11
+ readonly inFlight: boolean;
12
+ readonly record: CredentialRecordInfo;
13
+ }
14
+ /** The provider-login directory plus non-fatal record lookup failures. */
15
+ export interface ProviderAuthorizationDirectory {
16
+ readonly rows: readonly ProviderAuthorizationRow[];
17
+ readonly failures: readonly string[];
18
+ }
19
+ /** Load only model-provider flows; unrelated future authorization domains stay out of `/model`. */
20
+ export declare function loadProviderAuthorizations(ctx: Context): Promise<ProviderAuthorizationDirectory>;
21
+ /** Subscribe to login settlement and credential-record changes. */
22
+ export declare function subscribeProviderAuthorizations(ctx: Context, listener: () => void): () => void;
23
+ /** Begin one provider login through the interaction surface owned by the caller. */
24
+ export declare function beginProviderAuthorization(ctx: Context, row: Pick<ProviderAuthorizationRow, 'key'>, method: string, interaction: AuthorizationInteraction, signal?: AbortSignal): Promise<AuthorizationStatus>;
25
+ /** Cancel the attempt currently serving this provider, if any. */
26
+ export declare function cancelProviderAuthorization(ctx: Context, key: CredentialKey): void;
27
+ /** Remove an authorization record without changing the provider's settings profile. */
28
+ export declare function logoutProviderAuthorization(ctx: Context, row: ProviderAuthorizationRow): Promise<void>;
29
+ /** Open an authorization URL with the platform default browser, without invoking a shell. */
30
+ export declare function openAuthorizationUrl(raw: string): boolean;
31
+ /** Compact value-free status for the provider list. */
32
+ export declare function providerAuthorizationStatus(row: ProviderAuthorizationRow | undefined): string;
33
+ /** Find a provider's login flow from a previously loaded directory. */
34
+ export declare function authorizationForProvider(directory: ProviderAuthorizationDirectory | undefined, provider: string): ProviderAuthorizationRow | undefined;
35
+ /** Preserve the upstream entry type in declarations without leaking service internals into the TUI. */
36
+ export type { AuthorizationEntry };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Slash-command bridge: forwards terminal command lines into the shared
3
+ * `ctx.commands` registry (the same surface the web composer dispatches
4
+ * through) and exposes the live descriptor list as completion candidates.
5
+ * The runner keeps only its own TUI-local commands (`/help`, `/quit`,
6
+ * `/clear`, `/model`) ahead of the registry dispatch.
7
+ *
8
+ * @module @deepseek-ai/dsh-tui/commands
9
+ */
10
+ import type { Context } from '@deepseek-ai/cordis';
11
+ import type { Agent } from '@deepseek-ai/dsh-agent';
12
+ import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
13
+ /** Descriptor list snapshot the completion menu renders from. */
14
+ export interface CommandsView {
15
+ /** Name-sorted descriptors after scoped shadowing. */
16
+ readonly descriptors: readonly CommandDescriptor[];
17
+ /** Latest descriptor-read failure; the help panel exposes it in place. */
18
+ readonly error?: string;
19
+ /** Subscribe to list changes (`commands/change`); returns the unsubscribe function. */
20
+ subscribe(listener: () => void): () => void;
21
+ /** Retarget the agent whose scoped view the list is read through. */
22
+ setAgent(agent: Agent): void;
23
+ }
24
+ /**
25
+ * Watch the live command registry. Reads the current list immediately and
26
+ * re-reads on every registry mutation or agent retarget; notification
27
+ * failures are contained by the registry itself, so this watcher only ever
28
+ * re-reads. Without a `commands` service the view stays empty and all lines
29
+ * fall through to normal prompts.
30
+ * @param ctx - context carrying the `commands` service (optional).
31
+ * @returns the view the completion menu subscribes to.
32
+ */
33
+ export declare function watchCommands(ctx: Context): CommandsView;
34
+ /**
35
+ * Whether one command line is a syntactically valid slash command.
36
+ * @param line - the complete candidate line.
37
+ * @returns true when the line parses as `/name` or `/name input`.
38
+ */
39
+ export declare function isSlashLine(line: string): boolean;
40
+ /**
41
+ * The submission payload for one composer line. Trim is a blank check, not a
42
+ * rewrite: an ordinary prompt keeps its exact leading indentation, inner
43
+ * layout, and trailing spaces (pasted code must reach the model verbatim).
44
+ * Only trailing line terminators are stripped — a draft's final newline is a
45
+ * paste/Enter artifact (an open bracketed paste turns Enter into an inserted
46
+ * newline), never deliberate content. A syntactic slash line still normalizes
47
+ * fully so command routing stays stable (completion inserts a trailing space
48
+ * after `/name`).
49
+ * @param line - the complete draft text.
50
+ * @returns the text to submit verbatim.
51
+ */
52
+ export declare function submissionPayload(line: string): string;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * VS Code-family terminal keybinding repair. VS Code hands Ctrl+R to the
3
+ * workbench (Open Recent) even while an integrated terminal owns focus, so
4
+ * the reasoning-fold key never reaches the TUI. Workspace-scoped keybindings
5
+ * do not exist, so the fix is one user-level keybindings.json rule that
6
+ * forwards the raw Ctrl byte via sendSequence under terminalFocus. This
7
+ * module detects the hosting editor variant, resolves its user
8
+ * keybindings.json, and merges the rule idempotently; pure merge/detect
9
+ * helpers are separated from the fs orchestration so both stay testable.
10
+ * @module @deepseek-ai/dsh-code/editor-keys
11
+ */
12
+ /** Integrated-terminal editor variants this module can repair. */
13
+ export type EditorTerminalFamily = 'vscode' | 'cursor' | 'vscodium' | 'windsurf';
14
+ /**
15
+ * Detect the editor hosting this integrated terminal.
16
+ * @param env - process environment (TERM_PROGRAM decides; case/whitespace tolerant).
17
+ * @returns the family, or undefined outside VS Code-family terminals.
18
+ */
19
+ export declare function detectEditorTerminalFamily(env?: NodeJS.ProcessEnv): EditorTerminalFamily | undefined;
20
+ /**
21
+ * Whether the pty is hosted away from the editor UI (ssh/container/tunnel).
22
+ * Keybindings live on the client machine, so a remote session must never
23
+ * write them server-side.
24
+ */
25
+ export declare function isRemoteTerminalEnv(env?: NodeJS.ProcessEnv): boolean;
26
+ /** Filesystem anchors used to resolve editor config paths (injectable for tests). */
27
+ export interface EditorPathContext {
28
+ /** User home directory. */
29
+ homedir: string;
30
+ /** %APPDATA% on Windows; only read for win32 resolution. */
31
+ appdata?: string;
32
+ /** Node platform qualifier. */
33
+ platform: NodeJS.Platform;
34
+ }
35
+ /**
36
+ * Resolve the user keybindings.json candidates for one family, most likely
37
+ * install first. Only paths that exist on disk are repaired.
38
+ */
39
+ export declare function editorKeybindingCandidates(family: EditorTerminalFamily, context: EditorPathContext): readonly string[];
40
+ /** The one workbench rule that hands Ctrl+R to the focused terminal. */
41
+ export declare const CTRL_R_PASSTHROUGH_RULE: {
42
+ readonly key: "ctrl+r";
43
+ readonly command: "workbench.action.terminal.sendSequence";
44
+ readonly args: {
45
+ readonly text: "\u0012";
46
+ };
47
+ readonly when: "terminalFocus";
48
+ };
49
+ /**
50
+ * Remove // and block comments from one JSONC document. Double-quoted strings
51
+ * survive untouched, so comment markers inside string values are preserved.
52
+ */
53
+ export declare function stripJsoncComments(text: string): string;
54
+ /** Parse one JSONC document; trailing commas are tolerated. */
55
+ export declare function parseJsonc(text: string): unknown;
56
+ /** Outcome of merging the passthrough rule into one keybindings document. */
57
+ export type KeybindingsMerge = {
58
+ readonly status: 'present';
59
+ } | {
60
+ readonly status: 'updated';
61
+ readonly text: string;
62
+ } | {
63
+ readonly status: 'created';
64
+ readonly text: string;
65
+ };
66
+ /**
67
+ * Merge the Ctrl+R passthrough into one keybindings.json document. The raw
68
+ * text is preserved verbatim (comments included); the rule is inserted right
69
+ * after the array opener so it cannot be shadowed by later conflicting user
70
+ * rules. Missing files resolve to a fresh template.
71
+ * @throws when the document does not carry a rule array.
72
+ */
73
+ export declare function mergeCtrlRPassthrough(raw: string | undefined): KeybindingsMerge;
74
+ /** User-level marker file content: the startup hint fires at most once per install. */
75
+ export interface EditorKeysFlag {
76
+ hintShownAt?: string;
77
+ }
78
+ /** Parse one flag file snapshot; missing or corrupt content degrades to unshown. */
79
+ export declare function parseEditorKeysFlag(raw: string | undefined): EditorKeysFlag;
80
+ /** Persist the shown marker; best-effort, the hint is cosmetic and never a gate. */
81
+ export declare function markEditorKeysHintShown(path: string): Promise<void>;
82
+ /** Inputs shared by the apply and startup-hint flows. */
83
+ export interface EditorKeysEnv {
84
+ /** Process environment (TERM_PROGRAM / VSCODE_IPC_HOOK_CLI). */
85
+ env: NodeJS.ProcessEnv;
86
+ /** Filesystem anchors for editor config resolution. */
87
+ paths: EditorPathContext;
88
+ /** Absolute path of the one-shot hint marker under the DSH home. */
89
+ flagPath: string;
90
+ }
91
+ /**
92
+ * Apply the Ctrl+R passthrough to every local keybindings.json of the hosting
93
+ * editor and mark the startup hint shown. Existing files get a .dsh-bak
94
+ * backup before the first write.
95
+ * @returns a one-line user-facing summary.
96
+ * @throws with an actionable message when the environment cannot be repaired.
97
+ */
98
+ export declare function applyCtrlRPassthrough({ env, paths, flagPath }: EditorKeysEnv): Promise<string>;
99
+ /**
100
+ * Resolve the one-shot startup hint for VS Code-family terminals. Fires at
101
+ * most once per install (flag file), never when the passthrough rule is
102
+ * already present, and never in remote ptys where the repair cannot run.
103
+ * @returns the hint line, or undefined to stay silent.
104
+ */
105
+ export declare function resolveEditorKeysStartupHint({ env, paths, flagPath }: EditorKeysEnv): Promise<string | undefined>;
@@ -0,0 +1,6 @@
1
+ /** Host editor and clipboard adapters used by the terminal surface. */
2
+ import type { TranscriptView } from './render/projection.ts';
3
+ /** Copy UTF-8 text through the platform clipboard command. */
4
+ export declare function copyText(text: string): Promise<void>;
5
+ /** Latest complete assistant text, excluding streaming and reasoning. */
6
+ export declare function latestAssistantText(view: TranscriptView): string | undefined;
@@ -0,0 +1,8 @@
1
+ /** Pure session-fork boundary policy shared by the TUI command and tests. */
2
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
3
+ export interface ForkSeed {
4
+ readonly boundarySeq: number;
5
+ readonly events: readonly SessionEvent[];
6
+ }
7
+ /** Select a completed turn and trailing between-turn metadata. */
8
+ export declare function selectForkSeed(events: readonly SessionEvent[], atSeq?: number): ForkSeed;