@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
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import * as os from "node:os";
7
7
  import { type Component, truncateToWidth, wrapTextWithAnsi } from "@nghyane/arcane-tui";
8
- import { theme } from "../../../modes/theme/theme";
8
+ import { theme } from "../../../theme/theme";
9
9
  import type { Extension, ExtensionState } from "./types";
10
10
 
11
11
  export class InspectorPanel implements Component {
@@ -34,12 +34,17 @@ export class InspectorPanel implements Component {
34
34
  lines.push("");
35
35
 
36
36
  // Description (wrapped)
37
- if (ext.description) {
38
- const wrapped = wrapTextWithAnsi(ext.description, width - 2);
37
+ const desc = ext.description;
38
+ const isValidDescription = typeof desc === "string" && desc.length > 0;
39
+ if (isValidDescription && width > 2) {
40
+ const wrapped = wrapTextWithAnsi(desc, width - 2);
39
41
  for (const line of wrapped) {
40
42
  lines.push(truncateToWidth(line, width));
41
43
  }
42
44
  lines.push("");
45
+ } else if (isValidDescription) {
46
+ lines.push(truncateToWidth(desc, width));
47
+ lines.push("");
43
48
  }
44
49
 
45
50
  // Origin
@@ -3,9 +3,9 @@ import * as path from "node:path";
3
3
  import { type Component, padding, truncateToWidth, visibleWidth } from "@nghyane/arcane-tui";
4
4
  import { isEnoent } from "@nghyane/arcane-utils";
5
5
  import { getProjectDir } from "@nghyane/arcane-utils/dirs";
6
- import { theme } from "../../modes/theme/theme";
7
6
  import type { AgentSession } from "../../session/agent-session";
8
- import { shortenPath } from "../../tools/render-utils";
7
+ import { theme } from "../../theme/theme";
8
+ import { shortenPath } from "../../ui/render-utils";
9
9
 
10
10
  /**
11
11
  * Sanitize text for display in a single-line status.
@@ -10,8 +10,8 @@ import {
10
10
  truncateToWidth,
11
11
  visibleWidth,
12
12
  } from "@nghyane/arcane-tui";
13
- import { theme } from "../../modes/theme/theme";
14
13
  import type { HistoryEntry, HistoryStorage } from "../../session/history-storage";
14
+ import { theme } from "../../theme/theme";
15
15
  import { DynamicBorder } from "./dynamic-border";
16
16
 
17
17
  class HistoryResultsList implements Component {
@@ -3,7 +3,7 @@
3
3
  * Supports Ctrl+G for external editor.
4
4
  */
5
5
  import { Container, Editor, matchesKey, Spacer, Text, type TUI } from "@nghyane/arcane-tui";
6
- import { getEditorTheme, theme } from "../../modes/theme/theme";
6
+ import { getEditorTheme, theme } from "../../theme/theme";
7
7
  import { getEditorCommand, openInEditor } from "../../utils/external-editor";
8
8
  import { DynamicBorder } from "./dynamic-border";
9
9
 
@@ -2,7 +2,7 @@
2
2
  * Simple text input component for hooks.
3
3
  */
4
4
  import { Container, Input, matchesKey, Spacer, Text, type TUI } from "@nghyane/arcane-tui";
5
- import { theme } from "../../modes/theme/theme";
5
+ import { theme } from "../../theme/theme";
6
6
  import { CountdownTimer } from "./countdown-timer";
7
7
  import { DynamicBorder } from "./dynamic-border";
8
8
 
@@ -1,16 +1,16 @@
1
1
  import type { TextContent } from "@nghyane/arcane-ai";
2
2
  import type { Component } from "@nghyane/arcane-tui";
3
- import { Box, Container, Markdown, Spacer, Text } from "@nghyane/arcane-tui";
3
+ import { Container, LeftBorderBox, Markdown, Spacer, Text } from "@nghyane/arcane-tui";
4
4
  import type { HookMessageRenderer } from "../../extensibility/hooks/types";
5
- import { getMarkdownTheme, theme } from "../../modes/theme/theme";
6
5
  import type { HookMessage } from "../../session/messages";
6
+ import { getMarkdownTheme, theme } from "../../theme/theme";
7
7
 
8
8
  /**
9
9
  * Component that renders a custom message entry from hooks.
10
10
  * Uses distinct styling to differentiate from user messages.
11
11
  */
12
12
  export class HookMessageComponent extends Container {
13
- #box: Box;
13
+ #box: LeftBorderBox;
14
14
  #customComponent?: Component;
15
15
  #expanded = false;
16
16
 
@@ -22,8 +22,7 @@ export class HookMessageComponent extends Container {
22
22
 
23
23
  this.addChild(new Spacer(1));
24
24
 
25
- // Create box with purple background (used for default rendering)
26
- this.#box = new Box(1, 1, t => theme.bg("customMessageBg", t));
25
+ this.#box = new LeftBorderBox(1, 1, s => theme.fg("dim", s));
27
26
 
28
27
  this.#rebuild();
29
28
  }
@@ -3,7 +3,7 @@
3
3
  * Displays a list of string options with keyboard navigation.
4
4
  */
5
5
  import { Container, matchesKey, padding, Spacer, Text, type TUI, visibleWidth } from "@nghyane/arcane-tui";
6
- import { theme } from "../../modes/theme/theme";
6
+ import { theme } from "../../theme/theme";
7
7
  import { CountdownTimer } from "./countdown-timer";
8
8
  import { DynamicBorder } from "./dynamic-border";
9
9
 
@@ -19,7 +19,6 @@ export { LoginDialogComponent } from "./login-dialog";
19
19
  export { ModelSelectorComponent } from "./model-selector";
20
20
  export { OAuthSelectorComponent } from "./oauth-selector";
21
21
  export { QueueModeSelectorComponent } from "./queue-mode-selector";
22
- export { ReadToolGroupComponent } from "./read-tool-group";
23
22
  export { SessionSelectorComponent } from "./session-selector";
24
23
  export {
25
24
  type SettingsCallbacks,
@@ -37,5 +36,4 @@ export { TreeSelectorComponent } from "./tree-selector";
37
36
  export { TtsrNotificationComponent } from "./ttsr-notification";
38
37
  export { UserMessageComponent } from "./user-message";
39
38
  export { UserMessageSelectorComponent } from "./user-message-selector";
40
- export { truncateToVisualLines, type VisualTruncateResult } from "./visual-truncate";
41
39
  export { type LspServerInfo, type RecentSession, WelcomeComponent } from "./welcome";
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { type EditorAction, getEditorKeybindings, type KeyId } from "@nghyane/arcane-tui";
5
5
  import type { AppAction, KeybindingsManager } from "../../config/keybindings";
6
- import { theme } from "../../modes/theme/theme";
6
+ import { theme } from "../../theme/theme";
7
7
 
8
8
  /**
9
9
  * Format keys array as display string (e.g., ["ctrl+c", "escape"] -> "ctrl+c/escape").
@@ -1,6 +1,6 @@
1
1
  import { getOAuthProviders } from "@nghyane/arcane-ai";
2
2
  import { Container, getEditorKeybindings, Input, Spacer, Text, type TUI } from "@nghyane/arcane-tui";
3
- import { theme } from "../../modes/theme/theme";
3
+ import { theme } from "../../theme/theme";
4
4
  import { openPath } from "../../utils/open";
5
5
  import { DynamicBorder } from "./dynamic-border";
6
6
 
@@ -16,7 +16,7 @@ import {
16
16
  import { validateServerName } from "../../mcp/config-writer";
17
17
  import { analyzeAuthError, discoverOAuthEndpoints } from "../../mcp/oauth-discovery";
18
18
  import type { MCPHttpServerConfig, MCPServerConfig, MCPSseServerConfig, MCPStdioServerConfig } from "../../mcp/types";
19
- import { theme } from "../theme/theme";
19
+ import { theme } from "../../theme/theme";
20
20
  import { DynamicBorder } from "./dynamic-border";
21
21
 
22
22
  type TransportType = "stdio" | "http" | "sse";
@@ -14,7 +14,7 @@ import {
14
14
  import { MODEL_ROLE_IDS, MODEL_ROLES, type ModelRegistry, type ModelRole } from "../../config/model-registry";
15
15
  import { parseModelString } from "../../config/model-resolver";
16
16
  import type { Settings } from "../../config/settings";
17
- import { type ThemeColor, theme } from "../../modes/theme/theme";
17
+ import { type ThemeColor, theme } from "../../theme/theme";
18
18
  import { fuzzyFilter } from "../../utils/fuzzy";
19
19
  import { DynamicBorder } from "./dynamic-border";
20
20
 
@@ -1,7 +1,7 @@
1
1
  import { getOAuthProviders, type OAuthProviderInfo } from "@nghyane/arcane-ai";
2
2
  import { Container, matchesKey, Spacer, TruncatedText } from "@nghyane/arcane-tui";
3
- import { theme } from "../../modes/theme/theme";
4
3
  import type { AuthStorage } from "../../session/auth-storage";
4
+ import { theme } from "../../theme/theme";
5
5
  import { DynamicBorder } from "./dynamic-border";
6
6
  /**
7
7
  * Component that renders an OAuth provider selector.
@@ -19,7 +19,7 @@ import {
19
19
  } from "@nghyane/arcane-tui";
20
20
  import { PluginManager } from "../../extensibility/plugins/manager";
21
21
  import type { InstalledPlugin, PluginSettingSchema } from "../../extensibility/plugins/types";
22
- import { getSelectListTheme, getSettingsListTheme, theme } from "../../modes/theme/theme";
22
+ import { getSelectListTheme, getSettingsListTheme, theme } from "../../theme/theme";
23
23
  import { DynamicBorder } from "./dynamic-border";
24
24
 
25
25
  // =============================================================================
@@ -1,17 +1,16 @@
1
1
  /**
2
2
  * Component for displaying user-initiated Python execution with streaming output.
3
- * Shares the same kernel session as the agent's Python tool.
3
+ * Tree-style output: tail 4 lines on success, all on error.
4
4
  */
5
5
 
6
6
  import { sanitizeText } from "@nghyane/arcane-natives";
7
7
  import { Container, Loader, Spacer, Text, type TUI } from "@nghyane/arcane-tui";
8
- import { getSymbolTheme, highlightCode, theme } from "../../modes/theme/theme";
9
- import { formatBytes } from "../../session/streaming-output";
8
+ import { getSymbolTheme, theme } from "../../theme/theme";
10
9
  import type { TruncationMeta } from "../../tools/output-meta";
11
- import { DynamicBorder } from "./dynamic-border";
12
- import { truncateToVisualLines } from "./visual-truncate";
10
+ import { renderStatusLine } from "../../tui/status-line";
11
+ import { formatCount, replaceTabs } from "../../ui/render-utils";
13
12
 
14
- const PREVIEW_LINES = 20;
13
+ const TAIL_LINES = 4;
15
14
  const MAX_DISPLAY_LINE_CHARS = 4000;
16
15
 
17
16
  export class PythonExecutionComponent extends Container {
@@ -21,45 +20,36 @@ export class PythonExecutionComponent extends Container {
21
20
  #loader: Loader;
22
21
  #truncation?: TruncationMeta;
23
22
  #expanded = false;
24
- #contentContainer: Container;
25
-
26
- #formatHeader(colorKey: "dim" | "pythonMode"): Text {
27
- const prompt = theme.fg(colorKey, theme.bold(">>>"));
28
- const continuation = theme.fg(colorKey, " ");
29
- const codeLines = highlightCode(this.code, "python");
30
- const headerLines = codeLines.map((line, index) =>
31
- index === 0 ? `${prompt} ${line}` : `${continuation}${line}`,
32
- );
33
- return new Text(headerLines.join("\n"), 1, 0);
34
- }
23
+ #headerText: Text;
24
+ #bodyText: Text;
35
25
 
36
26
  constructor(
37
27
  private readonly code: string,
38
28
  ui: TUI,
39
- private readonly excludeFromContext = false,
29
+ _excludeFromContext = false,
40
30
  ) {
41
31
  super();
42
-
43
- const colorKey = this.excludeFromContext ? "dim" : "pythonMode";
44
- const borderColor = (str: string) => theme.fg(colorKey, str);
45
-
46
32
  this.addChild(new Spacer(1));
47
- this.addChild(new DynamicBorder(borderColor));
48
33
 
49
- this.#contentContainer = new Container();
50
- this.addChild(this.#contentContainer);
51
- this.#contentContainer.addChild(this.#formatHeader(colorKey));
34
+ const codePreview = code.split("\n")[0].slice(0, 60);
35
+ this.#headerText = new Text(
36
+ renderStatusLine({ icon: "running", title: "Python", description: `>>> ${codePreview}` }, theme),
37
+ 1,
38
+ 0,
39
+ );
40
+ this.addChild(this.#headerText);
41
+
42
+ this.#bodyText = new Text("", 1, 0);
43
+ this.addChild(this.#bodyText);
52
44
 
53
45
  this.#loader = new Loader(
54
46
  ui,
55
- spinner => theme.fg(colorKey, spinner),
47
+ spinner => theme.fg("accent", spinner),
56
48
  text => theme.fg("muted", text),
57
- `Running (esc to cancel)`,
49
+ "Running\u2026 (esc to cancel)",
58
50
  getSymbolTheme().spinnerFrames,
59
51
  );
60
- this.#contentContainer.addChild(this.#loader);
61
-
62
- this.addChild(new DynamicBorder(borderColor));
52
+ this.addChild(this.#loader);
63
53
  }
64
54
 
65
55
  setExpanded(expanded: boolean): void {
@@ -74,7 +64,6 @@ export class PythonExecutionComponent extends Container {
74
64
 
75
65
  appendOutput(chunk: string): void {
76
66
  const clean = sanitizeText(chunk);
77
-
78
67
  const newLines = clean.split("\n").map(line => this.#clampDisplayLine(line));
79
68
  if (this.#outputLines.length > 0 && newLines.length > 0) {
80
69
  this.#outputLines[this.#outputLines.length - 1] = this.#clampDisplayLine(
@@ -84,7 +73,6 @@ export class PythonExecutionComponent extends Container {
84
73
  } else {
85
74
  this.#outputLines.push(...newLines);
86
75
  }
87
-
88
76
  this.#updateDisplay();
89
77
  }
90
78
 
@@ -103,82 +91,51 @@ export class PythonExecutionComponent extends Container {
103
91
  if (options?.output !== undefined) {
104
92
  this.#setOutput(options.output);
105
93
  }
106
-
107
94
  this.#loader.stop();
108
95
  this.#updateDisplay();
109
96
  }
110
97
 
111
98
  #updateDisplay(): void {
112
- const availableLines = this.#outputLines;
113
- const previewLogicalLines = availableLines.slice(-PREVIEW_LINES);
114
- const hiddenLineCount = availableLines.length - previewLogicalLines.length;
115
-
116
- this.#contentContainer.clear();
117
-
118
- const colorKey = this.excludeFromContext ? "dim" : "pythonMode";
119
- this.#contentContainer.addChild(this.#formatHeader(colorKey));
120
-
121
- if (availableLines.length > 0) {
122
- if (this.#expanded) {
123
- const displayText = availableLines.map(line => theme.fg("muted", line)).join("\n");
124
- this.#contentContainer.addChild(new Text(`\n${displayText}`, 1, 0));
125
- } else {
126
- const styledOutput = previewLogicalLines.map(line => theme.fg("muted", line)).join("\n");
127
- const previewText = `\n${styledOutput}`;
128
- this.#contentContainer.addChild({
129
- render: (width: number) => {
130
- const { visualLines } = truncateToVisualLines(previewText, PREVIEW_LINES, width, 1);
131
- return visualLines;
132
- },
133
- invalidate: () => {},
134
- });
135
- }
99
+ const isError = this.#status === "error";
100
+ const isDone = this.#status !== "running";
101
+ const lines = this.#outputLines.filter(l => l.trim());
102
+ const total = lines.length;
103
+
104
+ if (isDone) {
105
+ const icon = isError ? "error" : this.#status === "cancelled" ? "warning" : "success";
106
+ const codePreview = this.code.split("\n")[0].slice(0, 60);
107
+ const meta: string[] = [];
108
+ if (isError && this.#exitCode !== undefined) meta.push(`exit ${this.#exitCode}`);
109
+ if (total > 0) meta.push(formatCount("line", total));
110
+ this.#headerText.setText(
111
+ renderStatusLine({ icon, title: "Python", description: `>>> ${codePreview}`, meta }, theme),
112
+ );
136
113
  }
137
114
 
138
- if (this.#status === "running") {
139
- this.#contentContainer.addChild(this.#loader);
140
- } else {
141
- const statusParts: string[] = [];
115
+ const bodyLines: string[] = [];
116
+ if (total > 0) {
117
+ const showAll = isError || this.#expanded;
118
+ const displayLines = showAll ? lines : lines.slice(-TAIL_LINES);
119
+ const skipped = total - displayLines.length;
142
120
 
143
- if (hiddenLineCount > 0) {
144
- statusParts.push(theme.fg("dim", `… ${hiddenLineCount} more lines (ctrl+o to expand)`));
121
+ if (skipped > 0) {
122
+ bodyLines.push(theme.fg("dim", `\u2026 (${skipped} earlier lines)`));
145
123
  }
146
-
147
- if (this.#status === "cancelled") {
148
- statusParts.push(theme.fg("warning", "(cancelled)"));
149
- } else if (this.#status === "error") {
150
- statusParts.push(theme.fg("error", `(exit ${this.#exitCode})`));
124
+ for (let i = 0; i < displayLines.length; i++) {
125
+ bodyLines.push(theme.fg("toolOutput", replaceTabs(displayLines[i])));
151
126
  }
152
-
153
127
  if (this.#truncation) {
154
- const warnings: string[] = [];
155
- if (this.#truncation.artifactId) {
156
- warnings.push(`Full output: artifact://${this.#truncation.artifactId}`);
157
- }
158
- if (this.#truncation.truncatedBy === "lines") {
159
- warnings.push(
160
- `Truncated: showing ${this.#truncation.outputLines} of ${this.#truncation.totalLines} lines`,
161
- );
162
- } else {
163
- warnings.push(
164
- `Truncated: ${this.#truncation.outputLines} lines shown (${formatBytes(this.#truncation.outputBytes)} limit)`,
165
- );
166
- }
167
- statusParts.push(theme.fg("warning", warnings.join(". ")));
168
- }
169
-
170
- if (statusParts.length > 0) {
171
- this.#contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`, 1, 0));
128
+ bodyLines.push(theme.fg("warning", "output truncated"));
172
129
  }
173
130
  }
131
+
132
+ this.#bodyText.setText(bodyLines.length > 0 ? bodyLines.join("\n") : "");
174
133
  }
175
134
 
176
135
  #clampDisplayLine(line: string): string {
177
- if (line.length <= MAX_DISPLAY_LINE_CHARS) {
178
- return line;
179
- }
136
+ if (line.length <= MAX_DISPLAY_LINE_CHARS) return line;
180
137
  const omitted = line.length - MAX_DISPLAY_LINE_CHARS;
181
- return `${line.slice(0, MAX_DISPLAY_LINE_CHARS)} [${omitted} chars omitted]`;
138
+ return `${line.slice(0, MAX_DISPLAY_LINE_CHARS)}\u2026 [${omitted} chars omitted]`;
182
139
  }
183
140
 
184
141
  #setOutput(output: string): void {
@@ -1,5 +1,5 @@
1
1
  import { Container, type SelectItem, SelectList } from "@nghyane/arcane-tui";
2
- import { getSelectListTheme } from "../../modes/theme/theme";
2
+ import { getSelectListTheme } from "../../theme/theme";
3
3
  import { DynamicBorder } from "./dynamic-border";
4
4
 
5
5
  /**
@@ -9,8 +9,8 @@ import {
9
9
  truncateToWidth,
10
10
  visibleWidth,
11
11
  } from "@nghyane/arcane-tui";
12
- import { theme } from "../../modes/theme/theme";
13
12
  import type { SessionInfo } from "../../session/session-manager";
13
+ import { theme } from "../../theme/theme";
14
14
  import { fuzzyFilter } from "../../utils/fuzzy";
15
15
  import { DynamicBorder } from "./dynamic-border";
16
16
 
@@ -74,16 +74,11 @@ const OPTION_PROVIDERS: Partial<Record<SettingPath, OptionProvider>> = {
74
74
  { value: "5", label: "5 retries" },
75
75
  { value: "10", label: "10 retries" },
76
76
  ],
77
- // Task max concurrency
78
- "task.maxConcurrency": [
79
- { value: "0", label: "Unlimited" },
80
- { value: "1", label: "1 task" },
81
- { value: "2", label: "2 tasks" },
82
- { value: "4", label: "4 tasks" },
83
- { value: "8", label: "8 tasks" },
84
- { value: "16", label: "16 tasks" },
85
- { value: "32", label: "32 tasks" },
86
- { value: "64", label: "64 tasks" },
77
+ // Verification max reminders
78
+ "verification.maxReminders": [
79
+ { value: "1", label: "1 reminder" },
80
+ { value: "2", label: "2 reminders" },
81
+ { value: "3", label: "3 reminders" },
87
82
  ],
88
83
  // Todo max reminders
89
84
  "todo.reminders.max": [
@@ -20,7 +20,7 @@ import type {
20
20
  StatusLineSeparatorStyle,
21
21
  } from "../../config/settings-schema";
22
22
  import { SETTING_TABS, TAB_METADATA } from "../../config/settings-schema";
23
- import { getCurrentThemeName, getSelectListTheme, getSettingsListTheme, theme } from "../../modes/theme/theme";
23
+ import { getCurrentThemeName, getSelectListTheme, getSettingsListTheme, theme } from "../../theme/theme";
24
24
  import { DynamicBorder } from "./dynamic-border";
25
25
  import { PluginSettingsComponent } from "./plugin-settings";
26
26
  import { getSettingsForTab, type SettingDef } from "./settings-defs";
@@ -1,5 +1,5 @@
1
1
  import { Container, type SelectItem, SelectList } from "@nghyane/arcane-tui";
2
- import { getSelectListTheme } from "../../modes/theme/theme";
2
+ import { getSelectListTheme } from "../../theme/theme";
3
3
  import { DynamicBorder } from "./dynamic-border";
4
4
 
5
5
  /**
@@ -1,11 +1,11 @@
1
1
  import type { TextContent } from "@nghyane/arcane-ai";
2
2
  import type { Component } from "@nghyane/arcane-tui";
3
- import { Box, Container, Markdown, Spacer, Text } from "@nghyane/arcane-tui";
4
- import { getMarkdownTheme, theme } from "../../modes/theme/theme";
3
+ import { Container, LeftBorderBox, Markdown, Spacer, Text } from "@nghyane/arcane-tui";
5
4
  import type { CustomMessage, SkillPromptDetails } from "../../session/messages";
5
+ import { getMarkdownTheme, theme } from "../../theme/theme";
6
6
 
7
7
  export class SkillMessageComponent extends Container {
8
- #box: Box;
8
+ #box: LeftBorderBox;
9
9
  #contentComponent?: Component;
10
10
  #expanded = false;
11
11
 
@@ -13,7 +13,7 @@ export class SkillMessageComponent extends Container {
13
13
  super();
14
14
  this.addChild(new Spacer(1));
15
15
 
16
- this.#box = new Box(1, 1, t => theme.bg("customMessageBg", t));
16
+ this.#box = new LeftBorderBox(1, 1, s => theme.fg("dim", s));
17
17
  this.#rebuild();
18
18
  }
19
19
 
@@ -1,7 +1,7 @@
1
1
  import * as os from "node:os";
2
2
  import { getProjectDir } from "@nghyane/arcane-utils/dirs";
3
- import { theme } from "../../../modes/theme/theme";
4
- import { shortenPath } from "../../../tools/render-utils";
3
+ import { theme } from "../../../theme/theme";
4
+ import { shortenPath } from "../../../ui/render-utils";
5
5
  import type { RenderedSegment, SegmentContext, StatusLineSegment, StatusLineSegmentId } from "./types";
6
6
 
7
7
  export type { SegmentContext } from "./types";
@@ -1,4 +1,4 @@
1
- import type { Theme } from "../../../modes/theme/theme";
1
+ import type { Theme } from "../../../theme/theme";
2
2
  import type { SeparatorDef, StatusLineSeparatorStyle } from "./types";
3
3
 
4
4
  function trimSep(value: string): string {
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { Container, matchesKey, padding } from "@nghyane/arcane-tui";
12
12
  import type { StatusLineSegmentId } from "../../config/settings-schema";
13
- import { theme } from "../../modes/theme/theme";
13
+ import { theme } from "../../theme/theme";
14
14
  import { ALL_SEGMENT_IDS } from "./status-line/segments";
15
15
 
16
16
  // Segment display names and short descriptions
@@ -6,8 +6,8 @@ import { getProjectDir } from "@nghyane/arcane-utils/dirs";
6
6
  import { $ } from "bun";
7
7
  import { settings } from "../../config/settings";
8
8
  import type { StatusLinePreset, StatusLineSegmentId, StatusLineSeparatorStyle } from "../../config/settings-schema";
9
- import { theme } from "../../modes/theme/theme";
10
9
  import type { AgentSession } from "../../session/agent-session";
10
+ import { theme } from "../../theme/theme";
11
11
  import { getPreset } from "./status-line/presets";
12
12
  import { renderSegment, type SegmentContext } from "./status-line/segments";
13
13
  import { getSeparator } from "./status-line/separators";
@@ -1,5 +1,5 @@
1
1
  import { Container, type SelectItem, SelectList } from "@nghyane/arcane-tui";
2
- import { getSelectListTheme } from "../../modes/theme/theme";
2
+ import { getSelectListTheme } from "../../theme/theme";
3
3
  import { DynamicBorder } from "./dynamic-border";
4
4
 
5
5
  /**
@@ -1,6 +1,6 @@
1
1
  import type { ThinkingLevel } from "@nghyane/arcane-agent";
2
2
  import { Container, type SelectItem, SelectList } from "@nghyane/arcane-tui";
3
- import { getSelectListTheme } from "../../modes/theme/theme";
3
+ import { getSelectListTheme } from "../../theme/theme";
4
4
  import { DynamicBorder } from "./dynamic-border";
5
5
 
6
6
  const LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {
@@ -1,8 +1,8 @@
1
1
  import * as path from "node:path";
2
2
  import { Ellipsis, Text, truncateToWidth } from "@nghyane/arcane-tui";
3
3
  import { logger } from "@nghyane/arcane-utils";
4
- import { theme } from "../../modes/theme/theme";
5
4
  import type { TodoItem } from "../../modes/types";
5
+ import { theme } from "../../theme/theme";
6
6
  import { Hasher, type RenderCache } from "../../tui";
7
7
 
8
8
  const TODO_FILE_NAME = "todos.json";
@@ -13,10 +13,8 @@ interface TodoFile {
13
13
  }
14
14
 
15
15
  async function loadTodoFile(filePath: string): Promise<TodoFile | null> {
16
- const file = Bun.file(filePath);
17
- if (!(await file.exists())) return null;
18
16
  try {
19
- const text = await file.text();
17
+ const text = await Bun.file(filePath).text();
20
18
  const data = JSON.parse(text) as TodoFile;
21
19
  if (!data || !Array.isArray(data.todos)) return null;
22
20
  return data;
@@ -1,5 +1,5 @@
1
- import { Box, Container, Spacer, Text } from "@nghyane/arcane-tui";
2
- import { theme } from "../../modes/theme/theme";
1
+ import { Container, LeftBorderBox, Spacer, Text } from "@nghyane/arcane-tui";
2
+ import { theme } from "../../theme/theme";
3
3
  import type { TodoItem } from "../../tools/todo-write";
4
4
 
5
5
  /**
@@ -7,7 +7,7 @@ import type { TodoItem } from "../../tools/todo-write";
7
7
  * Shows when the agent stops with incomplete todos.
8
8
  */
9
9
  export class TodoReminderComponent extends Container {
10
- #box: Box;
10
+ #box: LeftBorderBox;
11
11
 
12
12
  constructor(
13
13
  private readonly todos: TodoItem[],
@@ -18,7 +18,7 @@ export class TodoReminderComponent extends Container {
18
18
 
19
19
  this.addChild(new Spacer(1));
20
20
 
21
- this.#box = new Box(1, 1, t => theme.inverse(theme.fg("warning", t)));
21
+ this.#box = new LeftBorderBox(1, 1, s => theme.fg("warning", s));
22
22
  this.addChild(this.#box);
23
23
 
24
24
  this.#rebuild();