@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
@@ -0,0 +1,136 @@
1
+ /**
2
+ * `/copy` picker overlay: OMP-style list of transcript copy targets.
3
+ * Pure — the provider owns the clipboard write.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ import { SYMBOL } from "./theme.js";
7
+ import { truncateToWidth, visibleWidth, wrapText } from "./width.js";
8
+ /** Visible picker rows. */
9
+ export const COPY_SELECTOR_MAX_VISIBLE = 8;
10
+ /** Preview lines under the list. */
11
+ export const COPY_SELECTOR_PREVIEW_LINES = 4;
12
+ /** First overlay-local row that paints a target. */
13
+ export const COPY_SELECTOR_ITEM_ROW = 3;
14
+ /** Open the picker on the assembled targets. */
15
+ export function createCopySelector(items, selected = 0) {
16
+ return { items, selected: Math.max(0, Math.min(selected, Math.max(0, items.length - 1))) };
17
+ }
18
+ /** Visible item-index window around `selected`. */
19
+ export function copySelectorVisibleRange(count, selected, maxVisible = COPY_SELECTOR_MAX_VISIBLE) {
20
+ const max = Math.max(1, maxVisible);
21
+ const index = Math.max(0, Math.min(selected, Math.max(0, count - 1)));
22
+ const start = Math.max(0, Math.min(index - Math.floor(max / 2), Math.max(0, count - max)));
23
+ return { start, end: Math.min(count, start + max) };
24
+ }
25
+ /** Item index under an overlay-local row, or undefined on chrome. */
26
+ export function hitTestCopySelector(count, selected, localRow, maxVisible = COPY_SELECTOR_MAX_VISIBLE) {
27
+ const { start, end } = copySelectorVisibleRange(count, selected, maxVisible);
28
+ const index = start + (localRow - COPY_SELECTOR_ITEM_ROW);
29
+ if (index < start || index >= end)
30
+ return undefined;
31
+ return index;
32
+ }
33
+ /** Move the highlight to `index` without copying. */
34
+ export function selectCopyTarget(state, index) {
35
+ if (state.items.length === 0)
36
+ return state;
37
+ const selected = Math.max(0, Math.min(index, state.items.length - 1));
38
+ if (selected === state.selected)
39
+ return state;
40
+ return { ...state, selected };
41
+ }
42
+ function moveSelected(state, next) {
43
+ if (state.items.length === 0)
44
+ return state;
45
+ const n = state.items.length;
46
+ const selected = (next % n + n) % n;
47
+ if (selected === state.selected)
48
+ return state;
49
+ return { ...state, selected };
50
+ }
51
+ /** Apply one decoded event to the overlay. */
52
+ export function applyCopySelectorEvent(state, event) {
53
+ if (event.type === 'text' && event.value === ' ') {
54
+ const item = state.items[state.selected];
55
+ return item === undefined ? { kind: 'ignore' } : { kind: 'pick', item };
56
+ }
57
+ if (event.type !== 'key')
58
+ return { kind: 'ignore' };
59
+ switch (event.id) {
60
+ case 'enter': {
61
+ const item = state.items[state.selected];
62
+ return item === undefined ? { kind: 'ignore' } : { kind: 'pick', item };
63
+ }
64
+ case 'escape':
65
+ case 'ctrl+c':
66
+ return { kind: 'close' };
67
+ case 'up':
68
+ case 'shift+tab':
69
+ return { kind: 'update', state: moveSelected(state, state.selected - 1) };
70
+ case 'down':
71
+ case 'tab':
72
+ return { kind: 'update', state: moveSelected(state, state.selected + 1) };
73
+ case 'pageUp':
74
+ return { kind: 'update', state: moveSelected(state, state.selected - COPY_SELECTOR_MAX_VISIBLE) };
75
+ case 'pageDown':
76
+ return { kind: 'update', state: moveSelected(state, state.selected + COPY_SELECTOR_MAX_VISIBLE) };
77
+ case 'home':
78
+ return { kind: 'update', state: moveSelected(state, 0) };
79
+ case 'end':
80
+ return { kind: 'update', state: moveSelected(state, state.items.length - 1) };
81
+ default:
82
+ return { kind: 'ignore' };
83
+ }
84
+ }
85
+ /** Overlay frame: title, windowed rows, preview, hints. */
86
+ export function renderCopySelector(state, theme, width, maxVisible = COPY_SELECTOR_MAX_VISIBLE) {
87
+ const count = state.items.length;
88
+ const index = Math.max(0, Math.min(state.selected, Math.max(0, count - 1)));
89
+ const title = ' ' + theme.bold(theme.fg('accent', '⎘ Copy'));
90
+ const { start, end } = copySelectorVisibleRange(count, index, maxVisible);
91
+ const rows = [];
92
+ if (count === 0) {
93
+ rows.push(' ' + theme.fg('muted', SYMBOL.info + ' Nothing to copy.'));
94
+ }
95
+ else {
96
+ for (let i = start; i < end; i += 1) {
97
+ const item = state.items[i];
98
+ if (item === undefined)
99
+ continue;
100
+ rows.push(renderCopyRow(item, i === index, theme, width));
101
+ }
102
+ if (count > maxVisible) {
103
+ rows.push(theme.fg('dim', ' ' + String(index + 1) + '/' + String(count)));
104
+ }
105
+ }
106
+ const preview = renderCopyPreview(state.items[index], theme, width);
107
+ const hints = ' ' + theme.fg('dim', '↑↓ navigate') + theme.fg('dim', ' · ')
108
+ + theme.fg('dim', 'enter copy') + theme.fg('dim', ' · ')
109
+ + theme.fg('dim', 'esc close');
110
+ const lines = ['', title, '', ...rows, '', ...preview, '', hints];
111
+ return {
112
+ lines,
113
+ cursor: { row: COPY_SELECTOR_ITEM_ROW + (index - start), column: 2 },
114
+ };
115
+ }
116
+ function renderCopyRow(item, selected, theme, width) {
117
+ const cursor = selected ? theme.fg('accent', SYMBOL.cursor + ' ') : ' ';
118
+ const label = selected ? theme.bold(theme.fg('accent', item.label)) : item.label;
119
+ const hint = item.hint === '' ? '' : theme.fg('dim', item.hint);
120
+ const fill = Math.max(1, width - visibleWidth(cursor) - visibleWidth(label) - visibleWidth(hint));
121
+ return truncateToWidth(cursor + label + ' '.repeat(fill) + hint, width);
122
+ }
123
+ function renderCopyPreview(item, theme, width) {
124
+ const header = ' ' + theme.fg('dim', item === undefined ? 'Preview' : 'Preview · ' + item.hint);
125
+ if (item === undefined)
126
+ return [header];
127
+ const wrapped = wrapText(item.text.replace(/\t/g, ' '), Math.max(1, width - 2));
128
+ const cap = COPY_SELECTOR_PREVIEW_LINES;
129
+ const visible = wrapped.slice(0, cap);
130
+ const extra = wrapped.length > cap ? wrapped.length - cap : 0;
131
+ const body = visible.map((line) => truncateToWidth(' ' + theme.fg('muted', line), width));
132
+ if (extra > 0)
133
+ body.push(theme.fg('dim', ' … ' + String(extra) + ' more lines'));
134
+ return [header, ...body];
135
+ }
136
+ //# sourceMappingURL=copy-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-selector.js","sourceRoot":"","sources":["../src/copy-selector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `/copy` targets from the live transcript: last assistant text, last fenced
3
+ * code block, or last bash command. Pure — the provider owns the clipboard.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ import type { Block } from './event-views.ts';
7
+ /** What `/copy` should pull from the transcript. */
8
+ export type CopyKind = 'text' | 'code' | 'cmd';
9
+ /** One clipboard payload plus the status label shown after a successful copy. */
10
+ export interface CopyTarget {
11
+ text: string;
12
+ label: string;
13
+ }
14
+ /** Parse `/copy` arguments. Undefined when the token is not a known kind. */
15
+ export declare function parseCopyKind(args: string): CopyKind | undefined;
16
+ /** Fenced bodies in document order (`lang` is the info string). */
17
+ export declare function extractCodeBlocks(text: string): {
18
+ lang: string;
19
+ code: string;
20
+ }[];
21
+ /** Cap on how many picker rows `/copy` lists (OMP recent-message window). */
22
+ export declare const COPY_TARGET_LIMIT = 50;
23
+ /** One row in the `/copy` picker (flat: messages, fences, bash commands). */
24
+ export interface CopyPick {
25
+ id: string;
26
+ label: string;
27
+ hint: string;
28
+ text: string;
29
+ copyMessage: string;
30
+ }
31
+ /** Newest-first picker rows from the live transcript. */
32
+ export declare function buildCopyTargets(blocks: readonly Block[], limit?: number): CopyPick[];
33
+ /** Walk the transcript backwards for the requested copy target. */
34
+ export declare function extractCopyTarget(blocks: readonly Block[], kind: CopyKind): CopyTarget | undefined;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * `/copy` targets from the live transcript: last assistant text, last fenced
3
+ * code block, or last bash command. Pure — the provider owns the clipboard.
4
+ * @module @agi-fans/dsh-tui
5
+ */
6
+ const FENCE = /^```([^\n]*)$/;
7
+ /** Parse `/copy` arguments. Undefined when the token is not a known kind. */
8
+ export function parseCopyKind(args) {
9
+ const token = args.trim().toLowerCase();
10
+ if (token === '' || token === 'text')
11
+ return 'text';
12
+ if (token === 'code')
13
+ return 'code';
14
+ if (token === 'cmd' || token === 'command')
15
+ return 'cmd';
16
+ return undefined;
17
+ }
18
+ /** Fenced bodies in document order (`lang` is the info string). */
19
+ export function extractCodeBlocks(text) {
20
+ const lines = text.split('\n');
21
+ const blocks = [];
22
+ for (let i = 0; i < lines.length; i += 1) {
23
+ const open = FENCE.exec(lines[i] ?? '');
24
+ if (open === null)
25
+ continue;
26
+ let close = -1;
27
+ for (let k = i + 1; k < lines.length; k += 1) {
28
+ if ((lines[k] ?? '').startsWith('```')) {
29
+ close = k;
30
+ break;
31
+ }
32
+ }
33
+ if (close === -1)
34
+ continue;
35
+ blocks.push({ lang: (open[1] ?? '').trim(), code: lines.slice(i + 1, close).join('\n') });
36
+ i = close;
37
+ }
38
+ return blocks;
39
+ }
40
+ /** Cap on how many picker rows `/copy` lists (OMP recent-message window). */
41
+ export const COPY_TARGET_LIMIT = 50;
42
+ function firstLine(text) {
43
+ for (const line of text.split('\n')) {
44
+ const trimmed = line.trim();
45
+ if (trimmed !== '')
46
+ return trimmed.replace(/\s+/g, ' ');
47
+ }
48
+ return text.trim().replace(/\s+/g, ' ');
49
+ }
50
+ function pluralLines(text) {
51
+ const count = text.length === 0 ? 0 : text.split('\n').length;
52
+ return String(count) + ' line' + (count === 1 ? '' : 's');
53
+ }
54
+ function codeHint(lang, code) {
55
+ return lang === '' ? pluralLines(code) : lang + ' · ' + pluralLines(code);
56
+ }
57
+ function codeLabel(lang, code) {
58
+ const line = firstLine(code);
59
+ if (line !== '')
60
+ return line;
61
+ return lang === '' ? 'code block' : lang + ' block';
62
+ }
63
+ function pushCodePicks(items, source, nextId) {
64
+ for (const fence of extractCodeBlocks(source)) {
65
+ items.push({
66
+ id: nextId(),
67
+ label: codeLabel(fence.lang, fence.code),
68
+ hint: codeHint(fence.lang, fence.code),
69
+ text: fence.code,
70
+ copyMessage: fence.lang === '' ? 'code block' : fence.lang + ' block',
71
+ });
72
+ }
73
+ }
74
+ /** Newest-first picker rows from the live transcript. */
75
+ export function buildCopyTargets(blocks, limit = COPY_TARGET_LIMIT) {
76
+ const items = [];
77
+ let messages = 0;
78
+ let codes = 0;
79
+ let commands = 0;
80
+ const cap = Math.max(0, limit);
81
+ for (let i = blocks.length - 1; i >= 0 && items.length < cap; i -= 1) {
82
+ const block = blocks[i];
83
+ if (block === undefined)
84
+ continue;
85
+ if (block.kind === 'assistant' && block.text.trim() !== '') {
86
+ messages += 1;
87
+ items.push({
88
+ id: 'msg:' + String(messages),
89
+ label: firstLine(block.text),
90
+ hint: pluralLines(block.text),
91
+ text: block.text,
92
+ copyMessage: messages === 1 ? 'last message' : 'assistant text',
93
+ });
94
+ if (items.length >= cap)
95
+ break;
96
+ pushCodePicks(items, block.text, () => {
97
+ codes += 1;
98
+ return 'code:' + String(codes);
99
+ });
100
+ continue;
101
+ }
102
+ if (block.kind !== 'tool')
103
+ continue;
104
+ if (block.output.trim() !== '') {
105
+ pushCodePicks(items, block.output, () => {
106
+ codes += 1;
107
+ return 'code:' + String(codes);
108
+ });
109
+ }
110
+ if (items.length >= cap)
111
+ break;
112
+ if (block.name !== 'bash')
113
+ continue;
114
+ const command = bashCommand(block.args);
115
+ if (command === undefined)
116
+ continue;
117
+ commands += 1;
118
+ items.push({
119
+ id: 'cmd:' + String(commands),
120
+ label: firstLine(command),
121
+ hint: 'bash · ' + pluralLines(command),
122
+ text: command,
123
+ copyMessage: 'bash command',
124
+ });
125
+ }
126
+ return items.slice(0, cap);
127
+ }
128
+ function bashCommand(args) {
129
+ try {
130
+ const parsed = JSON.parse(args);
131
+ if (typeof parsed === 'object' && parsed !== null && 'command' in parsed) {
132
+ const command = parsed.command;
133
+ if (typeof command === 'string' && command !== '')
134
+ return command;
135
+ }
136
+ }
137
+ catch {
138
+ /* not JSON */
139
+ }
140
+ return undefined;
141
+ }
142
+ /** Walk the transcript backwards for the requested copy target. */
143
+ export function extractCopyTarget(blocks, kind) {
144
+ for (let i = blocks.length - 1; i >= 0; i -= 1) {
145
+ const block = blocks[i];
146
+ if (block === undefined)
147
+ continue;
148
+ if (kind === 'text' && block.kind === 'assistant' && block.text.trim() !== '') {
149
+ return { text: block.text, label: 'assistant text' };
150
+ }
151
+ if (kind === 'code') {
152
+ const source = block.kind === 'assistant'
153
+ ? block.text
154
+ : block.kind === 'tool' ? block.output : '';
155
+ const fences = extractCodeBlocks(source);
156
+ const last = fences[fences.length - 1];
157
+ if (last !== undefined) {
158
+ const lang = last.lang === '' ? 'code block' : last.lang + ' block';
159
+ return { text: last.code, label: lang };
160
+ }
161
+ }
162
+ if (kind === 'cmd' && block.kind === 'tool' && block.name === 'bash') {
163
+ const command = bashCommand(block.args);
164
+ if (command !== undefined)
165
+ return { text: command, label: 'bash command' };
166
+ }
167
+ }
168
+ return undefined;
169
+ }
170
+ //# sourceMappingURL=copy-targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-targets.js","sourceRoot":"","sources":["../src/copy-targets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * TUI capability seam — Service Definition.
3
+
4
+ * The tui service is the presentation role of the omdsh capability seam:
5
+ * the provider (./provider-local.ts) owns the terminal and the renderer,
6
+ * and consumers (./runner.ts) forward session events and read user input
7
+ * through this protocol. The vocabulary mirrors the SDK wire surface
8
+ * (session.event / session.status), so a future remote UI can reuse the
9
+ * definition unchanged.
10
+ * @module @agi-fans/dsh-tui
11
+ */
12
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
13
+ import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
14
+ import type { TuiToolPresentation } from './tool-renderers.ts';
15
+ /** Context service name providers publish under. */
16
+ export declare const TUI_SERVICE = "tui";
17
+ /** Whole-agent liveness, mirroring the SDK session.status vocabulary. */
18
+ export type TuiStatus = 'idle' | 'running';
19
+ /** Command metadata contributed by the active agent's plugin scope. */
20
+ export interface TuiCommand {
21
+ name: string;
22
+ description: string;
23
+ inputHint?: string;
24
+ }
25
+ /** One terminal-owned human prompt used by approval and question adapters. */
26
+ export interface TuiPrompt {
27
+ title: string;
28
+ question: string;
29
+ detail?: string;
30
+ options?: readonly {
31
+ /** Human-facing option name. */
32
+ label: string;
33
+ /** Answer returned to the caller; defaults to {@link label}. */
34
+ value?: string;
35
+ /** Secondary content preview shown above metadata in spacious lists. */
36
+ preview?: string;
37
+ description?: string;
38
+ /** Optional semantic badge painted after the description. */
39
+ badge?: {
40
+ label: string;
41
+ tone: 'success' | 'warning' | 'error' | 'muted';
42
+ };
43
+ }[];
44
+ multiSelect?: boolean;
45
+ allowCustom?: boolean;
46
+ /** Option value selected when a fixed-choice prompt opens. */
47
+ initialValue?: string;
48
+ /** Full-height searchable list instead of the default prompt card. */
49
+ presentation?: 'fullscreen-list' | 'plan-review';
50
+ /** Choice that approves a dedicated review; other choices may collect feedback. */
51
+ approveValue?: string;
52
+ /** Let typed text filter the available options. */
53
+ filterable?: boolean;
54
+ /** Verb shown after Enter in selector navigation, such as "run". */
55
+ submitLabel?: string;
56
+ signal?: AbortSignal;
57
+ }
58
+ /** Durable, Harness-owned session controls projected into terminal chrome. */
59
+ export interface TuiSessionControls {
60
+ /** Logged Plan Mode state, including a selection awaiting the next step boundary. */
61
+ plan?: {
62
+ active: boolean;
63
+ pending: boolean;
64
+ };
65
+ /** Effective permission preset, such as workspace-write or danger-full-access. */
66
+ permission?: string;
67
+ }
68
+ /** Lightweight durable session row used by the welcome card and resume UI. */
69
+ export interface TuiRecentSession {
70
+ id: string;
71
+ title: string;
72
+ preview?: string;
73
+ createdAt: number;
74
+ updatedAt?: number;
75
+ eventCount?: number;
76
+ status?: 'done' | 'interrupted' | 'blocked' | 'failed';
77
+ }
78
+ /** Optional whole-session figures shown below the editor. */
79
+ export interface TuiSessionStats {
80
+ turns: number;
81
+ steps: number;
82
+ /** Summed model wall time over completed assistant messages. */
83
+ llmMs: number;
84
+ /** Summed matched tool-call wall time. */
85
+ toolMs: number;
86
+ /** Summed first-token latency over {@link ttftSteps}. */
87
+ ttftMs: number;
88
+ /** Number of steps carrying a recorded first-token latency. */
89
+ ttftSteps: number;
90
+ /** Summed decode wall time over usage-reporting steps. */
91
+ decodeMs: number;
92
+ /** Output tokens covered by {@link decodeMs}. */
93
+ decodeTokens: number;
94
+ /** All disjoint prompt-side billing buckets combined. */
95
+ inputTokens: number;
96
+ outputTokens: number;
97
+ cacheReadTokens: number;
98
+ cacheWriteTokens: number;
99
+ contextTokens?: number;
100
+ contextWindow?: number;
101
+ elapsedMs?: number;
102
+ }
103
+ /** One unsent image draft owned by the terminal until submission succeeds. */
104
+ export interface TuiInputImage {
105
+ data: Uint8Array;
106
+ mediaType: ImageMediaType;
107
+ name?: string;
108
+ width?: number;
109
+ height?: number;
110
+ }
111
+ /** Atomic composer submission: visible text plus its client-owned image drafts. */
112
+ export interface TuiSubmission {
113
+ text: string;
114
+ images: readonly TuiInputImage[];
115
+ }
116
+ /**
117
+ * Terminal presentation service.
118
+ * Implementations must be single-consumer: one runner owns readInput().
119
+ */
120
+ export interface TuiService {
121
+ /** Render one session-log event (streamed as recorded). */
122
+ event(event: SessionEvent, presentation?: TuiToolPresentation): void;
123
+ /** Update the status line liveness. */
124
+ setStatus(status: TuiStatus): void;
125
+ /** Update the model and effective reasoning effort shown in the composer. */
126
+ setModel(model: string, reasoningEffort?: string): void;
127
+ /** Replace the tool list shown by `/tools`. */
128
+ setTools(tools: readonly {
129
+ name: string;
130
+ description: string;
131
+ }[]): void;
132
+ /** Replace commands contributed by the active agent's Harness scope. */
133
+ setCommands(commands: readonly TuiCommand[]): void;
134
+ /** Append a direct UI/command result without fabricating a session event. */
135
+ notice(text: string, level?: 'info' | 'error'): void;
136
+ /** Append one successful plugin command result using the command-output surface. */
137
+ commandOutput(command: string, text: string): void;
138
+ /** Temporarily own the composer and collect one human answer. */
139
+ prompt(request: TuiPrompt): Promise<string | null>;
140
+ /** Replace the transcript when a new or resumed session becomes active. */
141
+ replaceSession(events: readonly SessionEvent[], presentations?: ReadonlyMap<number, TuiToolPresentation>): void;
142
+ /** Update session identity, recent rows, projected controls, and aggregate figures. */
143
+ setSession(info: {
144
+ id: string;
145
+ recent: readonly TuiRecentSession[];
146
+ stats?: TuiSessionStats;
147
+ controls?: TuiSessionControls;
148
+ }): void;
149
+ /**
150
+ * Read the next submitted composer value. Resolves null when the user quits
151
+ * (Ctrl-D on empty input, or stdin EOF in non-tty mode). One in-flight
152
+ * call at a time.
153
+ */
154
+ readInput(): Promise<TuiSubmission | null>;
155
+ /** Restore an accepted draft when persistence or dispatch fails. */
156
+ restoreInput(submission: TuiSubmission): void;
157
+ /**
158
+ * Subscribe to Ctrl-C. The listener fires when the user presses Ctrl-C
159
+ * while a turn is running; an idle Ctrl-C clears the input line instead.
160
+ * @returns disposer removing the listener.
161
+ */
162
+ onInterrupt(listener: () => void): () => void;
163
+ /** Restore terminal state and settle a pending input read with null. */
164
+ dispose(): void;
165
+ }
166
+ declare module '@deepseek-ai/cordis' {
167
+ interface Context {
168
+ /** The omdsh terminal presentation service. */
169
+ tui: TuiService;
170
+ }
171
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TUI capability seam — Service Definition.
3
+
4
+ * The tui service is the presentation role of the omdsh capability seam:
5
+ * the provider (./provider-local.ts) owns the terminal and the renderer,
6
+ * and consumers (./runner.ts) forward session events and read user input
7
+ * through this protocol. The vocabulary mirrors the SDK wire surface
8
+ * (session.event / session.status), so a future remote UI can reuse the
9
+ * definition unchanged.
10
+ * @module @agi-fans/dsh-tui
11
+ */
12
+ /** Context service name providers publish under. */
13
+ export const TUI_SERVICE = 'tui';
14
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAA"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Input-editor state machine: OMP readline/emacs bindings over a single
3
+ * buffer that may contain newlines. Pure — the provider owns history,
4
+ * interrupt, and process lifetime.
5
+ * @module @agi-fans/dsh-tui
6
+ */
7
+ import type { KeyEvent } from './keys.ts';
8
+ /** What the provider should do after a key is applied. */
9
+ export type EditorCommand = {
10
+ kind: 'changed';
11
+ edited?: boolean;
12
+ } | {
13
+ kind: 'submit';
14
+ text: string;
15
+ } | {
16
+ kind: 'historyPrev';
17
+ } | {
18
+ kind: 'historyNext';
19
+ } | {
20
+ kind: 'interrupt';
21
+ } | {
22
+ kind: 'clear';
23
+ } | {
24
+ kind: 'quit';
25
+ } | {
26
+ kind: 'suspend';
27
+ } | {
28
+ kind: 'resetDisplay';
29
+ } | {
30
+ kind: 'ignored';
31
+ };
32
+ /** Emacs-style kill ring (consecutive kills accumulate). */
33
+ export declare class KillRing {
34
+ #private;
35
+ push(text: string, opts: {
36
+ prepend: boolean;
37
+ accumulate: boolean;
38
+ }): void;
39
+ peek(): string | undefined;
40
+ rotate(): void;
41
+ get length(): number;
42
+ }
43
+ /** Start index of the line containing `cursor`. */
44
+ export declare function lineStart(text: string, cursor: number): number;
45
+ /** End index (before newline, or length) of the line containing `cursor`. */
46
+ export declare function lineEnd(text: string, cursor: number): number;
47
+ /** Word-left: skip trailing whitespace, then the previous word. */
48
+ export declare function moveWordLeft(text: string, cursor: number): number;
49
+ /** Word-right: skip the current word, then following whitespace. */
50
+ export declare function moveWordRight(text: string, cursor: number): number;
51
+ /**
52
+ * Multiline input buffer with OMP editor bindings.
53
+ */
54
+ export declare class InputEditor {
55
+ #private;
56
+ get text(): string;
57
+ get cursor(): number;
58
+ /** Replace the buffer (history recall). Clears undo. */
59
+ setText(text: string, cursor?: number): void;
60
+ /** Move the caret without changing text or undo. */
61
+ setCursor(cursor: number): void;
62
+ /** Empty the buffer, keeping undo of the previous contents. */
63
+ clear(): void;
64
+ /** Apply one decoded event. */
65
+ handle(event: KeyEvent): EditorCommand;
66
+ }