@codemieai/code 0.0.1 → 0.0.3

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 (244) hide show
  1. package/.codemie/guides/git-workflow.md +493 -0
  2. package/CLAUDE.md +130 -761
  3. package/README.md +283 -695
  4. package/bin/codemie-claude.js +122 -0
  5. package/bin/codemie-code.js +90 -15
  6. package/bin/codemie-codex.js +138 -0
  7. package/bin/codemie.js +1 -1
  8. package/config.example.json +10 -0
  9. package/dist/agents/adapters/claude-code.d.ts +2 -2
  10. package/dist/agents/adapters/claude-code.d.ts.map +1 -1
  11. package/dist/agents/adapters/claude-code.js +20 -42
  12. package/dist/agents/adapters/claude-code.js.map +1 -1
  13. package/dist/agents/adapters/codemie-code.d.ts +11 -2
  14. package/dist/agents/adapters/codemie-code.d.ts.map +1 -1
  15. package/dist/agents/adapters/codemie-code.js +93 -25
  16. package/dist/agents/adapters/codemie-code.js.map +1 -1
  17. package/dist/agents/adapters/codex.d.ts +2 -2
  18. package/dist/agents/adapters/codex.d.ts.map +1 -1
  19. package/dist/agents/adapters/codex.js +31 -24
  20. package/dist/agents/adapters/codex.js.map +1 -1
  21. package/dist/agents/codemie-code/agent.d.ts +89 -0
  22. package/dist/agents/codemie-code/agent.d.ts.map +1 -0
  23. package/dist/agents/codemie-code/agent.js +523 -0
  24. package/dist/agents/codemie-code/agent.js.map +1 -0
  25. package/dist/agents/codemie-code/config.d.ts +40 -0
  26. package/dist/agents/codemie-code/config.d.ts.map +1 -0
  27. package/dist/agents/codemie-code/config.js +276 -0
  28. package/dist/agents/codemie-code/config.js.map +1 -0
  29. package/dist/agents/codemie-code/filters.d.ts +91 -0
  30. package/dist/agents/codemie-code/filters.d.ts.map +1 -0
  31. package/dist/agents/codemie-code/filters.js +328 -0
  32. package/dist/agents/codemie-code/filters.js.map +1 -0
  33. package/dist/agents/codemie-code/index.d.ts +78 -0
  34. package/dist/agents/codemie-code/index.d.ts.map +1 -0
  35. package/dist/agents/codemie-code/index.js +259 -0
  36. package/dist/agents/codemie-code/index.js.map +1 -0
  37. package/dist/agents/codemie-code/prompts.d.ts +11 -0
  38. package/dist/agents/codemie-code/prompts.d.ts.map +1 -0
  39. package/dist/agents/codemie-code/prompts.js +31 -0
  40. package/dist/agents/codemie-code/prompts.js.map +1 -0
  41. package/dist/agents/codemie-code/streaming/events.d.ts +7 -0
  42. package/dist/agents/codemie-code/streaming/events.d.ts.map +1 -0
  43. package/dist/agents/codemie-code/streaming/events.js +7 -0
  44. package/dist/agents/codemie-code/streaming/events.js.map +1 -0
  45. package/dist/agents/codemie-code/streaming/formatter.d.ts +2 -0
  46. package/dist/agents/codemie-code/streaming/formatter.d.ts.map +1 -0
  47. package/dist/agents/codemie-code/streaming/formatter.js +2 -0
  48. package/dist/agents/codemie-code/streaming/formatter.js.map +1 -0
  49. package/dist/agents/codemie-code/streaming/ui.d.ts +2 -0
  50. package/dist/agents/codemie-code/streaming/ui.d.ts.map +1 -0
  51. package/dist/agents/codemie-code/streaming/ui.js +2 -0
  52. package/dist/agents/codemie-code/streaming/ui.js.map +1 -0
  53. package/dist/agents/codemie-code/tokenUtils.d.ts +108 -0
  54. package/dist/agents/codemie-code/tokenUtils.d.ts.map +1 -0
  55. package/dist/agents/codemie-code/tokenUtils.js +220 -0
  56. package/dist/agents/codemie-code/tokenUtils.js.map +1 -0
  57. package/dist/agents/codemie-code/toolMetadata.d.ts +15 -0
  58. package/dist/agents/codemie-code/toolMetadata.d.ts.map +1 -0
  59. package/dist/agents/codemie-code/toolMetadata.js +315 -0
  60. package/dist/agents/codemie-code/toolMetadata.js.map +1 -0
  61. package/dist/agents/codemie-code/tools/command.d.ts +2 -0
  62. package/dist/agents/codemie-code/tools/command.d.ts.map +1 -0
  63. package/dist/agents/codemie-code/tools/command.js +2 -0
  64. package/dist/agents/codemie-code/tools/command.js.map +1 -0
  65. package/dist/agents/codemie-code/tools/filesystem.d.ts +2 -0
  66. package/dist/agents/codemie-code/tools/filesystem.d.ts.map +1 -0
  67. package/dist/agents/codemie-code/tools/filesystem.js +2 -0
  68. package/dist/agents/codemie-code/tools/filesystem.js.map +1 -0
  69. package/dist/agents/codemie-code/tools/git.d.ts +2 -0
  70. package/dist/agents/codemie-code/tools/git.d.ts.map +1 -0
  71. package/dist/agents/codemie-code/tools/git.js +2 -0
  72. package/dist/agents/codemie-code/tools/git.js.map +1 -0
  73. package/dist/agents/codemie-code/tools/index.d.ts +19 -0
  74. package/dist/agents/codemie-code/tools/index.d.ts.map +1 -0
  75. package/dist/agents/codemie-code/tools/index.js +239 -0
  76. package/dist/agents/codemie-code/tools/index.js.map +1 -0
  77. package/dist/agents/codemie-code/tools/security.d.ts +2 -0
  78. package/dist/agents/codemie-code/tools/security.d.ts.map +1 -0
  79. package/dist/agents/codemie-code/tools/security.js +2 -0
  80. package/dist/agents/codemie-code/tools/security.js.map +1 -0
  81. package/dist/agents/codemie-code/types.d.ts +254 -0
  82. package/dist/agents/codemie-code/types.d.ts.map +1 -0
  83. package/dist/agents/codemie-code/types.js +35 -0
  84. package/dist/agents/codemie-code/types.js.map +1 -0
  85. package/dist/agents/codemie-code/ui.d.ts +83 -0
  86. package/dist/agents/codemie-code/ui.d.ts.map +1 -0
  87. package/dist/agents/codemie-code/ui.js +624 -0
  88. package/dist/agents/codemie-code/ui.js.map +1 -0
  89. package/dist/agents/registry.d.ts +1 -1
  90. package/dist/agents/registry.d.ts.map +1 -1
  91. package/dist/agents/registry.js +7 -13
  92. package/dist/agents/registry.js.map +1 -1
  93. package/dist/cli/commands/config.d.ts +3 -0
  94. package/dist/cli/commands/config.d.ts.map +1 -0
  95. package/dist/cli/commands/config.js +323 -0
  96. package/dist/cli/commands/config.js.map +1 -0
  97. package/dist/cli/commands/doctor.d.ts.map +1 -1
  98. package/dist/cli/commands/doctor.js +113 -69
  99. package/dist/cli/commands/doctor.js.map +1 -1
  100. package/dist/cli/commands/env.d.ts +3 -0
  101. package/dist/cli/commands/env.d.ts.map +1 -0
  102. package/dist/cli/commands/env.js +19 -0
  103. package/dist/cli/commands/env.js.map +1 -0
  104. package/dist/cli/commands/install.js +27 -33
  105. package/dist/cli/commands/install.js.map +1 -1
  106. package/dist/cli/commands/list.js +18 -24
  107. package/dist/cli/commands/list.js.map +1 -1
  108. package/dist/cli/commands/run.d.ts.map +1 -1
  109. package/dist/cli/commands/run.js +307 -21
  110. package/dist/cli/commands/run.js.map +1 -1
  111. package/dist/cli/commands/setup.d.ts +3 -0
  112. package/dist/cli/commands/setup.d.ts.map +1 -0
  113. package/dist/cli/commands/setup.js +357 -0
  114. package/dist/cli/commands/setup.js.map +1 -0
  115. package/dist/cli/commands/uninstall.js +24 -30
  116. package/dist/cli/commands/uninstall.js.map +1 -1
  117. package/dist/cli/commands/version.d.ts.map +1 -1
  118. package/dist/cli/commands/version.js +11 -16
  119. package/dist/cli/commands/version.js.map +1 -1
  120. package/dist/cli/index.js +47 -31
  121. package/dist/cli/index.js.map +1 -1
  122. package/dist/env/manager.js +9 -46
  123. package/dist/env/manager.js.map +1 -1
  124. package/dist/index.d.ts +6 -13
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +6 -43
  127. package/dist/index.js.map +1 -1
  128. package/dist/utils/async-tips.d.ts.map +1 -1
  129. package/dist/utils/async-tips.js +16 -55
  130. package/dist/utils/async-tips.js.map +1 -1
  131. package/dist/utils/clipboard.d.ts +16 -0
  132. package/dist/utils/clipboard.d.ts.map +1 -0
  133. package/dist/utils/clipboard.js +179 -0
  134. package/dist/utils/clipboard.js.map +1 -0
  135. package/dist/utils/config-loader.d.ts +96 -0
  136. package/dist/utils/config-loader.d.ts.map +1 -0
  137. package/dist/utils/config-loader.js +351 -0
  138. package/dist/utils/config-loader.js.map +1 -0
  139. package/dist/utils/dirname.d.ts +7 -0
  140. package/dist/utils/dirname.d.ts.map +1 -0
  141. package/dist/utils/dirname.js +11 -0
  142. package/dist/utils/dirname.js.map +1 -0
  143. package/dist/utils/errors.js +7 -17
  144. package/dist/utils/errors.js.map +1 -1
  145. package/dist/utils/exec.js +3 -6
  146. package/dist/utils/exec.js.map +1 -1
  147. package/dist/utils/first-time.d.ts +34 -0
  148. package/dist/utils/first-time.d.ts.map +1 -0
  149. package/dist/utils/first-time.js +245 -0
  150. package/dist/utils/first-time.js.map +1 -0
  151. package/dist/utils/health-checker.d.ts +20 -0
  152. package/dist/utils/health-checker.d.ts.map +1 -0
  153. package/dist/utils/health-checker.js +168 -0
  154. package/dist/utils/health-checker.js.map +1 -0
  155. package/dist/utils/logger.js +12 -18
  156. package/dist/utils/logger.js.map +1 -1
  157. package/dist/utils/model-fetcher.d.ts +21 -0
  158. package/dist/utils/model-fetcher.d.ts.map +1 -0
  159. package/dist/utils/model-fetcher.js +137 -0
  160. package/dist/utils/model-fetcher.js.map +1 -0
  161. package/dist/utils/tips.d.ts.map +1 -1
  162. package/dist/utils/tips.js +13 -52
  163. package/dist/utils/tips.js.map +1 -1
  164. package/package.json +17 -23
  165. package/scripts/README.md +80 -0
  166. package/scripts/release.sh +156 -0
  167. package/dist/agents/adapters/aider.d.ts +0 -12
  168. package/dist/agents/adapters/aider.d.ts.map +0 -1
  169. package/dist/agents/adapters/aider.js +0 -80
  170. package/dist/agents/adapters/aider.js.map +0 -1
  171. package/dist/cli/cli.d.ts +0 -4
  172. package/dist/cli/cli.d.ts.map +0 -1
  173. package/dist/cli/cli.js +0 -107
  174. package/dist/cli/cli.js.map +0 -1
  175. package/dist/cli/commands/mcp.d.ts +0 -3
  176. package/dist/cli/commands/mcp.d.ts.map +0 -1
  177. package/dist/cli/commands/mcp.js +0 -459
  178. package/dist/cli/commands/mcp.js.map +0 -1
  179. package/dist/code/agent-events.d.ts +0 -39
  180. package/dist/code/agent-events.d.ts.map +0 -1
  181. package/dist/code/agent-events.js +0 -4
  182. package/dist/code/agent-events.js.map +0 -1
  183. package/dist/code/agent.d.ts +0 -19
  184. package/dist/code/agent.d.ts.map +0 -1
  185. package/dist/code/agent.js +0 -144
  186. package/dist/code/agent.js.map +0 -1
  187. package/dist/code/config.d.ts +0 -13
  188. package/dist/code/config.d.ts.map +0 -1
  189. package/dist/code/config.js +0 -41
  190. package/dist/code/config.js.map +0 -1
  191. package/dist/code/index.d.ts +0 -19
  192. package/dist/code/index.d.ts.map +0 -1
  193. package/dist/code/index.js +0 -400
  194. package/dist/code/index.js.map +0 -1
  195. package/dist/code/prompts.d.ts +0 -2
  196. package/dist/code/prompts.d.ts.map +0 -1
  197. package/dist/code/prompts.js +0 -45
  198. package/dist/code/prompts.js.map +0 -1
  199. package/dist/code/tools/command.d.ts +0 -8
  200. package/dist/code/tools/command.d.ts.map +0 -1
  201. package/dist/code/tools/command.js +0 -83
  202. package/dist/code/tools/command.js.map +0 -1
  203. package/dist/code/tools/diff-utils.d.ts +0 -2
  204. package/dist/code/tools/diff-utils.d.ts.map +0 -1
  205. package/dist/code/tools/diff-utils.js +0 -45
  206. package/dist/code/tools/diff-utils.js.map +0 -1
  207. package/dist/code/tools/filesystem.d.ts +0 -11
  208. package/dist/code/tools/filesystem.d.ts.map +0 -1
  209. package/dist/code/tools/filesystem.js +0 -442
  210. package/dist/code/tools/filesystem.js.map +0 -1
  211. package/dist/code/tools/git.d.ts +0 -7
  212. package/dist/code/tools/git.d.ts.map +0 -1
  213. package/dist/code/tools/git.js +0 -111
  214. package/dist/code/tools/git.js.map +0 -1
  215. package/dist/code/tools/mcp.d.ts +0 -13
  216. package/dist/code/tools/mcp.d.ts.map +0 -1
  217. package/dist/code/tools/mcp.js +0 -230
  218. package/dist/code/tools/mcp.js.map +0 -1
  219. package/dist/data/tips.json +0 -118
  220. package/dist/ui/terminal-ui.d.ts +0 -73
  221. package/dist/ui/terminal-ui.d.ts.map +0 -1
  222. package/dist/ui/terminal-ui.js +0 -900
  223. package/dist/ui/terminal-ui.js.map +0 -1
  224. package/dist/utils/env-mapper.d.ts +0 -40
  225. package/dist/utils/env-mapper.d.ts.map +0 -1
  226. package/dist/utils/env-mapper.js +0 -122
  227. package/dist/utils/env-mapper.js.map +0 -1
  228. package/docs/USER_GUIDE.md +0 -573
  229. package/tests/agent-direct.test.mjs +0 -45
  230. package/tests/agent-output.test.mjs +0 -64
  231. package/tests/codemie-code.test.mjs +0 -42
  232. package/tests/context7-only.test.mjs +0 -42
  233. package/tests/conversation-flow.test.mjs +0 -63
  234. package/tests/interactive-simulation.test.mjs +0 -60
  235. package/tests/live-output.test.mjs +0 -53
  236. package/tests/mcp-context7.test.mjs +0 -105
  237. package/tests/mcp-e2e.test.mjs +0 -109
  238. package/tests/mcp-time-server.test.mjs +0 -58
  239. package/tests/streaming.test.mjs +0 -57
  240. package/tests/test-helpers.mjs +0 -94
  241. package/tests/text-wrapping.test.mjs +0 -33
  242. package/tests/tool-count.test.mjs +0 -81
  243. package/tests/ui-format.test.mjs +0 -39
  244. package/tests/ui-state.test.mjs +0 -72
