@travisennis/acai 0.0.5 → 0.0.6

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 (311) hide show
  1. package/README.md +4 -2
  2. package/dist/agent/index.d.ts +119 -0
  3. package/dist/agent/index.d.ts.map +1 -0
  4. package/dist/agent/index.js +406 -0
  5. package/dist/agent/manual-loop.d.ts +41 -0
  6. package/dist/agent/manual-loop.d.ts.map +1 -0
  7. package/dist/agent/manual-loop.js +278 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +27 -33
  11. package/dist/commands/add-directory-command.d.ts +3 -0
  12. package/dist/commands/add-directory-command.d.ts.map +1 -0
  13. package/dist/commands/add-directory-command.js +85 -0
  14. package/dist/commands/application-log-command.d.ts.map +1 -1
  15. package/dist/commands/application-log-command.js +34 -0
  16. package/dist/commands/clear-command.d.ts.map +1 -1
  17. package/dist/commands/clear-command.js +8 -0
  18. package/dist/commands/compact-command.d.ts.map +1 -1
  19. package/dist/commands/compact-command.js +15 -2
  20. package/dist/commands/context-command.d.ts +3 -0
  21. package/dist/commands/context-command.d.ts.map +1 -0
  22. package/dist/commands/context-command.js +183 -0
  23. package/dist/commands/copy-command.d.ts.map +1 -1
  24. package/dist/commands/copy-command.js +28 -0
  25. package/dist/commands/edit-command.d.ts.map +1 -1
  26. package/dist/commands/edit-command.js +33 -0
  27. package/dist/commands/edit-prompt-command.d.ts.map +1 -1
  28. package/dist/commands/edit-prompt-command.js +28 -0
  29. package/dist/commands/exit-command.d.ts.map +1 -1
  30. package/dist/commands/exit-command.js +20 -0
  31. package/dist/commands/files-command.d.ts.map +1 -1
  32. package/dist/commands/files-command.js +57 -0
  33. package/dist/commands/generate-rules-command.d.ts.map +1 -1
  34. package/dist/commands/generate-rules-command.js +311 -1
  35. package/dist/commands/handoff-command.d.ts +3 -0
  36. package/dist/commands/handoff-command.d.ts.map +1 -0
  37. package/dist/commands/handoff-command.js +202 -0
  38. package/dist/commands/health-command.d.ts.map +1 -1
  39. package/dist/commands/health-command.js +119 -2
  40. package/dist/commands/help-command.d.ts.map +1 -1
  41. package/dist/commands/help-command.js +28 -0
  42. package/dist/commands/history-command.d.ts +3 -0
  43. package/dist/commands/history-command.d.ts.map +1 -0
  44. package/dist/commands/history-command.js +534 -0
  45. package/dist/commands/init-command.d.ts +1 -1
  46. package/dist/commands/init-command.d.ts.map +1 -1
  47. package/dist/commands/init-command.js +55 -18
  48. package/dist/commands/last-log-command.d.ts.map +1 -1
  49. package/dist/commands/last-log-command.js +27 -0
  50. package/dist/commands/list-directories-command.d.ts +3 -0
  51. package/dist/commands/list-directories-command.d.ts.map +1 -0
  52. package/dist/commands/list-directories-command.js +48 -0
  53. package/dist/commands/list-tools-command.d.ts.map +1 -1
  54. package/dist/commands/list-tools-command.js +66 -3
  55. package/dist/commands/manager.d.ts +15 -3
  56. package/dist/commands/manager.d.ts.map +1 -1
  57. package/dist/commands/manager.js +86 -26
  58. package/dist/commands/model-command.d.ts +22 -0
  59. package/dist/commands/model-command.d.ts.map +1 -1
  60. package/dist/commands/model-command.js +256 -0
  61. package/dist/commands/paste-command.d.ts.map +1 -1
  62. package/dist/commands/paste-command.js +92 -0
  63. package/dist/commands/pickup-command.d.ts +3 -0
  64. package/dist/commands/pickup-command.d.ts.map +1 -0
  65. package/dist/commands/pickup-command.js +161 -0
  66. package/dist/commands/prompt-command.d.ts +1 -1
  67. package/dist/commands/prompt-command.d.ts.map +1 -1
  68. package/dist/commands/prompt-command.js +117 -2
  69. package/dist/commands/remove-directory-command.d.ts +3 -0
  70. package/dist/commands/remove-directory-command.d.ts.map +1 -0
  71. package/dist/commands/remove-directory-command.js +87 -0
  72. package/dist/commands/reset-command.d.ts +1 -1
  73. package/dist/commands/reset-command.d.ts.map +1 -1
  74. package/dist/commands/reset-command.js +13 -2
  75. package/dist/commands/rules-command.d.ts.map +1 -1
  76. package/dist/commands/rules-command.js +65 -0
  77. package/dist/commands/save-command.d.ts.map +1 -1
  78. package/dist/commands/save-command.js +12 -0
  79. package/dist/commands/shell-command.d.ts.map +1 -1
  80. package/dist/commands/shell-command.js +68 -0
  81. package/dist/commands/types.d.ts +9 -4
  82. package/dist/commands/types.d.ts.map +1 -1
  83. package/dist/commands/usage-command.d.ts.map +1 -1
  84. package/dist/commands/usage-command.js +22 -0
  85. package/dist/config.d.ts +6 -7
  86. package/dist/config.d.ts.map +1 -1
  87. package/dist/config.js +23 -29
  88. package/dist/formatting.d.ts +108 -0
  89. package/dist/formatting.d.ts.map +1 -1
  90. package/dist/formatting.js +147 -0
  91. package/dist/index.d.ts +7 -2
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +140 -38
  94. package/dist/logger.d.ts.map +1 -1
  95. package/dist/logger.js +47 -18
  96. package/dist/mentions.d.ts +2 -1
  97. package/dist/mentions.d.ts.map +1 -1
  98. package/dist/mentions.js +16 -1
  99. package/dist/messages.d.ts +8 -0
  100. package/dist/messages.d.ts.map +1 -1
  101. package/dist/messages.js +56 -19
  102. package/dist/middleware/cache.d.ts +3 -0
  103. package/dist/middleware/cache.d.ts.map +1 -0
  104. package/dist/middleware/cache.js +53 -0
  105. package/dist/middleware/index.d.ts +1 -0
  106. package/dist/middleware/index.d.ts.map +1 -1
  107. package/dist/middleware/index.js +1 -0
  108. package/dist/models/ai-config.d.ts +4 -2
  109. package/dist/models/ai-config.d.ts.map +1 -1
  110. package/dist/models/ai-config.js +12 -2
  111. package/dist/models/anthropic-provider.d.ts.map +1 -1
  112. package/dist/models/anthropic-provider.js +3 -60
  113. package/dist/models/manager.d.ts +2 -1
  114. package/dist/models/manager.d.ts.map +1 -1
  115. package/dist/models/manager.js +26 -2
  116. package/dist/models/openrouter-provider.d.ts +7 -14
  117. package/dist/models/openrouter-provider.d.ts.map +1 -1
  118. package/dist/models/openrouter-provider.js +114 -169
  119. package/dist/models/providers.d.ts +1 -1
  120. package/dist/models/providers.d.ts.map +1 -1
  121. package/dist/prompts.d.ts +1 -0
  122. package/dist/prompts.d.ts.map +1 -1
  123. package/dist/prompts.js +53 -4
  124. package/dist/repl/display-tool-messages.d.ts +1 -1
  125. package/dist/repl/display-tool-messages.d.ts.map +1 -1
  126. package/dist/repl/display-tool-messages.js +47 -44
  127. package/dist/repl/get-prompt-header.d.ts.map +1 -1
  128. package/dist/repl/get-prompt-header.js +1 -30
  129. package/dist/repl/project-status-line.d.ts +2 -0
  130. package/dist/repl/project-status-line.d.ts.map +1 -0
  131. package/dist/repl/project-status-line.js +31 -0
  132. package/dist/repl/prompt.d.ts +21 -0
  133. package/dist/repl/prompt.d.ts.map +1 -0
  134. package/dist/{repl-prompt.js → repl/prompt.js} +119 -22
  135. package/dist/repl/tool-call-repair.d.ts.map +1 -1
  136. package/dist/repl/tool-call-repair.js +8 -4
  137. package/dist/repl-new.d.ts +53 -0
  138. package/dist/repl-new.d.ts.map +1 -0
  139. package/dist/repl-new.js +374 -0
  140. package/dist/repl.d.ts +3 -5
  141. package/dist/repl.d.ts.map +1 -1
  142. package/dist/repl.js +74 -166
  143. package/dist/terminal/checkbox-prompt.d.ts.map +1 -1
  144. package/dist/terminal/checkbox-prompt.js +10 -4
  145. package/dist/terminal/index.d.ts +7 -0
  146. package/dist/terminal/index.d.ts.map +1 -1
  147. package/dist/terminal/index.js +94 -0
  148. package/dist/terminal/input-prompt.d.ts +2 -1
  149. package/dist/terminal/input-prompt.d.ts.map +1 -1
  150. package/dist/terminal/markdown.js +3 -0
  151. package/dist/terminal/search-prompt.d.ts.map +1 -1
  152. package/dist/terminal/search-prompt.js +11 -10
  153. package/dist/terminal/select-prompt.d.ts +2 -2
  154. package/dist/terminal/select-prompt.d.ts.map +1 -1
  155. package/dist/terminal/select-prompt.js +47 -39
  156. package/dist/tokens/threshold.d.ts +35 -0
  157. package/dist/tokens/threshold.d.ts.map +1 -0
  158. package/dist/tokens/threshold.js +85 -0
  159. package/dist/tools/advanced-edit-file.d.ts +69 -0
  160. package/dist/tools/advanced-edit-file.d.ts.map +1 -0
  161. package/dist/tools/advanced-edit-file.js +281 -0
  162. package/dist/tools/agent.d.ts +16 -5
  163. package/dist/tools/agent.d.ts.map +1 -1
  164. package/dist/tools/agent.js +71 -58
  165. package/dist/tools/bash-utils.d.ts +1 -1
  166. package/dist/tools/bash-utils.d.ts.map +1 -1
  167. package/dist/tools/bash-utils.js +14 -6
  168. package/dist/tools/bash.d.ts +21 -12
  169. package/dist/tools/bash.d.ts.map +1 -1
  170. package/dist/tools/bash.js +88 -135
  171. package/dist/tools/code-interpreter.d.ts +21 -9
  172. package/dist/tools/code-interpreter.d.ts.map +1 -1
  173. package/dist/tools/code-interpreter.js +138 -137
  174. package/dist/tools/delete-file.d.ts +17 -10
  175. package/dist/tools/delete-file.d.ts.map +1 -1
  176. package/dist/tools/delete-file.js +51 -95
  177. package/dist/tools/directory-tree.d.ts +17 -6
  178. package/dist/tools/directory-tree.d.ts.map +1 -1
  179. package/dist/tools/directory-tree.js +47 -49
  180. package/dist/tools/dynamic-tool-loader.d.ts +18 -8
  181. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  182. package/dist/tools/dynamic-tool-loader.js +121 -129
  183. package/dist/tools/dynamic-tool-parser.d.ts +1 -0
  184. package/dist/tools/dynamic-tool-parser.d.ts.map +1 -1
  185. package/dist/tools/dynamic-tool-parser.js +1 -0
  186. package/dist/tools/edit-file.d.ts +35 -15
  187. package/dist/tools/edit-file.d.ts.map +1 -1
  188. package/dist/tools/edit-file.js +112 -112
  189. package/dist/tools/filesystem-utils.d.ts +2 -1
  190. package/dist/tools/filesystem-utils.d.ts.map +1 -1
  191. package/dist/tools/filesystem-utils.js +31 -17
  192. package/dist/tools/glob.d.ts +36 -0
  193. package/dist/tools/glob.d.ts.map +1 -0
  194. package/dist/tools/glob.js +143 -0
  195. package/dist/tools/grep.d.ts +73 -12
  196. package/dist/tools/grep.d.ts.map +1 -1
  197. package/dist/tools/grep.js +413 -168
  198. package/dist/tools/index.d.ts +204 -124
  199. package/dist/tools/index.d.ts.map +1 -1
  200. package/dist/tools/index.js +242 -135
  201. package/dist/tools/llm-edit-fixer.d.ts +25 -0
  202. package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
  203. package/dist/tools/llm-edit-fixer.js +150 -0
  204. package/dist/tools/move-file.d.ts +19 -7
  205. package/dist/tools/move-file.d.ts.map +1 -1
  206. package/dist/tools/move-file.js +40 -33
  207. package/dist/tools/read-file.d.ts +47 -9
  208. package/dist/tools/read-file.d.ts.map +1 -1
  209. package/dist/tools/read-file.js +74 -69
  210. package/dist/tools/read-multiple-files.d.ts +17 -6
  211. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  212. package/dist/tools/read-multiple-files.js +76 -73
  213. package/dist/tools/save-file.d.ts +45 -12
  214. package/dist/tools/save-file.d.ts.map +1 -1
  215. package/dist/tools/save-file.js +58 -101
  216. package/dist/tools/think.d.ts +15 -7
  217. package/dist/tools/think.d.ts.map +1 -1
  218. package/dist/tools/think.js +30 -22
  219. package/dist/tools/types.d.ts +4 -10
  220. package/dist/tools/types.d.ts.map +1 -1
  221. package/dist/tools/types.js +9 -0
  222. package/dist/tools/utils.d.ts +14 -0
  223. package/dist/tools/utils.d.ts.map +1 -0
  224. package/dist/tools/utils.js +16 -0
  225. package/dist/tools/web-fetch.d.ts +11 -4
  226. package/dist/tools/web-fetch.d.ts.map +1 -1
  227. package/dist/tools/web-fetch.js +39 -38
  228. package/dist/tools/web-search.d.ts +15 -6
  229. package/dist/tools/web-search.d.ts.map +1 -1
  230. package/dist/tools/web-search.js +50 -32
  231. package/dist/tui/autocomplete.d.ts +44 -0
  232. package/dist/tui/autocomplete.d.ts.map +1 -0
  233. package/dist/tui/autocomplete.js +466 -0
  234. package/dist/tui/components/assistant-message.d.ts +18 -0
  235. package/dist/tui/components/assistant-message.d.ts.map +1 -0
  236. package/dist/tui/components/assistant-message.js +29 -0
  237. package/dist/tui/components/editor.d.ts +51 -0
  238. package/dist/tui/components/editor.d.ts.map +1 -0
  239. package/dist/tui/components/editor.js +758 -0
  240. package/dist/tui/components/footer.d.ts +24 -0
  241. package/dist/tui/components/footer.d.ts.map +1 -0
  242. package/dist/tui/components/footer.js +197 -0
  243. package/dist/tui/components/input.d.ts +14 -0
  244. package/dist/tui/components/input.d.ts.map +1 -0
  245. package/dist/tui/components/input.js +122 -0
  246. package/dist/tui/components/loader.d.ts +19 -0
  247. package/dist/tui/components/loader.d.ts.map +1 -0
  248. package/dist/tui/components/loader.js +45 -0
  249. package/dist/tui/components/markdown.d.ts +103 -0
  250. package/dist/tui/components/markdown.d.ts.map +1 -0
  251. package/dist/tui/components/markdown.js +533 -0
  252. package/dist/tui/components/modal.d.ts +40 -0
  253. package/dist/tui/components/modal.d.ts.map +1 -0
  254. package/dist/tui/components/modal.js +292 -0
  255. package/dist/tui/components/prompt-status.d.ts +16 -0
  256. package/dist/tui/components/prompt-status.d.ts.map +1 -0
  257. package/dist/tui/components/prompt-status.js +21 -0
  258. package/dist/tui/components/select-list.d.ts +22 -0
  259. package/dist/tui/components/select-list.d.ts.map +1 -0
  260. package/dist/tui/components/select-list.js +143 -0
  261. package/dist/tui/components/spacer.d.ts +16 -0
  262. package/dist/tui/components/spacer.d.ts.map +1 -0
  263. package/dist/tui/components/spacer.js +27 -0
  264. package/dist/tui/components/text.d.ts +26 -0
  265. package/dist/tui/components/text.d.ts.map +1 -0
  266. package/dist/tui/components/text.js +143 -0
  267. package/dist/tui/components/thinking-block.d.ts +14 -0
  268. package/dist/tui/components/thinking-block.d.ts.map +1 -0
  269. package/dist/tui/components/thinking-block.js +30 -0
  270. package/dist/tui/components/tool-execution.d.ts +17 -0
  271. package/dist/tui/components/tool-execution.d.ts.map +1 -0
  272. package/dist/tui/components/tool-execution.js +153 -0
  273. package/dist/tui/components/user-message.d.ts +9 -0
  274. package/dist/tui/components/user-message.d.ts.map +1 -0
  275. package/dist/tui/components/user-message.js +21 -0
  276. package/dist/tui/components/welcome.d.ts +6 -0
  277. package/dist/tui/components/welcome.d.ts.map +1 -0
  278. package/dist/tui/components/welcome.js +30 -0
  279. package/dist/tui/index.d.ts +14 -0
  280. package/dist/tui/index.d.ts.map +1 -0
  281. package/dist/tui/index.js +18 -0
  282. package/dist/tui/terminal.d.ts +37 -0
  283. package/dist/tui/terminal.d.ts.map +1 -0
  284. package/dist/tui/terminal.js +104 -0
  285. package/dist/tui/tui.d.ts +67 -0
  286. package/dist/tui/tui.d.ts.map +1 -0
  287. package/dist/tui/tui.js +184 -0
  288. package/dist/tui/utils.d.ts +19 -0
  289. package/dist/tui/utils.d.ts.map +1 -0
  290. package/dist/tui/utils.js +31 -0
  291. package/dist/utils/generators.d.ts +3 -0
  292. package/dist/utils/generators.d.ts.map +1 -0
  293. package/dist/utils/generators.js +25 -0
  294. package/dist/utils/iterables.d.ts +2 -0
  295. package/dist/utils/iterables.d.ts.map +1 -0
  296. package/dist/utils/iterables.js +6 -0
  297. package/package.json +16 -16
  298. package/dist/conversation-analyzer.d.ts +0 -11
  299. package/dist/conversation-analyzer.d.ts.map +0 -1
  300. package/dist/conversation-analyzer.js +0 -88
  301. package/dist/repl-prompt.d.ts +0 -15
  302. package/dist/repl-prompt.d.ts.map +0 -1
  303. package/dist/tokens/manage-output.d.ts +0 -34
  304. package/dist/tokens/manage-output.d.ts.map +0 -1
  305. package/dist/tokens/manage-output.js +0 -44
  306. package/dist/tool-executor.d.ts +0 -28
  307. package/dist/tool-executor.d.ts.map +0 -1
  308. package/dist/tool-executor.js +0 -74
  309. package/dist/tools/file-editing-utils.d.ts +0 -2
  310. package/dist/tools/file-editing-utils.d.ts.map +0 -1
  311. package/dist/tools/file-editing-utils.js +0 -135
