@agi-fans/dsh-tui 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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -0
  3. package/lib/autocomplete.d.ts +80 -0
  4. package/lib/autocomplete.js +320 -0
  5. package/lib/autocomplete.js.map +1 -0
  6. package/lib/box.d.ts +79 -0
  7. package/lib/box.js +276 -0
  8. package/lib/box.js.map +1 -0
  9. package/lib/clipboard.d.ts +19 -0
  10. package/lib/clipboard.js +77 -0
  11. package/lib/clipboard.js.map +1 -0
  12. package/lib/command-integrations.d.ts +10 -0
  13. package/lib/command-integrations.js +49 -0
  14. package/lib/command-integrations.js.map +1 -0
  15. package/lib/command-mode.d.ts +5 -0
  16. package/lib/command-mode.js +73 -0
  17. package/lib/command-mode.js.map +1 -0
  18. package/lib/command-model.d.ts +5 -0
  19. package/lib/command-model.js +87 -0
  20. package/lib/command-model.js.map +1 -0
  21. package/lib/command-output.d.ts +6 -0
  22. package/lib/command-output.js +33 -0
  23. package/lib/command-output.js.map +1 -0
  24. package/lib/command-queue.d.ts +5 -0
  25. package/lib/command-queue.js +62 -0
  26. package/lib/command-queue.js.map +1 -0
  27. package/lib/command-registration.d.ts +5 -0
  28. package/lib/command-registration.js +20 -0
  29. package/lib/command-registration.js.map +1 -0
  30. package/lib/command-session.d.ts +5 -0
  31. package/lib/command-session.js +153 -0
  32. package/lib/command-session.js.map +1 -0
  33. package/lib/command-transcript.d.ts +5 -0
  34. package/lib/command-transcript.js +85 -0
  35. package/lib/command-transcript.js.map +1 -0
  36. package/lib/copy-selector.d.ts +52 -0
  37. package/lib/copy-selector.js +136 -0
  38. package/lib/copy-selector.js.map +1 -0
  39. package/lib/copy-targets.d.ts +34 -0
  40. package/lib/copy-targets.js +170 -0
  41. package/lib/copy-targets.js.map +1 -0
  42. package/lib/definition.d.ts +171 -0
  43. package/lib/definition.js +14 -0
  44. package/lib/definition.js.map +1 -0
  45. package/lib/editor.d.ts +66 -0
  46. package/lib/editor.js +365 -0
  47. package/lib/editor.js.map +1 -0
  48. package/lib/event-views.d.ts +188 -0
  49. package/lib/event-views.js +678 -0
  50. package/lib/event-views.js.map +1 -0
  51. package/lib/external-editor.d.ts +2 -0
  52. package/lib/external-editor.js +31 -0
  53. package/lib/external-editor.js.map +1 -0
  54. package/lib/history-search.d.ts +61 -0
  55. package/lib/history-search.js +239 -0
  56. package/lib/history-search.js.map +1 -0
  57. package/lib/history-store.d.ts +8 -0
  58. package/lib/history-store.js +36 -0
  59. package/lib/history-store.js.map +1 -0
  60. package/lib/hotkeys.d.ts +14 -0
  61. package/lib/hotkeys.js +115 -0
  62. package/lib/hotkeys.js.map +1 -0
  63. package/lib/human-interaction.d.ts +5 -0
  64. package/lib/human-interaction.js +8 -0
  65. package/lib/human-interaction.js.map +1 -0
  66. package/lib/image-paste.d.ts +21 -0
  67. package/lib/image-paste.js +277 -0
  68. package/lib/image-paste.js.map +1 -0
  69. package/lib/index.d.ts +10 -0
  70. package/lib/index.js +11 -0
  71. package/lib/index.js.map +1 -0
  72. package/lib/interaction-adapter.d.ts +18 -0
  73. package/lib/interaction-adapter.js +93 -0
  74. package/lib/interaction-adapter.js.map +1 -0
  75. package/lib/keybindings-config.d.ts +5 -0
  76. package/lib/keybindings-config.js +28 -0
  77. package/lib/keybindings-config.js.map +1 -0
  78. package/lib/keys.d.ts +59 -0
  79. package/lib/keys.js +263 -0
  80. package/lib/keys.js.map +1 -0
  81. package/lib/markdown.d.ts +13 -0
  82. package/lib/markdown.js +453 -0
  83. package/lib/markdown.js.map +1 -0
  84. package/lib/path-complete.d.ts +85 -0
  85. package/lib/path-complete.js +231 -0
  86. package/lib/path-complete.js.map +1 -0
  87. package/lib/path-mentions.d.ts +4 -0
  88. package/lib/path-mentions.js +50 -0
  89. package/lib/path-mentions.js.map +1 -0
  90. package/lib/project-context.d.ts +13 -0
  91. package/lib/project-context.js +52 -0
  92. package/lib/project-context.js.map +1 -0
  93. package/lib/project-file-search.d.ts +25 -0
  94. package/lib/project-file-search.js +207 -0
  95. package/lib/project-file-search.js.map +1 -0
  96. package/lib/prompt-selector.d.ts +56 -0
  97. package/lib/prompt-selector.js +297 -0
  98. package/lib/prompt-selector.js.map +1 -0
  99. package/lib/provider-local.d.ts +115 -0
  100. package/lib/provider-local.js +1760 -0
  101. package/lib/provider-local.js.map +1 -0
  102. package/lib/pwd.d.ts +13 -0
  103. package/lib/pwd.js +14 -0
  104. package/lib/pwd.js.map +1 -0
  105. package/lib/relative-time.d.ts +2 -0
  106. package/lib/relative-time.js +11 -0
  107. package/lib/relative-time.js.map +1 -0
  108. package/lib/renderer.d.ts +112 -0
  109. package/lib/renderer.js +181 -0
  110. package/lib/renderer.js.map +1 -0
  111. package/lib/runner.d.ts +9 -0
  112. package/lib/runner.js +94 -0
  113. package/lib/runner.js.map +1 -0
  114. package/lib/session-controller.d.ts +92 -0
  115. package/lib/session-controller.js +571 -0
  116. package/lib/session-controller.js.map +1 -0
  117. package/lib/session-runtime.d.ts +16 -0
  118. package/lib/session-runtime.js +17 -0
  119. package/lib/session-runtime.js.map +1 -0
  120. package/lib/settings-list.d.ts +67 -0
  121. package/lib/settings-list.js +380 -0
  122. package/lib/settings-list.js.map +1 -0
  123. package/lib/status-config.d.ts +32 -0
  124. package/lib/status-config.js +52 -0
  125. package/lib/status-config.js.map +1 -0
  126. package/lib/status-line.d.ts +41 -0
  127. package/lib/status-line.js +351 -0
  128. package/lib/status-line.js.map +1 -0
  129. package/lib/style.d.ts +22 -0
  130. package/lib/style.js +23 -0
  131. package/lib/style.js.map +1 -0
  132. package/lib/theme.d.ts +83 -0
  133. package/lib/theme.js +317 -0
  134. package/lib/theme.js.map +1 -0
  135. package/lib/tool-presentation.d.ts +20 -0
  136. package/lib/tool-presentation.js +79 -0
  137. package/lib/tool-presentation.js.map +1 -0
  138. package/lib/tool-renderers.d.ts +21 -0
  139. package/lib/tool-renderers.js +133 -0
  140. package/lib/tool-renderers.js.map +1 -0
  141. package/lib/tools-list.d.ts +14 -0
  142. package/lib/tools-list.js +61 -0
  143. package/lib/tools-list.js.map +1 -0
  144. package/lib/transcript-export.d.ts +4 -0
  145. package/lib/transcript-export.js +66 -0
  146. package/lib/transcript-export.js.map +1 -0
  147. package/lib/tui-settings.d.ts +20 -0
  148. package/lib/tui-settings.js +23 -0
  149. package/lib/tui-settings.js.map +1 -0
  150. package/lib/welcome-tips.d.ts +10 -0
  151. package/lib/welcome-tips.js +36 -0
  152. package/lib/welcome-tips.js.map +1 -0
  153. package/lib/width.d.ts +54 -0
  154. package/lib/width.js +323 -0
  155. package/lib/width.js.map +1 -0
  156. package/package.json +119 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 D.Yang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # @agi-fans/dsh-tui
