@nghyane/arcane 0.1.12 → 0.1.14

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 (333) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +21 -70
  3. package/scripts/format-prompts.ts +1 -3
  4. package/src/cli/args.ts +2 -7
  5. package/src/cli/config-cli.ts +1 -1
  6. package/src/cli/plugin-cli.ts +1 -1
  7. package/src/cli/setup-cli.ts +1 -1
  8. package/src/cli/update-cli.ts +1 -1
  9. package/src/cli/web-search-cli.ts +1 -1
  10. package/src/cli.ts +0 -1
  11. package/src/commands/config.ts +1 -1
  12. package/src/commands/grep.ts +1 -1
  13. package/src/commands/jupyter.ts +1 -1
  14. package/src/commands/plugin.ts +1 -1
  15. package/src/commands/setup.ts +1 -1
  16. package/src/commands/shell.ts +1 -1
  17. package/src/commands/ssh.ts +1 -1
  18. package/src/commands/stats.ts +1 -1
  19. package/src/commands/update.ts +1 -1
  20. package/src/config/model-registry.ts +3 -4
  21. package/src/config/model-resolver.ts +36 -9
  22. package/src/config/prompt-templates.ts +1 -9
  23. package/src/config/settings-schema.ts +32 -88
  24. package/src/config/settings.ts +3 -4
  25. package/src/debug/index.ts +1 -1
  26. package/src/debug/log-formatting.ts +1 -1
  27. package/src/debug/log-viewer.ts +2 -2
  28. package/src/discovery/helpers.ts +13 -3
  29. package/src/exa/company.ts +2 -7
  30. package/src/exa/index.ts +1 -35
  31. package/src/exa/linkedin.ts +2 -7
  32. package/src/exa/mcp-client.ts +21 -11
  33. package/src/exa/render.ts +30 -190
  34. package/src/exa/researcher.ts +2 -12
  35. package/src/exa/search.ts +5 -25
  36. package/src/exa/types.ts +3 -3
  37. package/src/exec/bash-executor.ts +2 -1
  38. package/src/exec/non-interactive-env.ts +43 -0
  39. package/src/export/html/index.ts +1 -1
  40. package/src/extensibility/custom-tools/loader.ts +1 -1
  41. package/src/extensibility/custom-tools/types.ts +5 -1
  42. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  43. package/src/extensibility/extensions/runner.ts +1 -1
  44. package/src/extensibility/extensions/types.ts +1 -1
  45. package/src/extensibility/extensions/wrapper.ts +7 -15
  46. package/src/extensibility/hooks/runner.ts +1 -1
  47. package/src/extensibility/hooks/types.ts +1 -1
  48. package/src/extensibility/plugins/doctor.ts +1 -1
  49. package/src/index.ts +13 -13
  50. package/src/lsp/index.ts +77 -24
  51. package/src/lsp/render.ts +34 -583
  52. package/src/lsp/types.ts +3 -3
  53. package/src/lsp/utils.ts +1 -1
  54. package/src/main.ts +1 -1
  55. package/src/mcp/tool-bridge.ts +1 -24
  56. package/src/modes/components/assistant-message.ts +7 -7
  57. package/src/modes/components/bash-execution.ts +48 -113
  58. package/src/modes/components/bordered-loader.ts +1 -1
  59. package/src/modes/components/branch-summary-message.ts +13 -10
  60. package/src/modes/components/compaction-summary-message.ts +14 -13
  61. package/src/modes/components/context-group.ts +106 -0
  62. package/src/modes/components/custom-message.ts +4 -5
  63. package/src/modes/components/diff.ts +2 -2
  64. package/src/modes/components/dynamic-border.ts +1 -1
  65. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  66. package/src/modes/components/extensions/extension-list.ts +1 -1
  67. package/src/modes/components/extensions/inspector-panel.ts +8 -3
  68. package/src/modes/components/footer.ts +2 -2
  69. package/src/modes/components/history-search.ts +1 -1
  70. package/src/modes/components/hook-editor.ts +1 -1
  71. package/src/modes/components/hook-input.ts +1 -1
  72. package/src/modes/components/hook-message.ts +4 -5
  73. package/src/modes/components/hook-selector.ts +1 -1
  74. package/src/modes/components/index.ts +0 -2
  75. package/src/modes/components/keybinding-hints.ts +1 -1
  76. package/src/modes/components/login-dialog.ts +1 -1
  77. package/src/modes/components/mcp-add-wizard.ts +1 -1
  78. package/src/modes/components/model-selector.ts +1 -1
  79. package/src/modes/components/oauth-selector.ts +1 -1
  80. package/src/modes/components/plugin-settings.ts +1 -1
  81. package/src/modes/components/python-execution.ts +49 -92
  82. package/src/modes/components/queue-mode-selector.ts +1 -1
  83. package/src/modes/components/session-selector.ts +1 -1
  84. package/src/modes/components/settings-defs.ts +5 -10
  85. package/src/modes/components/settings-selector.ts +1 -1
  86. package/src/modes/components/show-images-selector.ts +1 -1
  87. package/src/modes/components/skill-message.ts +4 -4
  88. package/src/modes/components/status-line/segments.ts +2 -2
  89. package/src/modes/components/status-line/separators.ts +1 -1
  90. package/src/modes/components/status-line-segment-editor.ts +1 -1
  91. package/src/modes/components/status-line.ts +1 -1
  92. package/src/modes/components/theme-selector.ts +1 -1
  93. package/src/modes/components/thinking-selector.ts +1 -1
  94. package/src/modes/components/todo-display.ts +2 -4
  95. package/src/modes/components/todo-reminder.ts +4 -4
  96. package/src/modes/components/tool-execution.ts +118 -440
  97. package/src/modes/components/tool-image-display.ts +107 -0
  98. package/src/modes/components/tree-selector.ts +2 -2
  99. package/src/modes/components/ttsr-notification.ts +4 -17
  100. package/src/modes/components/user-message-selector.ts +1 -1
  101. package/src/modes/components/user-message.ts +9 -10
  102. package/src/modes/components/welcome.ts +1 -1
  103. package/src/modes/controllers/command-controller.ts +1 -1
  104. package/src/modes/controllers/event-controller.ts +58 -187
  105. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  106. package/src/modes/controllers/input-controller.ts +3 -1
  107. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  108. package/src/modes/controllers/selector-controller.ts +3 -26
  109. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  110. package/src/modes/interactive-mode.ts +3 -7
  111. package/src/modes/print-mode.ts +5 -5
  112. package/src/modes/rpc/rpc-mode.ts +1 -1
  113. package/src/modes/types.ts +1 -2
  114. package/src/modes/utils/ui-helpers.ts +34 -32
  115. package/src/patch/edit-tool.ts +742 -0
  116. package/src/patch/index.ts +32 -898
  117. package/src/patch/schemas.ts +208 -0
  118. package/src/patch/shared.ts +83 -151
  119. package/src/prompts/agents/explore.md +22 -37
  120. package/src/prompts/agents/frontmatter.md +1 -1
  121. package/src/prompts/agents/init.md +2 -2
  122. package/src/prompts/agents/librarian.md +30 -21
  123. package/src/prompts/agents/oracle.md +9 -2
  124. package/src/prompts/agents/reviewer.md +15 -49
  125. package/src/prompts/agents/task.md +17 -9
  126. package/src/prompts/compaction/branch-summary-context.md +1 -1
  127. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  128. package/src/prompts/compaction/branch-summary.md +4 -1
  129. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  130. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  131. package/src/prompts/compaction/compaction-summary.md +4 -1
  132. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  133. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  134. package/src/prompts/memories/consolidation.md +1 -1
  135. package/src/prompts/memories/read_path.md +1 -1
  136. package/src/prompts/memories/stage_one_input.md +1 -1
  137. package/src/prompts/memories/stage_one_system.md +1 -1
  138. package/src/prompts/review-request.md +1 -1
  139. package/src/prompts/system/agent-creation-architect.md +1 -1
  140. package/src/prompts/system/agent-creation-user.md +1 -1
  141. package/src/prompts/system/custom-system-prompt.md +1 -1
  142. package/src/prompts/system/file-operations.md +1 -1
  143. package/src/prompts/system/subagent-system-prompt.md +2 -2
  144. package/src/prompts/system/summarization-system.md +1 -1
  145. package/src/prompts/system/system-prompt.md +163 -178
  146. package/src/prompts/system/title-system.md +1 -1
  147. package/src/prompts/system/ttsr-interrupt.md +1 -1
  148. package/src/prompts/system/verification-reminder.md +6 -0
  149. package/src/prompts/system/web-search.md +1 -1
  150. package/src/sdk.ts +0 -9
  151. package/src/session/agent-session.ts +244 -1459
  152. package/src/session/auth-storage.ts +5 -0
  153. package/src/session/model-controller.ts +406 -0
  154. package/src/session/retry-utils.ts +71 -0
  155. package/src/session/session-manager.ts +22 -186
  156. package/src/session/session-types.ts +312 -0
  157. package/src/session/stats.ts +387 -0
  158. package/src/session/streaming-edit.ts +258 -0
  159. package/src/session/ttsr.ts +213 -0
  160. package/src/slash-commands/builtin-registry.ts +0 -8
  161. package/src/ssh/connection-manager.ts +1 -0
  162. package/src/stt/recorder.ts +2 -2
  163. package/src/system-prompt.ts +1 -14
  164. package/src/task/agents.ts +7 -33
  165. package/src/task/executor.ts +50 -438
  166. package/src/task/index.ts +104 -71
  167. package/src/task/progress-tracker.ts +390 -0
  168. package/src/task/render.ts +371 -187
  169. package/src/task/subprocess-tool-registry.ts +1 -1
  170. package/src/task/types.ts +14 -47
  171. package/src/tools/ask.ts +31 -42
  172. package/src/tools/bash-interactive.ts +4 -47
  173. package/src/tools/bash-interceptor.ts +2 -2
  174. package/src/tools/bash-normalize.ts +1 -1
  175. package/src/tools/bash-skill-urls.ts +2 -2
  176. package/src/tools/bash.ts +87 -136
  177. package/src/tools/browser.ts +54 -84
  178. package/src/tools/create-tools.ts +186 -0
  179. package/src/tools/default-renderer.ts +104 -0
  180. package/src/tools/explore.ts +11 -10
  181. package/src/tools/fetch.ts +24 -114
  182. package/src/tools/find.ts +48 -132
  183. package/src/tools/gemini-image.ts +5 -15
  184. package/src/tools/github.ts +450 -0
  185. package/src/tools/grep.ts +43 -179
  186. package/src/tools/index.ts +35 -198
  187. package/src/tools/json-tree.ts +3 -3
  188. package/src/tools/librarian.ts +18 -18
  189. package/src/tools/list-limit.ts +2 -2
  190. package/src/tools/notebook.ts +35 -87
  191. package/src/tools/oracle.ts +25 -25
  192. package/src/tools/output-meta.ts +89 -4
  193. package/src/tools/output-utils.ts +2 -2
  194. package/src/tools/python.ts +86 -637
  195. package/src/tools/read.ts +36 -119
  196. package/src/tools/reviewer-tool.ts +19 -21
  197. package/src/tools/search-code.ts +128 -0
  198. package/src/tools/ssh.ts +67 -126
  199. package/src/tools/subagent-tool.ts +197 -123
  200. package/src/tools/todo-write.ts +15 -31
  201. package/src/tools/tool-errors.ts +0 -30
  202. package/src/tools/undo-edit.ts +30 -67
  203. package/src/tools/write.ts +78 -127
  204. package/src/tui/code-cell.ts +4 -4
  205. package/src/tui/file-list.ts +2 -2
  206. package/src/tui/output-block.ts +1 -1
  207. package/src/tui/status-line.ts +1 -1
  208. package/src/tui/tree-list.ts +2 -2
  209. package/src/tui/types.ts +1 -1
  210. package/src/tui/utils.ts +1 -1
  211. package/src/{tools → ui}/render-utils.ts +87 -126
  212. package/src/utils/external-editor.ts +4 -4
  213. package/src/utils/file-mentions.ts +1 -1
  214. package/src/utils/index.ts +30 -0
  215. package/src/utils/tools-manager.ts +9 -19
  216. package/src/web/github-client.ts +290 -0
  217. package/src/web/scrapers/github.ts +11 -62
  218. package/src/web/search/auth.ts +1 -3
  219. package/src/web/search/index.ts +85 -49
  220. package/src/web/search/provider.ts +11 -16
  221. package/src/web/search/providers/grep.ts +160 -0
  222. package/src/web/search/render.ts +48 -235
  223. package/src/web/search/types.ts +1 -1
  224. package/src/commands/commit.ts +0 -36
  225. package/src/commit/agentic/agent.ts +0 -311
  226. package/src/commit/agentic/fallback.ts +0 -96
  227. package/src/commit/agentic/index.ts +0 -359
  228. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  229. package/src/commit/agentic/prompts/session-user.md +0 -25
  230. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  231. package/src/commit/agentic/prompts/system.md +0 -38
  232. package/src/commit/agentic/state.ts +0 -69
  233. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  234. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  235. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  236. package/src/commit/agentic/tools/git-overview.ts +0 -84
  237. package/src/commit/agentic/tools/index.ts +0 -56
  238. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  239. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  240. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  241. package/src/commit/agentic/tools/split-commit.ts +0 -280
  242. package/src/commit/agentic/topo-sort.ts +0 -44
  243. package/src/commit/agentic/trivial.ts +0 -51
  244. package/src/commit/agentic/validation.ts +0 -200
  245. package/src/commit/analysis/conventional.ts +0 -165
  246. package/src/commit/analysis/index.ts +0 -4
  247. package/src/commit/analysis/scope.ts +0 -242
  248. package/src/commit/analysis/summary.ts +0 -112
  249. package/src/commit/analysis/validation.ts +0 -66
  250. package/src/commit/changelog/detect.ts +0 -37
  251. package/src/commit/changelog/generate.ts +0 -110
  252. package/src/commit/changelog/index.ts +0 -234
  253. package/src/commit/changelog/parse.ts +0 -44
  254. package/src/commit/cli.ts +0 -93
  255. package/src/commit/git/diff.ts +0 -148
  256. package/src/commit/git/errors.ts +0 -9
  257. package/src/commit/git/index.ts +0 -211
  258. package/src/commit/git/operations.ts +0 -54
  259. package/src/commit/index.ts +0 -5
  260. package/src/commit/map-reduce/index.ts +0 -64
  261. package/src/commit/map-reduce/map-phase.ts +0 -178
  262. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  263. package/src/commit/map-reduce/utils.ts +0 -9
  264. package/src/commit/message.ts +0 -11
  265. package/src/commit/model-selection.ts +0 -69
  266. package/src/commit/pipeline.ts +0 -243
  267. package/src/commit/prompts/analysis-system.md +0 -148
  268. package/src/commit/prompts/analysis-user.md +0 -38
  269. package/src/commit/prompts/changelog-system.md +0 -50
  270. package/src/commit/prompts/changelog-user.md +0 -18
  271. package/src/commit/prompts/file-observer-system.md +0 -24
  272. package/src/commit/prompts/file-observer-user.md +0 -8
  273. package/src/commit/prompts/reduce-system.md +0 -50
  274. package/src/commit/prompts/reduce-user.md +0 -17
  275. package/src/commit/prompts/summary-retry.md +0 -3
  276. package/src/commit/prompts/summary-system.md +0 -38
  277. package/src/commit/prompts/summary-user.md +0 -13
  278. package/src/commit/prompts/types-description.md +0 -2
  279. package/src/commit/types.ts +0 -109
  280. package/src/commit/utils/exclusions.ts +0 -42
  281. package/src/mcp/render.ts +0 -123
  282. package/src/modes/components/agent-dashboard.ts +0 -1130
  283. package/src/modes/components/codemode-group.ts +0 -369
  284. package/src/modes/components/read-tool-group.ts +0 -119
  285. package/src/modes/components/visual-truncate.ts +0 -63
  286. package/src/prompts/system/subagent-user-prompt.md +0 -8
  287. package/src/prompts/tools/ask.md +0 -44
  288. package/src/prompts/tools/bash.md +0 -24
  289. package/src/prompts/tools/browser.md +0 -33
  290. package/src/prompts/tools/calculator.md +0 -12
  291. package/src/prompts/tools/explore.md +0 -29
  292. package/src/prompts/tools/fetch.md +0 -16
  293. package/src/prompts/tools/find.md +0 -18
  294. package/src/prompts/tools/gemini-image.md +0 -23
  295. package/src/prompts/tools/grep.md +0 -28
  296. package/src/prompts/tools/hashline.md +0 -232
  297. package/src/prompts/tools/librarian.md +0 -24
  298. package/src/prompts/tools/lsp.md +0 -28
  299. package/src/prompts/tools/oracle.md +0 -26
  300. package/src/prompts/tools/patch.md +0 -74
  301. package/src/prompts/tools/python.md +0 -66
  302. package/src/prompts/tools/read.md +0 -36
  303. package/src/prompts/tools/replace.md +0 -38
  304. package/src/prompts/tools/reviewer.md +0 -41
  305. package/src/prompts/tools/ssh.md +0 -51
  306. package/src/prompts/tools/task-summary.md +0 -28
  307. package/src/prompts/tools/task.md +0 -146
  308. package/src/prompts/tools/todo-write.md +0 -65
  309. package/src/prompts/tools/undo-edit.md +0 -7
  310. package/src/prompts/tools/web-search.md +0 -19
  311. package/src/prompts/tools/write.md +0 -18
  312. package/src/task/batch.ts +0 -102
  313. package/src/task/discovery.ts +0 -126
  314. package/src/task/parallel.ts +0 -84
  315. package/src/task/template.ts +0 -32
  316. package/src/tools/calculator.ts +0 -537
  317. package/src/tools/jtd-to-typescript.ts +0 -198
  318. package/src/tools/renderers.ts +0 -60
  319. package/src/tools/tool-result.ts +0 -86
  320. /package/src/{modes/theme → theme}/dark.json +0 -0
  321. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  322. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  323. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  324. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  325. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  326. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  327. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  328. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  329. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  330. /package/src/{modes/theme → theme}/light.json +0 -0
  331. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  332. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  333. /package/src/{modes/theme → theme}/theme.ts +0 -0
