@nghyane/arcane 0.1.13 → 0.1.15

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 (303) 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/index.ts +1 -35
  30. package/src/exa/render.ts +30 -190
  31. package/src/export/html/index.ts +1 -1
  32. package/src/extensibility/custom-tools/loader.ts +1 -1
  33. package/src/extensibility/custom-tools/types.ts +5 -1
  34. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  35. package/src/extensibility/extensions/runner.ts +1 -1
  36. package/src/extensibility/extensions/types.ts +1 -1
  37. package/src/extensibility/extensions/wrapper.ts +7 -15
  38. package/src/extensibility/hooks/runner.ts +1 -1
  39. package/src/extensibility/hooks/types.ts +1 -1
  40. package/src/extensibility/plugins/doctor.ts +1 -1
  41. package/src/index.ts +13 -13
  42. package/src/lsp/index.ts +77 -24
  43. package/src/lsp/render.ts +34 -583
  44. package/src/lsp/types.ts +3 -3
  45. package/src/lsp/utils.ts +1 -1
  46. package/src/main.ts +1 -1
  47. package/src/mcp/tool-bridge.ts +1 -24
  48. package/src/modes/components/assistant-message.ts +7 -7
  49. package/src/modes/components/bash-execution.ts +50 -112
  50. package/src/modes/components/bordered-loader.ts +1 -1
  51. package/src/modes/components/branch-summary-message.ts +16 -10
  52. package/src/modes/components/compaction-summary-message.ts +20 -12
  53. package/src/modes/components/context-group.ts +106 -0
  54. package/src/modes/components/custom-message.ts +4 -5
  55. package/src/modes/components/diff.ts +2 -2
  56. package/src/modes/components/dynamic-border.ts +1 -1
  57. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  58. package/src/modes/components/extensions/extension-list.ts +1 -1
  59. package/src/modes/components/extensions/inspector-panel.ts +1 -1
  60. package/src/modes/components/footer.ts +2 -2
  61. package/src/modes/components/history-search.ts +1 -1
  62. package/src/modes/components/hook-editor.ts +1 -1
  63. package/src/modes/components/hook-input.ts +1 -1
  64. package/src/modes/components/hook-message.ts +4 -5
  65. package/src/modes/components/hook-selector.ts +1 -1
  66. package/src/modes/components/index.ts +0 -2
  67. package/src/modes/components/keybinding-hints.ts +1 -1
  68. package/src/modes/components/login-dialog.ts +1 -1
  69. package/src/modes/components/mcp-add-wizard.ts +1 -1
  70. package/src/modes/components/model-selector.ts +1 -1
  71. package/src/modes/components/oauth-selector.ts +1 -1
  72. package/src/modes/components/plugin-settings.ts +1 -1
  73. package/src/modes/components/python-execution.ts +51 -91
  74. package/src/modes/components/queue-mode-selector.ts +1 -1
  75. package/src/modes/components/session-selector.ts +1 -1
  76. package/src/modes/components/settings-defs.ts +5 -10
  77. package/src/modes/components/settings-selector.ts +1 -1
  78. package/src/modes/components/show-images-selector.ts +1 -1
  79. package/src/modes/components/skill-message.ts +4 -4
  80. package/src/modes/components/status-line/segments.ts +2 -2
  81. package/src/modes/components/status-line/separators.ts +1 -1
  82. package/src/modes/components/status-line-segment-editor.ts +1 -1
  83. package/src/modes/components/status-line.ts +1 -1
  84. package/src/modes/components/theme-selector.ts +1 -1
  85. package/src/modes/components/thinking-selector.ts +1 -1
  86. package/src/modes/components/todo-display.ts +2 -4
  87. package/src/modes/components/todo-reminder.ts +4 -4
  88. package/src/modes/components/tool-execution.ts +118 -440
  89. package/src/modes/components/tool-image-display.ts +107 -0
  90. package/src/modes/components/tree-selector.ts +2 -2
  91. package/src/modes/components/ttsr-notification.ts +4 -17
  92. package/src/modes/components/user-message-selector.ts +1 -1
  93. package/src/modes/components/user-message.ts +9 -10
  94. package/src/modes/components/welcome.ts +1 -1
  95. package/src/modes/controllers/command-controller.ts +1 -1
  96. package/src/modes/controllers/event-controller.ts +58 -187
  97. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  98. package/src/modes/controllers/input-controller.ts +3 -1
  99. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  100. package/src/modes/controllers/selector-controller.ts +3 -26
  101. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  102. package/src/modes/interactive-mode.ts +3 -7
  103. package/src/modes/print-mode.ts +5 -5
  104. package/src/modes/rpc/rpc-mode.ts +1 -1
  105. package/src/modes/types.ts +1 -2
  106. package/src/modes/utils/ui-helpers.ts +34 -32
  107. package/src/patch/edit-tool.ts +742 -0
  108. package/src/patch/index.ts +32 -898
  109. package/src/patch/schemas.ts +208 -0
  110. package/src/patch/shared.ts +83 -151
  111. package/src/prompts/agents/explore.md +22 -37
  112. package/src/prompts/agents/init.md +1 -1
  113. package/src/prompts/agents/librarian.md +29 -20
  114. package/src/prompts/agents/oracle.md +9 -2
  115. package/src/prompts/agents/reviewer.md +14 -48
  116. package/src/prompts/agents/task.md +16 -8
  117. package/src/prompts/compaction/branch-summary.md +4 -1
  118. package/src/prompts/compaction/compaction-summary.md +4 -1
  119. package/src/prompts/system/subagent-system-prompt.md +1 -1
  120. package/src/prompts/system/system-prompt.md +162 -178
  121. package/src/prompts/system/verification-reminder.md +6 -0
  122. package/src/sdk.ts +0 -9
  123. package/src/session/agent-session.ts +244 -1459
  124. package/src/session/model-controller.ts +406 -0
  125. package/src/session/retry-utils.ts +71 -0
  126. package/src/session/session-manager.ts +22 -186
  127. package/src/session/session-types.ts +312 -0
  128. package/src/session/stats.ts +387 -0
  129. package/src/session/streaming-edit.ts +258 -0
  130. package/src/session/ttsr.ts +213 -0
  131. package/src/slash-commands/builtin-registry.ts +0 -8
  132. package/src/stt/recorder.ts +2 -2
  133. package/src/system-prompt.ts +1 -14
  134. package/src/task/agents.ts +7 -33
  135. package/src/task/executor.ts +50 -438
  136. package/src/task/index.ts +104 -71
  137. package/src/task/progress-tracker.ts +390 -0
  138. package/src/task/render.ts +371 -187
  139. package/src/task/subprocess-tool-registry.ts +1 -1
  140. package/src/task/types.ts +14 -47
  141. package/src/tools/ask.ts +31 -42
  142. package/src/tools/bash-interactive.ts +2 -2
  143. package/src/tools/bash-interceptor.ts +2 -2
  144. package/src/tools/bash-normalize.ts +1 -1
  145. package/src/tools/bash-skill-urls.ts +2 -2
  146. package/src/tools/bash.ts +87 -136
  147. package/src/tools/browser.ts +54 -84
  148. package/src/tools/create-tools.ts +186 -0
  149. package/src/tools/default-renderer.ts +104 -0
  150. package/src/tools/explore.ts +11 -10
  151. package/src/tools/fetch.ts +24 -114
  152. package/src/tools/find.ts +48 -132
  153. package/src/tools/gemini-image.ts +5 -15
  154. package/src/tools/github.ts +450 -0
  155. package/src/tools/grep.ts +43 -179
  156. package/src/tools/index.ts +35 -198
  157. package/src/tools/json-tree.ts +3 -3
  158. package/src/tools/librarian.ts +18 -18
  159. package/src/tools/list-limit.ts +2 -2
  160. package/src/tools/notebook.ts +35 -87
  161. package/src/tools/oracle.ts +25 -25
  162. package/src/tools/output-meta.ts +89 -4
  163. package/src/tools/output-utils.ts +2 -2
  164. package/src/tools/python.ts +86 -637
  165. package/src/tools/read.ts +36 -119
  166. package/src/tools/reviewer-tool.ts +19 -21
  167. package/src/tools/search-code.ts +128 -0
  168. package/src/tools/ssh.ts +67 -126
  169. package/src/tools/subagent-tool.ts +197 -123
  170. package/src/tools/todo-write.ts +15 -31
  171. package/src/tools/tool-errors.ts +0 -30
  172. package/src/tools/undo-edit.ts +30 -67
  173. package/src/tools/write.ts +78 -127
  174. package/src/tui/code-cell.ts +4 -4
  175. package/src/tui/file-list.ts +2 -2
  176. package/src/tui/output-block.ts +1 -1
  177. package/src/tui/status-line.ts +1 -1
  178. package/src/tui/tree-list.ts +2 -2
  179. package/src/tui/types.ts +1 -1
  180. package/src/tui/utils.ts +1 -1
  181. package/src/{tools → ui}/render-utils.ts +87 -126
  182. package/src/utils/external-editor.ts +4 -4
  183. package/src/utils/file-mentions.ts +1 -1
  184. package/src/utils/index.ts +30 -0
  185. package/src/utils/tools-manager.ts +9 -19
  186. package/src/web/github-client.ts +290 -0
  187. package/src/web/scrapers/github.ts +11 -62
  188. package/src/web/search/auth.ts +1 -3
  189. package/src/web/search/index.ts +82 -46
  190. package/src/web/search/provider.ts +11 -16
  191. package/src/web/search/providers/grep.ts +160 -0
  192. package/src/web/search/render.ts +48 -235
  193. package/src/web/search/types.ts +1 -1
  194. package/src/commands/commit.ts +0 -36
  195. package/src/commit/agentic/agent.ts +0 -311
  196. package/src/commit/agentic/fallback.ts +0 -96
  197. package/src/commit/agentic/index.ts +0 -359
  198. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  199. package/src/commit/agentic/prompts/session-user.md +0 -25
  200. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  201. package/src/commit/agentic/prompts/system.md +0 -38
  202. package/src/commit/agentic/state.ts +0 -69
  203. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  204. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  205. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  206. package/src/commit/agentic/tools/git-overview.ts +0 -84
  207. package/src/commit/agentic/tools/index.ts +0 -56
  208. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  209. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  210. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  211. package/src/commit/agentic/tools/split-commit.ts +0 -280
  212. package/src/commit/agentic/topo-sort.ts +0 -44
  213. package/src/commit/agentic/trivial.ts +0 -51
  214. package/src/commit/agentic/validation.ts +0 -200
  215. package/src/commit/analysis/conventional.ts +0 -165
  216. package/src/commit/analysis/index.ts +0 -4
  217. package/src/commit/analysis/scope.ts +0 -242
  218. package/src/commit/analysis/summary.ts +0 -112
  219. package/src/commit/analysis/validation.ts +0 -66
  220. package/src/commit/changelog/detect.ts +0 -37
  221. package/src/commit/changelog/generate.ts +0 -110
  222. package/src/commit/changelog/index.ts +0 -234
  223. package/src/commit/changelog/parse.ts +0 -44
  224. package/src/commit/cli.ts +0 -93
  225. package/src/commit/git/diff.ts +0 -148
  226. package/src/commit/git/errors.ts +0 -9
  227. package/src/commit/git/index.ts +0 -211
  228. package/src/commit/git/operations.ts +0 -54
  229. package/src/commit/index.ts +0 -5
  230. package/src/commit/map-reduce/index.ts +0 -64
  231. package/src/commit/map-reduce/map-phase.ts +0 -178
  232. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  233. package/src/commit/map-reduce/utils.ts +0 -9
  234. package/src/commit/message.ts +0 -11
  235. package/src/commit/model-selection.ts +0 -69
  236. package/src/commit/pipeline.ts +0 -243
  237. package/src/commit/prompts/analysis-system.md +0 -148
  238. package/src/commit/prompts/analysis-user.md +0 -38
  239. package/src/commit/prompts/changelog-system.md +0 -50
  240. package/src/commit/prompts/changelog-user.md +0 -18
  241. package/src/commit/prompts/file-observer-system.md +0 -24
  242. package/src/commit/prompts/file-observer-user.md +0 -8
  243. package/src/commit/prompts/reduce-system.md +0 -50
  244. package/src/commit/prompts/reduce-user.md +0 -17
  245. package/src/commit/prompts/summary-retry.md +0 -3
  246. package/src/commit/prompts/summary-system.md +0 -38
  247. package/src/commit/prompts/summary-user.md +0 -13
  248. package/src/commit/prompts/types-description.md +0 -2
  249. package/src/commit/types.ts +0 -109
  250. package/src/commit/utils/exclusions.ts +0 -42
  251. package/src/mcp/render.ts +0 -123
  252. package/src/modes/components/agent-dashboard.ts +0 -1130
  253. package/src/modes/components/codemode-group.ts +0 -369
  254. package/src/modes/components/read-tool-group.ts +0 -119
  255. package/src/modes/components/visual-truncate.ts +0 -63
  256. package/src/prompts/system/subagent-user-prompt.md +0 -8
  257. package/src/prompts/tools/ask.md +0 -44
  258. package/src/prompts/tools/bash.md +0 -24
  259. package/src/prompts/tools/browser.md +0 -33
  260. package/src/prompts/tools/calculator.md +0 -12
  261. package/src/prompts/tools/explore.md +0 -29
  262. package/src/prompts/tools/fetch.md +0 -16
  263. package/src/prompts/tools/find.md +0 -18
  264. package/src/prompts/tools/gemini-image.md +0 -23
  265. package/src/prompts/tools/grep.md +0 -28
  266. package/src/prompts/tools/hashline.md +0 -232
  267. package/src/prompts/tools/librarian.md +0 -24
  268. package/src/prompts/tools/lsp.md +0 -28
  269. package/src/prompts/tools/oracle.md +0 -26
  270. package/src/prompts/tools/patch.md +0 -74
  271. package/src/prompts/tools/python.md +0 -66
  272. package/src/prompts/tools/read.md +0 -36
  273. package/src/prompts/tools/replace.md +0 -38
  274. package/src/prompts/tools/reviewer.md +0 -41
  275. package/src/prompts/tools/ssh.md +0 -51
  276. package/src/prompts/tools/task-summary.md +0 -28
  277. package/src/prompts/tools/task.md +0 -146
  278. package/src/prompts/tools/todo-write.md +0 -65
  279. package/src/prompts/tools/undo-edit.md +0 -7
  280. package/src/prompts/tools/web-search.md +0 -19
  281. package/src/prompts/tools/write.md +0 -18
  282. package/src/task/batch.ts +0 -102
  283. package/src/task/discovery.ts +0 -126
  284. package/src/task/parallel.ts +0 -84
  285. package/src/task/template.ts +0 -32
  286. package/src/tools/calculator.ts +0 -537
  287. package/src/tools/jtd-to-typescript.ts +0 -198
  288. package/src/tools/renderers.ts +0 -60
  289. package/src/tools/tool-result.ts +0 -86
  290. /package/src/{modes/theme → theme}/dark.json +0 -0
  291. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  292. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  293. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  294. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  295. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  296. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  297. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  298. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  299. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  300. /package/src/{modes/theme → theme}/light.json +0 -0
  301. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  302. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  303. /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 {
@@ -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 { formatClickHint, 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,54 @@ 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(". ")));
128
+ bodyLines.push(theme.fg("warning", "output truncated"));
168
129
  }
169
-
170
- if (statusParts.length > 0) {
171
- this.#contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`, 1, 0));
130
+ if (!showAll && skipped > 0) {
131
+ bodyLines.push(formatClickHint(theme));
172
132
  }
173
133
  }
134
+
135
+ this.#bodyText.setText(bodyLines.length > 0 ? bodyLines.join("\n") : "");
174
136
  }
175
137
 
176
138
  #clampDisplayLine(line: string): string {
177
- if (line.length <= MAX_DISPLAY_LINE_CHARS) {
178
- return line;
179
- }
139
+ if (line.length <= MAX_DISPLAY_LINE_CHARS) return line;
180
140
  const omitted = line.length - MAX_DISPLAY_LINE_CHARS;
181
- return `${line.slice(0, MAX_DISPLAY_LINE_CHARS)} [${omitted} chars omitted]`;
141
+ return `${line.slice(0, MAX_DISPLAY_LINE_CHARS)}\u2026 [${omitted} chars omitted]`;
182
142
  }
183
143
 
184
144
  #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();