2
+
3
+ The omdsh TUI capability seam: terminal presentation for the DeepSeek Harness core runtime. One capability seam, three roles, complete:
4
+
5
+ - **Service Definition** (`src/definition.ts`) — the `tui` context service: `event`, `setStatus`, `setModel`, `readline`, `onInterrupt`, `dispose`. The vocabulary mirrors the SDK wire surface (`session.event`, `session.status`), so a remote UI can reuse the definition unchanged.
6
+ - **Service Provider** (`src/provider-local.ts`) — owns the tty: raw-mode key input (editing, history, slash/tab, Ctrl-R search, PgUp/PgDn transcript scroll, bracketed paste, Ctrl-C interrupt, Ctrl-D quit), SIGWINCH reflow, and the differential renderer. Non-tty streams degrade to line input with plain append-only printing of settled blocks.
7
+ - **Consumer** (`src/runner.ts`) — the interactive driver in the `@deepseek-ai/dsh-headless` pattern: creates one Agent through the core registry, forwards its session events, and loops on `readline`.
8
+
9
+ The rendering pipeline (`renderer`, `style`, `event-views`) is pure and exported for tests and alternative providers.
10
+
11
+ ## Usage
12
+
13
+ Mount the provider and runner as ordinary cordis.yml rows (see `apps/omdsh/config/cordis.yml`); the app package owns the `omdsh` bin.
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Slash-command autocomplete: OMP-style leading-`/` matching, ranking, and
3
+ * completion apply. Pure — the provider owns popup selection and execution.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ import { type Theme } from './theme.ts';
7
+ /** One argument token a slash command can complete. */
8
+ export interface SlashArgument {
9
+ value: string;
10
+ aliases?: readonly string[];
11
+ description: string;
12
+ }
13
+ /** One slash command the editor can complete and the TUI can run. */
14
+ export interface SlashCommand {
15
+ name: string;
16
+ aliases?: readonly string[];
17
+ description: string;
18
+ arguments?: readonly SlashArgument[];
19
+ /** Free-form argument usage contributed by a runtime command plugin. */
20
+ inputHint?: string;
21
+ }
22
+ /** One ranked suggestion shown in the popup. */
23
+ export interface AutocompleteItem {
24
+ value: string;
25
+ label: string;
26
+ description?: string;
27
+ /** Argument and path rows paint without a leading `/`. */
28
+ kind?: 'command' | 'argument' | 'path';
29
+ }
30
+ /** Built-in session-surface commands (no extra backend required). */
31
+ export declare const BUILTIN_SLASH_COMMANDS: readonly SlashCommand[];
32
+ /** Visible popup rows (OMP editor default). */
33
+ export declare const AUTOCOMPLETE_MAX_VISIBLE = 5;
34
+ /** Index of the `/` that opens a leading slash command, or null. */
35
+ export declare function findLeadingSlashCommandStart(text: string): number | null;
36
+ /** Subsequence match (`wig` hits `skill:wig`). */
37
+ export declare function fuzzyMatch(query: string, target: string): boolean;
38
+ /**
39
+ * Rank a fuzzy hit. Exact > starts-with > contains > tight subsequence.
40
+ */
41
+ export declare function fuzzyScore(query: string, target: string): number;
42
+ /**
43
+ * Score a typed prefix against a command name or alias. Prefix matches share
44
+ * one flat rank so registry order is preserved (OMP `/set` vs `/settings`).
45
+ */
46
+ export declare function scoreCommandTextMatch(lowerPrefix: string, lowerTarget: string): number;
47
+ /** Ranked command-name completions for a prefix (no leading slash). */
48
+ export declare function buildSlashCommandCompletions(commands: readonly SlashCommand[], lowerPrefix: string): AutocompleteItem[];
49
+ /** Ranked argument completions for the token after `/name `. */
50
+ export declare function buildSlashArgumentCompletions(args: readonly SlashArgument[], lowerPrefix: string): AutocompleteItem[];
51
+ /** Dim ghost text after the caret for `/name ` argument state. */
52
+ export declare function slashInlineHint(text: string, cursor: number, commands?: readonly SlashCommand[]): string | null;
53
+ /** Suggestions for the live buffer, or null when the cursor is not in a command token. */
54
+ export declare function slashSuggestions(text: string, cursor: number, commands?: readonly SlashCommand[]): {
55
+ items: AutocompleteItem[];
56
+ prefix: string;
57
+ } | null;
58
+ /** Replace the live command or argument token with the selected completion. */
59
+ export declare function applySlashCompletion(text: string, cursor: number, item: AutocompleteItem): {
60
+ text: string;
61
+ cursor: number;
62
+ };
63
+ /** Parse a submitted line as `/name args`. Null when the line is not a slash command. */
64
+ export declare function parseSlashInput(text: string): {
65
+ name: string;
66
+ args: string;
67
+ } | null;
68
+ /** Resolve a typed name or alias to a catalog entry. */
69
+ export declare function resolveSlashCommand(name: string, commands?: readonly SlashCommand[]): SlashCommand | undefined;
70
+ /** Grouped Markdown command directory rendered by the command-output surface. */
71
+ export declare function formatHelpText(commands?: readonly SlashCommand[]): string;
72
+ /** Visible item-index window around `selected` (counter row is not included). */
73
+ export declare function autocompleteVisibleRange(count: number, selected: number): {
74
+ start: number;
75
+ end: number;
76
+ };
77
+ /** Item index under a popup-local row, or undefined on the counter/padding. */
78
+ export declare function hitTestAutocomplete(count: number, selected: number, localRow: number): number | undefined;
79
+ /** Popup rows: cursor + name + description, windowed around the selection. */
80
+ export declare function renderAutocomplete(items: readonly AutocompleteItem[], selected: number, theme: Theme, width: number): string[];
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Slash-command autocomplete: OMP-style leading-`/` matching, ranking, and
3
+ * completion apply. Pure — the provider owns popup selection and execution.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ import { SYMBOL } from "./theme.js";
7
+ import { truncateToWidth } from "./width.js";
8
+ const COPY_ARGUMENTS = [
9
+ { value: 'text', description: 'Last assistant reply' },
10
+ { value: 'code', description: 'Last fenced code block' },
11
+ { value: 'cmd', aliases: ['command'], description: 'Last bash command' },
12
+ ];
13
+ /** Built-in session-surface commands (no extra backend required). */
14
+ export const BUILTIN_SLASH_COMMANDS = [
15
+ { name: 'help', aliases: ['h', '?'], description: 'Show available slash commands' },
16
+ { name: 'settings', aliases: ['set'], description: 'Open settings' },
17
+ { name: 'hotkeys', description: 'Show keyboard shortcuts' },
18
+ { name: 'copy', description: 'Pick text, code, or a command to copy', arguments: COPY_ARGUMENTS },
19
+ { name: 'tools', description: 'Show tools visible to the agent' },
20
+ { name: 'pwd', aliases: ['dirs'], description: 'Show working directory and model' },
21
+ { name: 'clear', description: 'Clear the transcript display' },
22
+ { name: 'quit', aliases: ['q', 'exit'], description: 'Quit the application' },
23
+ ];
24
+ /** Visible popup rows (OMP editor default). */
25
+ export const AUTOCOMPLETE_MAX_VISIBLE = 5;
26
+ /** Index of the `/` that opens a leading slash command, or null. */
27
+ export function findLeadingSlashCommandStart(text) {
28
+ const trimmed = text.trimStart();
29
+ if (!trimmed.startsWith('/'))
30
+ return null;
31
+ return text.length - trimmed.length;
32
+ }
33
+ /** Subsequence match (`wig` hits `skill:wig`). */
34
+ export function fuzzyMatch(query, target) {
35
+ if (query.length === 0)
36
+ return true;
37
+ if (query.length > target.length)
38
+ return false;
39
+ let qi = 0;
40
+ for (let ti = 0; ti < target.length && qi < query.length; ti += 1) {
41
+ if (query[qi] === target[ti])
42
+ qi += 1;
43
+ }
44
+ return qi === query.length;
45
+ }
46
+ /**
47
+ * Rank a fuzzy hit. Exact > starts-with > contains > tight subsequence.
48
+ */
49
+ export function fuzzyScore(query, target) {
50
+ if (query.length === 0)
51
+ return 1;
52
+ if (target === query)
53
+ return 100;
54
+ if (target.startsWith(query))
55
+ return 80;
56
+ if (target.includes(query))
57
+ return 60;
58
+ let qi = 0;
59
+ let gaps = 0;
60
+ let last = -1;
61
+ for (let ti = 0; ti < target.length && qi < query.length; ti += 1) {
62
+ if (query[qi] === target[ti]) {
63
+ if (last >= 0 && ti - last > 1)
64
+ gaps += 1;
65
+ last = ti;
66
+ qi += 1;
67
+ }
68
+ }
69
+ if (qi !== query.length)
70
+ return 0;
71
+ return Math.max(1, 40 - gaps * 5);
72
+ }
73
+ /**
74
+ * Score a typed prefix against a command name or alias. Prefix matches share
75
+ * one flat rank so registry order is preserved (OMP `/set` vs `/settings`).
76
+ */
77
+ export function scoreCommandTextMatch(lowerPrefix, lowerTarget) {
78
+ if (lowerPrefix.length === 0)
79
+ return 1;
80
+ if (lowerPrefix === lowerTarget)
81
+ return 1000;
82
+ if (lowerTarget.startsWith(lowerPrefix))
83
+ return 900;
84
+ return fuzzyMatch(lowerPrefix, lowerTarget) ? fuzzyScore(lowerPrefix, lowerTarget) : 0;
85
+ }
86
+ function namesOf(value, aliases) {
87
+ return [value, ...(aliases ?? [])];
88
+ }
89
+ function buildNamedCompletions(entries, lowerPrefix, kind) {
90
+ if (kind === 'argument' && lowerPrefix.includes(' '))
91
+ return [];
92
+ return entries
93
+ .flatMap((entry) => {
94
+ let best;
95
+ for (const name of namesOf(entry.value, entry.aliases)) {
96
+ const score = scoreCommandTextMatch(lowerPrefix, name.toLowerCase());
97
+ if (score === 0)
98
+ continue;
99
+ if (best !== undefined && score <= best.score)
100
+ continue;
101
+ const item = {
102
+ value: entry.value,
103
+ label: name,
104
+ kind,
105
+ score,
106
+ };
107
+ if (entry.description !== '')
108
+ item.description = entry.description;
109
+ best = item;
110
+ }
111
+ return best === undefined ? [] : [best];
112
+ })
113
+ .sort((a, b) => b.score - a.score)
114
+ .map(({ score: _score, ...rest }) => rest);
115
+ }
116
+ /** Ranked command-name completions for a prefix (no leading slash). */
117
+ export function buildSlashCommandCompletions(commands, lowerPrefix) {
118
+ return buildNamedCompletions(commands.map((command) => ({
119
+ value: command.name,
120
+ ...(command.aliases === undefined ? {} : { aliases: command.aliases }),
121
+ description: command.description,
122
+ })), lowerPrefix, 'command');
123
+ }
124
+ /** Ranked argument completions for the token after `/name `. */
125
+ export function buildSlashArgumentCompletions(args, lowerPrefix) {
126
+ return buildNamedCompletions(args, lowerPrefix, 'argument');
127
+ }
128
+ function argumentHint(command) {
129
+ if (command.inputHint !== undefined && command.inputHint !== '')
130
+ return ' ' + command.inputHint;
131
+ const args = command.arguments;
132
+ if (args === undefined || args.length === 0)
133
+ return '';
134
+ return ' [' + args.map((arg) => arg.value).join('|') + ']';
135
+ }
136
+ /** Dim ghost text after the caret for `/name ` argument state. */
137
+ export function slashInlineHint(text, cursor, commands = BUILTIN_SLASH_COMMANDS) {
138
+ if (cursor !== text.length || text.includes('\n'))
139
+ return null;
140
+ const start = findLeadingSlashCommandStart(text);
141
+ if (start === null)
142
+ return null;
143
+ const token = text.slice(start);
144
+ if (token.slice(1).includes('/'))
145
+ return null;
146
+ const space = token.indexOf(' ');
147
+ if (space === -1)
148
+ return null;
149
+ const command = resolveSlashCommand(token.slice(1, space), commands);
150
+ const args = command?.arguments;
151
+ if (args === undefined || args.length === 0)
152
+ return null;
153
+ const prefix = token.slice(space + 1);
154
+ if (prefix.includes(' '))
155
+ return null;
156
+ if (prefix === '')
157
+ return args.map((arg) => arg.value).join('|');
158
+ const lower = prefix.toLowerCase();
159
+ for (const arg of args) {
160
+ for (const name of [arg.value, ...(arg.aliases ?? [])]) {
161
+ if (!name.toLowerCase().startsWith(lower))
162
+ continue;
163
+ const remaining = name.slice(prefix.length);
164
+ return remaining === '' ? null : remaining;
165
+ }
166
+ }
167
+ return null;
168
+ }
169
+ /** Suggestions for the live buffer, or null when the cursor is not in a command token. */
170
+ export function slashSuggestions(text, cursor, commands = BUILTIN_SLASH_COMMANDS) {
171
+ const before = text.slice(0, cursor);
172
+ if (text.includes('\n'))
173
+ return null;
174
+ const start = findLeadingSlashCommandStart(before);
175
+ if (start === null)
176
+ return null;
177
+ const token = before.slice(start);
178
+ if (token.slice(1).includes('/'))
179
+ return null;
180
+ const space = token.indexOf(' ');
181
+ if (space === -1) {
182
+ const items = buildSlashCommandCompletions(commands, token.slice(1).toLowerCase());
183
+ if (items.length === 0)
184
+ return null;
185
+ return { items, prefix: before };
186
+ }
187
+ const command = resolveSlashCommand(token.slice(1, space), commands);
188
+ const args = command?.arguments;
189
+ if (args === undefined || args.length === 0)
190
+ return null;
191
+ const items = buildSlashArgumentCompletions(args, token.slice(space + 1).toLowerCase());
192
+ if (items.length === 0)
193
+ return null;
194
+ return { items, prefix: before };
195
+ }
196
+ /** Replace the live command or argument token with the selected completion. */
197
+ export function applySlashCompletion(text, cursor, item) {
198
+ const before = text.slice(0, cursor);
199
+ const after = text.slice(cursor);
200
+ const start = findLeadingSlashCommandStart(before);
201
+ if (start === null)
202
+ return { text, cursor };
203
+ if (item.kind === 'argument') {
204
+ const space = before.slice(start).lastIndexOf(' ');
205
+ if (space === -1)
206
+ return { text, cursor };
207
+ const argStart = start + space + 1;
208
+ const insert = item.value.endsWith(' ') ? item.value : item.value + ' ';
209
+ return { text: text.slice(0, argStart) + insert + after, cursor: argStart + insert.length };
210
+ }
211
+ const insert = `/${item.value} `;
212
+ return { text: text.slice(0, start) + insert + after, cursor: start + insert.length };
213
+ }
214
+ /** Parse a submitted line as `/name args`. Null when the line is not a slash command. */
215
+ export function parseSlashInput(text) {
216
+ if (text.includes('\n'))
217
+ return null;
218
+ const trimmed = text.trim();
219
+ if (!trimmed.startsWith('/'))
220
+ return null;
221
+ const body = trimmed.slice(1);
222
+ if (body === '')
223
+ return { name: '', args: '' };
224
+ if (body.startsWith('skill:')) {
225
+ const space = body.search(/\s/u);
226
+ if (space === -1)
227
+ return { name: body, args: '' };
228
+ return { name: body.slice(0, space), args: body.slice(space + 1).trim() };
229
+ }
230
+ const sep = body.search(/[\s:]/);
231
+ if (sep === -1)
232
+ return { name: body, args: '' };
233
+ return { name: body.slice(0, sep), args: body.slice(sep + 1).trim() };
234
+ }
235
+ /** Resolve a typed name or alias to a catalog entry. */
236
+ export function resolveSlashCommand(name, commands = BUILTIN_SLASH_COMMANDS) {
237
+ const lower = name.toLowerCase();
238
+ return commands.find((command) => command.name === lower || (command.aliases ?? []).includes(lower));
239
+ }
240
+ function helpCell(value) {
241
+ return value.replace(/\|/gu, '\\|').replace(/\s+/gu, ' ').trim();
242
+ }
243
+ function helpTable(commands) {
244
+ if (commands.length === 0)
245
+ return [];
246
+ return [
247
+ '| Command | Description |',
248
+ '|---|---|',
249
+ ...commands.map((command) => {
250
+ const names = [command.name, ...(command.aliases ?? [])]
251
+ .map((name, index) => `\`${helpCell(`/${name}${index === 0 ? argumentHint(command) : ''}`)}\``)
252
+ .join(' / ');
253
+ return `| ${names} | ${helpCell(command.description)} |`;
254
+ }),
255
+ ];
256
+ }
257
+ /** Grouped Markdown command directory rendered by the command-output surface. */
258
+ export function formatHelpText(commands = BUILTIN_SLASH_COMMANDS) {
259
+ const skills = commands.filter(command => command.name.startsWith('skill:'));
260
+ const terminalNames = new Set(BUILTIN_SLASH_COMMANDS.map(command => command.name));
261
+ const terminal = commands.filter(command => terminalNames.has(command.name));
262
+ const agent = commands.filter(command => !command.name.startsWith('skill:') && !terminalNames.has(command.name));
263
+ const lines = [`Commands · ${terminal.length + agent.length} available`];
264
+ if (terminal.length > 0) {
265
+ lines.push('', `**Terminal Commands · ${terminal.length}**`, ...helpTable(terminal));
266
+ }
267
+ if (agent.length > 0) {
268
+ lines.push('', `**Agent Commands · ${agent.length}**`, ...helpTable(agent));
269
+ }
270
+ if (skills.length > 0) {
271
+ lines.push('', `**Skills · ${skills.length}**`, '', 'Type `/skill:` to browse and filter skills with descriptions.');
272
+ }
273
+ return lines.join('\n');
274
+ }
275
+ /** Visible item-index window around `selected` (counter row is not included). */
276
+ export function autocompleteVisibleRange(count, selected) {
277
+ const max = AUTOCOMPLETE_MAX_VISIBLE;
278
+ const index = Math.max(0, Math.min(selected, Math.max(0, count - 1)));
279
+ const start = Math.max(0, Math.min(index - Math.floor(max / 2), Math.max(0, count - max)));
280
+ return { start, end: Math.min(count, start + max) };
281
+ }
282
+ /** Item index under a popup-local row, or undefined on the counter/padding. */
283
+ export function hitTestAutocomplete(count, selected, localRow) {
284
+ const { start, end } = autocompleteVisibleRange(count, selected);
285
+ const index = start + localRow;
286
+ if (index < start || index >= end)
287
+ return undefined;
288
+ return index;
289
+ }
290
+ /** Popup rows: cursor + name + description, windowed around the selection. */
291
+ export function renderAutocomplete(items, selected, theme, width) {
292
+ if (items.length === 0 || width <= 0)
293
+ return [];
294
+ const { start, end } = autocompleteVisibleRange(items.length, selected);
295
+ const index = Math.max(0, Math.min(selected, items.length - 1));
296
+ const lines = [];
297
+ for (let i = start; i < end; i += 1) {
298
+ const item = items[i];
299
+ if (item === undefined)
300
+ continue;
301
+ const isSelected = i === index;
302
+ const cursor = isSelected ? theme.fg('accent', SYMBOL.cursor + ' ') : ' ';
303
+ const name = item.kind === 'argument' || item.kind === 'path' ? item.label : '/' + item.label;
304
+ const painted = isSelected ? theme.bold(theme.fg('accent', name)) : name;
305
+ const desc = item.description !== undefined && item.description !== ''
306
+ ? theme.fg('muted', ' ' + item.description)
307
+ : '';
308
+ lines.push(truncateToWidth(cursor + painted + desc, width));
309
+ }
310
+ const pathMode = items.some(item => item.kind === 'path');
311
+ if (pathMode) {
312
+ const position = items.length > 1 ? `${index + 1}/${items.length} · ` : '';
313
+ lines.push(theme.fg('dim', truncateToWidth(` ${position}↑↓ select · Tab insert · Enter send · Esc close`, width)));
314
+ }
315
+ else if (items.length > AUTOCOMPLETE_MAX_VISIBLE) {
316
+ lines.push(theme.fg('dim', ' ' + String(index + 1) + '/' + String(items.length)));
317
+ }
318
+ return lines;
319
+ }
320
+ //# sourceMappingURL=autocomplete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete.js","sourceRoot":"","sources":["../src/autocomplete.ts"],"names":[],"mappings":"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"}
package/lib/box.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Rounded-box chrome ported from oh-my-pi: framed tool output, the welcome
3
+ * card and the framed editor whose top border carries its compact label.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ import { type Theme, type ThemeColor } from './theme.ts';
7
+ import { type WelcomeTip } from './welcome-tips.ts';
8
+ /** Visual state that drives border + fill color. */
9
+ export type BoxState = 'idle' | 'info' | 'running' | 'ok' | 'error' | 'warning';
10
+ /** Options for a rounded output block (tool / notice). */
11
+ export interface FramedBlockOptions {
12
+ header?: string;
13
+ headerMeta?: string;
14
+ state?: BoxState;
15
+ lines?: readonly string[];
16
+ width: number;
17
+ applyBg?: boolean;
18
+ }
19
+ /**
20
+ * OMP `renderOutputBlock`: `╭─── header ────╮` / padded body / `╰────╯`.
21
+ */
22
+ export declare function renderFramedBlock(options: FramedBlockOptions, theme: Theme): string[];
23
+ /** Welcome card inputs. */
24
+ export interface WelcomeOptions {
25
+ width: number;
26
+ model: string;
27
+ /** Effective reasoning effort for the selected model, painted under the model name. */
28
+ reasoningEffort?: string;
29
+ version: string;
30
+ appName: string;
31
+ recentSessions?: readonly {
32
+ id: string;
33
+ title: string;
34
+ createdAt: number;
35
+ updatedAt?: number;
36
+ }[];
37
+ /** Per-process hint sample; defaults to a deterministic catalog prefix for pure callers. */
38
+ tips?: readonly WelcomeTip[];
39
+ }
40
+ /**
41
+ * Two-column welcome card: gradient DeepSeek logo + tips, titled `app vversion`.
42
+ */
43
+ export declare function renderWelcome(options: WelcomeOptions, theme: Theme): string[];
44
+ /** Editor chrome inputs. */
45
+ export interface EditorOptions {
46
+ width: number;
47
+ input: string;
48
+ inputCursor: number;
49
+ status: string;
50
+ border: ThemeColor;
51
+ /** Dim ghost text painted after the caret (slash-arg hint). */
52
+ inlineHint?: string;
53
+ /** Paint one wrapped input slice without changing its visible width. */
54
+ paintInput?: (text: string, sourceStart: number) => string;
55
+ }
56
+ /** Editor frame plus a cursor offset relative to the editor's first row. */
57
+ export interface EditorFrame {
58
+ lines: string[];
59
+ cursor: {
60
+ row: number;
61
+ column: number;
62
+ };
63
+ }
64
+ /**
65
+ * Rounded editor: its label lives in the top border, input occupies one or more
66
+ * body rows, and a dedicated bottom border keeps the cursor off the chrome.
67
+ */
68
+ export declare function renderEditor(options: EditorOptions, theme: Theme): EditorFrame;
69
+ /** Columns of left chrome before input text (`│ `). */
70
+ export declare const EDITOR_CONTENT_COL = 2;
71
+ /**
72
+ * Map a click in editor-local coordinates to a buffer index.
73
+ * Row 0 is the status cap (no hit). Undefined when the click is outside.
74
+ */
75
+ export declare function hitTestEditor(input: string, width: number, localRow: number, col: number): number | undefined;
76
+ /** DeepSeek Harness-aligned label shown while the model is driving a turn. */
77
+ export declare const DEEP_DRIVING_LABEL = "Deep Driving";
78
+ /** Activity row that sits above the editor while a turn is in flight. */
79
+ export declare function renderWorking(theme: Theme, spinnerFrame: number, action?: string, width?: number): string[];