@@ -1,900 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TerminalUI = void 0;
7
- // Suppress ALL console.error during blessed import to avoid terminal capability parsing errors
8
- const originalConsoleError = console.error;
9
- let suppressErrors = true;
10
- console.error = function (...args) {
11
- if (suppressErrors) {
12
- // Suppress all errors during initial setup
13
- return;
14
- }
15
- originalConsoleError.apply(console, args);
16
- };
17
- // Import blessed with error suppression
18
- const blessed_1 = __importDefault(require("blessed"));
19
- // Re-enable console.error after a short delay
20
- setTimeout(() => {
21
- suppressErrors = false;
22
- }, 100);
23
- class TerminalUI {
24
- screen;
25
- contentBox;
26
- inputBox;
27
- tipBox;
28
- commandSuggestionBox;
29
- config;
30
- isProcessing = false;
31
- currentAbortController = null;
32
- tipRotationInterval = null;
33
- currentTipIndex = 0;
34
- tips = [];
35
- shownTips = new Set();
36
- availableCommands = [
37
- { command: '/doctor', description: 'Diagnose and verify your CodeMie installation and settings' },
38
- { command: '/list', description: 'List all available agents and their status' },
39
- { command: '/clear', description: 'Clear conversation history and free up context', aliases: ['reset', 'new'] },
40
- { command: '/exit', description: 'Exit the REPL', aliases: ['quit'] },
41
- { command: '/help', description: 'Show help information' },
42
- { command: '/install', description: 'Install an agent (e.g., /install aider)' },
43
- { command: '/uninstall', description: 'Uninstall an agent' },
44
- { command: '/run', description: 'Run a specific agent' },
45
- ];
46
- filteredCommands = [];
47
- selectedCommandIndex = 0;
48
- isSuggestionsVisible = false;
49
- currentStreamingContent = '';
50
- currentToolCallContent = [];
51
- currentStreamingLineCount = 0;
52
- baseContentLines = [];
53
- isCancelling = false;
54
- currentContent = '';
55
- constructor(config) {
56
- this.config = config;
57
- this.screen = this.createScreen();
58
- this.contentBox = this.createContentBox();
59
- this.inputBox = this.createInputBox();
60
- this.tipBox = this.createTipBox();
61
- this.commandSuggestionBox = this.createCommandSuggestionBox();
62
- this.setupLayout();
63
- this.setupKeyBindings();
64
- this.setupInputHandlers();
65
- this.screen.render();
66
- }
67
- createScreen() {
68
- const screenOptions = {
69
- smartCSR: true,
70
- fullUnicode: true, // Enable full unicode for emoji support
71
- dockBorders: true,
72
- title: 'CodeMie Code Assistant',
73
- warnings: false, // Suppress terminfo warnings
74
- forceUnicode: true, // Force unicode support for better emoji rendering
75
- autoPadding: true,
76
- ignoreLocked: ['C-c'],
77
- // Enable mouse support for better text selection
78
- sendFocus: true,
79
- useBCE: false, // Disable BCE to avoid terminal capability issues
80
- // Disable cursor color and other advanced features that cause issues
81
- cursor: {
82
- artificial: false,
83
- shape: 'line',
84
- blink: true,
85
- color: null
86
- },
87
- // Terminal detection options
88
- terminal: 'xterm-256color',
89
- dump: false,
90
- debug: false
91
- };
92
- const screen = blessed_1.default.screen(screenOptions);
93
- // Suppress error output for terminal capabilities
94
- screen.on('warning', () => {
95
- // Silently ignore warnings
96
- });
97
- // Disable problematic terminal capabilities after screen creation
98
- if (screen.program && screen.program.setupColors) {
99
- try {
100
- // Override setupColors to prevent underline color issues
101
- const originalSetupColors = screen.program.setupColors;
102
- screen.program.setupColors = function () {
103
- try {
104
- originalSetupColors();
105
- }
106
- catch {
107
- // Ignore color setup errors
108
- }
109
- };
110
- }
111
- catch {
112
- // Ignore if setupColors doesn't exist
113
- }
114
- }
115
- // Suppress all console.error calls that might be terminal capability related
116
- // This catches errors from blessed's terminfo parser (like Setulc)
117
- if (screen.program) {
118
- const originalError = console.error;
119
- console.error = function (...args) {
120
- // Check if it's a terminal capability error
121
- const errorStr = args.join(' ');
122
- if (errorStr.includes('Error on xterm') ||
123
- errorStr.includes('Setulc') ||
124
- errorStr.includes('stack.pop') ||
125
- errorStr.includes('terminfo')) {
126
- // Silently ignore terminal capability errors
127
- return;
128
- }
129
- // Pass through other errors
130
- originalError.apply(console, args);
131
- };
132
- }
133
- return screen;
134
- }
135
- createContentBox() {
136
- const boxOptions = {
137
- top: 0,
138
- left: 0,
139
- width: '100%',
140
- bottom: 7, // Reserve space for input (3 lines) + tips (4 lines with borders)
141
- scrollable: true,
142
- alwaysScroll: true,
143
- scrollbar: {
144
- ch: '|',
145
- style: {
146
- fg: 'cyan'
147
- }
148
- },
149
- keys: true,
150
- vi: true,
151
- mouse: true,
152
- tags: true,
153
- border: 'line',
154
- style: {
155
- fg: 'white',
156
- bg: 'black',
157
- border: {
158
- fg: 'cyan'
159
- }
160
- },
161
- label: ' CodeMie Code ',
162
- // Enable text selection by allowing mouse events to pass through
163
- clickable: true,
164
- input: false,
165
- // Enable word wrapping to prevent text cutoff
166
- wrap: true,
167
- wordWrap: true
168
- };
169
- return blessed_1.default.box(boxOptions);
170
- }
171
- createInputBox() {
172
- // Use a simple box instead of textarea - just display the prompt
173
- const inputOptions = {
174
- bottom: 4,
175
- left: 0,
176
- width: '100%',
177
- height: 3,
178
- border: 'line',
179
- style: {
180
- fg: 'white',
181
- bg: 'black',
182
- border: {
183
- fg: 'green'
184
- }
185
- },
186
- label: ' You ',
187
- tags: true,
188
- content: '{white-fg}> {/white-fg}',
189
- scrollable: true,
190
- alwaysScroll: true,
191
- scrollbar: {
192
- ch: '|',
193
- style: {
194
- fg: 'cyan'
195
- }
196
- }
197
- };
198
- const box = blessed_1.default.box(inputOptions);
199
- // Track input text
200
- let inputText = '';
201
- // Update display with multiline support and dynamic height
202
- const updateDisplay = () => {
203
- // Split into lines and add "> " only to first line, " " to continuation lines
204
- const lines = inputText.split('\n');
205
- const formattedLines = lines.map((line, index) => {
206
- const prefix = index === 0 ? '> ' : ' ';
207
- return '{white-fg}' + prefix + this.escapeForBlessed(line) + '{/white-fg}';
208
- });
209
- box.setContent(formattedLines.join('\n'));
210
- // Dynamically adjust height based on number of lines (min 3, max 10)
211
- const lineCount = lines.length;
212
- const newHeight = Math.min(Math.max(lineCount + 2, 3), 10 + 2); // +2 for borders
213
- if (box.height !== newHeight) {
214
- box.height = newHeight;
215
- // Need to reposition dependent elements (tip box position stays same at bottom: 0)
216
- this.screen.render();
217
- }
218
- // Auto-scroll to bottom if content exceeds box height
219
- box.setScrollPerc(100);
220
- this.screen.render();
221
- };
222
- // Store methods and data for getting/clearing input
223
- box.getInputText = () => inputText;
224
- box.clearInputText = () => {
225
- inputText = '';
226
- box.inputText = inputText;
227
- // Reset height to minimum when cleared
228
- box.height = 3;
229
- updateDisplay();
230
- };
231
- box.addNewline = () => {
232
- inputText += '\n';
233
- box.inputText = inputText;
234
- updateDisplay();
235
- };
236
- box.setInputText = (text) => {
237
- inputText = text;
238
- box.inputText = inputText;
239
- // Reset height when setting new text (usually for autocomplete)
240
- box.height = 3;
241
- updateDisplay();
242
- };
243
- // Store inputText directly on box for external access
244
- box.inputText = inputText;
245
- // Listen to screen keypresses when box is focused
246
- box.on('focus', () => {
247
- box._inputFocused = true;
248
- });
249
- box.on('blur', () => {
250
- box._inputFocused = false;
251
- });
252
- // Capture input at screen level
253
- this.screen.on('keypress', (ch, key) => {
254
- if (!box._inputFocused)
255
- return;
256
- if (!key)
257
- return;
258
- // Handle input
259
- if (key.full === 'backspace') {
260
- if (inputText.length > 0) {
261
- inputText = inputText.slice(0, -1);
262
- box.inputText = inputText; // Keep in sync
263
- updateDisplay();
264
- }
265
- }
266
- else if (key.full === 'enter' || key.full === 'return') {
267
- // Let the key handler deal with this (shift+enter handled elsewhere)
268
- return;
269
- }
270
- else if (ch && typeof ch === 'string' && ch.length === 1 && !key.ctrl && !key.meta) {
271
- inputText += ch;
272
- box.inputText = inputText; // Keep in sync
273
- updateDisplay();
274
- }
275
- });
276
- // Make it focusable
277
- box.clickable = true;
278
- box.keyable = true;
279
- box.keys = true;
280
- box.input = true;
281
- return box;
282
- }
283
- createTipBox() {
284
- const tipOptions = {
285
- bottom: 0,
286
- left: 0,
287
- width: '100%',
288
- height: 4,
289
- tags: true,
290
- border: 'line',
291
- style: {
292
- fg: 'cyan',
293
- border: {
294
- fg: 'cyan'
295
- }
296
- },
297
- label: ' Tip '
298
- };
299
- return blessed_1.default.box(tipOptions);
300
- }
301
- createCommandSuggestionBox() {
302
- const suggestionOptions = {
303
- bottom: 7,
304
- left: 0,
305
- width: '100%',
306
- height: 'shrink',
307
- tags: true,
308
- border: 'line',
309
- style: {
310
- fg: 'white',
311
- bg: 'black',
312
- border: {
313
- fg: 'yellow'
314
- }
315
- },
316
- label: ' Available Commands ',
317
- hidden: true,
318
- scrollable: true,
319
- alwaysScroll: true
320
- };
321
- return blessed_1.default.box(suggestionOptions);
322
- }
323
- setupLayout() {
324
- this.screen.append(this.contentBox);
325
- this.screen.append(this.inputBox);
326
- this.screen.append(this.tipBox);
327
- this.screen.append(this.commandSuggestionBox);
328
- // Show welcome message
329
- this.appendToContent('{cyan-fg}========================================{/cyan-fg}');
330
- this.appendToContent('{cyan-fg} CodeMie Code Assistant {/cyan-fg}');
331
- this.appendToContent('{cyan-fg}========================================{/cyan-fg}');
332
- this.appendToContent('');
333
- this.appendToContent(`{white-fg}Working directory: ${this.config.workingDirectory}{/white-fg}`);
334
- this.appendToContent(`{white-fg}Model: ${this.config.model} (${this.config.provider}){/white-fg}`);
335
- this.appendToContent('');
336
- this.appendToContent('{gray-fg}Press Enter to send, Shift+Enter for new line{/gray-fg}');
337
- this.appendToContent('{gray-fg}Use /command for CLI commands (e.g., /doctor, /list){/gray-fg}');
338
- this.appendToContent('{gray-fg}Press Esc to cancel execution, Ctrl+C or "q" to quit{/gray-fg}');
339
- this.appendToContent('');
340
- // Focus input by default
341
- this.inputBox.focus();
342
- }
343
- setupKeyBindings() {
344
- // Ctrl+C to exit - use both screen and inputBox
345
- const exitHandler = () => {
346
- this.destroy();
347
- this.config.onExit();
348
- };
349
- this.screen.key(['C-c', 'q'], exitHandler);
350
- this.inputBox.key(['C-c'], exitHandler);
351
- // Esc to cancel agent execution
352
- this.screen.key(['escape'], () => {
353
- if (this.isProcessing && this.currentAbortController && !this.isCancelling) {
354
- this.isCancelling = true;
355
- this.appendToContent('');
356
- this.appendToContent('{yellow-fg}Cancelling execution...{/yellow-fg}');
357
- this.currentAbortController.abort();
358
- }
359
- });
360
- // Enter to submit
361
- this.inputBox.key(['enter'], async () => {
362
- await this.handleSubmit();
363
- });
364
- // Shift+Enter for newline (multiline support)
365
- this.inputBox.key(['S-enter'], () => {
366
- // Add newline using the built-in method
367
- const box = this.inputBox;
368
- box.addNewline();
369
- });
370
- // Arrow keys for command navigation when suggestions are visible
371
- this.inputBox.key(['up'], () => {
372
- if (this.isSuggestionsVisible && this.filteredCommands.length > 0) {
373
- this.selectedCommandIndex = Math.max(0, this.selectedCommandIndex - 1);
374
- this.updateCommandSuggestions();
375
- }
376
- });
377
- this.inputBox.key(['down'], () => {
378
- if (this.isSuggestionsVisible && this.filteredCommands.length > 0) {
379
- this.selectedCommandIndex = Math.min(this.filteredCommands.length - 1, this.selectedCommandIndex + 1);
380
- this.updateCommandSuggestions();
381
- }
382
- });
383
- // Tab for autocomplete
384
- this.inputBox.key(['tab'], () => {
385
- if (this.isSuggestionsVisible && this.filteredCommands.length > 0) {
386
- const selectedCommand = this.filteredCommands[this.selectedCommandIndex];
387
- if (selectedCommand) {
388
- // Set the input text using our custom method
389
- const newText = selectedCommand.command + ' ';
390
- const box = this.inputBox;
391
- box.setInputText(newText);
392
- this.hideCommandSuggestions();
393
- }
394
- return false; // Prevent default tab behavior
395
- }
396
- });
397
- // Scroll content with arrow keys when not focused on input
398
- this.screen.key(['up'], () => {
399
- if (this.screen.focused !== this.inputBox) {
400
- this.contentBox.scroll(-1);
401
- this.screen.render();
402
- }
403
- });
404
- this.screen.key(['down'], () => {
405
- if (this.screen.focused !== this.inputBox) {
406
- this.contentBox.scroll(1);
407
- this.screen.render();
408
- }
409
- });
410
- // Page up/down for faster scrolling
411
- this.screen.key(['pageup'], () => {
412
- this.contentBox.scroll(-10);
413
- this.screen.render();
414
- });
415
- this.screen.key(['pagedown'], () => {
416
- this.contentBox.scroll(10);
417
- this.screen.render();
418
- });
419
- // Ctrl+Tab to switch focus between content and input (tab is used for autocomplete)
420
- this.screen.key(['C-tab'], () => {
421
- if (this.screen.focused === this.inputBox) {
422
- this.contentBox.focus();
423
- }
424
- else {
425
- this.inputBox.focus();
426
- }
427
- this.screen.render();
428
- });
429
- }
430
- setupInputHandlers() {
431
- // Watch for input changes to show command suggestions
432
- this.inputBox.on('keypress', () => {
433
- // Use setImmediate to get the updated value after keypress
434
- setImmediate(() => {
435
- // Get the actual input text from our custom method
436
- const box = this.inputBox;
437
- const currentValue = box.getInputText() || '';
438
- if (currentValue.startsWith('/') && !currentValue.includes('\n')) {
439
- // Show command suggestions
440
- this.showCommandSuggestions(currentValue);
441
- }
442
- else {
443
- // Hide suggestions
444
- this.hideCommandSuggestions();
445
- }
446
- });
447
- });
448
- }
449
- showCommandSuggestions(input) {
450
- const searchTerm = input.slice(1).toLowerCase();
451
- // Filter commands based on search term
452
- this.filteredCommands = this.availableCommands.filter(cmd => {
453
- const cmdName = cmd.command.slice(1);
454
- return cmdName.startsWith(searchTerm) || searchTerm === '';
455
- });
456
- // Reset selection if out of bounds
457
- if (this.selectedCommandIndex >= this.filteredCommands.length) {
458
- this.selectedCommandIndex = 0;
459
- }
460
- if (this.filteredCommands.length > 0) {
461
- this.isSuggestionsVisible = true;
462
- this.updateCommandSuggestions();
463
- }
464
- else {
465
- this.hideCommandSuggestions();
466
- }
467
- }
468
- updateCommandSuggestions() {
469
- if (!this.isSuggestionsVisible || this.filteredCommands.length === 0)
470
- return;
471
- const separator = '{gray-fg}' + '─'.repeat(140) + '{/gray-fg}';
472
- // Calculate column widths
473
- const commandColWidth = 30;
474
- let suggestions = '';
475
- this.filteredCommands.forEach((cmd, index) => {
476
- const isSelected = index === this.selectedCommandIndex;
477
- const bgColor = isSelected ? '{black-bg}{white-fg}' : '';
478
- const endColor = isSelected ? '{/white-fg}{/black-bg}' : '';
479
- // Format command with aliases
480
- const aliasText = cmd.aliases ? ` {gray-fg}(${cmd.aliases.join(', ')}){/gray-fg}` : '';
481
- const commandText = `{yellow-fg}${cmd.command}{/yellow-fg}${aliasText}`;
482
- // Calculate padding to align descriptions
483
- // Note: We need to account for the actual visible length without tags
484
- const visibleCmdLength = cmd.command.length + (cmd.aliases ? ` (${cmd.aliases.join(', ')})`.length : 0);
485
- const padding = Math.max(0, commandColWidth - visibleCmdLength);
486
- suggestions += `${bgColor} ${commandText}${' '.repeat(padding)}${cmd.description}${endColor}\n`;
487
- });
488
- this.commandSuggestionBox.setContent(separator + '\n' + suggestions + separator);
489
- this.commandSuggestionBox.show();
490
- // Adjust height based on number of matching commands
491
- const lines = this.filteredCommands.length;
492
- this.commandSuggestionBox.height = Math.min(lines + 3, 15);
493
- this.screen.render();
494
- }
495
- hideCommandSuggestions() {
496
- if (!this.commandSuggestionBox.hidden) {
497
- this.isSuggestionsVisible = false;
498
- this.selectedCommandIndex = 0;
499
- this.filteredCommands = [];
500
- this.commandSuggestionBox.hide();
501
- this.screen.render();
502
- }
503
- }
504
- async handleSubmit() {
505
- if (this.isProcessing)
506
- return;
507
- // Get message from our custom input method
508
- const box = this.inputBox;
509
- const message = (box.getInputText() || '').trim();
510
- if (!message)
511
- return;
512
- // Hide command suggestions
513
- this.hideCommandSuggestions();
514
- // Handle special commands
515
- if (message.toLowerCase() === 'exit') {
516
- this.destroy();
517
- this.config.onExit();
518
- return;
519
- }
520
- if (message.toLowerCase() === 'clear' || message.toLowerCase() === '/clear') {
521
- this.config.onClear();
522
- this.clearContent();
523
- const box1 = this.inputBox;
524
- box1.clearInputText();
525
- this.screen.render();
526
- return;
527
- }
528
- // Clear input and reset prompt
529
- const box2 = this.inputBox;
530
- box2.clearInputText();
531
- // Show user message
532
- this.appendToContent('');
533
- this.appendToContent(`{white-fg}> ${this.escapeForBlessed(message)}{/white-fg}`);
534
- this.appendToContent('');
535
- // Handle slash commands
536
- if (message.startsWith('/')) {
537
- const parts = message.slice(1).split(/\s+/);
538
- const command = parts[0];
539
- const args = parts.slice(1);
540
- this.appendToContent(`{yellow-fg}Running command:{/yellow-fg} {white-fg}/${command} ${args.join(' ')}{/white-fg}`);
541
- this.appendToContent('');
542
- this.isProcessing = true;
543
- this.screen.render();
544
- try {
545
- const result = await this.config.onSlashCommand(command, args);
546
- this.appendToContent(`{cyan-fg}Output:{/cyan-fg}`);
547
- // Split result into lines and append each with proper formatting
548
- const lines = result.split('\n');
549
- for (const line of lines) {
550
- this.appendToContent(`{white-fg}${this.escapeForBlessed(line)}{/white-fg}`);
551
- }
552
- this.appendToContent('');
553
- }
554
- catch (error) {
555
- const errorMessage = error instanceof Error ? error.message : String(error);
556
- this.appendToContent(`{red-fg}Error:{/red-fg} {white-fg}${this.escapeForBlessed(errorMessage)}{/white-fg}`);
557
- this.appendToContent('');
558
- this.appendToContent('{gray-fg}You can continue using the assistant or try the command again with correct arguments.{/gray-fg}');
559
- this.appendToContent('');
560
- }
561
- finally {
562
- // Ensure state is always restored, even if an error occurred
563
- this.isProcessing = false;
564
- // Use setImmediate to ensure focus happens after all other processing
565
- setImmediate(() => {
566
- this.inputBox.focus();
567
- this.screen.render();
568
- });
569
- }
570
- return;
571
- }
572
- this.isProcessing = true;
573
- // Create AbortController for cancellation
574
- this.currentAbortController = new AbortController();
575
- this.screen.render();
576
- try {
577
- // Use streaming if available
578
- if (this.config.onSubmitStream) {
579
- await this.config.onSubmitStream(message, (event) => {
580
- try {
581
- switch (event.type) {
582
- case 'thinking_start':
583
- this.showThinking();
584
- break;
585
- case 'thinking_end':
586
- this.hideThinking();
587
- break;
588
- case 'content_chunk':
589
- if (this.currentStreamingContent === '') {
590
- // First chunk - hide thinking and start streaming response
591
- this.hideThinking();
592
- this.startStreamingResponse();
593
- }
594
- this.appendStreamChunk(event.content);
595
- break;
596
- case 'tool_call_start':
597
- // Hide thinking indicator when tool execution starts
598
- this.hideThinking();
599
- // End any current streaming content before showing tool call
600
- if (this.currentStreamingContent !== '') {
601
- this.endStreamingResponse();
602
- }
603
- this.showToolCallStart(event.toolName, event.toolArgs);
604
- break;
605
- case 'tool_call_result':
606
- this.showToolCallResult(event.toolName, event.result);
607
- break;
608
- case 'tool_call_error':
609
- this.showToolCallError(event.toolName, event.error);
610
- break;
611
- case 'cancelled':
612
- this.endStreamingResponse();
613
- // Replace the "Cancelling execution..." line with "Execution cancelled."
614
- this.removeLastLine(); // Remove empty line
615
- this.removeLastLine(); // Remove "Cancelling execution..."
616
- this.appendToContent('{yellow-fg}Execution cancelled.{/yellow-fg}');
617
- this.appendToContent('');
618
- break;
619
- case 'complete':
620
- this.endStreamingResponse();
621
- break;
622
- case 'error':
623
- this.showError(event.error);
624
- break;
625
- }
626
- }
627
- catch (err) {
628
- // Catch any errors in event handling to prevent breaking the flow
629
- console.error('Error handling event:', err);
630
- }
631
- }, this.currentAbortController.signal);
632
- }
633
- else {
634
- // Fallback to non-streaming
635
- this.appendToContent('{cyan-fg}Assistant:{/cyan-fg} {gray-fg}(thinking...){/gray-fg}');
636
- await this.config.onSubmit(message);
637
- }
638
- }
639
- catch (error) {
640
- const errorMessage = error instanceof Error ? error.message : String(error);
641
- // Silently ignore cancellation errors - already handled via 'cancelled' event
642
- if (errorMessage === 'Execution cancelled by user') {
643
- // Don't return early - fall through to finally block for proper cleanup
644
- }
645
- else {
646
- // Ensure error is displayed to user
647
- this.showError(errorMessage || 'An error occurred');
648
- }
649
- }
650
- finally {
651
- // ALWAYS reset processing state, even if there was an error
652
- this.isProcessing = false;
653
- this.currentAbortController = null;
654
- this.isCancelling = false;
655
- // Use setImmediate to ensure focus happens after all rendering is complete
656
- setImmediate(() => {
657
- this.inputBox.focus();
658
- this.screen.render();
659
- });
660
- }
661
- }
662
- appendToContent(text) {
663
- this.contentBox.pushLine(text);
664
- this.contentBox.setScrollPerc(100); // Auto-scroll to bottom
665
- this.screen.render();
666
- }
667
- removeLastLine() {
668
- const lines = this.contentBox.getLines();
669
- if (lines.length > 0) {
670
- this.contentBox.deleteBottom();
671
- this.screen.render();
672
- }
673
- }
674
- clearContent() {
675
- this.contentBox.setContent('');
676
- this.appendToContent('{yellow-fg}Conversation history cleared.{/yellow-fg}');
677
- this.appendToContent('');
678
- }
679
- showAssistantResponse(response) {
680
- // Remove the "thinking..." line
681
- this.removeLastLine();
682
- // Show assistant response
683
- this.appendToContent(`{cyan-fg}Assistant:{/cyan-fg} {white-fg}${this.escapeForBlessed(response)}{/white-fg}`);
684
- this.appendToContent('');
685
- }
686
- showError(error) {
687
- // Remove the "thinking..." line
688
- this.removeLastLine();
689
- this.appendToContent(`{red-fg}Error:{/red-fg} {white-fg}${this.escapeForBlessed(error)}{/white-fg}`);
690
- this.appendToContent('');
691
- this.appendToContent('{yellow-fg}Note: You can continue the conversation or type "exit" to quit.{/yellow-fg}');
692
- this.appendToContent('');
693
- }
694
- escapeForBlessed(text) {
695
- // Escape blessed tags
696
- return text
697
- .replace(/\{/g, '\\{')
698
- .replace(/\}/g, '\\}');
699
- }
700
- shortenFilePath(path) {
701
- // Check if this looks like a file path (contains / or \)
702
- if (!path.includes('/') && !path.includes('\\')) {
703
- return path;
704
- }
705
- // Split by both forward and back slashes
706
- const parts = path.split(/[/\\]/);
707
- // If path has 2 or fewer parts, return as is
708
- if (parts.length <= 2) {
709
- return path;
710
- }
711
- // Return last 2 parts (parent dir + filename)
712
- return parts.slice(-2).join('/');
713
- }
714
- shortenAllPathsInText(text) {
715
- // Match absolute paths (starting with / or drive letter on Windows)
716
- // Pattern: /path/to/file or C:\path\to\file
717
- const pathPattern = /(?:^|[\s(,["'])([/\\][\w\-./\\]+[\w\-.]|[A-Z]:[/\\][\w\-./\\]+[\w\-.])/g;
718
- return text.replace(pathPattern, (match, path) => {
719
- const before = match[0] !== '/' && match[0] !== '\\' && !/[A-Z]:/.test(match.slice(0, 2)) ? match[0] : '';
720
- const shortened = this.shortenFilePath(path.trim());
721
- return before + shortened;
722
- });
723
- }
724
- formatToolArg(key, value) {
725
- let strValue;
726
- if (typeof value === 'string') {
727
- // Check if it's a file path and shorten it
728
- strValue = this.shortenFilePath(value);
729
- }
730
- else {
731
- strValue = JSON.stringify(value);
732
- }
733
- return strValue;
734
- }
735
- setTips(tips) {
736
- this.tips = tips;
737
- if (tips.length > 0) {
738
- this.showRandomTip();
739
- this.startTipRotation();
740
- }
741
- }
742
- getRandomTip() {
743
- if (this.tips.length === 0)
744
- return null;
745
- const availableTips = this.tips
746
- .map((tip, index) => ({ tip, index }))
747
- .filter(({ index }) => !this.shownTips.has(index));
748
- // Reset if all tips shown
749
- if (availableTips.length === 0) {
750
- this.shownTips.clear();
751
- return this.getRandomTip();
752
- }
753
- const selected = availableTips[Math.floor(Math.random() * availableTips.length)];
754
- this.shownTips.add(selected.index);
755
- this.currentTipIndex = selected.index;
756
- return selected.tip;
757
- }
758
- showRandomTip() {
759
- const tip = this.getRandomTip();
760
- if (tip) {
761
- let tipText = `{cyan-fg}[Tip]{/cyan-fg} ${this.escapeForBlessed(tip.message)}`;
762
- if (tip.command) {
763
- tipText += `\n{gray-fg} =>{/gray-fg} {yellow-fg}${this.escapeForBlessed(tip.command)}{/yellow-fg}`;
764
- }
765
- this.tipBox.setContent(tipText);
766
- this.screen.render();
767
- }
768
- }
769
- startTipRotation(intervalMs = 15000) {
770
- if (this.tipRotationInterval) {
771
- clearInterval(this.tipRotationInterval);
772
- }
773
- this.tipRotationInterval = setInterval(() => {
774
- if (!this.isProcessing) {
775
- this.showRandomTip();
776
- }
777
- }, intervalMs);
778
- }
779
- render() {
780
- this.screen.render();
781
- }
782
- // Streaming-specific methods
783
- startStreamingResponse() {
784
- this.currentStreamingContent = '';
785
- this.currentToolCallContent = [];
786
- this.currentStreamingLineCount = 0;
787
- // Store current content state
788
- this.baseContentLines = this.contentBox.getLines().slice();
789
- }
790
- appendStreamChunk(chunk) {
791
- this.currentStreamingContent += chunk;
792
- // Rebuild content from base + streaming
793
- const allLines = [...this.baseContentLines];
794
- // Split streaming content into logical lines
795
- const streamingLines = this.currentStreamingContent.split('\n');
796
- // Add first line with green dot
797
- allLines.push(`{green-fg}⏺{/green-fg} {white-fg}${this.escapeForBlessed(streamingLines[0])}{/white-fg}`);
798
- // Add continuation lines without the dot
799
- for (let i = 1; i < streamingLines.length; i++) {
800
- allLines.push(`{white-fg}${this.escapeForBlessed(streamingLines[i])}{/white-fg}`);
801
- }
802
- // Replace entire content
803
- this.contentBox.setContent(allLines.join('\n'));
804
- this.contentBox.setScrollPerc(100); // Auto-scroll to bottom
805
- this.screen.render();
806
- }
807
- showThinking() {
808
- this.appendToContent(`{gray-fg}(thinking...){/gray-fg}`);
809
- }
810
- hideThinking() {
811
- this.removeLastLine();
812
- }
813
- showToolCallStart(toolName, toolArgs) {
814
- // Format tool call as: ⏺ ToolName with only file path (hide large content args and null values)
815
- // Extract file path if present (and not null/undefined)
816
- let fileInfo = '';
817
- if (toolArgs.file_path && toolArgs.file_path !== null && toolArgs.file_path !== undefined) {
818
- fileInfo = `(${this.shortenFilePath(String(toolArgs.file_path))})`;
819
- }
820
- else if (toolArgs.path && toolArgs.path !== null && toolArgs.path !== undefined) {
821
- fileInfo = `(${this.shortenFilePath(String(toolArgs.path))})`;
822
- }
823
- else if (toolArgs.notebook_path && toolArgs.notebook_path !== null && toolArgs.notebook_path !== undefined) {
824
- fileInfo = `(${this.shortenFilePath(String(toolArgs.notebook_path))})`;
825
- }
826
- const toolMessage = `{green-fg}⏺{/green-fg} {white-fg}${this.escapeForBlessed(toolName)}${fileInfo ? ' ' + this.escapeForBlessed(fileInfo) : ''}{/white-fg}`;
827
- this.appendToContent(toolMessage);
828
- this.currentToolCallContent.push(toolMessage);
829
- }
830
- showToolCallResult(toolName, result) {
831
- // Format result with indentation: ⎿ first line\n continuation...
832
- // Shorten all file paths in the result
833
- const shortenedResult = this.shortenAllPathsInText(result);
834
- const lines = shortenedResult.split('\n');
835
- const maxLines = 3;
836
- const displayLines = lines.slice(0, maxLines);
837
- const hiddenLines = Math.max(0, lines.length - maxLines);
838
- let resultMessage = ' {gray-fg}⎿{/gray-fg} ' + this.escapeForBlessed(displayLines[0] || '');
839
- for (let i = 1; i < displayLines.length; i++) {
840
- resultMessage += '\n ' + this.escapeForBlessed(displayLines[i]);
841
- }
842
- if (hiddenLines > 0) {
843
- resultMessage += `\n {gray-fg}… +${hiddenLines} lines (ctrl+o to expand){/gray-fg}`;
844
- }
845
- this.appendToContent(resultMessage);
846
- this.appendToContent('');
847
- this.currentToolCallContent.push(resultMessage);
848
- }
849
- showToolCallError(toolName, error) {
850
- // Format error with red dot
851
- const errorMessage = `{red-fg}⏺ Error in ${this.escapeForBlessed(toolName)}{/red-fg}\n {gray-fg}⎿{/gray-fg} {red-fg}${this.escapeForBlessed(error)}{/red-fg}`;
852
- this.appendToContent(errorMessage);
853
- this.appendToContent('');
854
- this.currentToolCallContent.push(errorMessage);
855
- }
856
- endStreamingResponse() {
857
- // Finalize the streaming content by adding it properly
858
- if (this.currentStreamingContent) {
859
- // The content is already displayed, just need to update base
860
- this.baseContentLines = this.contentBox.getLines().slice();
861
- }
862
- // Add a blank line after the response
863
- this.appendToContent('');
864
- this.currentStreamingContent = '';
865
- this.currentToolCallContent = [];
866
- this.currentStreamingLineCount = 0;
867
- }
868
- destroy() {
869
- try {
870
- if (this.tipRotationInterval) {
871
- clearInterval(this.tipRotationInterval);
872
- this.tipRotationInterval = null;
873
- }
874
- // Hide all widgets before destroying
875
- this.commandSuggestionBox.hide();
876
- this.tipBox.hide();
877
- this.inputBox.hide();
878
- this.contentBox.hide();
879
- // Reset terminal state
880
- if (this.screen) {
881
- this.screen.program.clear();
882
- this.screen.program.disableMouse();
883
- this.screen.program.showCursor();
884
- this.screen.program.normalBuffer();
885
- // Destroy the screen (suppress any errors)
886
- try {
887
- this.screen.destroy();
888
- }
889
- catch {
890
- // Ignore terminfo errors on cleanup
891
- }
892
- }
893
- }
894
- catch {
895
- // Silently handle any cleanup errors
896
- }
897
- }
898
- }
899
- exports.TerminalUI = TerminalUI;
900
- //# sourceMappingURL=terminal-ui.js.map