@butlerw/vellum 0.1.0

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 (446) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +411 -0
  3. package/__fixtures__/responses/code-generation.json +42 -0
  4. package/__fixtures__/responses/error-response.json +20 -0
  5. package/__fixtures__/responses/hello-world.json +32 -0
  6. package/dist/auth-6MCXESOH.js +26 -0
  7. package/dist/chunk-SECXJGWA.js +597 -0
  8. package/dist/index.js +34023 -0
  9. package/package.json +67 -0
  10. package/src/__tests__/commands.e2e.test.ts +728 -0
  11. package/src/__tests__/credentials.test.ts +713 -0
  12. package/src/__tests__/mode-e2e.test.ts +391 -0
  13. package/src/__tests__/tui-integration.test.tsx +1271 -0
  14. package/src/agents/__tests__/task-persistence.test.ts +235 -0
  15. package/src/agents/commands/delegate.ts +240 -0
  16. package/src/agents/commands/index.ts +10 -0
  17. package/src/agents/commands/resume.ts +335 -0
  18. package/src/agents/index.ts +29 -0
  19. package/src/agents/task-persistence.ts +272 -0
  20. package/src/agents/task-resumption.ts +242 -0
  21. package/src/app.tsx +4737 -0
  22. package/src/commands/__tests__/.gitkeep +1 -0
  23. package/src/commands/__tests__/agents.test.ts +606 -0
  24. package/src/commands/__tests__/auth.test.ts +626 -0
  25. package/src/commands/__tests__/autocomplete.test.ts +683 -0
  26. package/src/commands/__tests__/batch.test.ts +287 -0
  27. package/src/commands/__tests__/chain-pipe-parser.test.ts +654 -0
  28. package/src/commands/__tests__/completion.test.ts +238 -0
  29. package/src/commands/__tests__/core.test.ts +363 -0
  30. package/src/commands/__tests__/executor.test.ts +496 -0
  31. package/src/commands/__tests__/exit-codes.test.ts +220 -0
  32. package/src/commands/__tests__/init.test.ts +243 -0
  33. package/src/commands/__tests__/language.test.ts +353 -0
  34. package/src/commands/__tests__/mode-cli.test.ts +667 -0
  35. package/src/commands/__tests__/model.test.ts +277 -0
  36. package/src/commands/__tests__/parser.test.ts +493 -0
  37. package/src/commands/__tests__/performance.bench.ts +380 -0
  38. package/src/commands/__tests__/registry.test.ts +534 -0
  39. package/src/commands/__tests__/resume.test.ts +449 -0
  40. package/src/commands/__tests__/security.test.ts +845 -0
  41. package/src/commands/__tests__/stream-json.test.ts +372 -0
  42. package/src/commands/__tests__/user-commands.test.ts +597 -0
  43. package/src/commands/adapters.ts +267 -0
  44. package/src/commands/agent.ts +395 -0
  45. package/src/commands/agents/generate.ts +506 -0
  46. package/src/commands/agents/index.ts +272 -0
  47. package/src/commands/agents/show.ts +271 -0
  48. package/src/commands/agents/validate.ts +387 -0
  49. package/src/commands/auth.ts +883 -0
  50. package/src/commands/autocomplete.ts +480 -0
  51. package/src/commands/batch/command.ts +388 -0
  52. package/src/commands/batch/executor.ts +361 -0
  53. package/src/commands/batch/index.ts +12 -0
  54. package/src/commands/commit.ts +235 -0
  55. package/src/commands/completion/index.ts +371 -0
  56. package/src/commands/condense.ts +191 -0
  57. package/src/commands/config.ts +344 -0
  58. package/src/commands/context-provider.ts +173 -0
  59. package/src/commands/copy.ts +329 -0
  60. package/src/commands/core/clear.ts +38 -0
  61. package/src/commands/core/exit.ts +43 -0
  62. package/src/commands/core/help.ts +354 -0
  63. package/src/commands/core/index.ts +15 -0
  64. package/src/commands/cost.ts +179 -0
  65. package/src/commands/credentials.tsx +618 -0
  66. package/src/commands/custom-agents/__tests__/custom-agents.test.ts +709 -0
  67. package/src/commands/custom-agents/create.ts +377 -0
  68. package/src/commands/custom-agents/export.ts +135 -0
  69. package/src/commands/custom-agents/import.ts +199 -0
  70. package/src/commands/custom-agents/index.ts +372 -0
  71. package/src/commands/custom-agents/info.ts +318 -0
  72. package/src/commands/custom-agents/list.ts +267 -0
  73. package/src/commands/custom-agents/validate.ts +388 -0
  74. package/src/commands/diff-mode.ts +241 -0
  75. package/src/commands/env.ts +53 -0
  76. package/src/commands/executor.ts +579 -0
  77. package/src/commands/exit-codes.ts +202 -0
  78. package/src/commands/index.ts +701 -0
  79. package/src/commands/init/index.ts +15 -0
  80. package/src/commands/init/prompts.ts +366 -0
  81. package/src/commands/init/templates/commands-readme.md +80 -0
  82. package/src/commands/init/templates/example-command.md +79 -0
  83. package/src/commands/init/templates/example-skill.md +168 -0
  84. package/src/commands/init/templates/example-workflow.md +101 -0
  85. package/src/commands/init/templates/prompts-readme.md +52 -0
  86. package/src/commands/init/templates/rules-readme.md +63 -0
  87. package/src/commands/init/templates/skills-readme.md +83 -0
  88. package/src/commands/init/templates/workflows-readme.md +94 -0
  89. package/src/commands/init.ts +391 -0
  90. package/src/commands/install.ts +90 -0
  91. package/src/commands/language.ts +191 -0
  92. package/src/commands/loaders/.gitkeep +1 -0
  93. package/src/commands/lsp.ts +199 -0
  94. package/src/commands/markdown-commands.ts +253 -0
  95. package/src/commands/mcp.ts +588 -0
  96. package/src/commands/memory/export.ts +341 -0
  97. package/src/commands/memory/index.ts +148 -0
  98. package/src/commands/memory/list.ts +261 -0
  99. package/src/commands/memory/search.ts +346 -0
  100. package/src/commands/memory/utils.ts +15 -0
  101. package/src/commands/metrics.ts +75 -0
  102. package/src/commands/migrate/index.ts +16 -0
  103. package/src/commands/migrate/prompts.ts +477 -0
  104. package/src/commands/mode.ts +331 -0
  105. package/src/commands/model.ts +298 -0
  106. package/src/commands/onboard.ts +205 -0
  107. package/src/commands/open.ts +169 -0
  108. package/src/commands/output/stream-json.ts +373 -0
  109. package/src/commands/parser/chain-parser.ts +370 -0
  110. package/src/commands/parser/index.ts +29 -0
  111. package/src/commands/parser/pipe-parser.ts +480 -0
  112. package/src/commands/parser.ts +588 -0
  113. package/src/commands/persistence.ts +355 -0
  114. package/src/commands/progress.ts +18 -0
  115. package/src/commands/prompt/index.ts +17 -0
  116. package/src/commands/prompt/validate.ts +621 -0
  117. package/src/commands/prompt-priority.ts +401 -0
  118. package/src/commands/registry.ts +374 -0
  119. package/src/commands/sandbox/index.ts +131 -0
  120. package/src/commands/security/index.ts +21 -0
  121. package/src/commands/security/input-sanitizer.ts +168 -0
  122. package/src/commands/security/permission-checker.ts +456 -0
  123. package/src/commands/security/sensitive-data.ts +350 -0
  124. package/src/commands/session/delete.ts +38 -0
  125. package/src/commands/session/export.ts +39 -0
  126. package/src/commands/session/index.ts +26 -0
  127. package/src/commands/session/list.ts +26 -0
  128. package/src/commands/session/resume.ts +562 -0
  129. package/src/commands/session/search.ts +434 -0
  130. package/src/commands/session/show.ts +26 -0
  131. package/src/commands/settings.ts +368 -0
  132. package/src/commands/setup.ts +23 -0
  133. package/src/commands/shell/index.ts +16 -0
  134. package/src/commands/shell/setup.ts +422 -0
  135. package/src/commands/shell-init.ts +50 -0
  136. package/src/commands/shell-integration/index.ts +194 -0
  137. package/src/commands/skill.ts +1220 -0
  138. package/src/commands/spec.ts +558 -0
  139. package/src/commands/status.ts +246 -0
  140. package/src/commands/theme.ts +211 -0
  141. package/src/commands/think.ts +551 -0
  142. package/src/commands/trust.ts +211 -0
  143. package/src/commands/tutorial.ts +522 -0
  144. package/src/commands/types.ts +512 -0
  145. package/src/commands/update.ts +274 -0
  146. package/src/commands/usage.ts +213 -0
  147. package/src/commands/user-commands.ts +630 -0
  148. package/src/commands/utils.ts +142 -0
  149. package/src/commands/vim.ts +152 -0
  150. package/src/commands/workflow.ts +257 -0
  151. package/src/components/header.tsx +25 -0
  152. package/src/components/input.tsx +25 -0
  153. package/src/components/message-list.tsx +32 -0
  154. package/src/components/status-bar.tsx +23 -0
  155. package/src/index.tsx +614 -0
  156. package/src/onboarding/__tests__/tutorial.test.ts +740 -0
  157. package/src/onboarding/index.ts +69 -0
  158. package/src/onboarding/tips/index.ts +9 -0
  159. package/src/onboarding/tips/tip-engine.ts +459 -0
  160. package/src/onboarding/tutorial/index.ts +88 -0
  161. package/src/onboarding/tutorial/lessons/basics.ts +151 -0
  162. package/src/onboarding/tutorial/lessons/index.ts +151 -0
  163. package/src/onboarding/tutorial/lessons/modes.ts +230 -0
  164. package/src/onboarding/tutorial/lessons/tools.ts +172 -0
  165. package/src/onboarding/tutorial/progress-tracker.ts +350 -0
  166. package/src/onboarding/tutorial/storage.ts +249 -0
  167. package/src/onboarding/tutorial/tutorial-system.ts +462 -0
  168. package/src/onboarding/tutorial/types.ts +310 -0
  169. package/src/orchestrator-singleton.ts +129 -0
  170. package/src/shutdown.ts +33 -0
  171. package/src/test/e2e/assertions.ts +267 -0
  172. package/src/test/e2e/fixtures.ts +204 -0
  173. package/src/test/e2e/harness.ts +575 -0
  174. package/src/test/e2e/index.ts +57 -0
  175. package/src/test/e2e/types.ts +228 -0
  176. package/src/test/fixtures/__tests__/fake-response-loader.test.ts +314 -0
  177. package/src/test/fixtures/fake-response-loader.ts +314 -0
  178. package/src/test/fixtures/index.ts +20 -0
  179. package/src/tui/__tests__/mcp-panel.test.tsx +82 -0
  180. package/src/tui/__tests__/mcp-wiring.test.tsx +78 -0
  181. package/src/tui/__tests__/mode-components.test.tsx +395 -0
  182. package/src/tui/__tests__/permission-ask-flow.test.tsx +138 -0
  183. package/src/tui/__tests__/sidebar-panel-data.test.tsx +148 -0
  184. package/src/tui/__tests__/tools-panel-hotkeys.test.tsx +41 -0
  185. package/src/tui/adapters/agent-adapter.ts +1008 -0
  186. package/src/tui/adapters/index.ts +48 -0
  187. package/src/tui/adapters/message-adapter.ts +315 -0
  188. package/src/tui/adapters/persistence-bridge.ts +331 -0
  189. package/src/tui/adapters/session-adapter.ts +419 -0
  190. package/src/tui/buffered-stdout.ts +223 -0
  191. package/src/tui/components/AgentProgress.tsx +424 -0
  192. package/src/tui/components/Banner/AsciiArt.ts +160 -0
  193. package/src/tui/components/Banner/Banner.tsx +355 -0
  194. package/src/tui/components/Banner/ShimmerContext.tsx +131 -0
  195. package/src/tui/components/Banner/ShimmerText.tsx +193 -0
  196. package/src/tui/components/Banner/TypeWriterGradient.tsx +321 -0
  197. package/src/tui/components/Banner/index.ts +61 -0
  198. package/src/tui/components/Banner/useShimmer.ts +241 -0
  199. package/src/tui/components/ChatView.tsx +11 -0
  200. package/src/tui/components/Checkpoint/CheckpointDiffView.tsx +371 -0
  201. package/src/tui/components/Checkpoint/SnapshotCheckpointPanel.tsx +440 -0
  202. package/src/tui/components/Checkpoint/index.ts +19 -0
  203. package/src/tui/components/CostDisplay.tsx +226 -0
  204. package/src/tui/components/InitErrorBanner.tsx +122 -0
  205. package/src/tui/components/Input/Autocomplete.tsx +603 -0
  206. package/src/tui/components/Input/EnhancedCommandInput.tsx +471 -0
  207. package/src/tui/components/Input/HighlightedText.tsx +236 -0
  208. package/src/tui/components/Input/MentionAutocomplete.tsx +375 -0
  209. package/src/tui/components/Input/TextInput.tsx +1002 -0
  210. package/src/tui/components/Input/__tests__/Autocomplete.test.tsx +374 -0
  211. package/src/tui/components/Input/__tests__/TextInput.test.tsx +241 -0
  212. package/src/tui/components/Input/__tests__/highlight.test.ts +219 -0
  213. package/src/tui/components/Input/__tests__/slash-command-utils.test.ts +104 -0
  214. package/src/tui/components/Input/highlight.ts +362 -0
  215. package/src/tui/components/Input/index.ts +36 -0
  216. package/src/tui/components/Input/slash-command-utils.ts +135 -0
  217. package/src/tui/components/Layout.tsx +432 -0
  218. package/src/tui/components/McpPanel.tsx +137 -0
  219. package/src/tui/components/MemoryPanel.tsx +448 -0
  220. package/src/tui/components/Messages/CodeBlock.tsx +527 -0
  221. package/src/tui/components/Messages/DiffView.tsx +679 -0
  222. package/src/tui/components/Messages/ImageReference.tsx +89 -0
  223. package/src/tui/components/Messages/MarkdownBlock.tsx +228 -0
  224. package/src/tui/components/Messages/MarkdownRenderer.tsx +498 -0
  225. package/src/tui/components/Messages/MessageBubble.tsx +270 -0
  226. package/src/tui/components/Messages/MessageList.tsx +1719 -0
  227. package/src/tui/components/Messages/StreamingText.tsx +216 -0
  228. package/src/tui/components/Messages/ThinkingBlock.tsx +408 -0
  229. package/src/tui/components/Messages/ToolResultPreview.tsx +243 -0
  230. package/src/tui/components/Messages/__tests__/CodeBlock.test.tsx +296 -0
  231. package/src/tui/components/Messages/__tests__/DiffView.test.tsx +239 -0
  232. package/src/tui/components/Messages/__tests__/MarkdownRenderer.test.tsx +303 -0
  233. package/src/tui/components/Messages/__tests__/MessageBubble.test.tsx +268 -0
  234. package/src/tui/components/Messages/__tests__/MessageList.test.tsx +324 -0
  235. package/src/tui/components/Messages/__tests__/StreamingText.test.tsx +215 -0
  236. package/src/tui/components/Messages/index.ts +25 -0
  237. package/src/tui/components/ModeIndicator.tsx +177 -0
  238. package/src/tui/components/ModeSelector.tsx +216 -0
  239. package/src/tui/components/ModelSelector.tsx +339 -0
  240. package/src/tui/components/OnboardingWizard.tsx +670 -0
  241. package/src/tui/components/PhaseProgressIndicator.tsx +270 -0
  242. package/src/tui/components/RateLimitIndicator.tsx +82 -0
  243. package/src/tui/components/ScreenReaderLayout.tsx +295 -0
  244. package/src/tui/components/SettingsPanel.tsx +643 -0
  245. package/src/tui/components/Sidebar/SystemStatusPanel.tsx +284 -0
  246. package/src/tui/components/Sidebar/index.ts +9 -0
  247. package/src/tui/components/Status/ModelStatusBar.tsx +270 -0
  248. package/src/tui/components/Status/index.ts +12 -0
  249. package/src/tui/components/StatusBar/AgentModeIndicator.tsx +257 -0
  250. package/src/tui/components/StatusBar/ContextProgress.tsx +167 -0
  251. package/src/tui/components/StatusBar/FileChangesIndicator.tsx +62 -0
  252. package/src/tui/components/StatusBar/GitIndicator.tsx +89 -0
  253. package/src/tui/components/StatusBar/HeaderBar.tsx +126 -0
  254. package/src/tui/components/StatusBar/ModelIndicator.tsx +157 -0
  255. package/src/tui/components/StatusBar/PersistenceStatusIndicator.tsx +210 -0
  256. package/src/tui/components/StatusBar/ResilienceIndicator.tsx +106 -0
  257. package/src/tui/components/StatusBar/SandboxIndicator.tsx +167 -0
  258. package/src/tui/components/StatusBar/StatusBar.tsx +368 -0
  259. package/src/tui/components/StatusBar/ThinkingModeIndicator.tsx +170 -0
  260. package/src/tui/components/StatusBar/TokenBreakdown.tsx +246 -0
  261. package/src/tui/components/StatusBar/TokenCounter.tsx +135 -0
  262. package/src/tui/components/StatusBar/TrustModeIndicator.tsx +130 -0
  263. package/src/tui/components/StatusBar/WorkspaceIndicator.tsx +86 -0
  264. package/src/tui/components/StatusBar/__tests__/AgentModeIndicator.test.tsx +193 -0
  265. package/src/tui/components/StatusBar/__tests__/StatusBar.test.tsx +729 -0
  266. package/src/tui/components/StatusBar/index.ts +60 -0
  267. package/src/tui/components/TipBanner.tsx +115 -0
  268. package/src/tui/components/TodoItem.tsx +208 -0
  269. package/src/tui/components/TodoPanel.tsx +455 -0
  270. package/src/tui/components/Tools/ApprovalQueue.tsx +407 -0
  271. package/src/tui/components/Tools/OptionSelector.tsx +160 -0
  272. package/src/tui/components/Tools/PermissionDialog.tsx +286 -0
  273. package/src/tui/components/Tools/ToolParams.tsx +483 -0
  274. package/src/tui/components/Tools/ToolsPanel.tsx +178 -0
  275. package/src/tui/components/Tools/__tests__/PermissionDialog.test.tsx +510 -0
  276. package/src/tui/components/Tools/__tests__/ToolParams.test.tsx +432 -0
  277. package/src/tui/components/Tools/index.ts +21 -0
  278. package/src/tui/components/TrustPrompt.tsx +279 -0
  279. package/src/tui/components/UpdateBanner.tsx +166 -0
  280. package/src/tui/components/VimModeIndicator.tsx +112 -0
  281. package/src/tui/components/backtrack/BacktrackControls.tsx +402 -0
  282. package/src/tui/components/backtrack/index.ts +13 -0
  283. package/src/tui/components/common/AutoApprovalStatus.tsx +251 -0
  284. package/src/tui/components/common/CostWarning.tsx +294 -0
  285. package/src/tui/components/common/DynamicShortcutHints.tsx +209 -0
  286. package/src/tui/components/common/EnhancedLoadingIndicator.tsx +305 -0
  287. package/src/tui/components/common/ErrorBoundary.tsx +140 -0
  288. package/src/tui/components/common/GradientText.tsx +224 -0
  289. package/src/tui/components/common/HotkeyHelpModal.tsx +193 -0
  290. package/src/tui/components/common/HotkeyHints.tsx +70 -0
  291. package/src/tui/components/common/MaxSizedBox.tsx +354 -0
  292. package/src/tui/components/common/NewMessagesBadge.tsx +65 -0
  293. package/src/tui/components/common/ProtectedFileLegend.tsx +89 -0
  294. package/src/tui/components/common/ScrollIndicator.tsx +160 -0
  295. package/src/tui/components/common/Spinner.tsx +342 -0
  296. package/src/tui/components/common/StreamingIndicator.tsx +316 -0
  297. package/src/tui/components/common/VirtualizedList/VirtualizedList.tsx +428 -0
  298. package/src/tui/components/common/VirtualizedList/hooks/index.ts +19 -0
  299. package/src/tui/components/common/VirtualizedList/hooks/useBatchedScroll.ts +64 -0
  300. package/src/tui/components/common/VirtualizedList/hooks/useScrollAnchor.ts +290 -0
  301. package/src/tui/components/common/VirtualizedList/hooks/useVirtualization.ts +340 -0
  302. package/src/tui/components/common/VirtualizedList/index.ts +30 -0
  303. package/src/tui/components/common/VirtualizedList/types.ts +107 -0
  304. package/src/tui/components/common/__tests__/NewMessagesBadge.test.tsx +74 -0
  305. package/src/tui/components/common/__tests__/ScrollIndicator.test.tsx +193 -0
  306. package/src/tui/components/common/index.ts +110 -0
  307. package/src/tui/components/index.ts +79 -0
  308. package/src/tui/components/session/CheckpointPanel.tsx +323 -0
  309. package/src/tui/components/session/RollbackDialog.tsx +169 -0
  310. package/src/tui/components/session/SessionItem.tsx +136 -0
  311. package/src/tui/components/session/SessionListPanel.tsx +252 -0
  312. package/src/tui/components/session/SessionPicker.tsx +449 -0
  313. package/src/tui/components/session/SessionPreview.tsx +240 -0
  314. package/src/tui/components/session/__tests__/session.test.tsx +408 -0
  315. package/src/tui/components/session/index.ts +28 -0
  316. package/src/tui/components/session/types.ts +116 -0
  317. package/src/tui/components/theme/__tests__/tokens.test.ts +471 -0
  318. package/src/tui/components/theme/index.ts +227 -0
  319. package/src/tui/components/theme/tokens.ts +484 -0
  320. package/src/tui/config/defaults.ts +134 -0
  321. package/src/tui/config/index.ts +17 -0
  322. package/src/tui/context/AnimationContext.tsx +284 -0
  323. package/src/tui/context/AppContext.tsx +349 -0
  324. package/src/tui/context/BracketedPasteContext.tsx +372 -0
  325. package/src/tui/context/LspContext.tsx +192 -0
  326. package/src/tui/context/McpContext.tsx +325 -0
  327. package/src/tui/context/MessagesContext.tsx +870 -0
  328. package/src/tui/context/OverflowContext.tsx +213 -0
  329. package/src/tui/context/RateLimitContext.tsx +108 -0
  330. package/src/tui/context/ResilienceContext.tsx +275 -0
  331. package/src/tui/context/RootProvider.tsx +136 -0
  332. package/src/tui/context/ScrollContext.tsx +331 -0
  333. package/src/tui/context/ToolsContext.tsx +702 -0
  334. package/src/tui/context/__tests__/BracketedPasteContext.test.tsx +416 -0
  335. package/src/tui/context/index.ts +140 -0
  336. package/src/tui/enterprise-integration.ts +282 -0
  337. package/src/tui/hooks/__tests__/useBacktrack.test.tsx +138 -0
  338. package/src/tui/hooks/__tests__/useBracketedPaste.test.tsx +222 -0
  339. package/src/tui/hooks/__tests__/useCopyMode.test.tsx +336 -0
  340. package/src/tui/hooks/__tests__/useHotkeys.ctrl-input.test.tsx +96 -0
  341. package/src/tui/hooks/__tests__/useHotkeys.test.tsx +454 -0
  342. package/src/tui/hooks/__tests__/useInputHistory.test.tsx +660 -0
  343. package/src/tui/hooks/__tests__/useLineBuffer.test.ts +295 -0
  344. package/src/tui/hooks/__tests__/useModeController.test.ts +137 -0
  345. package/src/tui/hooks/__tests__/useModeShortcuts.test.tsx +142 -0
  346. package/src/tui/hooks/__tests__/useScrollController.test.ts +464 -0
  347. package/src/tui/hooks/__tests__/useVim.test.tsx +531 -0
  348. package/src/tui/hooks/index.ts +252 -0
  349. package/src/tui/hooks/useAgentLoop.ts +712 -0
  350. package/src/tui/hooks/useAlternateBuffer.ts +398 -0
  351. package/src/tui/hooks/useAnimatedScrollbar.ts +241 -0
  352. package/src/tui/hooks/useBacktrack.ts +443 -0
  353. package/src/tui/hooks/useBracketedPaste.ts +104 -0
  354. package/src/tui/hooks/useCollapsible.ts +240 -0
  355. package/src/tui/hooks/useCopyMode.ts +382 -0
  356. package/src/tui/hooks/useCostSummary.ts +75 -0
  357. package/src/tui/hooks/useDesktopNotification.ts +414 -0
  358. package/src/tui/hooks/useDiffMode.ts +44 -0
  359. package/src/tui/hooks/useFileChangeStats.ts +110 -0
  360. package/src/tui/hooks/useFileSuggestions.ts +284 -0
  361. package/src/tui/hooks/useFlickerDetector.ts +250 -0
  362. package/src/tui/hooks/useGitStatus.ts +200 -0
  363. package/src/tui/hooks/useHotkeys.ts +579 -0
  364. package/src/tui/hooks/useImagePaste.ts +114 -0
  365. package/src/tui/hooks/useInputHighlight.ts +145 -0
  366. package/src/tui/hooks/useInputHistory.ts +246 -0
  367. package/src/tui/hooks/useKeyboardScroll.ts +209 -0
  368. package/src/tui/hooks/useLineBuffer.ts +356 -0
  369. package/src/tui/hooks/useMentionAutocomplete.ts +235 -0
  370. package/src/tui/hooks/useModeController.ts +167 -0
  371. package/src/tui/hooks/useModeShortcuts.ts +196 -0
  372. package/src/tui/hooks/usePermissionHandler.ts +146 -0
  373. package/src/tui/hooks/usePersistence.ts +480 -0
  374. package/src/tui/hooks/usePersistenceShortcuts.ts +225 -0
  375. package/src/tui/hooks/usePlaceholderRotation.ts +143 -0
  376. package/src/tui/hooks/useProviderStatus.ts +270 -0
  377. package/src/tui/hooks/useRateLimitStatus.ts +90 -0
  378. package/src/tui/hooks/useScreenReader.ts +315 -0
  379. package/src/tui/hooks/useScrollController.ts +450 -0
  380. package/src/tui/hooks/useScrollEventBatcher.ts +185 -0
  381. package/src/tui/hooks/useSidebarPanelData.ts +115 -0
  382. package/src/tui/hooks/useSmoothScroll.ts +202 -0
  383. package/src/tui/hooks/useSnapshots.ts +300 -0
  384. package/src/tui/hooks/useStateAndRef.ts +50 -0
  385. package/src/tui/hooks/useTerminalSize.ts +206 -0
  386. package/src/tui/hooks/useToolApprovalController.ts +91 -0
  387. package/src/tui/hooks/useVim.ts +334 -0
  388. package/src/tui/hooks/useWorkspace.ts +56 -0
  389. package/src/tui/i18n/__tests__/init.test.ts +278 -0
  390. package/src/tui/i18n/__tests__/language-config.test.ts +199 -0
  391. package/src/tui/i18n/__tests__/locale-detection.test.ts +250 -0
  392. package/src/tui/i18n/__tests__/settings-integration.test.ts +262 -0
  393. package/src/tui/i18n/index.ts +72 -0
  394. package/src/tui/i18n/init.ts +131 -0
  395. package/src/tui/i18n/language-config.ts +106 -0
  396. package/src/tui/i18n/locale-detection.ts +173 -0
  397. package/src/tui/i18n/settings-integration.ts +557 -0
  398. package/src/tui/i18n/tui-namespace.ts +538 -0
  399. package/src/tui/i18n/types.ts +312 -0
  400. package/src/tui/index.ts +43 -0
  401. package/src/tui/lsp-integration.ts +409 -0
  402. package/src/tui/metrics-integration.ts +366 -0
  403. package/src/tui/plugins.ts +383 -0
  404. package/src/tui/resilience.ts +342 -0
  405. package/src/tui/sandbox-integration.ts +317 -0
  406. package/src/tui/services/clipboard.ts +348 -0
  407. package/src/tui/services/fuzzy-search.ts +441 -0
  408. package/src/tui/services/index.ts +72 -0
  409. package/src/tui/services/markdown-renderer.ts +565 -0
  410. package/src/tui/services/open-external.ts +247 -0
  411. package/src/tui/services/syntax-highlighter.ts +483 -0
  412. package/src/tui/slash-commands.ts +12 -0
  413. package/src/tui/theme/index.ts +15 -0
  414. package/src/tui/theme/provider.tsx +206 -0
  415. package/src/tui/tip-integration.ts +300 -0
  416. package/src/tui/types/__tests__/ink-extended.test.ts +121 -0
  417. package/src/tui/types/ink-extended.ts +87 -0
  418. package/src/tui/utils/__tests__/bracketedPaste.test.ts +231 -0
  419. package/src/tui/utils/__tests__/heightEstimator.test.ts +157 -0
  420. package/src/tui/utils/__tests__/text-width.test.ts +158 -0
  421. package/src/tui/utils/__tests__/textSanitizer.test.ts +266 -0
  422. package/src/tui/utils/__tests__/ui-sizing.test.ts +169 -0
  423. package/src/tui/utils/bracketedPaste.ts +107 -0
  424. package/src/tui/utils/cursor-manager.ts +131 -0
  425. package/src/tui/utils/detectTerminal.ts +596 -0
  426. package/src/tui/utils/findLastSafeSplitPoint.ts +92 -0
  427. package/src/tui/utils/heightEstimator.ts +198 -0
  428. package/src/tui/utils/index.ts +91 -0
  429. package/src/tui/utils/isNarrowWidth.ts +52 -0
  430. package/src/tui/utils/stdoutGuard.ts +90 -0
  431. package/src/tui/utils/synchronized-update.ts +70 -0
  432. package/src/tui/utils/text-width.ts +225 -0
  433. package/src/tui/utils/textSanitizer.ts +225 -0
  434. package/src/tui/utils/textUtils.ts +114 -0
  435. package/src/tui/utils/ui-sizing.ts +192 -0
  436. package/src/tui-blessed/app.ts +160 -0
  437. package/src/tui-blessed/index.ts +2 -0
  438. package/src/tui-blessed/neo-blessed.d.ts +6 -0
  439. package/src/tui-blessed/test.ts +21 -0
  440. package/src/tui-blessed/types.ts +14 -0
  441. package/src/utils/icons.ts +130 -0
  442. package/src/utils/index.ts +33 -0
  443. package/src/utils/resume-hint.ts +86 -0
  444. package/src/version.ts +1 -0
  445. package/tsconfig.json +8 -0
  446. package/vitest.config.ts +35 -0