@@ -0,0 +1,533 @@
1
+ import Table from "cli-table3";
2
+ import { marked } from "marked";
3
+ import { DEFAULT_THEME } from "../../terminal/default-theme.js";
4
+ import { highlight, supportsLanguage } from "../../terminal/highlight/index.js";
5
+ import { getListNumber } from "../../terminal/markdown-utils.js";
6
+ import style from "../../terminal/style.js";
7
+ import wrapAnsi from "../../terminal/wrap-ansi.js";
8
+ import { applyBackgroundToLine, visibleWidth } from "../utils.js";
9
+ export class Markdown {
10
+ text;
11
+ bgColor;
12
+ customBgRgb;
13
+ paddingX; // Left/right padding
14
+ paddingY; // Top/bottom padding
15
+ // Cache for rendered output
16
+ cachedText;
17
+ cachedWidth;
18
+ cachedLines;
19
+ constructor(text = "", bgColor, _fgColor, customBgRgb, paddingX = 1, paddingY = 1) {
20
+ this.text = text;
21
+ this.bgColor = bgColor;
22
+ this.customBgRgb = customBgRgb;
23
+ this.paddingX = paddingX;
24
+ this.paddingY = paddingY;
25
+ }
26
+ setText(text) {
27
+ this.text = text;
28
+ // Invalidate cache when text changes
29
+ this.cachedText = undefined;
30
+ this.cachedWidth = undefined;
31
+ this.cachedLines = undefined;
32
+ }
33
+ setBgColor(bgColor) {
34
+ this.bgColor = bgColor;
35
+ // Invalidate cache when color changes
36
+ this.cachedText = undefined;
37
+ this.cachedWidth = undefined;
38
+ this.cachedLines = undefined;
39
+ }
40
+ setCustomBgRgb(customBgRgb) {
41
+ this.customBgRgb = customBgRgb;
42
+ // Invalidate cache when color changes
43
+ this.cachedText = undefined;
44
+ this.cachedWidth = undefined;
45
+ this.cachedLines = undefined;
46
+ }
47
+ invalidate() {
48
+ this.cachedText = undefined;
49
+ this.cachedWidth = undefined;
50
+ this.cachedLines = undefined;
51
+ }
52
+ /**
53
+ * Get the background color function based on current configuration
54
+ */
55
+ getBackgroundFunction() {
56
+ if (this.customBgRgb) {
57
+ const { r, g, b } = this.customBgRgb;
58
+ return (text) => style.bgRgb(r, g, b)(text);
59
+ }
60
+ if (this.bgColor) {
61
+ const bgColor = this.bgColor;
62
+ return (text) => style[bgColor](text);
63
+ }
64
+ return undefined;
65
+ }
66
+ render(width) {
67
+ // Check cache
68
+ if (this.cachedLines &&
69
+ this.cachedText === this.text &&
70
+ this.cachedWidth === width) {
71
+ return this.cachedLines;
72
+ }
73
+ // Calculate available width for content (subtract horizontal padding)
74
+ const contentWidth = Math.max(1, width - this.paddingX * 2);
75
+ // Don't render anything if there's no actual text
76
+ if (!this.text || this.text.trim() === "") {
77
+ const result = [];
78
+ // Update cache
79
+ this.cachedText = this.text;
80
+ this.cachedWidth = width;
81
+ this.cachedLines = result;
82
+ return result;
83
+ }
84
+ // Replace tabs with 3 spaces for consistent rendering
85
+ const normalizedText = this.text.replace(/\t/g, " ");
86
+ // Parse markdown to HTML-like tokens
87
+ const tokens = marked.lexer(normalizedText);
88
+ // Convert tokens to styled terminal output
89
+ const renderedLines = [];
90
+ for (let i = 0; i < tokens.length; i++) {
91
+ const token = tokens[i];
92
+ const nextToken = tokens[i + 1];
93
+ const tokenLines = this.renderToken(token, contentWidth, nextToken?.type);
94
+ renderedLines.push(...tokenLines);
95
+ }
96
+ // Wrap lines (NO padding, NO background yet)
97
+ const wrappedLines = [];
98
+ for (const line of renderedLines) {
99
+ wrappedLines.push(...this.wrapLine(line, contentWidth));
100
+ }
101
+ // Add margins and background to each wrapped line
102
+ const leftMargin = " ".repeat(this.paddingX);
103
+ const rightMargin = " ".repeat(this.paddingX);
104
+ const bgFn = this.getBackgroundFunction();
105
+ const contentLines = [];
106
+ for (const line of wrappedLines) {
107
+ const lineWithMargins = leftMargin + line + rightMargin;
108
+ if (bgFn) {
109
+ contentLines.push(applyBackgroundToLine(lineWithMargins, width, bgFn));
110
+ }
111
+ else {
112
+ // No background - just pad to width
113
+ const visibleLen = visibleWidth(lineWithMargins);
114
+ const paddingNeeded = Math.max(0, width - visibleLen);
115
+ contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
116
+ }
117
+ }
118
+ // Add top/bottom padding (empty lines)
119
+ const emptyLine = " ".repeat(width);
120
+ const emptyLines = [];
121
+ for (let i = 0; i < this.paddingY; i++) {
122
+ const line = bgFn
123
+ ? applyBackgroundToLine(emptyLine, width, bgFn)
124
+ : emptyLine;
125
+ emptyLines.push(line);
126
+ }
127
+ const result = [...emptyLines, ...contentLines, ...emptyLines];
128
+ // Update cache
129
+ this.cachedText = this.text;
130
+ this.cachedWidth = width;
131
+ this.cachedLines = result;
132
+ return result.length > 0 ? result : [""];
133
+ }
134
+ renderToken(token, width, nextTokenType) {
135
+ const lines = [];
136
+ switch (token.type) {
137
+ case "heading": {
138
+ const headingLevel = token.depth;
139
+ const headingPrefix = `${"#".repeat(headingLevel)} `;
140
+ const headingText = this.renderInlineTokens(token.tokens || []);
141
+ if (headingLevel === 1) {
142
+ lines.push(style.bold.underline.yellow(headingText));
143
+ }
144
+ else if (headingLevel === 2) {
145
+ lines.push(style.bold.yellow(headingText));
146
+ }
147
+ else {
148
+ lines.push(style.bold(headingPrefix + headingText));
149
+ }
150
+ lines.push(""); // Add spacing after headings
151
+ break;
152
+ }
153
+ case "paragraph": {
154
+ const paragraphText = this.renderInlineTokens(token.tokens || []);
155
+ lines.push(paragraphText);
156
+ // Don't add spacing if next token is space or list
157
+ if (nextTokenType &&
158
+ nextTokenType !== "list" &&
159
+ nextTokenType !== "space") {
160
+ lines.push("");
161
+ }
162
+ break;
163
+ }
164
+ case "code": {
165
+ if (token.lang && supportsLanguage(token.lang)) {
166
+ // Use syntax highlighting for supported languages
167
+ const highlightedCode = highlight(token.text, {
168
+ language: token.lang,
169
+ theme: DEFAULT_THEME,
170
+ });
171
+ const codeLines = highlightedCode.split("\n");
172
+ lines.push(style.gray(`\`\`\`${token.lang}`));
173
+ for (const codeLine of codeLines) {
174
+ lines.push(style.dim(" ") + codeLine);
175
+ }
176
+ lines.push(style.gray("```"));
177
+ }
178
+ else {
179
+ // Fallback to basic styling for unsupported languages
180
+ lines.push(style.gray(`\`\`\`${token.lang || ""}`));
181
+ const codeLines = token.text.split("\n");
182
+ for (const codeLine of codeLines) {
183
+ lines.push(style.dim(" ") + style.green(codeLine));
184
+ }
185
+ lines.push(style.gray("```"));
186
+ }
187
+ lines.push(""); // Add spacing after code blocks
188
+ break;
189
+ }
190
+ case "list": {
191
+ const listLines = this.renderList(token, 0);
192
+ lines.push(...listLines);
193
+ // Don't add spacing after lists if a space token follows
194
+ // (the space token will handle it)
195
+ break;
196
+ }
197
+ case "table": {
198
+ const tableLines = this.renderTable(token);
199
+ lines.push(...tableLines);
200
+ break;
201
+ }
202
+ case "blockquote": {
203
+ const quoteText = this.renderInlineTokens(token.tokens || []);
204
+ const quoteLines = quoteText.split("\n");
205
+ for (const quoteLine of quoteLines) {
206
+ lines.push(style.gray("│ ") + style.italic(quoteLine));
207
+ }
208
+ lines.push(""); // Add spacing after blockquotes
209
+ break;
210
+ }
211
+ case "hr":
212
+ lines.push(style.gray("─".repeat(Math.min(width, 80))));
213
+ lines.push(""); // Add spacing after horizontal rules
214
+ break;
215
+ case "image": {
216
+ const alt = (token.title ?? token.text ?? "").toString().trim();
217
+ if (alt.length > 0) {
218
+ lines.push(`[Image: ${alt} (${token.href})]`);
219
+ }
220
+ else {
221
+ lines.push(`[Image: ${token.href}]`);
222
+ }
223
+ break;
224
+ }
225
+ case "html":
226
+ // Render HTML tags with dim styling and content as normal text
227
+ lines.push(style.dim(token.text));
228
+ break;
229
+ case "space":
230
+ // Space tokens represent blank lines in markdown
231
+ lines.push("");
232
+ break;
233
+ default:
234
+ // Handle any other token types as plain text
235
+ if ("text" in token && typeof token.text === "string") {
236
+ lines.push(token.text);
237
+ }
238
+ }
239
+ return lines;
240
+ }
241
+ renderInlineTokens(tokens) {
242
+ let result = "";
243
+ for (const token of tokens) {
244
+ switch (token.type) {
245
+ case "text":
246
+ // Text tokens in list items can have nested tokens for inline formatting
247
+ if (token.tokens && token.tokens.length > 0) {
248
+ result += this.renderInlineTokens(token.tokens);
249
+ }
250
+ else {
251
+ result += token.text;
252
+ }
253
+ break;
254
+ case "strong":
255
+ result += style.bold(this.renderInlineTokens(token.tokens || []));
256
+ break;
257
+ case "em":
258
+ result += style.italic(this.renderInlineTokens(token.tokens || []));
259
+ break;
260
+ case "codespan":
261
+ result += style.gray("`") + style.cyan(token.text) + style.gray("`");
262
+ break;
263
+ case "link": {
264
+ const linkText = this.renderInlineTokens(token.tokens || []);
265
+ // If link text matches href, only show the link once
266
+ if (linkText === token.href) {
267
+ result += style.underline.blue(linkText);
268
+ }
269
+ else {
270
+ result +=
271
+ style.underline.blue(linkText) + style.gray(` (${token.href})`);
272
+ }
273
+ break;
274
+ }
275
+ case "br":
276
+ result += "\n";
277
+ break;
278
+ case "del":
279
+ result += style.strikethrough(this.renderInlineTokens(token.tokens || []));
280
+ break;
281
+ case "image": {
282
+ const alt = (token.title ?? token.text ?? "").toString().trim();
283
+ if (alt.length > 0) {
284
+ result += `[Image: ${alt} (${token.href})]`;
285
+ }
286
+ else {
287
+ result += `[Image: ${token.href}]`;
288
+ }
289
+ break;
290
+ }
291
+ default:
292
+ // Handle any other inline token types as plain text
293
+ if ("text" in token && typeof token.text === "string") {
294
+ result += token.text;
295
+ }
296
+ }
297
+ }
298
+ return result;
299
+ }
300
+ wrapLine(line, width) {
301
+ // Handle undefined or null lines
302
+ if (!line) {
303
+ return [""];
304
+ }
305
+ // Protect inline code spans from being split across lines
306
+ // by temporarily replacing them with placeholders
307
+ const { protectedText, codeSpans } = this.protectCodeSpans(line);
308
+ // Use the existing wrapAnsi function for robust ANSI-aware wrapping
309
+ const wrappedText = wrapAnsi(protectedText, width, { trim: false });
310
+ const lines = wrappedText.split("\n");
311
+ // Restore the code spans
312
+ const restoredLines = this.restoreCodeSpans(lines, codeSpans);
313
+ return restoredLines;
314
+ }
315
+ /**
316
+ * Protect inline code spans by replacing them with placeholders
317
+ * This prevents wrapAnsi from breaking code spans across lines
318
+ */
319
+ protectCodeSpans(text) {
320
+ const codeSpans = [];
321
+ let protectedText = text;
322
+ let placeholderIndex = 0;
323
+ // Find all inline code spans (text between backticks with ANSI styling)
324
+ // Only protect actual code spans that have been styled by renderInlineTokens
325
+ // Pattern: gray backtick + cyan content + gray backtick
326
+ // Use a simpler approach that doesn't rely on specific ANSI codes
327
+ const codeSpanRegex = /`[^`]+`/g;
328
+ let match = null;
329
+ // biome-ignore lint/suspicious/noAssignInExpressions: Need assignment in while condition
330
+ while ((match = codeSpanRegex.exec(text)) !== null) {
331
+ const codeSpan = match[0];
332
+ // Only protect code spans that are actual code (not escaped backticks)
333
+ // We can identify actual code spans by checking if they're surrounded by ANSI codes
334
+ // or if they appear in contexts where escaped backticks would have been processed
335
+ const startIndex = match.index;
336
+ const endIndex = startIndex + codeSpan.length;
337
+ // Check if this looks like an actual code span (not escaped backticks)
338
+ // Escaped backticks would appear as literal backticks without ANSI styling
339
+ // Actual code spans would have been processed by renderInlineTokens
340
+ if (this.isActualCodeSpan(text, startIndex, endIndex)) {
341
+ const placeholder = `__CODE_SPAN_${placeholderIndex}__`;
342
+ codeSpans.push(codeSpan);
343
+ protectedText = protectedText.replace(codeSpan, placeholder);
344
+ placeholderIndex++;
345
+ }
346
+ }
347
+ return { protectedText, codeSpans };
348
+ }
349
+ /**
350
+ * Check if a potential code span is an actual code span (not escaped backticks)
351
+ */
352
+ isActualCodeSpan(text, startIndex, endIndex) {
353
+ // If the text around the code span contains ANSI escape sequences,
354
+ // it's likely an actual code span that was processed by renderInlineTokens
355
+ // Look for ANSI escape sequences in the surrounding context
356
+ const contextStart = Math.max(0, startIndex - 10);
357
+ const contextEnd = Math.min(text.length, endIndex + 10);
358
+ const context = text.slice(contextStart, contextEnd);
359
+ // Check for ANSI escape sequences that would indicate styled code
360
+ // Use String.fromCharCode(27) to avoid control characters in regex
361
+ const escapeChar = String.fromCharCode(27);
362
+ return context.includes(`${escapeChar}[`);
363
+ }
364
+ /**
365
+ * Check if a line represents a nested list item
366
+ */
367
+ isNestedListLine(line, currentDepth) {
368
+ // A nested list line should have proper indentation for its depth
369
+ // and typically starts with a bullet (cyan colored number or dash)
370
+ const expectedIndent = " ".repeat(currentDepth + 1);
371
+ const escapeChar = String.fromCharCode(27);
372
+ // Check if the line starts with the expected indent for a nested list
373
+ // and contains a cyan bullet (either number or dash) after the indent
374
+ if (line.startsWith(expectedIndent)) {
375
+ const afterIndent = line.slice(expectedIndent.length);
376
+ // Look for cyan-colored content at the start (bullet)
377
+ // Pattern: cyan escape sequence followed by content, then reset
378
+ const cyanPattern = `${escapeChar}[36m`;
379
+ const resetPattern = `${escapeChar}[39m`;
380
+ if (afterIndent.startsWith(cyanPattern)) {
381
+ const afterCyan = afterIndent.slice(cyanPattern.length);
382
+ const resetIndex = afterCyan.indexOf(resetPattern);
383
+ if (resetIndex > 0) {
384
+ const bulletContent = afterCyan.slice(0, resetIndex);
385
+ // Check if this looks like a list bullet (number with dot or dash)
386
+ return /^(\d+\.|-)/.test(bulletContent);
387
+ }
388
+ }
389
+ }
390
+ return false;
391
+ }
392
+ /**
393
+ * Restore code spans from placeholders after wrapping
394
+ */
395
+ restoreCodeSpans(lines, codeSpans) {
396
+ return lines.map((line) => {
397
+ let restoredLine = line;
398
+ // Restore each code span placeholder
399
+ for (let i = 0; i < codeSpans.length; i++) {
400
+ const placeholder = `__CODE_SPAN_${i}__`;
401
+ const codeSpan = codeSpans[i];
402
+ restoredLine = restoredLine.replace(placeholder, codeSpan);
403
+ }
404
+ return restoredLine;
405
+ });
406
+ }
407
+ /**
408
+ * Render a list with proper nesting support
409
+ */
410
+ renderList(token, depth) {
411
+ const lines = [];
412
+ const indent = " ".repeat(depth);
413
+ for (let i = 0; i < token.items.length; i++) {
414
+ const item = token.items[i];
415
+ const startNumber = typeof token.start === "string"
416
+ ? Number.parseInt(token.start, 10)
417
+ : token.start;
418
+ const bullet = token.ordered
419
+ ? `${getListNumber(depth, (startNumber ?? 1) + i)}. `
420
+ : "- ";
421
+ // Process item tokens to handle nested lists
422
+ const itemLines = this.renderListItem(item.tokens || [], depth);
423
+ if (itemLines.length > 0) {
424
+ // First line - check if it's a nested list
425
+ const firstLine = itemLines[0];
426
+ const isNestedList = this.isNestedListLine(firstLine, depth);
427
+ if (isNestedList) {
428
+ // This is a nested list, just add it as-is (already has full indent)
429
+ lines.push(firstLine);
430
+ }
431
+ else {
432
+ // Regular text content - add indent and bullet
433
+ lines.push(indent + style.cyan(bullet) + firstLine);
434
+ }
435
+ // Rest of the lines
436
+ for (let j = 1; j < itemLines.length; j++) {
437
+ const line = itemLines[j];
438
+ const isNestedListLine = line.includes("\x1b[36m"); // cyan bullet color
439
+ if (isNestedListLine) {
440
+ // Nested list line - already has full indent
441
+ lines.push(line);
442
+ }
443
+ else {
444
+ // Regular content - add parent indent + 2 spaces for continuation
445
+ lines.push(`${indent} ${line}`);
446
+ }
447
+ }
448
+ }
449
+ else {
450
+ lines.push(indent + style.cyan(bullet));
451
+ }
452
+ }
453
+ return lines;
454
+ }
455
+ /**
456
+ * Render list item tokens, handling nested lists
457
+ * Returns lines WITHOUT the parent indent (renderList will add it)
458
+ */
459
+ renderListItem(tokens, parentDepth) {
460
+ const lines = [];
461
+ for (const token of tokens) {
462
+ if (token.type === "list") {
463
+ // Nested list - render with one additional indent level
464
+ // These lines will have their own indent, so we just add them as-is
465
+ const nestedLines = this.renderList(token, parentDepth + 1);
466
+ lines.push(...nestedLines);
467
+ }
468
+ else if (token.type === "text") {
469
+ // Text content (may have inline tokens)
470
+ const text = token.tokens && token.tokens.length > 0
471
+ ? this.renderInlineTokens(token.tokens)
472
+ : token.text || "";
473
+ lines.push(text);
474
+ }
475
+ else if (token.type === "paragraph") {
476
+ // Paragraph in list item
477
+ const text = this.renderInlineTokens(token.tokens || []);
478
+ lines.push(text);
479
+ }
480
+ else if (token.type === "code") {
481
+ // Code block in list item
482
+ lines.push(style.gray(`\`\`\`${token.lang || ""}`));
483
+ const codeLines = token.text.split("\n");
484
+ for (const codeLine of codeLines) {
485
+ lines.push(style.dim(" ") + style.green(codeLine));
486
+ }
487
+ lines.push(style.gray("```"));
488
+ }
489
+ else {
490
+ // Other token types - try to render as inline
491
+ const text = this.renderInlineTokens([token]);
492
+ if (text) {
493
+ lines.push(text);
494
+ }
495
+ }
496
+ }
497
+ return lines;
498
+ }
499
+ /**
500
+ * Render a table
501
+ */
502
+ renderTable(token) {
503
+ const lines = [];
504
+ // Extract header and row texts
505
+ const header = token.header.map((cell) => {
506
+ const headerCell = cell;
507
+ return this.renderInlineTokens(headerCell.tokens || []);
508
+ });
509
+ const rows = token.rows.map((row) => row.map((cell) => {
510
+ const rowCell = cell;
511
+ return this.renderInlineTokens(rowCell.tokens || []);
512
+ }));
513
+ // Calculate column widths based on available width
514
+ const padding = 5; // Account for table borders and padding
515
+ const availableWidth = Math.max(10, 80 - padding); // Use reasonable default width for TUI
516
+ const colCount = header?.length ?? 1;
517
+ const width = Math.max(10, Math.floor(availableWidth / Math.max(1, colCount)));
518
+ const computedColWidths = new Array(colCount).fill(width);
519
+ // Create table using cli-table3
520
+ const table = new Table({
521
+ head: header,
522
+ colWidths: computedColWidths,
523
+ wordWrap: true, // Enable word wrapping for the description column
524
+ });
525
+ table.push(...rows);
526
+ // Split table output into lines
527
+ const tableOutput = table.toString();
528
+ const tableLines = tableOutput.split("\n");
529
+ lines.push(...tableLines);
530
+ lines.push(""); // Add spacing after table
531
+ return lines;
532
+ }
533
+ }
@@ -0,0 +1,40 @@
1
+ import type { Component } from "../tui.ts";
2
+ import { Container } from "../tui.ts";
3
+ /**
4
+ * Modal component - displays content in an overlay on top of the main UI
5
+ */
6
+ export declare class Modal extends Container implements Component {
7
+ private title;
8
+ backdrop: boolean;
9
+ private onClose?;
10
+ private maxWidth;
11
+ private maxHeight;
12
+ private scrollPosition;
13
+ constructor(title: string, content: Component, backdrop?: boolean, onClose?: () => void, maxWidth?: number, maxHeight?: number);
14
+ handleInput(data: string): void;
15
+ close(): void;
16
+ render(width: number): string[];
17
+ getCursorPosition(): [number, number] | null;
18
+ }
19
+ /**
20
+ * ModalText component - displays text content in a modal with word wrapping
21
+ */
22
+ export declare class ModalText extends Container {
23
+ private text;
24
+ private paddingX;
25
+ private paddingY;
26
+ constructor(text: string, paddingX?: number, paddingY?: number);
27
+ render(width: number): string[];
28
+ }
29
+ /**
30
+ * ModalTable component - displays tabular data in a modal
31
+ * Uses the terminal table function for proper text wrapping and formatting
32
+ */
33
+ export declare class ModalTable extends Container {
34
+ private data;
35
+ private headers?;
36
+ private colWidths?;
37
+ constructor(data: (string | number)[][], headers?: string[], colWidths?: number[]);
38
+ render(width: number): string[];
39
+ }
40
+ //# sourceMappingURL=modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../../../source/tui/components/modal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC;;GAEG;AACH,qBAAa,KAAM,SAAQ,SAAU,YAAW,SAAS;IACvD,OAAO,CAAC,KAAK,CAAS;IACf,QAAQ,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAK;gBAGzB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,EAClB,QAAQ,UAAO,EACf,OAAO,CAAC,EAAE,MAAM,IAAI,EACpB,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM;IAYpB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAgD/B,KAAK,IAAI,IAAI;IAMJ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAqHxC,iBAAiB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;CA2B7C;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACtC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAI,EAAE,QAAQ,SAAI;IAO3C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAkFzC;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,OAAO,CAAC,CAAW;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAW;gBAG3B,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,EAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,EAClB,SAAS,CAAC,EAAE,MAAM,EAAE;IAQb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAezC"}