package/src/lsp/render.ts CHANGED
@@ -1,26 +1,11 @@
1
1
  /**
2
2
  * LSP Tool TUI Rendering
3
- *
4
- * Renders LSP tool calls and results in the TUI with:
5
- * - Syntax-highlighted hover information
6
- * - Color-coded diagnostics by severity
7
- * - Grouped references and symbols
8
- * - Collapsible/expandable views
9
3
  */
10
4
  import type { RenderResultOptions } from "@nghyane/arcane-agent";
11
- import { type HighlightColors, highlightCode as nativeHighlightCode, supportsLanguage } from "@nghyane/arcane-natives";
12
5
  import { type Component, Text } from "@nghyane/arcane-tui";
13
- import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
14
- import {
15
- formatExpandHint,
16
- formatMoreItems,
17
- formatStatusIcon,
18
- shortenPath,
19
- TRUNCATE_LENGTHS,
20
- truncateToWidth,
21
- } from "../tools/render-utils";
6
+ import type { Theme } from "../theme/theme";
22
7
  import { renderStatusLine } from "../tui";
23
- import { CachedOutputBlock } from "../tui/output-block";
8
+ import { formatCount, formatErrorMessage, shortenPath, TRUNCATE_LENGTHS, truncateToWidth } from "../ui/render-utils";
24
9
  import type { LspParams, LspToolDetails } from "./types";