@@ -0,0 +1,538 @@
1
+ /**
2
+ * TUI i18n Namespace Hook
3
+ *
4
+ * Provides internationalization support for TUI components.
5
+ * Wraps the translation system with the 'tui' namespace for type-safe access.
6
+ *
7
+ * @module tui/i18n/tui-namespace
8
+ */
9
+
10
+ import { useCallback, useMemo, useState } from "react";
11
+ import type { TranslationFunction, UseTUITranslationReturn } from "./types.js";
12
+
13
+ /**
14
+ * English translations (embedded for bundling compatibility).
15
+ */
16
+ const EN_TRANSLATIONS: Record<string, unknown> = {
17
+ status: {
18
+ model: "Model",
19
+ mode: "Mode",
20
+ tokens: "Tokens",
21
+ cost: "Cost",
22
+ ready: "Ready",
23
+ loading: "Loading...",
24
+ streaming: "Streaming...",
25
+ waiting: "Waiting for response...",
26
+ error: "Error",
27
+ idle: "Idle",
28
+ connected: "Connected",
29
+ disconnected: "Disconnected",
30
+ session: "Session",
31
+ elapsed: "Elapsed",
32
+ },
33
+ input: {
34
+ placeholder: "Type a message...",
35
+ multilinePlaceholder: "Type a message... (Shift+Enter for newline)",
36
+ commandHint: "Type / for commands",
37
+ emptyMessage: "Message cannot be empty",
38
+ submit: "Send",
39
+ cancel: "Cancel",
40
+ clear: "Clear",
41
+ },
42
+ permission: {
43
+ title: "Permission Required",
44
+ description: "The following action requires your approval:",
45
+ toolName: "Tool",
46
+ action: "Action",
47
+ allow: "Allow",
48
+ allowOnce: "Allow Once",
49
+ allowAlways: "Always Allow",
50
+ deny: "Deny",
51
+ denyAlways: "Always Deny",
52
+ abort: "Abort",
53
+ details: "Details",
54
+ reason: "Reason",
55
+ path: "Path",
56
+ command: "Command",
57
+ file: {
58
+ read: "Read file",
59
+ write: "Write file",
60
+ delete: "Delete file",
61
+ },
62
+ shell: {
63
+ execute: "Execute command",
64
+ },
65
+ mcp: {
66
+ connect: "Connect to MCP server",
67
+ call: "Call MCP tool",
68
+ },
69
+ },
70
+ vim: {
71
+ normal: "NORMAL",
72
+ insert: "INSERT",
73
+ visual: "VISUAL",
74
+ command: "COMMAND",
75
+ replace: "REPLACE",
76
+ modeIndicator: "Mode: {{mode}}",
77
+ },
78
+ messages: {
79
+ thinking: "Thinking...",
80
+ generating: "Generating...",
81
+ user: "You",
82
+ assistant: "Assistant",
83
+ system: "System",
84
+ error: "Error",
85
+ empty: "No messages yet",
86
+ copied: "Copied to clipboard",
87
+ copyFailed: "Failed to copy",
88
+ },
89
+ tools: {
90
+ executing: "Executing...",
91
+ completed: "Completed",
92
+ failed: "Failed",
93
+ pending: "Pending approval",
94
+ approved: "Approved",
95
+ rejected: "Rejected",
96
+ name: "Tool",
97
+ duration: "Duration",
98
+ result: "Result",
99
+ },
100
+ commands: {
101
+ help: "Show available commands",
102
+ clear: "Clear messages",
103
+ exit: "Exit application",
104
+ model: "Change model",
105
+ theme: "Change theme",
106
+ history: "Show history",
107
+ compact: "Toggle compact mode",
108
+ },
109
+ memory: {
110
+ title: "Memory",
111
+ empty: "No memories yet",
112
+ emptyHint: "Memories will appear here as the assistant learns",
113
+ entry: "entry",
114
+ entries: "entries",
115
+ created: "Created: ",
116
+ updated: "Updated: ",
117
+ tags: "Tags: ",
118
+ importance: "Importance: ",
119
+ keybindings: "j/k: navigate • Enter: select • g/G: top/bottom",
120
+ },
121
+ thinking: {
122
+ expandHint: "(press Enter to expand)",
123
+ collapseHint: "(press Enter to collapse)",
124
+ label: "Thinking...",
125
+ },
126
+ errors: {
127
+ connectionFailed: "Connection failed",
128
+ timeout: "Request timed out",
129
+ invalidInput: "Invalid input",
130
+ unknown: "An unknown error occurred",
131
+ },
132
+ common: {
133
+ yes: "Yes",
134
+ no: "No",
135
+ ok: "OK",
136
+ confirm: "Confirm",
137
+ retry: "Retry",
138
+ close: "Close",
139
+ loading: "Loading...",
140
+ processing: "Processing...",
141
+ },
142
+ language: {
143
+ current: "Current language: {{name}}",
144
+ available: "Available languages:",
145
+ switchedTo: "Switched to {{name}}",
146
+ autoDetect: "Language set to auto-detect ({{locale}})",
147
+ invalid: "Invalid language code: {{code}}",
148
+ invalidHint: "Available: {{codes}}",
149
+ saved: "Language preference saved",
150
+ },
151
+ onboarding: {
152
+ selectProvider: "Select your AI Provider:",
153
+ providerNav: "Use ↑/↓ to navigate, Enter to select",
154
+ apiKeyRequired: "(requires API key)",
155
+ noApiKeyNeeded: "(local, no key needed)",
156
+ selectMode: "Choose Your Coding Mode:",
157
+ modeNav: "Use ↑/↓ to navigate, Enter to select",
158
+ modeSwitchHint: "Tip: Use /mode command or Alt+1/2/3 to switch modes later",
159
+ },
160
+ providers: {
161
+ anthropic: {
162
+ name: "Anthropic",
163
+ shortcut: "[A]",
164
+ description: "Claude 4.5 Opus - Best for coding tasks",
165
+ },
166
+ openai: { name: "OpenAI", shortcut: "[O]", description: "GPT 5.2 - Versatile and powerful" },
167
+ google: {
168
+ name: "Google AI",
169
+ shortcut: "[G]",
170
+ description: "Gemini 3 Pro - Latest Google model",
171
+ },
172
+ mistral: { name: "Mistral AI", shortcut: "[M]", description: "Open weight models" },
173
+ groq: { name: "Groq", shortcut: "[R]", description: "Ultra-fast inference" },
174
+ openrouter: { name: "OpenRouter", shortcut: "[X]", description: "Multi-provider gateway" },
175
+ deepseek: { name: "DeepSeek", shortcut: "[D]", description: "DeepSeek-V3 - Chinese AI model" },
176
+ qwen: { name: "Qwen", shortcut: "[Q]", description: "Alibaba Qwen-72B" },
177
+ moonshot: { name: "Moonshot", shortcut: "[S]", description: "Moonshot-v1" },
178
+ ollama: { name: "Ollama", shortcut: "[L]", description: "Local models" },
179
+ },
180
+ };
181
+
182
+ /**
183
+ * Chinese translations (embedded for bundling compatibility).
184
+ */
185
+ const ZH_TRANSLATIONS: Record<string, unknown> = {
186
+ status: {
187
+ model: "模型",
188
+ mode: "模式",
189
+ tokens: "令牌",
190
+ cost: "费用",
191
+ ready: "就绪",
192
+ loading: "加载中...",
193
+ streaming: "流式输出中...",
194
+ waiting: "等待响应...",
195
+ error: "错误",
196
+ idle: "空闲",
197
+ connected: "已连接",
198
+ disconnected: "已断开",
199
+ session: "会话",
200
+ elapsed: "已用时间",
201
+ },
202
+ input: {
203
+ placeholder: "输入消息...",
204
+ multilinePlaceholder: "输入消息... (Shift+Enter 换行)",
205
+ commandHint: "输入 / 打开命令菜单",
206
+ emptyMessage: "消息不能为空",
207
+ submit: "发送",
208
+ cancel: "取消",
209
+ clear: "清除",
210
+ },
211
+ permission: {
212
+ title: "需要权限",
213
+ description: "以下操作需要您的批准:",
214
+ toolName: "工具",
215
+ action: "操作",
216
+ allow: "允许",
217
+ allowOnce: "允许一次",
218
+ allowAlways: "始终允许",
219
+ deny: "拒绝",
220
+ denyAlways: "始终拒绝",
221
+ abort: "中止",
222
+ details: "详情",
223
+ reason: "原因",
224
+ path: "路径",
225
+ command: "命令",
226
+ file: {
227
+ read: "读取文件",
228
+ write: "写入文件",
229
+ delete: "删除文件",
230
+ },
231
+ shell: {
232
+ execute: "执行命令",
233
+ },
234
+ mcp: {
235
+ connect: "连接 MCP 服务器",
236
+ call: "调用 MCP 工具",
237
+ },
238
+ },
239
+ vim: {
240
+ normal: "普通",
241
+ insert: "插入",
242
+ visual: "可视",
243
+ command: "命令",
244
+ replace: "替换",
245
+ modeIndicator: "模式: {{mode}}",
246
+ },
247
+ messages: {
248
+ thinking: "思考中...",
249
+ generating: "生成中...",
250
+ user: "你",
251
+ assistant: "助手",
252
+ system: "系统",
253
+ error: "错误",
254
+ empty: "暂无消息",
255
+ copied: "已复制到剪贴板",
256
+ copyFailed: "复制失败",
257
+ },
258
+ tools: {
259
+ executing: "执行中...",
260
+ completed: "已完成",
261
+ failed: "失败",
262
+ pending: "等待批准",
263
+ approved: "已批准",
264
+ rejected: "已拒绝",
265
+ name: "工具",
266
+ duration: "耗时",
267
+ result: "结果",
268
+ },
269
+ commands: {
270
+ help: "显示可用命令",
271
+ clear: "清除消息",
272
+ exit: "退出应用",
273
+ model: "切换模型",
274
+ theme: "切换主题",
275
+ history: "显示历史",
276
+ compact: "切换紧凑模式",
277
+ },
278
+ memory: {
279
+ title: "记忆",
280
+ empty: "暂无记忆",
281
+ emptyHint: "助手学习时记忆将显示在这里",
282
+ entry: "条",
283
+ entries: "条",
284
+ created: "创建时间:",
285
+ updated: "更新时间:",
286
+ tags: "标签:",
287
+ importance: "重要性:",
288
+ keybindings: "j/k: 导航 • Enter: 选择 • g/G: 顶部/底部",
289
+ },
290
+ thinking: {
291
+ expandHint: "(按 Enter 展开)",
292
+ collapseHint: "(按 Enter 折叠)",
293
+ label: "思考中...",
294
+ },
295
+ errors: {
296
+ connectionFailed: "连接失败",
297
+ timeout: "请求超时",
298
+ invalidInput: "无效输入",
299
+ unknown: "发生未知错误",
300
+ },
301
+ common: {
302
+ yes: "是",
303
+ no: "否",
304
+ ok: "确定",
305
+ confirm: "确认",
306
+ retry: "重试",
307
+ close: "关闭",
308
+ loading: "加载中...",
309
+ processing: "处理中...",
310
+ },
311
+ language: {
312
+ current: "当前语言: {{name}}",
313
+ available: "可用语言:",
314
+ switchedTo: "已切换到 {{name}}",
315
+ autoDetect: "语言设置为自动检测 ({{locale}})",
316
+ invalid: "无效的语言代码: {{code}}",
317
+ invalidHint: "可用: {{codes}}",
318
+ saved: "语言偏好已保存",
319
+ },
320
+ onboarding: {
321
+ selectProvider: "选择您的 AI 提供商:",
322
+ providerNav: "使用 ↑/↓ 导航,Enter 选择",
323
+ apiKeyRequired: "(需要 API 密钥)",
324
+ noApiKeyNeeded: "(本地运行,无需密钥)",
325
+ selectMode: "选择编码模式:",
326
+ modeNav: "使用 ↑/↓ 导航,Enter 选择",
327
+ modeSwitchHint: "提示:之后可使用 /mode 命令或 Alt+1/2/3 快捷键切换模式",
328
+ },
329
+ providers: {
330
+ anthropic: {
331
+ name: "Anthropic",
332
+ shortcut: "[A]",
333
+ description: "Claude 4.5 Opus - 最适合编程任务",
334
+ },
335
+ openai: { name: "OpenAI", shortcut: "[O]", description: "GPT 5.2 - 多功能且强大" },
336
+ google: { name: "Google AI", shortcut: "[G]", description: "Gemini 3 Pro - 最新谷歌模型" },
337
+ mistral: { name: "Mistral AI", shortcut: "[M]", description: "开源权重模型" },
338
+ groq: { name: "Groq", shortcut: "[R]", description: "超快推理" },
339
+ openrouter: { name: "OpenRouter", shortcut: "[X]", description: "多提供商网关" },
340
+ deepseek: { name: "DeepSeek", shortcut: "[D]", description: "DeepSeek-V3 - 中国 AI 模型" },
341
+ qwen: { name: "Qwen", shortcut: "[Q]", description: "阿里巴巴 Qwen-72B" },
342
+ moonshot: { name: "Moonshot", shortcut: "[S]", description: "Moonshot-v1" },
343
+ ollama: { name: "Ollama", shortcut: "[L]", description: "本地模型" },
344
+ },
345
+ };
346
+
347
+ /**
348
+ * Available locales and their translations.
349
+ */
350
+ const TRANSLATIONS: Record<string, Record<string, unknown>> = {
351
+ en: EN_TRANSLATIONS,
352
+ zh: ZH_TRANSLATIONS,
353
+ };
354
+
355
+ /**
356
+ * List of available locale codes.
357
+ */
358
+ const AVAILABLE_LOCALES = Object.keys(TRANSLATIONS) as readonly string[];
359
+
360
+ /**
361
+ * Default locale when none is specified.
362
+ */
363
+ const DEFAULT_LOCALE = "en";
364
+
365
+ /**
366
+ * Global locale state for the application.
367
+ * In a full implementation, this would be managed by a context provider.
368
+ */
369
+ let globalLocale = DEFAULT_LOCALE;
370
+
371
+ /**
372
+ * Get a nested value from an object using dot notation.
373
+ *
374
+ * @param obj - The object to traverse
375
+ * @param path - Dot-notation path (e.g., "status.model")
376
+ * @returns The value at the path, or undefined if not found
377
+ */
378
+ function getNestedValue(obj: Record<string, unknown>, path: string): string | undefined {
379
+ const keys = path.split(".");
380
+ let current: unknown = obj;
381
+
382
+ for (const key of keys) {
383
+ if (current === null || current === undefined || typeof current !== "object") {
384
+ return undefined;
385
+ }
386
+ current = (current as Record<string, unknown>)[key];
387
+ }
388
+
389
+ return typeof current === "string" ? current : undefined;
390
+ }
391
+
392
+ /**
393
+ * Interpolate variables in a translation string.
394
+ *
395
+ * @param template - The translation template with {{variable}} placeholders
396
+ * @param values - Object containing variable values
397
+ * @returns Interpolated string
398
+ *
399
+ * @example
400
+ * interpolate("Mode: {{mode}}", { mode: "NORMAL" }) // → "Mode: NORMAL"
401
+ */
402
+ function interpolate(template: string, values?: Record<string, string | number>): string {
403
+ if (!values) return template;
404
+
405
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key: string) => {
406
+ const value = values[key];
407
+ return value !== undefined ? String(value) : `{{${key}}}`;
408
+ });
409
+ }
410
+
411
+ /**
412
+ * Create a translation function for a specific locale.
413
+ *
414
+ * @param locale - The locale to use
415
+ * @returns Translation function
416
+ */
417
+ function createTranslationFunction(locale: string): TranslationFunction {
418
+ const translations = TRANSLATIONS[locale] ?? TRANSLATIONS[DEFAULT_LOCALE];
419
+ const fallback = TRANSLATIONS[DEFAULT_LOCALE];
420
+
421
+ return (key: string, options?: Record<string, string | number>): string => {
422
+ // Try current locale first
423
+ let value = translations ? getNestedValue(translations, key) : undefined;
424
+
425
+ // Fall back to default locale if not found
426
+ if (value === undefined && fallback) {
427
+ value = getNestedValue(fallback, key);
428
+ }
429
+
430
+ // Return key if no translation found
431
+ if (value === undefined) {
432
+ return key;
433
+ }
434
+
435
+ // Interpolate any variables
436
+ return interpolate(value, options);
437
+ };
438
+ }
439
+
440
+ /**
441
+ * Hook for accessing TUI translations.
442
+ *
443
+ * Provides a type-safe translation function scoped to the 'tui' namespace.
444
+ * Includes locale management and fallback support.
445
+ *
446
+ * @returns Translation utilities for TUI components
447
+ *
448
+ * @example
449
+ * ```tsx
450
+ * function StatusBar() {
451
+ * const { t } = useTUITranslation();
452
+ *
453
+ * return (
454
+ * <Box>
455
+ * <Text>{t('status.model')}: GPT-4</Text>
456
+ * <Text>{t('vim.modeIndicator', { mode: 'NORMAL' })}</Text>
457
+ * </Box>
458
+ * );
459
+ * }
460
+ * ```
461
+ *
462
+ * @example
463
+ * ```tsx
464
+ * function LanguageSwitcher() {
465
+ * const { locale, changeLocale, availableLocales } = useTUITranslation();
466
+ *
467
+ * return (
468
+ * <Select
469
+ * value={locale}
470
+ * onChange={(value) => changeLocale(value)}
471
+ * options={availableLocales.map(l => ({ label: l, value: l }))}
472
+ * />
473
+ * );
474
+ * }
475
+ * ```
476
+ */
477
+ export function useTUITranslation(): UseTUITranslationReturn {
478
+ // Local state to trigger re-renders on locale change
479
+ const [locale, setLocale] = useState(globalLocale);
480
+
481
+ // Create memoized translation function
482
+ const t = useMemo(() => createTranslationFunction(locale), [locale]);
483
+
484
+ // Change locale callback
485
+ const changeLocale = useCallback((newLocale: string) => {
486
+ if (AVAILABLE_LOCALES.includes(newLocale)) {
487
+ globalLocale = newLocale;
488
+ setLocale(newLocale);
489
+ }
490
+ }, []);
491
+
492
+ // Check if locale is available
493
+ const isLocaleAvailable = useCallback((checkLocale: string) => {
494
+ return AVAILABLE_LOCALES.includes(checkLocale);
495
+ }, []);
496
+
497
+ return {
498
+ t,
499
+ locale,
500
+ changeLocale,
501
+ isLocaleAvailable,
502
+ availableLocales: AVAILABLE_LOCALES,
503
+ };
504
+ }
505
+
506
+ /**
507
+ * Set the global locale without using the hook.
508
+ * Useful for initialization before React renders.
509
+ *
510
+ * @param locale - The locale to set
511
+ */
512
+ export function setGlobalLocale(locale: string): void {
513
+ if (AVAILABLE_LOCALES.includes(locale)) {
514
+ globalLocale = locale;
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Get the current global locale.
520
+ *
521
+ * @returns Current locale code
522
+ */
523
+ export function getGlobalLocale(): string {
524
+ return globalLocale;
525
+ }
526
+
527
+ /**
528
+ * Get a translation directly without using the hook.
529
+ * Useful for non-React code or server-side rendering.
530
+ *
531
+ * @param key - Translation key
532
+ * @param options - Interpolation values
533
+ * @returns Translated string
534
+ */
535
+ export function translate(key: string, options?: Record<string, string | number>): string {
536
+ const t = createTranslationFunction(globalLocale);
537
+ return t(key, options);
538
+ }