25
10
 
26
11
  // =============================================================================
@@ -97,593 +82,59 @@ export function renderCall(args: LspParams, _options: RenderResultOptions, theme
97
82
  // =============================================================================
98
83
 
99
84
  /**
100
- * Render LSP tool result with intelligent formatting based on result type.
101
- * Detects hover, diagnostics, references, symbols, etc. and formats accordingly.
85
+ * Render LSP tool result as a single dim status line.
102
86
  */
103
87
  export function renderResult(
104
88
  result: { content: Array<{ type: string; text?: string }>; details?: LspToolDetails; isError?: boolean },
105
- options: RenderResultOptions,
89
+ _options: RenderResultOptions,
106
90
  theme: Theme,
107
91
  args?: LspParams & { file?: string; files?: string[] },
108
92
  ): Component {
109
93
  const content = result.content?.[0];
110
- if (!content || content.type !== "text" || !("text" in content) || !content.text) {
111
- const icon = formatStatusIcon("warning", theme, options.spinnerFrame);
112
- const header = `${icon} LSP`;
113
- return new Text([header, theme.fg("dim", "No result")].join("\n"), 0, 0);
94
+ const text = content?.type === "text" ? (content.text ?? "") : "";
95
+
96
+ if (result.isError || text.startsWith("Error:")) {
97
+ const errorText = result.content?.find(c => c.type === "text")?.text || "Unknown error";
98
+ return new Text(formatErrorMessage(errorText, theme), 0, 0);
114
99
  }
115
100
 
116
- const text = content.text;
117
- const lines = text.split("\n");
101
+ const request = args ?? result.details?.request;
102
+ const action = (request?.action ?? result.details?.action ?? "request").replace(/_/g, " ");
103
+ const meta: string[] = [];
118
104
 
119
- // Static type detection (result content doesn't change between renders)
120
- const codeBlockMatch = text.match(/```(\w*)\n([\s\S]*?)```/);
105
+ // Extract counts from result text
121
106
  const errorMatch = text.match(/(\d+)\s+error\(s\)/);
122
107
  const warningMatch = text.match(/(\d+)\s+warning\(s\)/);
123
108
  const refMatch = text.match(/(\d+)\s+reference\(s\)/);
124
- const symbolsMatch = text.match(/Symbols in (.+):/);
125
- const hasStatusError = text.includes(theme.status.error);
109
+ const renameMatch = text.match(/Applied.*?(\d+)\s+file/);
126
110
 
127
- // Static request info
128
- const request = args ?? result.details?.request;
129
- const requestLines: string[] = [];
111
+ let description = "";
130
112
  if (request?.file) {
131
- requestLines.push(theme.fg("toolOutput", request.file));
113
+ description = shortenPath(request.file);
114
+ if (request.line !== undefined) description += `:${request.line}`;
132
115
  } else if (request?.files?.length === 1) {
133
- requestLines.push(theme.fg("toolOutput", request.files[0]));
116
+ description = shortenPath(request.files[0]);
134
117
  } else if (request?.files?.length) {
135
- requestLines.push(theme.fg("dim", `${request.files.length} file(s)`));
136
- }
137
- if (request?.line !== undefined) {
138
- const col = request.column !== undefined ? `:${request.column}` : "";
139
- requestLines.push(theme.fg("dim", `line ${request.line}${col}`));
140
- }
141
- if (request?.end_line !== undefined) {
142
- const endCol = request.end_character !== undefined ? `:${request.end_character}` : "";
143
- requestLines.push(theme.fg("dim", `end ${request.end_line}${endCol}`));
144
- }
145
- if (request?.query) requestLines.push(theme.fg("dim", `query: ${request.query}`));
146
- if (request?.new_name) requestLines.push(theme.fg("dim", `new name: ${request.new_name}`));
147
- if (request?.apply !== undefined) requestLines.push(theme.fg("dim", `apply: ${request.apply ? "true" : "false"}`));
148
- if (request?.include_declaration !== undefined) {
149
- requestLines.push(theme.fg("dim", `include declaration: ${request.include_declaration ? "true" : "false"}`));
150
- }
151
-
152
- const outputBlock = new CachedOutputBlock();
153
-
154
- return {
155
- render(width: number): string[] {
156
- // Read mutable state at render time
157
- const { expanded, isPartial, spinnerFrame } = options;
158
-
159
- // Determine label, state, bodyLines based on type + current expanded
160
- let label = "Result";
161
- let state: "success" | "warning" | "error" = "success";
162
- let bodyLines: string[] = [];
163
-
164
- if (codeBlockMatch) {
165
- label = "Hover";
166
- bodyLines = renderHover(codeBlockMatch, text, lines, expanded, theme);
167
- } else if (errorMatch || warningMatch || hasStatusError) {
168
- label = "Diagnostics";
169
- const errorCount = errorMatch ? Number.parseInt(errorMatch[1], 10) : 0;
170
- const warnCount = warningMatch ? Number.parseInt(warningMatch[1], 10) : 0;
171
- state = errorCount > 0 ? "error" : warnCount > 0 ? "warning" : "success";
172
- bodyLines = renderDiagnostics(errorMatch, warningMatch, lines, expanded, theme);
173
- } else if (refMatch) {
174
- label = "References";
175
- bodyLines = renderReferences(refMatch, lines, expanded, theme);
176
- } else if (symbolsMatch) {
177
- label = "Symbols";
178
- bodyLines = renderSymbols(symbolsMatch, lines, expanded, theme);
179
- } else {
180
- label = "Response";
181
- bodyLines = renderGeneric(text, lines, expanded, theme);
182
- }
183
-
184
- const actionLabel = (request?.action ?? result.details?.action ?? label.toLowerCase()).replace(/_/g, " ");
185
- const status = isPartial ? "running" : result.isError ? "error" : "success";
186
- const icon = formatStatusIcon(status, theme, spinnerFrame);
187
- const header = `${icon} LSP ${actionLabel}`;
188
-
189
- return outputBlock.render(
190
- {
191
- header,
192
- state,
193
- sections: [
194
- ...(requestLines.length > 0 ? [{ lines: requestLines }] : []),
195
- { label: theme.fg("toolTitle", "Response"), lines: bodyLines },
196
- ],
197
- width,
198
- applyBg: false,
199
- },
200
- theme,
201
- );
202
- },
203
- invalidate() {
204
- outputBlock.invalidate();
205
- },
206
- };
207
- }
208
-
209
- // =============================================================================
210
- // Hover Rendering
211
- // =============================================================================
212
-
213
- /**
214
- * Render hover information with syntax-highlighted code blocks.
215
- */
216
- function renderHover(
217
- codeBlockMatch: RegExpMatchArray,
218
- fullText: string,
219
- _lines: string[],
220
- expanded: boolean,
221
- theme: Theme,
222
- ): string[] {
223
- const lang = codeBlockMatch[1] || "";
224
- const code = codeBlockMatch[2].trim();
225
- const codeStart = codeBlockMatch.index ?? 0;
226
- const beforeCode = fullText.slice(0, codeStart).trimEnd();
227
- const afterCode = fullText.slice(fullText.indexOf("```", 3) + 3).trim();
228
-
229
- const codeLines = highlightCode(code, lang, theme);
230
- const icon = theme.styledSymbol("status.info", "accent");
231
- const langLabel = lang ? theme.fg("mdCodeBlockBorder", ` ${lang}`) : "";
232
-
233
- if (expanded) {
234
- const h = theme.boxSharp.horizontal;
235
- const v = theme.boxSharp.vertical;
236
- const top = `${theme.boxSharp.topLeft}${h.repeat(3)}`;
237
- const bottom = `${theme.boxSharp.bottomLeft}${h.repeat(3)}`;
238
- let output = `${icon}${langLabel}`;
239
- if (beforeCode) {
240
- for (const line of beforeCode.split("\n")) {
241
- output += `\n ${theme.fg("muted", line)}`;
242
- }
243
- }
244
- output += `\n ${theme.fg("mdCodeBlockBorder", top)}`;
245
- for (const line of codeLines) {
246
- output += `\n ${theme.fg("mdCodeBlockBorder", v)} ${line}`;
247
- }
248
- output += `\n ${theme.fg("mdCodeBlockBorder", bottom)}`;
249
- if (afterCode) {
250
- output += `\n ${theme.fg("muted", afterCode)}`;
251
- }
252
- return output.split("\n");
253
- }
254
-
255
- // Collapsed view
256
- const firstCodeLine = codeLines[0] || "";
257
- const hasMore = codeLines.length > 1 || Boolean(afterCode) || Boolean(beforeCode);
258
- const expandHint = formatExpandHint(theme, expanded, hasMore);
259
-
260
- let output = `${icon}${langLabel}${expandHint}`;
261
- if (beforeCode) {
262
- const preview = truncateToWidth(beforeCode, TRUNCATE_LENGTHS.TITLE);
263
- output += `\n ${theme.fg("dim", theme.tree.branch)} ${theme.fg("muted", preview)}`;
264
- }
265
- const h = theme.boxSharp.horizontal;
266
- const v = theme.boxSharp.vertical;
267
- const bottom = `${theme.boxSharp.bottomLeft}${h.repeat(3)}`;
268
- output += `\n ${theme.fg("mdCodeBlockBorder", v)} ${firstCodeLine}`;
269
-
270
- if (codeLines.length > 1) {
271
- output += `\n ${theme.fg("mdCodeBlockBorder", v)} ${theme.fg("muted", `… ${codeLines.length - 1} more lines`)}`;
272
- }
273
-
274
- if (afterCode) {
275
- const docPreview = truncateToWidth(afterCode, TRUNCATE_LENGTHS.TITLE);
276
- output += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg("muted", docPreview)}`;
277
- } else {
278
- output += `\n ${theme.fg("mdCodeBlockBorder", bottom)}`;
279
- }
280
-
281
- return output.split("\n");
282
- }
283
-
284
- /**
285
- * Syntax highlight code using native highlighter.
286
- */
287
- function highlightCode(codeText: string, language: string, theme: Theme): string[] {
288
- const validLang = language && supportsLanguage(language) ? language : undefined;
289
- try {
290
- const colors: HighlightColors = {
291
- comment: theme.getFgAnsi("syntaxComment"),
292
- keyword: theme.getFgAnsi("syntaxKeyword"),
293
- function: theme.getFgAnsi("syntaxFunction"),
294
- variable: theme.getFgAnsi("syntaxVariable"),
295
- string: theme.getFgAnsi("syntaxString"),
296
- number: theme.getFgAnsi("syntaxNumber"),
297
- type: theme.getFgAnsi("syntaxType"),
298
- operator: theme.getFgAnsi("syntaxOperator"),
299
- punctuation: theme.getFgAnsi("syntaxPunctuation"),
300
- inserted: theme.getFgAnsi("toolDiffAdded"),
301
- deleted: theme.getFgAnsi("toolDiffRemoved"),
302
- };
303
- return nativeHighlightCode(codeText, validLang, colors).split("\n");
304
- } catch {
305
- return codeText.split("\n");
306
- }
307
- }
308
-
309
- // =============================================================================
310
- // Diagnostics Rendering
311
- // =============================================================================
312
-
313
- function formatDiagnosticLocation(file: string, line: string | number, col: string | number, theme: Theme): string {
314
- const lang = getLanguageFromPath(file);
315
- const icon = theme.fg("muted", theme.getLangIcon(lang));
316
- return `${icon} ${file}:${line}:${col}`;
317
- }
318
-
319
- /**
320
- * Render diagnostics with color-coded severity.
321
- */
322
- function renderDiagnostics(
323
- errorMatch: RegExpMatchArray | null,
324
- warningMatch: RegExpMatchArray | null,
325
- lines: string[],
326
- expanded: boolean,
327
- theme: Theme,
328
- ): string[] {
329
- const errorCount = errorMatch ? Number.parseInt(errorMatch[1], 10) : 0;
330
- const warnCount = warningMatch ? Number.parseInt(warningMatch[1], 10) : 0;
331
-
332
- const icon =
333
- errorCount > 0
334
- ? theme.styledSymbol("status.error", "error")
335
- : warnCount > 0
336
- ? theme.styledSymbol("status.warning", "warning")
337
- : theme.styledSymbol("status.success", "success");
338
-
339
- const meta: string[] = [];
340
- if (errorCount > 0) meta.push(`${errorCount} error${errorCount !== 1 ? "s" : ""}`);
341
- if (warnCount > 0) meta.push(`${warnCount} warning${warnCount !== 1 ? "s" : ""}`);
342
- if (meta.length === 0) meta.push("No issues");
343
-
344
- const diagLines = lines.filter(l => l.includes(theme.status.error) || /:\d+:\d+/.test(l));
345
- const parsedDiagnostics = diagLines
346
- .map(line => parseDiagnosticLine(line))
347
- .filter((diag): diag is ParsedDiagnostic => diag !== null);
348
- const fallbackDiagnostics: RawDiagnostic[] = diagLines.map(line => ({ raw: line.trim() }));
349
-
350
- if (expanded) {
351
- let output = `${icon} ${theme.fg("dim", meta.join(theme.sep.dot))}`;
352
- const items: DiagnosticItem[] = parsedDiagnostics.length > 0 ? parsedDiagnostics : fallbackDiagnostics;
353
- for (let i = 0; i < items.length; i++) {
354
- const item = items[i];
355
- const isLast = i === items.length - 1;
356
- const branch = isLast ? theme.tree.last : theme.tree.branch;
357
- const detailPrefix = isLast ? " " : `${theme.tree.vertical} `;
358
- if ("raw" in item) {
359
- output += `\n ${theme.fg("dim", branch)} ${theme.fg("muted", item.raw)}`;
360
- continue;
361
- }
362
- const severityColor = severityToColor(item.severity);
363
- const location = formatDiagnosticLocation(item.file, item.line, item.col, theme);
364
- output += `\n ${theme.fg("dim", branch)} ${theme.fg(severityColor, location)} ${theme.fg(
365
- "dim",
366
- `[${item.severity}]`,
367
- )}`;
368
- if (item.message) {
369
- output += `\n ${theme.fg("dim", detailPrefix)}${theme.fg(
370
- "muted",
371
- truncateToWidth(item.message, TRUNCATE_LENGTHS.LINE),
372
- )}`;
373
- }
374
- }
375
- return output.split("\n");
376
- }
377
-
378
- // Collapsed view
379
- const previewItems: DiagnosticItem[] =
380
- parsedDiagnostics.length > 0 ? parsedDiagnostics.slice(0, 3) : fallbackDiagnostics.slice(0, 3);
381
- const remaining =
382
- (parsedDiagnostics.length > 0 ? parsedDiagnostics.length : fallbackDiagnostics.length) - previewItems.length;
383
- const expandHint = formatExpandHint(theme, expanded, remaining > 0);
384
- let output = `${icon} ${theme.fg("dim", meta.join(theme.sep.dot))}${expandHint}`;
385
- for (let i = 0; i < previewItems.length; i++) {
386
- const item = previewItems[i];
387
- const isLast = i === previewItems.length - 1 && remaining <= 0;
388
- const branch = isLast ? theme.tree.last : theme.tree.branch;
389
- if ("raw" in item) {
390
- output += `\n ${theme.fg("dim", branch)} ${theme.fg("muted", item.raw)}`;
391
- continue;
392
- }
393
- const severityColor = severityToColor(item.severity);
394
- const location = formatDiagnosticLocation(item.file, item.line, item.col, theme);
395
- const message = item.message
396
- ? ` ${theme.fg("muted", truncateToWidth(item.message, TRUNCATE_LENGTHS.CONTENT))}`
397
- : "";
398
- output += `\n ${theme.fg("dim", branch)} ${theme.fg(severityColor, location)}${message}`;
399
- }
400
- if (remaining > 0) {
401
- output += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg("muted", `… ${remaining} more`)}`;
402
- }
403
-
404
- return output.split("\n");
405
- }
406
-
407
- // =============================================================================
408
- // References Rendering
409
- // =============================================================================
410
-
411
- /**
412
- * Render references grouped by file.
413
- */
414
- function renderReferences(refMatch: RegExpMatchArray, lines: string[], expanded: boolean, theme: Theme): string[] {
415
- const refCount = Number.parseInt(refMatch[1], 10);
416
- const icon =
417
- refCount > 0 ? theme.styledSymbol("status.success", "success") : theme.styledSymbol("status.warning", "warning");
418
-
419
- const locLines = lines.filter(l => /^\s*\S+:\d+:\d+/.test(l));
420
-
421
- // Group by file
422
- const byFile = new Map<string, Array<[string, string]>>();
423
- for (const loc of locLines) {
424
- const match = loc.trim().match(/^(.+):(\d+):(\d+)$/);
425
- if (match) {
426
- const [, file, line, col] = match;
427
- if (!byFile.has(file)) byFile.set(file, []);
428
- byFile.get(file)!.push([line, col]);
429
- }
118
+ description = `${request.files.length} files`;
430
119
  }
431
120
 
432
- const files = Array.from(byFile.keys());
433
-
434
- const renderGrouped = (maxFiles: number, maxLocsPerFile: number, showHint: boolean): string => {
435
- const expandHint = formatExpandHint(theme, undefined, showHint);
436
- let output = `${icon} ${theme.fg("dim", `${refCount} found`)}${expandHint}`;
437
-
438
- const filesToShow = files.slice(0, maxFiles);
439
- for (let fi = 0; fi < filesToShow.length; fi++) {
440
- const file = filesToShow[fi];
441
- const locs = byFile.get(file)!;
442
- const isLastFile = fi === filesToShow.length - 1 && files.length <= maxFiles;
443
- const fileBranch = isLastFile ? theme.tree.last : theme.tree.branch;
444
- const fileCont = isLastFile ? " " : `${theme.tree.vertical} `;
445
-
446
- const fileMeta = `${locs.length} reference${locs.length !== 1 ? "s" : ""}`;
447
- output += `\n ${theme.fg("dim", fileBranch)} ${theme.fg("accent", file)} ${theme.fg("dim", fileMeta)}`;
448
-
449
- if (maxLocsPerFile > 0) {
450
- const locsToShow = locs.slice(0, maxLocsPerFile);
451
- for (let li = 0; li < locsToShow.length; li++) {
452
- const [line, col] = locsToShow[li];
453
- const isLastLoc = li === locsToShow.length - 1 && locs.length <= maxLocsPerFile;
454
- const locBranch = isLastLoc ? theme.tree.last : theme.tree.branch;
455
- const locCont = isLastLoc ? " " : `${theme.tree.vertical} `;
456
- output += `\n ${theme.fg("dim", fileCont)}${theme.fg("dim", locBranch)} ${theme.fg(
457
- "muted",
458
- `line ${line}, col ${col}`,
459
- )}`;
460
- if (expanded) {
461
- const context = `at ${file}:${line}:${col}`;
462
- output += `\n ${theme.fg("dim", fileCont)}${theme.fg("dim", locCont)}${theme.fg(
463
- "muted",
464
- truncateToWidth(context, TRUNCATE_LENGTHS.LINE),
465
- )}`;
466
- }
467
- }
468
- if (locs.length > maxLocsPerFile) {
469
- output += `\n ${theme.fg("dim", fileCont)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
470
- "muted",
471
- `… ${locs.length - maxLocsPerFile} more`,
472
- )}`;
473
- }
474
- }
475
- }
476
-
477
- if (files.length > maxFiles) {
478
- output += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg(
479
- "muted",
480
- formatMoreItems(files.length - maxFiles, "file"),
481
- )}`;
482
- }
483
-
484
- return output;
485
- };
486
-
487
- if (expanded) {
488
- return renderGrouped(files.length, 3, false).split("\n");
121
+ if (errorMatch) meta.push(`${errorMatch[1]} errors`);
122
+ if (warningMatch) meta.push(`${warningMatch[1]} warnings`);
123
+ if (refMatch) {
124
+ meta.push(formatCount("ref", Number.parseInt(refMatch[1], 10)));
125
+ const fileSet = new Set(
126
+ text
127
+ .split("\n")
128
+ .map(l => l.match(/^\s*(\S+):\d+:\d+/)?.[1])
129
+ .filter(Boolean),
130
+ );
131
+ if (fileSet.size > 0) meta.push(formatCount("file", fileSet.size));
489
132
  }
133
+ if (renameMatch) meta.push(`${renameMatch[1]} files`);
134
+ if (request?.new_name && request?.query) meta.push(`${request.query} → ${request.new_name}`);
490
135
 
491
- return renderGrouped(3, 1, true).split("\n");
136
+ return new Text(renderStatusLine({ icon: "success", title: `LSP ${action}`, description, meta }, theme), 0, 0);
492
137
  }
493
138
 
494
139
  // =============================================================================
495
- // Symbols Rendering
496
- // =============================================================================
497
-
498
- /**
499
- * Render document symbols in a hierarchical tree.
500
- */
501
- function renderSymbols(symbolsMatch: RegExpMatchArray, lines: string[], expanded: boolean, theme: Theme): string[] {
502
- const fileName = symbolsMatch[1];
503
- const icon = theme.styledSymbol("status.info", "accent");
504
-
505
- interface SymbolInfo {
506
- name: string;
507
- line: string;
508
- indent: number;
509
- icon: string;
510
- }
511
-
512
- const symbolLines = lines.filter(l => l.includes("@") && l.includes("line"));
513
- const symbols: SymbolInfo[] = [];
514
-
515
- for (const line of symbolLines) {
516
- const indent = line.match(/^(\s*)/)?.[1].length ?? 0;
517
- const symMatch = line.trim().match(/^(\S+)\s+(.+?)\s*@\s*line\s*(\d+)/);
518
- if (symMatch) {
519
- symbols.push({ icon: symMatch[1], name: symMatch[2], line: symMatch[3], indent });
520
- }
521
- }
522
-
523
- const isLastSibling = (i: number): boolean => {
524
- const myIndent = symbols[i].indent;
525
- for (let j = i + 1; j < symbols.length; j++) {
526
- const nextIndent = symbols[j].indent;
527
- if (nextIndent === myIndent) return false;
528
- if (nextIndent < myIndent) return true;
529
- }
530
- return true;
531
- };
532
-
533
- const getPrefix = (i: number): string => {
534
- const myIndent = symbols[i].indent;
535
- if (myIndent === 0) return " ";
536
-
537
- let prefix = " ";
538
- for (let level = 2; level <= myIndent; level += 2) {
539
- let ancestorIdx = -1;
540
- for (let j = i - 1; j >= 0; j--) {
541
- if (symbols[j].indent === level - 2) {
542
- ancestorIdx = j;
543
- break;
544
- }
545
- }
546
- if (ancestorIdx >= 0 && isLastSibling(ancestorIdx)) {
547
- prefix += " ";
548
- } else {
549
- prefix += `${theme.tree.vertical} `;
550
- }
551
- }
552
- return prefix;
553
- };
554
-
555
- const topLevelCount = symbols.filter(s => s.indent === 0).length;
556
-
557
- if (expanded) {
558
- let output = `${icon} ${theme.fg("dim", `in ${fileName}`)}`;
559
-
560
- for (let i = 0; i < symbols.length; i++) {
561
- const sym = symbols[i];
562
- const prefix = getPrefix(i);
563
- const isLast = isLastSibling(i);
564
- const branch = isLast ? theme.tree.last : theme.tree.branch;
565
- const detailPrefix = isLast ? " " : `${theme.tree.vertical} `;
566
- output += `\n${prefix}${theme.fg("dim", branch)} ${theme.fg("accent", sym.icon)} ${theme.fg("accent", sym.name)}`;
567
- output += `\n${prefix}${theme.fg("dim", detailPrefix)}${theme.fg("muted", `line ${sym.line}`)}`;
568
- }
569
- return output.split("\n");
570
- }
571
-
572
- // Collapsed: show first 3 top-level symbols
573
- const topLevel = symbols.filter(s => s.indent === 0).slice(0, 3);
574
- const hasMoreSymbols = symbols.length > topLevel.length;
575
- const expandHint = formatExpandHint(theme, expanded, hasMoreSymbols);
576
- let output = `${icon} ${theme.fg("dim", `in ${fileName}`)}${expandHint}`;
577
- for (let i = 0; i < topLevel.length; i++) {
578
- const sym = topLevel[i];
579
- const isLast = i === topLevel.length - 1 && topLevelCount <= 3;
580
- const branch = isLast ? theme.tree.last : theme.tree.branch;
581
- output += `\n ${theme.fg("dim", branch)} ${theme.fg("accent", sym.icon)} ${theme.fg("accent", sym.name)} ${theme.fg(
582
- "muted",
583
- `line ${sym.line}`,
584
- )}`;
585
- }
586
- if (topLevelCount > 3) {
587
- output += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg("muted", `… ${topLevelCount - 3} more`)}`;
588
- }
589
-
590
- return output.split("\n");
591
- }
592
-
593
- // =============================================================================
594
- // Generic Rendering
595
- // =============================================================================
596
-
597
- /**
598
- * Generic fallback rendering for unknown result types.
599
- */
600
- function renderGeneric(text: string, lines: string[], expanded: boolean, theme: Theme): string[] {
601
- const hasError = text.includes("Error:") || text.includes(theme.status.error);
602
- const hasSuccess = text.includes(theme.status.success) || text.includes("Applied");
603
-
604
- const icon =
605
- hasError && !hasSuccess
606
- ? theme.styledSymbol("status.error", "error")
607
- : hasSuccess && !hasError
608
- ? theme.styledSymbol("status.success", "success")
609
- : theme.styledSymbol("status.info", "accent");
610
-
611
- if (expanded) {
612
- let output = `${icon} ${theme.fg("dim", "Output")}`;
613
- for (let i = 0; i < lines.length; i++) {
614
- const isLast = i === lines.length - 1;
615
- const branch = isLast ? theme.tree.last : theme.tree.branch;
616
- output += `\n ${theme.fg("dim", branch)} ${lines[i]}`;
617
- }
618
- return output.split("\n");
619
- }
620
-
621
- const firstLine = lines[0] || "No output";
622
- const expandHint = formatExpandHint(theme, expanded, lines.length > 1);
623
- let output = `${icon} ${theme.fg("dim", truncateToWidth(firstLine, TRUNCATE_LENGTHS.TITLE))}${expandHint}`;
624
-
625
- if (lines.length > 1) {
626
- const previewLines = lines.slice(1, 4);
627
- for (let i = 0; i < previewLines.length; i++) {
628
- const isLast = i === previewLines.length - 1 && lines.length <= 4;
629
- const branch = isLast ? theme.tree.last : theme.tree.branch;
630
- output += `\n ${theme.fg("dim", branch)} ${theme.fg(
631
- "dim",
632
- truncateToWidth(previewLines[i].trim(), TRUNCATE_LENGTHS.CONTENT),
633
- )}`;
634
- }
635
- if (lines.length > 4) {
636
- output += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg(
637
- "muted",
638
- formatMoreItems(lines.length - 4, "line"),
639
- )}`;
640
- }
641
- }
642
-
643
- return output.split("\n");
644
- }
645
-
646
- // =============================================================================
647
- // Parsing Helpers
648
- // =============================================================================
649
-
650
- interface ParsedDiagnostic {
651
- file: string;
652
- line: string;
653
- col: string;
654
- severity: string;
655
- message: string;
656
- }
657
-
658
- interface RawDiagnostic {
659
- raw: string;
660
- }
661
-
662
- type DiagnosticItem = ParsedDiagnostic | RawDiagnostic;
663
-
664
- function parseDiagnosticLine(line: string): ParsedDiagnostic | null {
665
- const match = line.trim().match(/^(.*):(\d+):(\d+)\s+\[(\w+)\]\s*(.*)$/);
666
- if (!match) return null;
667
- const [, file, lineNum, colNum, severity, message] = match;
668
- return { file, line: lineNum, col: colNum, severity: severity.toLowerCase(), message };
669
- }
670
-
671
- function severityToColor(severity: string): "error" | "warning" | "accent" | "dim" {
672
- switch (severity) {
673
- case "error":
674
- return "error";
675
- case "warning":
676
- return "warning";
677
- case "info":
678
- return "accent";
679
- default:
680
- return "dim";
681
- }
682
- }
683
-
684
- export const lspToolRenderer = {
685
- renderCall,
686
- renderResult,
687
- mergeCallAndResult: true,
688
- inline: true,
689
- };
140
+ // Hover Rendering
package/src/lsp/types.ts CHANGED
@@ -10,14 +10,14 @@ export const lspSchema = Type.Object({
10
10
  action: StringEnum(["diagnostics", "definition", "references", "hover", "symbols", "rename", "status", "reload"], {
11
11
  description: "LSP operation",
12
12
  }),
13
- files: Type.Optional(Type.Array(Type.String({ description: "File path" }))),
14
- file: Type.Optional(Type.String({ description: "File path" })),
13
+ files: Type.Optional(Type.Array(Type.String(), { description: "File paths for diagnostics" })),
14
+ file: Type.Optional(Type.String({ description: "File path for symbol operations" })),
15
15
  line: Type.Optional(Type.Number({ description: "Line number (1-indexed)" })),
16
16
  column: Type.Optional(Type.Number({ description: "Column number (1-indexed)" })),
17
17
  end_line: Type.Optional(Type.Number({ description: "End line for range (1-indexed)" })),
18
18
  end_character: Type.Optional(Type.Number({ description: "End column for range (1-indexed)" })),
19
19
  query: Type.Optional(Type.String({ description: "Search query or SSR pattern" })),
20
- new_name: Type.Optional(Type.String({ description: "New name for rename" })),
20
+ new_name: Type.Optional(Type.String({ description: "New name for rename operation" })),
21
21
  apply: Type.Optional(Type.Boolean({ description: "Apply edits (default: true)" })),
22
22
  include_declaration: Type.Optional(Type.Boolean({ description: "Include declaration in refs (default: true)" })),
23
23
  });
package/src/lsp/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- import { type Theme, theme } from "../modes/theme/theme";
2
+ import { type Theme, theme } from "../theme/theme";
3
3
  import type {
4
4
  Diagnostic,
5
5
  DiagnosticSeverity,