@ai-agent-forge/agent-forge 0.86.7 → 0.87.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 (665) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +8 -9
  3. package/dist/artifacts/artifact-store.d.ts.map +1 -1
  4. package/dist/artifacts/artifact-store.js +9 -5
  5. package/dist/artifacts/artifact-store.js.map +1 -1
  6. package/dist/bundle/.build-manifest.json +410 -371
  7. package/dist/bundle/chunks/{chunk-A7GUOX2H.js → chunk-6ZKDNZHA.js} +5 -1
  8. package/dist/bundle/chunks/chunk-BFC2BDVJ.js +13 -0
  9. package/dist/bundle/chunks/chunk-MOHOLL3F.js +1456 -0
  10. package/dist/bundle/chunks/image-resize-worker.js +12 -1
  11. package/dist/bundle/chunks/{virtual-modules-3IZ4MYSQ.js → virtual-modules-KZ5DRH7Q.js} +1 -1
  12. package/dist/bundle/cli.js +1 -1
  13. package/dist/bundle/client.js +1 -1
  14. package/dist/bundle/index.js +2 -2
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/cli/args.d.ts.map +1 -1
  17. package/dist/cli/args.js +231 -185
  18. package/dist/cli/args.js.map +1 -1
  19. package/dist/cli/auth-check.d.ts.map +1 -1
  20. package/dist/cli/auth-check.js +3 -2
  21. package/dist/cli/auth-check.js.map +1 -1
  22. package/dist/cli/auth-command.d.ts.map +1 -1
  23. package/dist/cli/auth-command.js +15 -9
  24. package/dist/cli/auth-command.js.map +1 -1
  25. package/dist/cli/credential-print.d.ts.map +1 -1
  26. package/dist/cli/credential-print.js +14 -7
  27. package/dist/cli/credential-print.js.map +1 -1
  28. package/dist/cli/experimental/command.d.ts.map +1 -1
  29. package/dist/cli/experimental/command.js +6 -5
  30. package/dist/cli/experimental/command.js.map +1 -1
  31. package/dist/cli/list-models.d.ts.map +1 -1
  32. package/dist/cli/list-models.js +9 -8
  33. package/dist/cli/list-models.js.map +1 -1
  34. package/dist/cli/plugin-manager-controller.d.ts.map +1 -1
  35. package/dist/cli/plugin-manager-controller.js +2 -1
  36. package/dist/cli/plugin-manager-controller.js.map +1 -1
  37. package/dist/cli/serve.d.ts.map +1 -1
  38. package/dist/cli/serve.js +8 -5
  39. package/dist/cli/serve.js.map +1 -1
  40. package/dist/client/remote-session.d.ts.map +1 -1
  41. package/dist/client/remote-session.js +16 -9
  42. package/dist/client/remote-session.js.map +1 -1
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +2 -1
  45. package/dist/config.js.map +1 -1
  46. package/dist/core/agent-capability-contract.d.ts +0 -7
  47. package/dist/core/agent-capability-contract.d.ts.map +1 -1
  48. package/dist/core/agent-capability-contract.js +72 -68
  49. package/dist/core/agent-capability-contract.js.map +1 -1
  50. package/dist/core/agent-session-bash.d.ts.map +1 -1
  51. package/dist/core/agent-session-bash.js +5 -4
  52. package/dist/core/agent-session-bash.js.map +1 -1
  53. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  54. package/dist/core/agent-session-compaction.js +28 -22
  55. package/dist/core/agent-session-compaction.js.map +1 -1
  56. package/dist/core/agent-session-context.d.ts.map +1 -1
  57. package/dist/core/agent-session-context.js +18 -13
  58. package/dist/core/agent-session-context.js.map +1 -1
  59. package/dist/core/agent-session-model.d.ts.map +1 -1
  60. package/dist/core/agent-session-model.js +2 -1
  61. package/dist/core/agent-session-model.js.map +1 -1
  62. package/dist/core/agent-session-retry.d.ts.map +1 -1
  63. package/dist/core/agent-session-retry.js +3 -2
  64. package/dist/core/agent-session-retry.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  66. package/dist/core/agent-session-runtime.js +7 -6
  67. package/dist/core/agent-session-runtime.js.map +1 -1
  68. package/dist/core/agent-session-services.d.ts +1 -1
  69. package/dist/core/agent-session-services.d.ts.map +1 -1
  70. package/dist/core/agent-session-services.js.map +1 -1
  71. package/dist/core/agent-session-tools.d.ts.map +1 -1
  72. package/dist/core/agent-session-tools.js +3 -2
  73. package/dist/core/agent-session-tools.js.map +1 -1
  74. package/dist/core/agent-session.d.ts +40 -2
  75. package/dist/core/agent-session.d.ts.map +1 -1
  76. package/dist/core/agent-session.js +142 -34
  77. package/dist/core/agent-session.js.map +1 -1
  78. package/dist/core/auth-guidance.d.ts.map +1 -1
  79. package/dist/core/auth-guidance.js +11 -5
  80. package/dist/core/auth-guidance.js.map +1 -1
  81. package/dist/core/auth-storage.d.ts.map +1 -1
  82. package/dist/core/auth-storage.js +9 -6
  83. package/dist/core/auth-storage.js.map +1 -1
  84. package/dist/core/compaction/compaction.d.ts.map +1 -1
  85. package/dist/core/compaction/compaction.js +2 -1
  86. package/dist/core/compaction/compaction.js.map +1 -1
  87. package/dist/core/embedded-sdk.d.ts.map +1 -1
  88. package/dist/core/embedded-sdk.js +10 -6
  89. package/dist/core/embedded-sdk.js.map +1 -1
  90. package/dist/core/export-html/index.d.ts.map +1 -1
  91. package/dist/core/export-html/index.js +9 -4
  92. package/dist/core/export-html/index.js.map +1 -1
  93. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  94. package/dist/core/extensions/agent-composition.js +26 -19
  95. package/dist/core/extensions/agent-composition.js.map +1 -1
  96. package/dist/core/extensions/bootstrap-agent-loop.d.ts.map +1 -1
  97. package/dist/core/extensions/bootstrap-agent-loop.js +3 -2
  98. package/dist/core/extensions/bootstrap-agent-loop.js.map +1 -1
  99. package/dist/core/extensions/bootstrap-lifecycle.d.ts.map +1 -1
  100. package/dist/core/extensions/bootstrap-lifecycle.js +20 -17
  101. package/dist/core/extensions/bootstrap-lifecycle.js.map +1 -1
  102. package/dist/core/extensions/bootstrap-overflow-policy.d.ts.map +1 -1
  103. package/dist/core/extensions/bootstrap-overflow-policy.js +2 -1
  104. package/dist/core/extensions/bootstrap-overflow-policy.js.map +1 -1
  105. package/dist/core/extensions/bootstrap-retry-policy.d.ts.map +1 -1
  106. package/dist/core/extensions/bootstrap-retry-policy.js +2 -1
  107. package/dist/core/extensions/bootstrap-retry-policy.js.map +1 -1
  108. package/dist/core/extensions/bootstrap-skills.d.ts.map +1 -1
  109. package/dist/core/extensions/bootstrap-skills.js +7 -6
  110. package/dist/core/extensions/bootstrap-skills.js.map +1 -1
  111. package/dist/core/extensions/bootstrap-tools.d.ts.map +1 -1
  112. package/dist/core/extensions/bootstrap-tools.js +2 -1
  113. package/dist/core/extensions/bootstrap-tools.js.map +1 -1
  114. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  115. package/dist/core/extensions/capability-plugin.js +37 -13
  116. package/dist/core/extensions/capability-plugin.js.map +1 -1
  117. package/dist/core/extensions/capability-runtime-events.d.ts.map +1 -1
  118. package/dist/core/extensions/capability-runtime-events.js +17 -13
  119. package/dist/core/extensions/capability-runtime-events.js.map +1 -1
  120. package/dist/core/extensions/capability-runtime-guards.d.ts.map +1 -1
  121. package/dist/core/extensions/capability-runtime-guards.js +16 -15
  122. package/dist/core/extensions/capability-runtime-guards.js.map +1 -1
  123. package/dist/core/extensions/capability-runtime-manifest.d.ts.map +1 -1
  124. package/dist/core/extensions/capability-runtime-manifest.js +52 -30
  125. package/dist/core/extensions/capability-runtime-manifest.js.map +1 -1
  126. package/dist/core/extensions/capability-runtime-validation.d.ts.map +1 -1
  127. package/dist/core/extensions/capability-runtime-validation.js +66 -65
  128. package/dist/core/extensions/capability-runtime-validation.js.map +1 -1
  129. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  130. package/dist/core/extensions/capability-runtime.js +147 -127
  131. package/dist/core/extensions/capability-runtime.js.map +1 -1
  132. package/dist/core/extensions/compaction-memory-failure-mode.d.ts.map +1 -1
  133. package/dist/core/extensions/compaction-memory-failure-mode.js +3 -2
  134. package/dist/core/extensions/compaction-memory-failure-mode.js.map +1 -1
  135. package/dist/core/extensions/context-strategy-binding.d.ts.map +1 -1
  136. package/dist/core/extensions/context-strategy-binding.js +7 -4
  137. package/dist/core/extensions/context-strategy-binding.js.map +1 -1
  138. package/dist/core/extensions/lifecycle-catalog.d.ts.map +1 -1
  139. package/dist/core/extensions/lifecycle-catalog.js +290 -279
  140. package/dist/core/extensions/lifecycle-catalog.js.map +1 -1
  141. package/dist/core/extensions/lifecycle-delivery-queue.d.ts.map +1 -1
  142. package/dist/core/extensions/lifecycle-delivery-queue.js +3 -2
  143. package/dist/core/extensions/lifecycle-delivery-queue.js.map +1 -1
  144. package/dist/core/facade/coding-agent-facade.d.ts +6 -0
  145. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  146. package/dist/core/facade/coding-agent-facade.js +2 -0
  147. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  148. package/dist/core/http-dispatcher.d.ts.map +1 -1
  149. package/dist/core/http-dispatcher.js +2 -1
  150. package/dist/core/http-dispatcher.js.map +1 -1
  151. package/dist/core/i18n/index.d.ts +14 -0
  152. package/dist/core/i18n/index.d.ts.map +1 -0
  153. package/dist/core/i18n/index.js +67 -0
  154. package/dist/core/i18n/index.js.map +1 -0
  155. package/dist/core/i18n/locales/en/example.d.ts +7 -0
  156. package/dist/core/i18n/locales/en/example.d.ts.map +1 -0
  157. package/dist/core/i18n/locales/en/example.js +7 -0
  158. package/dist/core/i18n/locales/en/example.js.map +1 -0
  159. package/dist/core/i18n/locales/zh-cn/cli.d.ts +8 -0
  160. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -0
  161. package/dist/core/i18n/locales/zh-cn/cli.js +227 -0
  162. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -0
  163. package/dist/core/i18n/locales/zh-cn/common.d.ts +6 -0
  164. package/dist/core/i18n/locales/zh-cn/common.d.ts.map +1 -0
  165. package/dist/core/i18n/locales/zh-cn/common.js +6 -0
  166. package/dist/core/i18n/locales/zh-cn/common.js.map +1 -0
  167. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts +13 -0
  168. package/dist/core/i18n/locales/zh-cn/core-contract-core.d.ts.map +1 -0
  169. package/dist/core/i18n/locales/zh-cn/core-contract-core.js +173 -0
  170. package/dist/core/i18n/locales/zh-cn/core-contract-core.js.map +1 -0
  171. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts +12 -0
  172. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.d.ts.map +1 -0
  173. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js +582 -0
  174. package/dist/core/i18n/locales/zh-cn/core-contract-extensions.js.map +1 -0
  175. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +9 -0
  176. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -0
  177. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +55 -0
  178. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -0
  179. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts +11 -0
  180. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -0
  181. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +455 -0
  182. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -0
  183. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts +9 -0
  184. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -0
  185. package/dist/core/i18n/locales/zh-cn/core-errors.js +191 -0
  186. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -0
  187. package/dist/core/i18n/locales/zh-cn/example.d.ts +7 -0
  188. package/dist/core/i18n/locales/zh-cn/example.d.ts.map +1 -0
  189. package/dist/core/i18n/locales/zh-cn/example.js +10 -0
  190. package/dist/core/i18n/locales/zh-cn/example.js.map +1 -0
  191. package/dist/core/i18n/locales/zh-cn/index.d.ts +2 -0
  192. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -0
  193. package/dist/core/i18n/locales/zh-cn/index.js +41 -0
  194. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -0
  195. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts +10 -0
  196. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -0
  197. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +265 -0
  198. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -0
  199. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts +11 -0
  200. package/dist/core/i18n/locales/zh-cn/keybindings.d.ts.map +1 -0
  201. package/dist/core/i18n/locales/zh-cn/keybindings.js +67 -0
  202. package/dist/core/i18n/locales/zh-cn/keybindings.js.map +1 -0
  203. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts +7 -0
  204. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -0
  205. package/dist/core/i18n/locales/zh-cn/slash-commands.js +39 -0
  206. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -0
  207. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts +10 -0
  208. package/dist/core/i18n/locales/zh-cn/tui-builtin.d.ts.map +1 -0
  209. package/dist/core/i18n/locales/zh-cn/tui-builtin.js +15 -0
  210. package/dist/core/i18n/locales/zh-cn/tui-builtin.js.map +1 -0
  211. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts +13 -0
  212. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -0
  213. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +102 -0
  214. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -0
  215. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts +12 -0
  216. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.d.ts.map +1 -0
  217. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js +288 -0
  218. package/dist/core/i18n/locales/zh-cn/tui-components-selectors.js.map +1 -0
  219. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts +9 -0
  220. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.d.ts.map +1 -0
  221. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js +79 -0
  222. package/dist/core/i18n/locales/zh-cn/tui-interactive-misc.js.map +1 -0
  223. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts +8 -0
  224. package/dist/core/i18n/locales/zh-cn/tui-self-owned.d.ts.map +1 -0
  225. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js +72 -0
  226. package/dist/core/i18n/locales/zh-cn/tui-self-owned.js.map +1 -0
  227. package/dist/core/keybindings.d.ts +15 -0
  228. package/dist/core/keybindings.d.ts.map +1 -1
  229. package/dist/core/keybindings.js +18 -0
  230. package/dist/core/keybindings.js.map +1 -1
  231. package/dist/core/logger.d.ts.map +1 -1
  232. package/dist/core/logger.js +5 -1
  233. package/dist/core/logger.js.map +1 -1
  234. package/dist/core/model-registry.d.ts.map +1 -1
  235. package/dist/core/model-registry.js +2 -1
  236. package/dist/core/model-registry.js.map +1 -1
  237. package/dist/core/model-runtime.d.ts.map +1 -1
  238. package/dist/core/model-runtime.js +8 -4
  239. package/dist/core/model-runtime.js.map +1 -1
  240. package/dist/core/package-install-host.d.ts.map +1 -1
  241. package/dist/core/package-install-host.js +4 -3
  242. package/dist/core/package-install-host.js.map +1 -1
  243. package/dist/core/package-manager.d.ts.map +1 -1
  244. package/dist/core/package-manager.js +15 -10
  245. package/dist/core/package-manager.js.map +1 -1
  246. package/dist/core/package-resource-collection.d.ts.map +1 -1
  247. package/dist/core/package-resource-collection.js +2 -1
  248. package/dist/core/package-resource-collection.js.map +1 -1
  249. package/dist/core/package-source.d.ts.map +1 -1
  250. package/dist/core/package-source.js +3 -2
  251. package/dist/core/package-source.js.map +1 -1
  252. package/dist/core/provider-composer.d.ts.map +1 -1
  253. package/dist/core/provider-composer.js +22 -13
  254. package/dist/core/provider-composer.js.map +1 -1
  255. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  256. package/dist/core/remote-catalog-provider.js +6 -2
  257. package/dist/core/remote-catalog-provider.js.map +1 -1
  258. package/dist/core/resolve-config-value.d.ts.map +1 -1
  259. package/dist/core/resolve-config-value.js +15 -5
  260. package/dist/core/resolve-config-value.js.map +1 -1
  261. package/dist/core/sdk.d.ts +19 -5
  262. package/dist/core/sdk.d.ts.map +1 -1
  263. package/dist/core/sdk.js +74 -54
  264. package/dist/core/sdk.js.map +1 -1
  265. package/dist/core/session-cwd.d.ts.map +1 -1
  266. package/dist/core/session-cwd.js +5 -2
  267. package/dist/core/session-cwd.js.map +1 -1
  268. package/dist/core/session-export.d.ts.map +1 -1
  269. package/dist/core/session-export.js +2 -1
  270. package/dist/core/session-export.js.map +1 -1
  271. package/dist/core/session-manager.d.ts.map +1 -1
  272. package/dist/core/session-manager.js +39 -29
  273. package/dist/core/session-manager.js.map +1 -1
  274. package/dist/core/session-storage.d.ts.map +1 -1
  275. package/dist/core/session-storage.js +3 -3
  276. package/dist/core/session-storage.js.map +1 -1
  277. package/dist/core/settings-manager.d.ts +11 -0
  278. package/dist/core/settings-manager.d.ts.map +1 -1
  279. package/dist/core/settings-manager.js +27 -5
  280. package/dist/core/settings-manager.js.map +1 -1
  281. package/dist/core/slash-commands.d.ts.map +1 -1
  282. package/dist/core/slash-commands.js +53 -32
  283. package/dist/core/slash-commands.js.map +1 -1
  284. package/dist/core/system-prompt.d.ts.map +1 -1
  285. package/dist/core/system-prompt.js +25 -2
  286. package/dist/core/system-prompt.js.map +1 -1
  287. package/dist/core/tools/bash.d.ts.map +1 -1
  288. package/dist/core/tools/bash.js +11 -7
  289. package/dist/core/tools/bash.js.map +1 -1
  290. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  291. package/dist/core/tools/edit-diff.js +9 -4
  292. package/dist/core/tools/edit-diff.js.map +1 -1
  293. package/dist/core/tools/edit.d.ts.map +1 -1
  294. package/dist/core/tools/edit.js +4 -3
  295. package/dist/core/tools/edit.js.map +1 -1
  296. package/dist/core/tools/index.d.ts.map +1 -1
  297. package/dist/core/tools/index.js +3 -2
  298. package/dist/core/tools/index.js.map +1 -1
  299. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  300. package/dist/core/tools/output-accumulator.js +2 -1
  301. package/dist/core/tools/output-accumulator.js.map +1 -1
  302. package/dist/core/tools/read.d.ts.map +1 -1
  303. package/dist/core/tools/read.js +6 -2
  304. package/dist/core/tools/read.js.map +1 -1
  305. package/dist/core/tools/write.d.ts.map +1 -1
  306. package/dist/core/tools/write.js +2 -1
  307. package/dist/core/tools/write.js.map +1 -1
  308. package/dist/durable/durable-service.d.ts.map +1 -1
  309. package/dist/durable/durable-service.js +25 -18
  310. package/dist/durable/durable-service.js.map +1 -1
  311. package/dist/host/checkpoint-commit.d.ts.map +1 -1
  312. package/dist/host/checkpoint-commit.js +2 -1
  313. package/dist/host/checkpoint-commit.js.map +1 -1
  314. package/dist/host/manual-compaction.d.ts.map +1 -1
  315. package/dist/host/manual-compaction.js +2 -1
  316. package/dist/host/manual-compaction.js.map +1 -1
  317. package/dist/host/output-projection.d.ts +0 -13
  318. package/dist/host/output-projection.d.ts.map +1 -1
  319. package/dist/host/output-projection.js +16 -2
  320. package/dist/host/output-projection.js.map +1 -1
  321. package/dist/host/summary-retry.d.ts.map +1 -1
  322. package/dist/host/summary-retry.js +3 -2
  323. package/dist/host/summary-retry.js.map +1 -1
  324. package/dist/main.d.ts.map +1 -1
  325. package/dist/main.js +94 -58
  326. package/dist/main.js.map +1 -1
  327. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/agents-view.js +18 -15
  329. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  330. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/assistant-message.js +6 -5
  332. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  333. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/bash-execution.js +12 -7
  335. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  336. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/bordered-loader.js +2 -1
  338. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  339. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/branch-summary-message.js +6 -5
  341. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  342. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  343. package/dist/modes/interactive/components/compaction-summary-message.js +9 -5
  344. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  345. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/config-selector.js +18 -15
  347. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  349. package/dist/modes/interactive/components/custom-entry.js +2 -1
  350. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  351. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/dialog-editor.js +5 -4
  353. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  354. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/dialog-input.js +2 -1
  356. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  357. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  358. package/dist/modes/interactive/components/dialog-selector.js +4 -3
  359. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/first-time-setup.js +11 -10
  362. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  363. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/footer.js +7 -4
  365. package/dist/modes/interactive/components/footer.js.map +1 -1
  366. package/dist/modes/interactive/components/index.d.ts +1 -0
  367. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  368. package/dist/modes/interactive/components/index.js +1 -0
  369. package/dist/modes/interactive/components/index.js.map +1 -1
  370. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/keybinding-hints.js +3 -2
  372. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  373. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/login-dialog.js +12 -11
  375. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  376. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/mermaid.js +6 -2
  378. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  379. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/model-selector.js +28 -16
  381. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/oauth-selector.js +10 -9
  384. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/plugin-manager-entry.js +22 -13
  387. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  388. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/plugin-selection-entry.js +27 -12
  390. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  391. package/dist/modes/interactive/components/queue-manager-selector.d.ts +60 -0
  392. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -0
  393. package/dist/modes/interactive/components/queue-manager-selector.js +166 -0
  394. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -0
  395. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  396. package/dist/modes/interactive/components/scoped-models-selector.js +16 -14
  397. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  398. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/session-selector.js +43 -31
  400. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  401. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  402. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/settings-selector.js +113 -96
  404. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  405. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  406. package/dist/modes/interactive/components/settings-submenu.js +5 -4
  407. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  408. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/show-images-selector.js +3 -2
  410. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  411. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  412. package/dist/modes/interactive/components/skill-invocation-message.js +4 -3
  413. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  414. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/status-indicator.js +14 -5
  416. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  417. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/theme-selector.js +2 -1
  419. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  420. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/thinking-selector.js +11 -4
  422. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  423. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/tool-execution.js +8 -3
  425. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  426. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/tree-list.js +7 -6
  428. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  429. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/tree-render.js +28 -23
  431. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  432. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/tree-selector.js +9 -7
  434. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  435. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  436. package/dist/modes/interactive/components/user-message-selector.js +5 -4
  437. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  438. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  439. package/dist/modes/interactive/components/workflow-view.js +36 -21
  440. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  441. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  442. package/dist/modes/interactive/external-editor.js +2 -1
  443. package/dist/modes/interactive/external-editor.js.map +1 -1
  444. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  445. package/dist/modes/interactive/interactive-auth.js +71 -40
  446. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  447. package/dist/modes/interactive/interactive-commands.d.ts +1 -0
  448. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  449. package/dist/modes/interactive/interactive-commands.js +3 -0
  450. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  451. package/dist/modes/interactive/interactive-dialog-ui.d.ts.map +1 -1
  452. package/dist/modes/interactive/interactive-dialog-ui.js +5 -5
  453. package/dist/modes/interactive/interactive-dialog-ui.js.map +1 -1
  454. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  455. package/dist/modes/interactive/interactive-format.js +34 -18
  456. package/dist/modes/interactive/interactive-format.js.map +1 -1
  457. package/dist/modes/interactive/interactive-helpers.d.ts.map +1 -1
  458. package/dist/modes/interactive/interactive-helpers.js +7 -2
  459. package/dist/modes/interactive/interactive-helpers.js.map +1 -1
  460. package/dist/modes/interactive/interactive-mode.d.ts +4 -1
  461. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  462. package/dist/modes/interactive/interactive-mode.js +327 -243
  463. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  464. package/dist/modes/interactive/interactive-selectors.d.ts +9 -0
  465. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  466. package/dist/modes/interactive/interactive-selectors.js +79 -25
  467. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  468. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  469. package/dist/modes/interactive/theme/theme-controller.js +5 -1
  470. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  471. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  472. package/dist/modes/interactive/theme/theme.js +26 -23
  473. package/dist/modes/interactive/theme/theme.js.map +1 -1
  474. package/dist/modes/json-event.d.ts.map +1 -1
  475. package/dist/modes/json-event.js +3 -2
  476. package/dist/modes/json-event.js.map +1 -1
  477. package/dist/modes/print-mode.d.ts.map +1 -1
  478. package/dist/modes/print-mode.js +3 -2
  479. package/dist/modes/print-mode.js.map +1 -1
  480. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  481. package/dist/modes/rpc/rpc-client.js +3 -2
  482. package/dist/modes/rpc/rpc-client.js.map +1 -1
  483. package/dist/package-manager-cli.d.ts.map +1 -1
  484. package/dist/package-manager-cli.js +28 -13
  485. package/dist/package-manager-cli.js.map +1 -1
  486. package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
  487. package/dist/plugins/ecosystem/catalog.js +3 -2
  488. package/dist/plugins/ecosystem/catalog.js.map +1 -1
  489. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  490. package/dist/plugins/ecosystem/cli.js +2 -1
  491. package/dist/plugins/ecosystem/cli.js.map +1 -1
  492. package/dist/plugins/ecosystem/default-plugin-market.d.ts.map +1 -1
  493. package/dist/plugins/ecosystem/default-plugin-market.js +3 -2
  494. package/dist/plugins/ecosystem/default-plugin-market.js.map +1 -1
  495. package/dist/plugins/ecosystem/distribution.d.ts.map +1 -1
  496. package/dist/plugins/ecosystem/distribution.js +2 -1
  497. package/dist/plugins/ecosystem/distribution.js.map +1 -1
  498. package/dist/plugins/ecosystem/installer.d.ts.map +1 -1
  499. package/dist/plugins/ecosystem/installer.js +3 -2
  500. package/dist/plugins/ecosystem/installer.js.map +1 -1
  501. package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
  502. package/dist/plugins/ecosystem/node-disk-registry-source.js +20 -17
  503. package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
  504. package/dist/plugins/ecosystem/node-distribution-host.d.ts.map +1 -1
  505. package/dist/plugins/ecosystem/node-distribution-host.js +35 -34
  506. package/dist/plugins/ecosystem/node-distribution-host.js.map +1 -1
  507. package/dist/plugins/ecosystem/node-npm-registry-source.d.ts.map +1 -1
  508. package/dist/plugins/ecosystem/node-npm-registry-source.js +35 -34
  509. package/dist/plugins/ecosystem/node-npm-registry-source.js.map +1 -1
  510. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  511. package/dist/plugins/ecosystem/node-package-install-host.js +9 -8
  512. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  513. package/dist/plugins/ecosystem/node-package-install-persistence.d.ts.map +1 -1
  514. package/dist/plugins/ecosystem/node-package-install-persistence.js +4 -3
  515. package/dist/plugins/ecosystem/node-package-install-persistence.js.map +1 -1
  516. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  517. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +21 -5
  518. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  519. package/dist/plugins/ecosystem/node-plugin-trust-root.d.ts.map +1 -1
  520. package/dist/plugins/ecosystem/node-plugin-trust-root.js +10 -9
  521. package/dist/plugins/ecosystem/node-plugin-trust-root.js.map +1 -1
  522. package/dist/plugins/ecosystem/node-registry-source.d.ts.map +1 -1
  523. package/dist/plugins/ecosystem/node-registry-source.js +31 -30
  524. package/dist/plugins/ecosystem/node-registry-source.js.map +1 -1
  525. package/dist/plugins/ecosystem/node-release-package-source.d.ts.map +1 -1
  526. package/dist/plugins/ecosystem/node-release-package-source.js +30 -29
  527. package/dist/plugins/ecosystem/node-release-package-source.js.map +1 -1
  528. package/dist/plugins/ecosystem/node-tar-writer.d.ts.map +1 -1
  529. package/dist/plugins/ecosystem/node-tar-writer.js +11 -10
  530. package/dist/plugins/ecosystem/node-tar-writer.js.map +1 -1
  531. package/dist/plugins/ecosystem/node-url-package-source.d.ts.map +1 -1
  532. package/dist/plugins/ecosystem/node-url-package-source.js +21 -20
  533. package/dist/plugins/ecosystem/node-url-package-source.js.map +1 -1
  534. package/dist/plugins/ecosystem/plugin-acquisition.d.ts.map +1 -1
  535. package/dist/plugins/ecosystem/plugin-acquisition.js +3 -2
  536. package/dist/plugins/ecosystem/plugin-acquisition.js.map +1 -1
  537. package/dist/plugins/ecosystem/registry-cli-adapter.d.ts.map +1 -1
  538. package/dist/plugins/ecosystem/registry-cli-adapter.js +2 -1
  539. package/dist/plugins/ecosystem/registry-cli-adapter.js.map +1 -1
  540. package/dist/plugins/ecosystem/registry.d.ts.map +1 -1
  541. package/dist/plugins/ecosystem/registry.js +35 -32
  542. package/dist/plugins/ecosystem/registry.js.map +1 -1
  543. package/dist/plugins/ecosystem/resolver.d.ts.map +1 -1
  544. package/dist/plugins/ecosystem/resolver.js +3 -2
  545. package/dist/plugins/ecosystem/resolver.js.map +1 -1
  546. package/dist/plugins/ecosystem/selection-store.d.ts.map +1 -1
  547. package/dist/plugins/ecosystem/selection-store.js +11 -10
  548. package/dist/plugins/ecosystem/selection-store.js.map +1 -1
  549. package/dist/plugins/ecosystem/selection.d.ts.map +1 -1
  550. package/dist/plugins/ecosystem/selection.js +8 -7
  551. package/dist/plugins/ecosystem/selection.js.map +1 -1
  552. package/dist/plugins/ecosystem/state.d.ts.map +1 -1
  553. package/dist/plugins/ecosystem/state.js +24 -23
  554. package/dist/plugins/ecosystem/state.js.map +1 -1
  555. package/dist/plugins/ecosystem/updates.d.ts.map +1 -1
  556. package/dist/plugins/ecosystem/updates.js +5 -4
  557. package/dist/plugins/ecosystem/updates.js.map +1 -1
  558. package/dist/plugins/mcp-http.d.ts +0 -17
  559. package/dist/plugins/mcp-http.d.ts.map +1 -1
  560. package/dist/plugins/mcp-http.js +30 -7
  561. package/dist/plugins/mcp-http.js.map +1 -1
  562. package/dist/plugins/plugin-supervisor.d.ts.map +1 -1
  563. package/dist/plugins/plugin-supervisor.js +19 -1
  564. package/dist/plugins/plugin-supervisor.js.map +1 -1
  565. package/dist/profile/first-roles.d.ts.map +1 -1
  566. package/dist/profile/first-roles.js +10 -1
  567. package/dist/profile/first-roles.js.map +1 -1
  568. package/dist/profile/goal-plugin.d.ts.map +1 -1
  569. package/dist/profile/goal-plugin.js +24 -5
  570. package/dist/profile/goal-plugin.js.map +1 -1
  571. package/dist/profile/identity.d.ts.map +1 -1
  572. package/dist/profile/identity.js +7 -6
  573. package/dist/profile/identity.js.map +1 -1
  574. package/dist/profile/lock.d.ts.map +1 -1
  575. package/dist/profile/lock.js +15 -1
  576. package/dist/profile/lock.js.map +1 -1
  577. package/dist/profile/plan-plugin.d.ts.map +1 -1
  578. package/dist/profile/plan-plugin.js +26 -13
  579. package/dist/profile/plan-plugin.js.map +1 -1
  580. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  581. package/dist/profile/plugin-profiles.js +2 -1
  582. package/dist/profile/plugin-profiles.js.map +1 -1
  583. package/dist/profile/policy-manifest.d.ts.map +1 -1
  584. package/dist/profile/policy-manifest.js +5 -4
  585. package/dist/profile/policy-manifest.js.map +1 -1
  586. package/dist/profile/profile-registry.d.ts +0 -12
  587. package/dist/profile/profile-registry.d.ts.map +1 -1
  588. package/dist/profile/profile-registry.js +14 -1
  589. package/dist/profile/profile-registry.js.map +1 -1
  590. package/dist/profile/role-catalog.d.ts +0 -1
  591. package/dist/profile/role-catalog.d.ts.map +1 -1
  592. package/dist/profile/role-catalog.js +17 -15
  593. package/dist/profile/role-catalog.js.map +1 -1
  594. package/dist/profile/role-orchestrator.d.ts.map +1 -1
  595. package/dist/profile/role-orchestrator.js +8 -7
  596. package/dist/profile/role-orchestrator.js.map +1 -1
  597. package/dist/profile/role-runner.d.ts.map +1 -1
  598. package/dist/profile/role-runner.js +3 -2
  599. package/dist/profile/role-runner.js.map +1 -1
  600. package/dist/profile/root-facade.d.ts.map +1 -1
  601. package/dist/profile/root-facade.js +2 -1
  602. package/dist/profile/root-facade.js.map +1 -1
  603. package/dist/profile/skill-discovery-wiring.d.ts.map +1 -1
  604. package/dist/profile/skill-discovery-wiring.js +7 -2
  605. package/dist/profile/skill-discovery-wiring.js.map +1 -1
  606. package/dist/profile/state-store.d.ts.map +1 -1
  607. package/dist/profile/state-store.js +13 -9
  608. package/dist/profile/state-store.js.map +1 -1
  609. package/dist/profile/todo-plugin.d.ts.map +1 -1
  610. package/dist/profile/todo-plugin.js +9 -4
  611. package/dist/profile/todo-plugin.js.map +1 -1
  612. package/dist/profiles/builtin-suites.d.ts +13 -6
  613. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  614. package/dist/profiles/builtin-suites.js +15 -6
  615. package/dist/profiles/builtin-suites.js.map +1 -1
  616. package/dist/profiles/suite-loader.d.ts +25 -1
  617. package/dist/profiles/suite-loader.d.ts.map +1 -1
  618. package/dist/profiles/suite-loader.js +34 -9
  619. package/dist/profiles/suite-loader.js.map +1 -1
  620. package/dist/remote/server-entry.d.ts.map +1 -1
  621. package/dist/remote/server-entry.js +3 -2
  622. package/dist/remote/server-entry.js.map +1 -1
  623. package/dist/remote/session-source.d.ts.map +1 -1
  624. package/dist/remote/session-source.js +8 -4
  625. package/dist/remote/session-source.js.map +1 -1
  626. package/dist/share/session-share.d.ts.map +1 -1
  627. package/dist/share/session-share.js +14 -2
  628. package/dist/share/session-share.js.map +1 -1
  629. package/dist/testing/plugin-testkit.d.ts.map +1 -1
  630. package/dist/testing/plugin-testkit.js +4 -3
  631. package/dist/testing/plugin-testkit.js.map +1 -1
  632. package/dist/testing/runtime-delivery-queue.d.ts.map +1 -1
  633. package/dist/testing/runtime-delivery-queue.js +2 -1
  634. package/dist/testing/runtime-delivery-queue.js.map +1 -1
  635. package/dist/testing/session-plugin-testkit.d.ts.map +1 -1
  636. package/dist/testing/session-plugin-testkit.js +10 -7
  637. package/dist/testing/session-plugin-testkit.js.map +1 -1
  638. package/dist/utils/ansi.d.ts.map +1 -1
  639. package/dist/utils/ansi.js +2 -1
  640. package/dist/utils/ansi.js.map +1 -1
  641. package/dist/utils/clipboard.d.ts.map +1 -1
  642. package/dist/utils/clipboard.js +7 -6
  643. package/dist/utils/clipboard.js.map +1 -1
  644. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  645. package/dist/utils/image-resize-worker.js +3 -2
  646. package/dist/utils/image-resize-worker.js.map +1 -1
  647. package/dist/utils/shell.d.ts.map +1 -1
  648. package/dist/utils/shell.js +9 -8
  649. package/dist/utils/shell.js.map +1 -1
  650. package/dist/utils/tools-manager.d.ts.map +1 -1
  651. package/dist/utils/tools-manager.js +23 -13
  652. package/dist/utils/tools-manager.js.map +1 -1
  653. package/dist/utils/version-check.d.ts.map +1 -1
  654. package/dist/utils/version-check.js +5 -1
  655. package/dist/utils/version-check.js.map +1 -1
  656. package/docs/keybindings.md +3 -0
  657. package/docs/quickstart.md +1 -1
  658. package/docs/settings.md +1 -0
  659. package/docs/terminal-setup.md +2 -3
  660. package/docs/usage.md +6 -5
  661. package/examples/extensions/with-deps/package-lock.json +2 -2
  662. package/examples/extensions/with-deps/package.json +1 -1
  663. package/examples/extensions/with-deps/plugin.json +1 -1
  664. package/package.json +1 -1
  665. package/dist/bundle/chunks/chunk-EALJ5DDX.js +0 -1452
@@ -20,6 +20,7 @@ import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defau
20
20
  import { createCodingAgentFacade, createCodingAgentRuntimeFacade, } from "../../core/facade/index.js";
21
21
  import { FooterDataProvider } from "../../core/footer-data-provider.js";
22
22
  import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
23
+ import { setI18nLanguage, t } from "../../core/i18n/index.js";
23
24
  import { KeybindingsManager } from "../../core/keybindings.js";
24
25
  import { createCompactionSummaryMessage } from "../../core/messages.js";
25
26
  import { DefaultPackageManager } from "../../core/package-manager.js";
@@ -149,6 +150,14 @@ export function createInteractiveTui(options) {
149
150
  return error instanceof Error ? error.message : String(error);
150
151
  }
151
152
  },
153
+ // tui 包自带文案的注入式翻译(批次⑦):默认英文,en 下逐字节不变;
154
+ // 前导/尾随空格在 t() 外拼接(t() 会 trim key)。
155
+ labels: {
156
+ searchTitle: ` ${t("Find transcript")}`,
157
+ searchNoMatches: `${t("No matches")} `,
158
+ copied: t("Copied!"),
159
+ copyFailed: t("Copy failed"),
160
+ },
152
161
  });
153
162
  }
154
163
  return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);
@@ -168,7 +177,7 @@ export function createInteractiveTuiReference(getTui) {
168
177
  if (currentTui !== methodTui) {
169
178
  const currentMethod = Reflect.get(currentTui, property, currentTui);
170
179
  if (typeof currentMethod !== "function") {
171
- throw new TypeError(`TUI property ${String(property)} is not callable`);
180
+ throw new TypeError(t("TUI property {property} is not callable", { property: String(property) }));
172
181
  }
173
182
  methodTui = currentTui;
174
183
  method = currentMethod;
@@ -270,8 +279,8 @@ export class InteractiveMode {
270
279
  workingMessage = undefined;
271
280
  workingVisible = true;
272
281
  workingIndicatorOptions = undefined;
273
- defaultWorkingMessage = "Working...";
274
- defaultHiddenThinkingLabel = "Thinking...";
282
+ defaultWorkingMessage = t("Working...");
283
+ defaultHiddenThinkingLabel = t("Thinking...");
275
284
  hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
276
285
  lastSigintTime = 0;
277
286
  lastEscapeTime = 0;
@@ -366,6 +375,7 @@ export class InteractiveMode {
366
375
  // manager (D-047) and the constructor uses it before anything else.
367
376
  this.options = { ...options };
368
377
  this.runtimeHost = runtimeHost;
378
+ setI18nLanguage(this.settingsManager.getUiLanguage());
369
379
  setCapabilityOverrides(this.settingsManager.getTerminalCapabilityOverrides());
370
380
  const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
371
381
  this.options.tuiMode = tuiMode;
@@ -577,11 +587,14 @@ export class InteractiveMode {
577
587
  if (this.settingsManager.getCollapseChangelog()) {
578
588
  const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
579
589
  const latestVersion = versionMatch ? versionMatch[1] : this.version;
580
- const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
590
+ const condensedText = t("Updated to v{version}. Use {command} to view full changelog.", {
591
+ version: latestVersion,
592
+ command: theme.bold("/changelog"),
593
+ });
581
594
  this.chatContainer.addChild(new Text(condensedText, 1, 0));
582
595
  }
583
596
  else {
584
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
597
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", t("What's New"))), 1, 0));
585
598
  this.chatContainer.addChild(new Spacer(1));
586
599
  this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
587
600
  this.chatContainer.addChild(new Spacer(1));
@@ -593,7 +606,7 @@ export class InteractiveMode {
593
606
  tui.addChild(component);
594
607
  if (TuiLayouts.isViewportTUI(tui)) {
595
608
  if (!this.fullscreenLayoutRoot)
596
- throw new Error("Fullscreen layout is not initialized");
609
+ throw new Error(t("Fullscreen layout is not initialized"));
597
610
  tui.setLayoutRoot(this.fullscreenLayoutRoot);
598
611
  }
599
612
  }
@@ -673,9 +686,11 @@ export class InteractiveMode {
673
686
  .join(", ");
674
687
  const cycleKeys = this.keybindings.getKeys("app.model.cycleForward");
675
688
  const cycleHint = cycleKeys.length > 0
676
- ? theme.fg("muted", ` (${formatKeyText(cycleKeys.join("/"), { capitalize: true })} to cycle)`)
689
+ ? theme.fg("muted", ` ${t("({key} to cycle)", {
690
+ key: formatKeyText(cycleKeys.join("/"), { capitalize: true }),
691
+ })}`)
677
692
  : "";
678
- console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
693
+ console.log(theme.fg("dim", t("Model scope: {models}{hint}", { models: modelList, hint: cycleHint })));
679
694
  }
680
695
  // Keep one component tree and remount it when changing renderers.
681
696
  // Widget chrome is fixed empty; no initialization render needed.
@@ -722,30 +737,32 @@ export class InteractiveMode {
722
737
  // Build startup instructions using keybinding hint helpers
723
738
  const hint = (keybinding, description) => keyHint(keybinding, description);
724
739
  const expandedInstructions = [
725
- hint("app.interrupt", "to interrupt"),
726
- hint("app.clear", "to clear"),
727
- rawKeyHint(`${keyText("app.clear")} twice`, "to exit"),
728
- hint("app.exit", "to exit (empty)"),
729
- hint("app.suspend", "to suspend"),
730
- keyHint("tui.editor.deleteToLineEnd", "to delete to end"),
731
- hint("app.tools.expand", "to expand tools"),
732
- hint("app.thinking.toggle", "to expand thinking"),
733
- hint("app.editor.external", "for external editor"),
734
- rawKeyHint("/", "for commands"),
735
- rawKeyHint("!", "to run bash"),
736
- rawKeyHint("!!", "to run bash (no context)"),
737
- hint("app.clipboard.pasteImage", "to paste image (with text fallback)"),
738
- rawKeyHint("drop files", "to attach"),
740
+ hint("app.interrupt", t("to interrupt")),
741
+ hint("app.clear", t("to clear")),
742
+ rawKeyHint(t("{key} twice", { key: keyText("app.clear") }), t("to exit")),
743
+ hint("app.exit", t("to exit (empty)")),
744
+ hint("app.suspend", t("to suspend")),
745
+ keyHint("tui.editor.deleteToLineEnd", t("to delete to end")),
746
+ hint("app.tools.expand", t("to expand tools")),
747
+ hint("app.thinking.toggle", t("to expand thinking")),
748
+ hint("app.editor.external", t("for external editor")),
749
+ rawKeyHint("/", t("for commands")),
750
+ rawKeyHint("!", t("to run bash")),
751
+ rawKeyHint("!!", t("to run bash (no context)")),
752
+ hint("app.clipboard.pasteImage", t("to paste image (with text fallback)")),
753
+ rawKeyHint("drop files", t("to attach")),
739
754
  ].join("\n");
740
755
  const compactInstructions = [
741
- hint("app.interrupt", "interrupt"),
742
- rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, "clear/exit"),
743
- rawKeyHint("/", "commands"),
744
- rawKeyHint("!", "bash"),
745
- hint("app.tools.expand", "more"),
756
+ hint("app.interrupt", t("interrupt")),
757
+ rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, t("clear/exit")),
758
+ rawKeyHint("/", t("commands")),
759
+ rawKeyHint("!", t("bash")),
760
+ hint("app.tools.expand", t("more")),
746
761
  ].join(theme.fg("muted", " · "));
747
- const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
748
- const onboarding = theme.fg("dim", `Agent Forge can explain its own features and look up its docs. Ask it how to use or extend Agent Forge.`);
762
+ const compactOnboarding = theme.fg("dim", t("Press {key} to show full startup help and loaded resources.", {
763
+ key: keyText("app.tools.expand"),
764
+ }));
765
+ const onboarding = theme.fg("dim", t("Agent Forge can explain its own features and look up its docs. Ask it how to use or extend Agent Forge."));
749
766
  this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
750
767
  // Setup UI layout
751
768
  this.headerContainer.addChild(new Spacer(1));
@@ -873,11 +890,11 @@ export class InteractiveMode {
873
890
  }
874
891
  }
875
892
  if (migratedProviders && migratedProviders.length > 0) {
876
- this.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(", ")}`);
893
+ this.showWarning(t("Migrated credentials to auth.json: {providers}", { providers: migratedProviders.join(", ") }));
877
894
  }
878
895
  const modelsJsonError = this.facade.getModelsError();
879
896
  if (modelsJsonError) {
880
- this.showError(`models.json error: ${modelsJsonError}`);
897
+ this.showError(t("models.json error: {error}", { error: modelsJsonError }));
881
898
  }
882
899
  if (modelFallbackMessage) {
883
900
  this.showWarning(modelFallbackMessage);
@@ -889,7 +906,7 @@ export class InteractiveMode {
889
906
  await this.facade.prompt(initialMessage, { images: initialImages });
890
907
  }
891
908
  catch (error) {
892
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
909
+ const errorMessage = error instanceof Error ? error.message : t("Unknown error occurred");
893
910
  this.showError(errorMessage);
894
911
  }
895
912
  }
@@ -899,7 +916,7 @@ export class InteractiveMode {
899
916
  await this.facade.prompt(message);
900
917
  }
901
918
  catch (error) {
902
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
919
+ const errorMessage = error instanceof Error ? error.message : t("Unknown error occurred");
903
920
  this.showError(errorMessage);
904
921
  }
905
922
  }
@@ -918,7 +935,7 @@ export class InteractiveMode {
918
935
  await this.promptWithEmptyReplyRetry(userInput);
919
936
  }
920
937
  catch (error) {
921
- const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
938
+ const errorMessage = error instanceof Error ? error.message : t("Unknown error occurred");
922
939
  this.showError(errorMessage);
923
940
  }
924
941
  }
@@ -942,7 +959,7 @@ export class InteractiveMode {
942
959
  return;
943
960
  if (contentText(lastAssistant.content).trim().length > 0)
944
961
  return;
945
- this.showStatus("Previous reply was empty, retrying...");
962
+ this.showStatus(t("Previous reply was empty, retrying..."));
946
963
  await this.facade.prompt(EMPTY_REPLY_RETRY_PROMPT);
947
964
  }
948
965
  async checkForPackageUpdates() {
@@ -996,10 +1013,10 @@ export class InteractiveMode {
996
1013
  if (extendedKeys === undefined)
997
1014
  return undefined;
998
1015
  if (extendedKeys !== "on" && extendedKeys !== "always") {
999
- return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
1016
+ return t("tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.");
1000
1017
  }
1001
1018
  if (extendedKeysFormat === "xterm") {
1002
- return "tmux extended-keys-format is xterm. Agent Forge works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
1019
+ return t("tmux extended-keys-format is xterm. Agent Forge works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.");
1003
1020
  }
1004
1021
  return undefined;
1005
1022
  }
@@ -1137,7 +1154,7 @@ export class InteractiveMode {
1137
1154
  .map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
1138
1155
  .join("\n");
1139
1156
  const contextCompactList = formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1140
- addLoadedSection("Context", contextCompactList, contextList);
1157
+ addLoadedSection(t("Context"), contextCompactList, contextList);
1141
1158
  }
1142
1159
  const skills = skillsResult.skills;
1143
1160
  if (skills.length > 0) {
@@ -1147,7 +1164,7 @@ export class InteractiveMode {
1147
1164
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1148
1165
  });
1149
1166
  const skillCompactList = formatCompactList(skills.map((skill) => skill.name));
1150
- addLoadedSection("Skills", skillCompactList, skillList);
1167
+ addLoadedSection(t("Skills"), skillCompactList, skillList);
1151
1168
  }
1152
1169
  const templates = this.facade.getPromptTemplates();
1153
1170
  if (templates.length > 0) {
@@ -1166,7 +1183,7 @@ export class InteractiveMode {
1166
1183
  },
1167
1184
  });
1168
1185
  const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));
1169
- addLoadedSection("Prompts", promptCompactList, templateList);
1186
+ addLoadedSection(t("Prompts"), promptCompactList, templateList);
1170
1187
  }
1171
1188
  // Show loaded themes (excluding built-in)
1172
1189
  const loadedThemes = themesResult.themes;
@@ -1181,7 +1198,7 @@ export class InteractiveMode {
1181
1198
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1182
1199
  });
1183
1200
  const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? this.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
1184
- addLoadedSection("Themes", themeCompactList, themeList);
1201
+ addLoadedSection(t("Themes"), themeCompactList, themeList);
1185
1202
  }
1186
1203
  }
1187
1204
  // v8 ignore next -- showDiagnostics 为假时上方已提前返回,此处恒为真
@@ -1189,19 +1206,19 @@ export class InteractiveMode {
1189
1206
  const skillDiagnostics = skillsResult.diagnostics;
1190
1207
  if (skillDiagnostics.length > 0) {
1191
1208
  const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);
1192
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
1209
+ this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", t("[Skill conflicts]"))}\n${warningLines}`, 0, 0));
1193
1210
  this.loadedResourcesContainer.addChild(new Spacer(1));
1194
1211
  }
1195
1212
  const promptDiagnostics = promptsResult.diagnostics;
1196
1213
  if (promptDiagnostics.length > 0) {
1197
1214
  const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);
1198
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
1215
+ this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", t("[Prompt conflicts]"))}\n${warningLines}`, 0, 0));
1199
1216
  this.loadedResourcesContainer.addChild(new Spacer(1));
1200
1217
  }
1201
1218
  const themeDiagnostics = themesResult.diagnostics;
1202
1219
  if (themeDiagnostics.length > 0) {
1203
1220
  const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
1204
- this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
1221
+ this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", t("[Theme conflicts]"))}\n${warningLines}`, 0, 0));
1205
1222
  this.loadedResourcesContainer.addChild(new Spacer(1));
1206
1223
  }
1207
1224
  }
@@ -1222,6 +1239,7 @@ export class InteractiveMode {
1222
1239
  this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
1223
1240
  }
1224
1241
  applyRuntimeSettings() {
1242
+ setI18nLanguage(this.settingsManager.getUiLanguage());
1225
1243
  setCapabilityOverrides(this.settingsManager.getTerminalCapabilityOverrides());
1226
1244
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
1227
1245
  this.applyFullscreenScrollbarSetting();
@@ -1378,7 +1396,7 @@ export class InteractiveMode {
1378
1396
  this.workingVisible = true;
1379
1397
  this.setWorkingIndicator();
1380
1398
  if (this.activeStatusIndicator?.kind === "working") {
1381
- this.activeStatusIndicator.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
1399
+ this.activeStatusIndicator.setMessage(`${this.defaultWorkingMessage} ${t("({key} to interrupt)", { key: keyText("app.interrupt") })}`);
1382
1400
  }
1383
1401
  this.setHiddenThinkingLabel();
1384
1402
  }
@@ -1598,7 +1616,7 @@ export class InteractiveMode {
1598
1616
  if (!text.trim())
1599
1617
  return;
1600
1618
  this.pendingUserInputs.push(text);
1601
- this.showStatus("Startup in progress — input queued and will run when startup completes");
1619
+ this.showStatus(t("Startup in progress — input queued and will run when startup completes"));
1602
1620
  }
1603
1621
  setupEditorSubmitHandler() {
1604
1622
  this.defaultEditor.onSubmit = async (rawText) => {
@@ -1656,7 +1674,7 @@ export class InteractiveMode {
1656
1674
  const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
1657
1675
  if (command) {
1658
1676
  if (this.facade.isBashRunning()) {
1659
- this.showWarning("A bash command is already running. Press Esc to cancel it first.");
1677
+ this.showWarning(t("A bash command is already running. Press Esc to cancel it first."));
1660
1678
  this.editor.setText(text);
1661
1679
  return true;
1662
1680
  }
@@ -1813,14 +1831,16 @@ export class InteractiveMode {
1813
1831
  const retryAttempt = this.facade.getRetryAttempt();
1814
1832
  errorMessage =
1815
1833
  retryAttempt > 0
1816
- ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
1817
- : "Operation aborted";
1834
+ ? retryAttempt === 1
1835
+ ? t("Aborted after {count} retry attempt", { count: retryAttempt })
1836
+ : t("Aborted after {count} retry attempts", { count: retryAttempt })
1837
+ : t("Operation aborted");
1818
1838
  this.streamingMessage.errorMessage = errorMessage;
1819
1839
  }
1820
1840
  this.streamingComponent.updateContent(this.streamingMessage, false);
1821
1841
  if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
1822
1842
  if (!errorMessage) {
1823
- errorMessage = this.streamingMessage.errorMessage || "Error";
1843
+ errorMessage = this.streamingMessage.errorMessage || t("Error");
1824
1844
  }
1825
1845
  for (const [, component] of this.pendingTools.entries()) {
1826
1846
  component.updateResult({
@@ -1929,16 +1949,16 @@ export class InteractiveMode {
1929
1949
  this.clearStatusIndicator("compaction");
1930
1950
  if (event.aborted) {
1931
1951
  if (event.reason === "manual") {
1932
- this.showError("Compaction cancelled");
1952
+ this.showError(t("Compaction cancelled"));
1933
1953
  }
1934
1954
  else {
1935
- this.showStatus("Auto-compaction cancelled");
1955
+ this.showStatus(t("Auto-compaction cancelled"));
1936
1956
  }
1937
1957
  }
1938
1958
  else if (event.result) {
1939
1959
  const entries = this.facade.getContextEntries();
1940
1960
  if (entries[0]?.type !== "compaction") {
1941
- throw new Error("Completed compaction is missing from the session context");
1961
+ throw new Error(t("Completed compaction is missing from the session context"));
1942
1962
  }
1943
1963
  this.chatContainer.clear();
1944
1964
  // The latest compaction is prepended for model context; append it below at its chronological position.
@@ -1967,7 +1987,7 @@ export class InteractiveMode {
1967
1987
  break;
1968
1988
  }
1969
1989
  case "compaction_skipped": {
1970
- this.showStatus("Auto-compaction skipped: nothing to compact");
1990
+ this.showStatus(t("Auto-compaction skipped: nothing to compact"));
1971
1991
  this.ui.requestRender();
1972
1992
  break;
1973
1993
  }
@@ -1990,7 +2010,10 @@ export class InteractiveMode {
1990
2010
  this.clearStatusIndicator("retry");
1991
2011
  // Show error only on final failure (success shows normal response)
1992
2012
  if (!event.success) {
1993
- this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
2013
+ this.showError(t("Retry failed after {count} attempts: {error}", {
2014
+ count: event.attempt,
2015
+ error: event.finalError || t("Unknown error"),
2016
+ }));
1994
2017
  }
1995
2018
  this.ui.requestRender();
1996
2019
  break;
@@ -2034,7 +2057,7 @@ export class InteractiveMode {
2034
2057
  this.chatContainer.addChild(new Spacer(1));
2035
2058
  this.managedToolStatusStarted = true;
2036
2059
  }
2037
- const message = status.type === "warning" ? `Warning: ${status.message}` : status.message;
2060
+ const message = status.type === "warning" ? t("Warning: {message}", { message: status.message }) : status.message;
2038
2061
  const color = status.type === "warning" ? "warning" : "dim";
2039
2062
  this.chatContainer.addChild(new Text(theme.fg(color, message), 1, 0));
2040
2063
  this.lastStatusSpacer = undefined;
@@ -2183,11 +2206,13 @@ export class InteractiveMode {
2183
2206
  const retryAttempt = this.facade.getRetryAttempt();
2184
2207
  errorMessage =
2185
2208
  retryAttempt > 0
2186
- ? `Aborted after ${retryAttempt} retry attempt${retryAttempt > 1 ? "s" : ""}`
2187
- : "Operation aborted";
2209
+ ? retryAttempt === 1
2210
+ ? t("Aborted after {count} retry attempt", { count: retryAttempt })
2211
+ : t("Aborted after {count} retry attempts", { count: retryAttempt })
2212
+ : t("Operation aborted");
2188
2213
  }
2189
2214
  else {
2190
- errorMessage = message.errorMessage || "Error";
2215
+ errorMessage = message.errorMessage || t("Error");
2191
2216
  }
2192
2217
  component.updateResult({ content: [{ type: "text", text: errorMessage }], isError: true });
2193
2218
  }
@@ -2249,9 +2274,9 @@ export class InteractiveMode {
2249
2274
  const { usage } = notice;
2250
2275
  const tokens = usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
2251
2276
  const cost = usage.cost.total >= 0.01 ? ` (~$${usage.cost.total.toFixed(2)})` : "";
2252
- const label = notice.kind === "compaction" ? "Compaction" : "Branch summary";
2277
+ const label = notice.kind === "compaction" ? t("Compaction") : t("Branch summary");
2253
2278
  this.chatContainer.addChild(new Spacer(1));
2254
- this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
2279
+ this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${t("{tokens} tokens billed{cost}", { tokens: formatTokens(tokens), cost })}`), 1, 0));
2255
2280
  }
2256
2281
  static countDroppedThinkingBlocks(message) {
2257
2282
  let count = 0;
@@ -2286,9 +2311,8 @@ export class InteractiveMode {
2286
2311
  }
2287
2312
  if (droppedCount <= previousDroppedCount)
2288
2313
  return;
2289
- const noun = droppedCount === 1 ? "thinking block" : "thinking blocks";
2290
2314
  this.chatContainer.addChild(new Spacer(1));
2291
- this.chatContainer.addChild(new Text(theme.fg("warning", `Anthropic dropped ${droppedCount} ${noun} (details in session)`), 1, 0));
2315
+ this.chatContainer.addChild(new Text(theme.fg("warning", t("Anthropic dropped {count} thinking blocks (details in session)", { count: droppedCount })), 1, 0));
2292
2316
  }
2293
2317
  /**
2294
2318
  * Show a transcript notice when a completed assistant message paid for a
@@ -2307,13 +2331,13 @@ export class InteractiveMode {
2307
2331
  if (miss.missedTokens < 20_000 && miss.missedCost < 0.1)
2308
2332
  return;
2309
2333
  const cost = miss.missedCost >= 0.01 ? ` (~$${miss.missedCost.toFixed(2)})` : "";
2310
- const reBilled = `${formatTokens(miss.missedTokens)} tokens re-billed${cost}`;
2311
- let label = "Cache miss";
2334
+ const reBilled = t("{tokens} tokens re-billed{cost}", { tokens: formatTokens(miss.missedTokens), cost });
2335
+ let label = t("Cache miss");
2312
2336
  if (miss.modelChanged) {
2313
- label = "Cache miss after model switch";
2337
+ label = t("Cache miss after model switch");
2314
2338
  }
2315
2339
  else if (miss.idleMs >= CACHE_TTL_MS) {
2316
- label = `Cache miss after ${Math.round(miss.idleMs / 60_000)}m idle`;
2340
+ label = t("Cache miss after {minutes}m idle", { minutes: Math.round(miss.idleMs / 60_000) });
2317
2341
  }
2318
2342
  const text = theme.fg("warning", `${label}: ${reBilled}`);
2319
2343
  this.chatContainer.addChild(new Spacer(1));
@@ -2329,8 +2353,9 @@ export class InteractiveMode {
2329
2353
  const allEntries = this.facade.getEntries();
2330
2354
  const compactionCount = allEntries.filter((e) => e.type === "compaction").length;
2331
2355
  if (compactionCount > 0) {
2332
- const times = compactionCount === 1 ? "1 time" : `${compactionCount} times`;
2333
- this.showStatus(`Session compacted ${times}`);
2356
+ this.showStatus(compactionCount === 1
2357
+ ? t("Session compacted {count} time", { count: compactionCount })
2358
+ : t("Session compacted {count} times", { count: compactionCount }));
2334
2359
  }
2335
2360
  }
2336
2361
  async getUserInput() {
@@ -2404,7 +2429,7 @@ export class InteractiveMode {
2404
2429
  await this.runtimeFacade.dispose();
2405
2430
  const resumeCommand = formatResumeCommand(this.runtimeFacade);
2406
2431
  if (resumeCommand) {
2407
- process.stdout.write(`${chalk.dim("To resume this session:")} ${resumeCommand}\n`);
2432
+ process.stdout.write(`${chalk.dim(t("To resume this session:"))} ${resumeCommand}\n`);
2408
2433
  }
2409
2434
  process.exit(0);
2410
2435
  }
@@ -2444,7 +2469,7 @@ export class InteractiveMode {
2444
2469
  this.ui.stop();
2445
2470
  }
2446
2471
  catch { }
2447
- console.error(`${APP_NAME} exiting due to uncaughtException:`);
2472
+ console.error(t("{app} exiting due to uncaughtException:", { app: APP_NAME }));
2448
2473
  console.error(error);
2449
2474
  process.exit(1);
2450
2475
  }
@@ -2499,7 +2524,7 @@ export class InteractiveMode {
2499
2524
  }
2500
2525
  handleCtrlZ() {
2501
2526
  if (process.platform === "win32") {
2502
- this.showStatus("Suspend to background is not supported on Windows");
2527
+ this.showStatus(t("Suspend to background is not supported on Windows"));
2503
2528
  return;
2504
2529
  }
2505
2530
  // Keep the event loop alive while suspended. Without this, stopping the TUI
@@ -2560,16 +2585,19 @@ export class InteractiveMode {
2560
2585
  handleDequeue() {
2561
2586
  const restored = this.restoreQueuedMessagesToEditor();
2562
2587
  if (restored === 0) {
2563
- this.showStatus("No queued messages to restore");
2588
+ this.showStatus(t("No queued messages to restore"));
2589
+ }
2590
+ else if (restored === 1) {
2591
+ this.showStatus(t("Restored {count} queued message to editor", { count: restored }));
2564
2592
  }
2565
2593
  else {
2566
- this.showStatus(`Restored ${restored} queued message${restored > 1 ? "s" : ""} to editor`);
2594
+ this.showStatus(t("Restored {count} queued messages to editor", { count: restored }));
2567
2595
  }
2568
2596
  }
2569
2597
  /** /queue command host face (single-entry iron law): queues the given text for after the current run. A bare /queue cannot mirror the keybinding — the editor buffer is cleared on submit before the command runs — so it prints usage instead of silently doing nothing. */
2570
2598
  handleQueueCommand(text) {
2571
2599
  if (text === undefined || text.trim() === "") {
2572
- this.showStatus("Usage: /queue <text>");
2600
+ this.showStatus(t("Usage: /queue <text>"));
2573
2601
  return Promise.resolve();
2574
2602
  }
2575
2603
  return this.handleFollowUp(text);
@@ -2578,6 +2606,16 @@ export class InteractiveMode {
2578
2606
  handleDequeueCommand() {
2579
2607
  this.handleDequeue();
2580
2608
  }
2609
+ /** /queue-list command host face: open the queued-message manager selector. Both queues empty is a status message, not an empty overlay. */
2610
+ handleQueueListCommand() {
2611
+ const steering = this.facade.getSteeringMessages();
2612
+ const followUp = this.facade.getFollowUpMessages();
2613
+ if (steering.length === 0 && followUp.length === 0) {
2614
+ this.showStatus(t("No queued messages to manage"));
2615
+ return;
2616
+ }
2617
+ selectorsFlow.showQueueManagerSelector(this);
2618
+ }
2581
2619
  /** /editor command host face: edit the current input in an external editor. */
2582
2620
  handleEditorCommand() {
2583
2621
  return this.handleOpenExternalEditor();
@@ -2596,26 +2634,31 @@ export class InteractiveMode {
2596
2634
  cycleThinkingLevel() {
2597
2635
  const newLevel = this.facade.cycleThinkingLevel();
2598
2636
  if (newLevel === undefined) {
2599
- this.showStatus("Current model does not support thinking");
2637
+ this.showStatus(t("Current model does not support thinking"));
2600
2638
  }
2601
2639
  else {
2602
2640
  this.footer.invalidate();
2603
2641
  this.updateEditorBorderColor();
2604
- this.showStatus(`Thinking level: ${newLevel}`);
2642
+ this.showStatus(t("Thinking level: {level}", { level: newLevel }));
2605
2643
  }
2606
2644
  }
2607
2645
  async cycleModel(direction) {
2608
2646
  try {
2609
2647
  const result = await this.facade.cycleModel(direction);
2610
2648
  if (result === undefined) {
2611
- const msg = this.facade.getScopedModels().length > 0 ? "Only one model in scope" : "Only one model available";
2649
+ const msg = this.facade.getScopedModels().length > 0 ? t("Only one model in scope") : t("Only one model available");
2612
2650
  this.showStatus(msg);
2613
2651
  }
2614
2652
  else {
2615
2653
  this.footer.invalidate();
2616
2654
  this.updateEditorBorderColor();
2617
- const thinkingStr = result.model.reasoning && result.thinkingLevel !== "off" ? ` (thinking: ${result.thinkingLevel})` : "";
2618
- this.showStatus(`Switched to ${result.model.name || result.model.id}${thinkingStr}`);
2655
+ const thinkingStr = result.model.reasoning && result.thinkingLevel !== "off"
2656
+ ? ` ${t("(thinking: {level})", { level: result.thinkingLevel })}`
2657
+ : "";
2658
+ this.showStatus(t("Switched to {model}{thinking}", {
2659
+ model: result.model.name || result.model.id,
2660
+ thinking: thinkingStr,
2661
+ }));
2619
2662
  void this.maybeWarnAboutAnthropicSubscriptionAuth(result.model);
2620
2663
  }
2621
2664
  }
@@ -2641,7 +2684,7 @@ export class InteractiveMode {
2641
2684
  }
2642
2685
  }
2643
2686
  }
2644
- this.showStatus(`Tool output: ${expanded ? "expanded" : "collapsed"}`);
2687
+ this.showStatus(expanded ? t("Tool output: expanded") : t("Tool output: collapsed"));
2645
2688
  }
2646
2689
  /** Update rendered assistant messages without rebuilding live tool components. */
2647
2690
  updateThinkingBlockVisibility() {
@@ -2656,7 +2699,7 @@ export class InteractiveMode {
2656
2699
  this.hideThinkingBlock = !this.hideThinkingBlock;
2657
2700
  this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
2658
2701
  this.updateThinkingBlockVisibility();
2659
- this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
2702
+ this.showStatus(this.hideThinkingBlock ? t("Thinking blocks: hidden") : t("Thinking blocks: visible"));
2660
2703
  }
2661
2704
  async handleOpenExternalEditor() {
2662
2705
  const editorCmd = this.settingsManager.getExternalEditorCommand();
@@ -2685,28 +2728,28 @@ export class InteractiveMode {
2685
2728
  }
2686
2729
  showError(errorMessage) {
2687
2730
  this.chatContainer.addChild(new Spacer(1));
2688
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
2731
+ this.chatContainer.addChild(new Text(theme.fg("error", t("Error: {message}", { message: errorMessage })), this.outputPad, 0));
2689
2732
  this.ui.requestRender();
2690
2733
  }
2691
2734
  showWarning(warningMessage) {
2692
2735
  this.chatContainer.addChild(new Spacer(1));
2693
- this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
2736
+ this.chatContainer.addChild(new Text(theme.fg("warning", t("Warning: {message}", { message: warningMessage })), 1, 0));
2694
2737
  this.ui.requestRender();
2695
2738
  }
2696
2739
  showNewVersionNotification(release) {
2697
2740
  const action = theme.fg("accent", `${APP_NAME} update`);
2698
- const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
2741
+ const updateInstruction = theme.fg("muted", `${t("New version {version} is available. Run", { version: release.version })} `) + action;
2699
2742
  const changelogUrl = process.env.AGENT_FORGE_CHANGELOG_URL;
2700
2743
  const changelogLine = changelogUrl
2701
- ? theme.fg("muted", "Changelog: ") +
2744
+ ? theme.fg("muted", `${t("Changelog:")} `) +
2702
2745
  (getCapabilities().hyperlinks
2703
2746
  ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
2704
2747
  : theme.fg("accent", changelogUrl))
2705
- : theme.fg("muted", "Changelog URL is not configured.");
2748
+ : theme.fg("muted", t("Changelog URL is not configured."));
2706
2749
  const note = release.note?.trim();
2707
2750
  this.chatContainer.addChild(new Spacer(1));
2708
2751
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
2709
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Update Available"))}\n${updateInstruction}`, 1, 0));
2752
+ this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", t("Update Available")))}\n${updateInstruction}`, 1, 0));
2710
2753
  if (note) {
2711
2754
  this.chatContainer.addChild(new Spacer(1));
2712
2755
  this.chatContainer.addChild(new Markdown(note, 1, 0, this.getMarkdownThemeWithSettings(), {
@@ -2720,11 +2763,11 @@ export class InteractiveMode {
2720
2763
  }
2721
2764
  showPackageUpdateNotification(packages) {
2722
2765
  const action = theme.fg("accent", `${APP_NAME} update --extensions`);
2723
- const updateInstruction = theme.fg("muted", "Package updates are available. Run ") + action;
2766
+ const updateInstruction = theme.fg("muted", `${t("Package updates are available. Run")} `) + action;
2724
2767
  const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
2725
2768
  this.chatContainer.addChild(new Spacer(1));
2726
2769
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
2727
- this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", "Package Updates Available"))}\n${updateInstruction}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, 1, 0));
2770
+ this.chatContainer.addChild(new Text(`${theme.bold(theme.fg("warning", t("Package Updates Available")))}\n${updateInstruction}\n${theme.fg("muted", `${t("Packages:")}`)}\n${packageLines}`, 1, 0));
2728
2771
  this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
2729
2772
  this.ui.requestRender();
2730
2773
  }
@@ -2762,23 +2805,24 @@ export class InteractiveMode {
2762
2805
  followUp: [...followUp, ...compactionFollowUp],
2763
2806
  };
2764
2807
  }
2808
+ /** Host-visible for ./interactive-selectors.ts (queue manager close path). */
2765
2809
  updatePendingMessagesDisplay() {
2766
2810
  this.pendingMessagesContainer.clear();
2767
2811
  const { steering: steeringMessages, followUp: followUpMessages } = this.getAllQueuedMessages();
2768
2812
  if (steeringMessages.length > 0 || followUpMessages.length > 0) {
2769
2813
  this.pendingMessagesContainer.addChild(new Spacer(1));
2770
2814
  for (const message of steeringMessages) {
2771
- const text = theme.fg("dim", `Steering: ${message}`);
2815
+ const text = theme.fg("dim", t("Steering: {message}", { message }));
2772
2816
  this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
2773
2817
  }
2774
2818
  for (const message of followUpMessages) {
2775
- const text = theme.fg("dim", `Follow-up: ${message}`);
2819
+ const text = theme.fg("dim", t("Follow-up: {message}", { message }));
2776
2820
  this.pendingMessagesContainer.addChild(new TruncatedText(text, 1, 0));
2777
2821
  }
2778
2822
  // The dequeue keybinding's shipped default was cleared (iron law):
2779
2823
  // /queue's sibling command is the discoverable entry.
2780
2824
  const dequeueHint = this.getAppKeyDisplay("app.message.dequeue") || "/dequeue";
2781
- const hintText = theme.fg("dim", `↳ ${dequeueHint} to edit all queued messages`);
2825
+ const hintText = theme.fg("dim", t("↳ {key} to edit all queued messages", { key: dequeueHint }));
2782
2826
  this.pendingMessagesContainer.addChild(new TruncatedText(hintText, 1, 0));
2783
2827
  }
2784
2828
  }
@@ -2810,7 +2854,7 @@ export class InteractiveMode {
2810
2854
  this.editor.addToHistory?.(text);
2811
2855
  this.editor.setText("");
2812
2856
  this.updatePendingMessagesDisplay();
2813
- this.showStatus("Queued message for after compaction");
2857
+ this.showStatus(t("Queued message for after compaction"));
2814
2858
  }
2815
2859
  async flushCompactionQueue(options) {
2816
2860
  if (this.compactionQueuedMessages.length === 0) {
@@ -2823,7 +2867,13 @@ export class InteractiveMode {
2823
2867
  this.facade.clearQueue();
2824
2868
  this.compactionQueuedMessages = queuedMessages;
2825
2869
  this.updatePendingMessagesDisplay();
2826
- this.showError(`Failed to send queued message${queuedMessages.length > 1 ? "s" : ""}: ${error instanceof Error ? error.message : String(error)}`);
2870
+ this.showError(queuedMessages.length > 1
2871
+ ? t("Failed to send queued messages: {error}", {
2872
+ error: error instanceof Error ? error.message : String(error),
2873
+ })
2874
+ : t("Failed to send queued message: {error}", {
2875
+ error: error instanceof Error ? error.message : String(error),
2876
+ }));
2827
2877
  };
2828
2878
  try {
2829
2879
  if (options?.willRetry) {
@@ -2920,7 +2970,7 @@ export class InteractiveMode {
2920
2970
  let selector;
2921
2971
  const defaultProvider = this.settingsManager.getDefaultProvider();
2922
2972
  const defaultModelId = this.settingsManager.getDefaultModel();
2923
- const defaultModel = defaultProvider && defaultModelId ? `${defaultProvider}/${defaultModelId}` : "not set";
2973
+ const defaultModel = defaultProvider && defaultModelId ? `${defaultProvider}/${defaultModelId}` : t("not set");
2924
2974
  selector = new SettingsSelectorComponent({
2925
2975
  autoCompact: this.facade.isAutoCompactionEnabled(),
2926
2976
  defaultModel,
@@ -2945,6 +2995,7 @@ export class InteractiveMode {
2945
2995
  mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
2946
2996
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
2947
2997
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
2998
+ uiLanguage: this.settingsManager.getUiLanguage(),
2948
2999
  treeFilterMode: this.settingsManager.getTreeFilterMode(),
2949
3000
  showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
2950
3001
  showCacheMissNotices: this.settingsManager.getShowCacheMissNotices(),
@@ -3004,7 +3055,7 @@ export class InteractiveMode {
3004
3055
  onHttpIdleTimeoutMsChange: (timeoutMs) => {
3005
3056
  this.settingsManager.setHttpIdleTimeoutMs(timeoutMs);
3006
3057
  configureHttpDispatcher(timeoutMs);
3007
- this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);
3058
+ this.showStatus(t("HTTP idle timeout: {value}", { value: formatHttpIdleTimeoutMs(timeoutMs) }));
3008
3059
  },
3009
3060
  onModelThinkingLevelChange: (provider, modelId, level) => {
3010
3061
  this.settingsManager.setModelThinkingLevel(provider, modelId, level);
@@ -3055,6 +3106,11 @@ export class InteractiveMode {
3055
3106
  onDoubleEscapeActionChange: (action) => {
3056
3107
  this.settingsManager.setDoubleEscapeAction(action);
3057
3108
  },
3109
+ onUiLanguageChange: (language) => {
3110
+ this.settingsManager.setUiLanguage(language);
3111
+ setI18nLanguage(language);
3112
+ this.ui.requestRender();
3113
+ },
3058
3114
  onTreeFilterModeChange: (mode) => {
3059
3115
  this.settingsManager.setTreeFilterMode(mode);
3060
3116
  },
@@ -3108,13 +3164,13 @@ export class InteractiveMode {
3108
3164
  onTuiModeChange: (mode) => {
3109
3165
  if (!this.switchTuiMode(mode)) {
3110
3166
  selector?.getSettingsList().updateValue("tui-mode", this.ui.mode);
3111
- this.showStatus("Close active overlays before changing TUI mode");
3167
+ this.showStatus(t("Close active overlays before changing TUI mode"));
3112
3168
  return;
3113
3169
  }
3114
3170
  this.settingsManager.setTuiMode(mode);
3115
3171
  if (!this.activeStatusIndicator)
3116
3172
  this.statusContainer.clear();
3117
- this.showStatus(`TUI mode: ${mode}`);
3173
+ this.showStatus(t("TUI mode: {mode}", { mode }));
3118
3174
  },
3119
3175
  onFullscreenExitOutputChange: (output) => {
3120
3176
  this.settingsManager.setFullscreenExitOutput(output);
@@ -3222,22 +3278,26 @@ export class InteractiveMode {
3222
3278
  const selected = await new Promise((resolve) => {
3223
3279
  this.openSuiteListSelector({
3224
3280
  availableSuites: pending.available,
3225
- note: `Suite "${pending.requestedId}" was not found. The selected suite applies to the new session.`,
3281
+ note: t('Suite "{id}" was not found. The selected suite applies to the new session.', {
3282
+ id: pending.requestedId,
3283
+ }),
3226
3284
  onSelect: (suiteId) => resolve(suiteId),
3227
3285
  onCancel: () => resolve(undefined),
3228
3286
  });
3229
3287
  });
3230
3288
  if (selected === undefined) {
3231
- this.showWarning(`Suite "${pending.requestedId}" was not found — continuing without a suite. Use /suite to choose one.`);
3289
+ this.showWarning(t('Suite "{id}" was not found — continuing without a suite. Use /suite to choose one.', {
3290
+ id: pending.requestedId,
3291
+ }));
3232
3292
  return;
3233
3293
  }
3234
3294
  this.settingsManager.setProjectSuite(selected);
3235
3295
  try {
3236
3296
  await this.runtimeFacade.newSession();
3237
- this.showStatus(`Suite set to ${selected} — new session started`);
3297
+ this.showStatus(t("Suite set to {id} — new session started", { id: selected }));
3238
3298
  }
3239
3299
  catch (error) {
3240
- await this.handleFatalRuntimeError("Failed to create session", error);
3300
+ await this.handleFatalRuntimeError(t("Failed to create session"), error);
3241
3301
  }
3242
3302
  }
3243
3303
  /** /model command entry; implementation in ./interactive-selectors.ts (S5 slice 5). */
@@ -3273,7 +3333,7 @@ export class InteractiveMode {
3273
3333
  try {
3274
3334
  if ((await this.facade.checkProviderAuth("anthropic"))?.type === "oauth") {
3275
3335
  this.anthropicSubscriptionWarningShown = true;
3276
- this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);
3336
+ this.showWarning(t(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING));
3277
3337
  return;
3278
3338
  }
3279
3339
  const apiKey = (await this.facade.getProviderAuth(model.provider))?.auth.apiKey;
@@ -3281,7 +3341,7 @@ export class InteractiveMode {
3281
3341
  return;
3282
3342
  }
3283
3343
  this.anthropicSubscriptionWarningShown = true;
3284
- this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);
3344
+ this.showWarning(t(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING));
3285
3345
  }
3286
3346
  catch {
3287
3347
  // Ignore auth lookup failures for warning-only checks.
@@ -3314,7 +3374,7 @@ export class InteractiveMode {
3314
3374
  .getEntries()
3315
3375
  .some((entry) => entry.type === "custom" && entry.customType === "workflow.state");
3316
3376
  if (!hasSnapshot) {
3317
- this.showStatus("No workflow in this session");
3377
+ this.showStatus(t("No workflow in this session"));
3318
3378
  return;
3319
3379
  }
3320
3380
  this.showSelector((done) => {
@@ -3328,7 +3388,7 @@ export class InteractiveMode {
3328
3388
  done();
3329
3389
  this.editor.setText(text);
3330
3390
  this.ui.requestRender();
3331
- this.showStatus("Workflow action staged — review in the editor and submit");
3391
+ this.showStatus(t("Workflow action staged — review in the editor and submit"));
3332
3392
  };
3333
3393
  return { component: view, focus: view, dispose: () => view.dispose() };
3334
3394
  });
@@ -3344,7 +3404,7 @@ export class InteractiveMode {
3344
3404
  const agentDir = getAgentDir();
3345
3405
  const sessions = listAgentSessions({ agentDir, parentAgentSession: this.facade.getSessionId() });
3346
3406
  if (sessions.length === 0) {
3347
- this.showStatus("No subagent sessions in this session");
3407
+ this.showStatus(t("No subagent sessions in this session"));
3348
3408
  return;
3349
3409
  }
3350
3410
  this.showSelector((done) => {
@@ -3363,7 +3423,7 @@ export class InteractiveMode {
3363
3423
  const realLeafId = this.facade.getLeafId();
3364
3424
  const initialFilterMode = this.settingsManager.getTreeFilterMode();
3365
3425
  if (tree.length === 0) {
3366
- this.showStatus("No entries in session");
3426
+ this.showStatus(t("No entries in session"));
3367
3427
  return;
3368
3428
  }
3369
3429
  this.showSelector((done) => {
@@ -3371,7 +3431,7 @@ export class InteractiveMode {
3371
3431
  // Selecting the current leaf is a no-op (already there)
3372
3432
  if (entryId === this.facade.getLeafId()) {
3373
3433
  done();
3374
- this.showStatus("Already at this point");
3434
+ this.showStatus(t("Already at this point"));
3375
3435
  return;
3376
3436
  }
3377
3437
  // Ask about summarization
@@ -3382,19 +3442,19 @@ export class InteractiveMode {
3382
3442
  // Check if we should skip the prompt (user preference to always default to no summary)
3383
3443
  if (!this.settingsManager.getBranchSummarySkipPrompt()) {
3384
3444
  while (true) {
3385
- const summaryChoice = await this.showDialogSelector("Summarize branch?", [
3386
- "No summary",
3387
- "Summarize",
3388
- "Summarize with custom prompt",
3445
+ const summaryChoice = await this.showDialogSelector(t("Summarize branch?"), [
3446
+ t("No summary"),
3447
+ t("Summarize"),
3448
+ t("Summarize with custom prompt"),
3389
3449
  ]);
3390
3450
  if (summaryChoice === undefined) {
3391
3451
  // User pressed escape - re-show tree selector with same selection
3392
3452
  this.showTreeSelector(entryId);
3393
3453
  return;
3394
3454
  }
3395
- wantsSummary = summaryChoice !== "No summary";
3396
- if (summaryChoice === "Summarize with custom prompt") {
3397
- customInstructions = await this.showDialogEditor("Custom summarization instructions");
3455
+ wantsSummary = summaryChoice !== t("No summary");
3456
+ if (summaryChoice === t("Summarize with custom prompt")) {
3457
+ customInstructions = await this.showDialogEditor(t("Custom summarization instructions"));
3398
3458
  if (customInstructions === undefined) {
3399
3459
  // User cancelled - loop back to summary selector
3400
3460
  continue;
@@ -3429,12 +3489,12 @@ export class InteractiveMode {
3429
3489
  });
3430
3490
  if (result.aborted) {
3431
3491
  // Summarization aborted - re-show tree selector with same selection
3432
- this.showStatus("Branch summarization cancelled");
3492
+ this.showStatus(t("Branch summarization cancelled"));
3433
3493
  this.showTreeSelector(entryId);
3434
3494
  return;
3435
3495
  }
3436
3496
  if (result.cancelled) {
3437
- this.showStatus("Navigation cancelled");
3497
+ this.showStatus(t("Navigation cancelled"));
3438
3498
  return;
3439
3499
  }
3440
3500
  // Update UI
@@ -3443,7 +3503,7 @@ export class InteractiveMode {
3443
3503
  if (result.editorText && !this.editor.getText().trim()) {
3444
3504
  this.editor.setText(result.editorText);
3445
3505
  }
3446
- this.showStatus("Navigated to selected point");
3506
+ this.showStatus(t("Navigated to selected point"));
3447
3507
  void this.flushCompactionQueue({ willRetry: false });
3448
3508
  }
3449
3509
  catch (error) {
@@ -3464,12 +3524,12 @@ export class InteractiveMode {
3464
3524
  }, initialSelectedId, initialFilterMode);
3465
3525
  selector.onCopy = async (text) => {
3466
3526
  if (!text) {
3467
- this.showError("Selected entry has no text to copy");
3527
+ this.showError(t("Selected entry has no text to copy"));
3468
3528
  return;
3469
3529
  }
3470
3530
  try {
3471
3531
  await copyToClipboard(text);
3472
- this.showStatus("Copied selected message to clipboard");
3532
+ this.showStatus(t("Copied selected message to clipboard"));
3473
3533
  }
3474
3534
  catch (error) {
3475
3535
  this.showError(error instanceof Error ? error.message : String(error));
@@ -3517,7 +3577,7 @@ export class InteractiveMode {
3517
3577
  if (result.cancelled) {
3518
3578
  return result;
3519
3579
  }
3520
- this.showStatus("Resumed session");
3580
+ this.showStatus(t("Resumed session"));
3521
3581
  this.detectCrossSuiteResume();
3522
3582
  return result;
3523
3583
  }
@@ -3525,7 +3585,7 @@ export class InteractiveMode {
3525
3585
  if (error instanceof MissingSessionCwdError) {
3526
3586
  const selectedCwd = await this.promptForMissingSessionCwd(error);
3527
3587
  if (!selectedCwd) {
3528
- this.showStatus("Resume cancelled");
3588
+ this.showStatus(t("Resume cancelled"));
3529
3589
  return { cancelled: true };
3530
3590
  }
3531
3591
  const result = await this.runtimeFacade.switchSession(sessionPath, {
@@ -3535,11 +3595,11 @@ export class InteractiveMode {
3535
3595
  if (result.cancelled) {
3536
3596
  return result;
3537
3597
  }
3538
- this.showStatus("Resumed session in current cwd");
3598
+ this.showStatus(t("Resumed session in current cwd"));
3539
3599
  this.detectCrossSuiteResume();
3540
3600
  return result;
3541
3601
  }
3542
- return this.handleFatalRuntimeError("Failed to resume session", error);
3602
+ return this.handleFatalRuntimeError(t("Failed to resume session"), error);
3543
3603
  }
3544
3604
  }
3545
3605
  /**
@@ -3563,7 +3623,10 @@ export class InteractiveMode {
3563
3623
  });
3564
3624
  if (currentSuiteId === originalSuiteId)
3565
3625
  return;
3566
- this.showStatus(`Cross-suite compatible mode: session created with "${originalSuiteId}", assembling with "${currentSuiteId}"`);
3626
+ this.showStatus(t('Cross-suite compatible mode: session created with "{from}", assembling with "{to}"', {
3627
+ from: originalSuiteId,
3628
+ to: currentSuiteId,
3629
+ }));
3567
3630
  this.facade.recordSuiteMismatch(originalSuiteId, currentSuiteId);
3568
3631
  }
3569
3632
  // =========================================================================
@@ -3681,11 +3744,11 @@ export class InteractiveMode {
3681
3744
  // =========================================================================
3682
3745
  async handleReloadCommand() {
3683
3746
  if (this.facade.isStreaming()) {
3684
- this.showWarning("Wait for the current response to finish before reloading.");
3747
+ this.showWarning(t("Wait for the current response to finish before reloading."));
3685
3748
  return;
3686
3749
  }
3687
3750
  if (this.facade.isCompacting()) {
3688
- this.showWarning("Wait for compaction to finish before reloading.");
3751
+ this.showWarning(t("Wait for compaction to finish before reloading."));
3689
3752
  return;
3690
3753
  }
3691
3754
  this.resetDialogUI();
@@ -3693,7 +3756,7 @@ export class InteractiveMode {
3693
3756
  const borderColor = (s) => theme.fg("border", s);
3694
3757
  reloadBox.addChild(new DynamicBorder(borderColor));
3695
3758
  reloadBox.addChild(new Spacer(1));
3696
- reloadBox.addChild(new Text(theme.fg("muted", "Reloading keybindings, skills, prompts, themes, and context files..."), 1, 0));
3759
+ reloadBox.addChild(new Text(theme.fg("muted", t("Reloading keybindings, skills, prompts, themes, and context files...")), 1, 0));
3697
3760
  reloadBox.addChild(new Spacer(1));
3698
3761
  reloadBox.addChild(new DynamicBorder(borderColor));
3699
3762
  const previousEditor = this.editor;
@@ -3737,9 +3800,9 @@ export class InteractiveMode {
3737
3800
  });
3738
3801
  const modelsJsonError = this.facade.getModelsError();
3739
3802
  if (modelsJsonError) {
3740
- this.showError(`models.json error: ${modelsJsonError}`);
3803
+ this.showError(t("models.json error: {error}", { error: modelsJsonError }));
3741
3804
  }
3742
- this.showStatus("Reloaded keybindings, skills, prompts, themes, and context files");
3805
+ this.showStatus(t("Reloaded keybindings, skills, prompts, themes, and context files"));
3743
3806
  dismissReloadBox(this.editor);
3744
3807
  reloadBoxDismissed = true;
3745
3808
  }
@@ -3748,7 +3811,7 @@ export class InteractiveMode {
3748
3811
  if (!reloadBoxDismissed) {
3749
3812
  dismissReloadBox(previousEditor);
3750
3813
  }
3751
- this.showError(`Reload failed: ${error instanceof Error ? error.message : String(error)}`);
3814
+ this.showError(t("Reload failed: {error}", { error: error instanceof Error ? error.message : String(error) }));
3752
3815
  }
3753
3816
  }
3754
3817
  async handleExportCommand(text) {
@@ -3756,17 +3819,19 @@ export class InteractiveMode {
3756
3819
  try {
3757
3820
  if (outputPath?.endsWith(".jsonl")) {
3758
3821
  const filePath = this.facade.exportToJsonl(outputPath);
3759
- this.showStatus(`Session exported to: ${filePath}`);
3822
+ this.showStatus(t("Session exported to: {path}", { path: filePath }));
3760
3823
  }
3761
3824
  else {
3762
3825
  const filePath = await this.facade.exportToHtml(outputPath, {
3763
3826
  themeName: theme.name,
3764
3827
  });
3765
- this.showStatus(`Session exported to: ${filePath}`);
3828
+ this.showStatus(t("Session exported to: {path}", { path: filePath }));
3766
3829
  }
3767
3830
  }
3768
3831
  catch (error) {
3769
- this.showError(`Failed to export session: ${error instanceof Error ? error.message : "Unknown error"}`);
3832
+ this.showError(t("Failed to export session: {error}", {
3833
+ error: error instanceof Error ? error.message : t("Unknown error"),
3834
+ }));
3770
3835
  }
3771
3836
  }
3772
3837
  getPathCommandArgument(text, command) {
@@ -3797,43 +3862,43 @@ export class InteractiveMode {
3797
3862
  async handleImportCommand(text) {
3798
3863
  const inputPath = this.getPathCommandArgument(text, "/import");
3799
3864
  if (!inputPath) {
3800
- this.showError("Usage: /import <path.jsonl>");
3865
+ this.showError(t("Usage: /import <path.jsonl>"));
3801
3866
  return;
3802
3867
  }
3803
- const confirmed = await this.showDialogConfirm("Import session", `Replace current session with ${inputPath}?`);
3868
+ const confirmed = await this.showDialogConfirm(t("Import session"), t("Replace current session with {path}?", { path: inputPath }));
3804
3869
  if (!confirmed) {
3805
- this.showStatus("Import cancelled");
3870
+ this.showStatus(t("Import cancelled"));
3806
3871
  return;
3807
3872
  }
3808
3873
  try {
3809
3874
  this.clearStatusIndicator();
3810
3875
  const result = await this.runtimeFacade.importFromJsonl(inputPath);
3811
3876
  if (result.cancelled) {
3812
- this.showStatus("Import cancelled");
3877
+ this.showStatus(t("Import cancelled"));
3813
3878
  return;
3814
3879
  }
3815
- this.showStatus(`Session imported from: ${inputPath}`);
3880
+ this.showStatus(t("Session imported from: {path}", { path: inputPath }));
3816
3881
  }
3817
3882
  catch (error) {
3818
3883
  if (error instanceof MissingSessionCwdError) {
3819
3884
  const selectedCwd = await this.promptForMissingSessionCwd(error);
3820
3885
  if (!selectedCwd) {
3821
- this.showStatus("Import cancelled");
3886
+ this.showStatus(t("Import cancelled"));
3822
3887
  return;
3823
3888
  }
3824
3889
  const result = await this.runtimeFacade.importFromJsonl(inputPath, selectedCwd);
3825
3890
  if (result.cancelled) {
3826
- this.showStatus("Import cancelled");
3891
+ this.showStatus(t("Import cancelled"));
3827
3892
  return;
3828
3893
  }
3829
- this.showStatus(`Session imported from: ${inputPath}`);
3894
+ this.showStatus(t("Session imported from: {path}", { path: inputPath }));
3830
3895
  return;
3831
3896
  }
3832
3897
  if (error instanceof SessionImportFileNotFoundError) {
3833
- this.showError(`Failed to import session: ${error.message}`);
3898
+ this.showError(t("Failed to import session: {error}", { error: error.message }));
3834
3899
  return;
3835
3900
  }
3836
- await this.handleFatalRuntimeError("Failed to import session", error);
3901
+ await this.handleFatalRuntimeError(t("Failed to import session"), error);
3837
3902
  }
3838
3903
  }
3839
3904
  async handleCopyCommand(options = {}) {
@@ -3846,16 +3911,16 @@ export class InteractiveMode {
3846
3911
  }
3847
3912
  const text = this.facade.getLastAssistantText();
3848
3913
  if (!text) {
3849
- this.showError("No agent messages to copy yet.");
3914
+ this.showError(t("No agent messages to copy yet."));
3850
3915
  return;
3851
3916
  }
3852
3917
  try {
3853
3918
  await copyToClipboard(text);
3854
3919
  if (options.flashConfirmation && this.ui instanceof TuiAltScreen) {
3855
- this.ui.flash("Copied!");
3920
+ this.ui.flash(t("Copied!"));
3856
3921
  }
3857
3922
  else {
3858
- this.showStatus("Copied last agent message to clipboard");
3923
+ this.showStatus(t("Copied last agent message to clipboard"));
3859
3924
  }
3860
3925
  }
3861
3926
  catch (error) {
@@ -3868,10 +3933,10 @@ export class InteractiveMode {
3868
3933
  const currentName = this.facade.getSessionName();
3869
3934
  if (currentName) {
3870
3935
  this.chatContainer.addChild(new Spacer(1));
3871
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name: ${currentName}`), 1, 0));
3936
+ this.chatContainer.addChild(new Text(theme.fg("dim", t("Session name: {name}", { name: currentName })), 1, 0));
3872
3937
  }
3873
3938
  else {
3874
- this.showWarning("Usage: /name <name>");
3939
+ this.showWarning(t("Usage: /name <name>"));
3875
3940
  }
3876
3941
  this.ui.requestRender();
3877
3942
  return;
@@ -3879,10 +3944,13 @@ export class InteractiveMode {
3879
3944
  this.facade.setSessionName(name);
3880
3945
  const sessionName = this.facade.getSessionName();
3881
3946
  if (sessionName !== name) {
3882
- this.showWarning(`Session name was normalized from ${JSON.stringify(name)} to ${JSON.stringify(sessionName)}`);
3947
+ this.showWarning(t("Session name was normalized from {from} to {to}", {
3948
+ from: JSON.stringify(name),
3949
+ to: JSON.stringify(sessionName),
3950
+ }));
3883
3951
  }
3884
3952
  this.chatContainer.addChild(new Spacer(1));
3885
- this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${sessionName ?? name}`), 1, 0));
3953
+ this.chatContainer.addChild(new Text(theme.fg("dim", t("Session name set: {name}", { name: sessionName ?? name })), 1, 0));
3886
3954
  this.ui.requestRender();
3887
3955
  }
3888
3956
  /**
@@ -3892,11 +3960,13 @@ export class InteractiveMode {
3892
3960
  handleStopAgentsCommand() {
3893
3961
  const active = this.facade.getActiveAgentTaskCount();
3894
3962
  if (active === 0) {
3895
- this.showStatus("No background subagents running");
3963
+ this.showStatus(t("No background subagents running"));
3896
3964
  return;
3897
3965
  }
3898
3966
  this.facade.abortAgentTasks();
3899
- this.showStatus(`Terminated ${active} background subagent${active === 1 ? "" : "s"}`);
3967
+ this.showStatus(active === 1
3968
+ ? t("Terminated {count} background subagent", { count: active })
3969
+ : t("Terminated {count} background subagents", { count: active }));
3900
3970
  }
3901
3971
  handleSessionCommand() {
3902
3972
  const stats = this.facade.getSessionStats();
@@ -3907,71 +3977,81 @@ export class InteractiveMode {
3907
3977
  // resolves to a concrete responseModel). Usage without model attribution is
3908
3978
  // grouped separately so the breakdown reconciles with the session total.
3909
3979
  const usageBreakdown = getUsageCostBreakdown(entries);
3910
- let info = `${theme.bold("Session Info")}\n\n`;
3980
+ let info = `${theme.bold(t("Session Info"))}\n\n`;
3911
3981
  if (sessionName) {
3912
- info += `${theme.fg("dim", "Name:")} ${sessionName}\n`;
3913
- }
3914
- info += `${theme.fg("dim", "File:")} ${stats.sessionFile ?? "In-memory"}\n`;
3915
- info += `${theme.fg("dim", "ID:")} ${stats.sessionId}\n\n`;
3916
- info += `${theme.bold("Messages")}\n`;
3917
- info += `${theme.fg("dim", "Total:")} ${stats.totalMessages}\n`;
3918
- info += `${theme.fg("dim", "User:")} ${stats.userMessages}\n`;
3919
- info += `${theme.fg("dim", "Assistant:")} ${stats.assistantMessages}\n`;
3920
- info += `${theme.fg("dim", "Tools:")} ${stats.toolCalls} calls, ${stats.toolResults} results\n\n`;
3921
- info += `${theme.bold("Tokens")}\n`;
3982
+ info += `${theme.fg("dim", t("Name:"))} ${sessionName}\n`;
3983
+ }
3984
+ info += `${theme.fg("dim", t("File:"))} ${stats.sessionFile ?? t("In-memory")}\n`;
3985
+ info += `${theme.fg("dim", t("ID:"))} ${stats.sessionId}\n\n`;
3986
+ info += `${theme.bold(t("Messages"))}\n`;
3987
+ info += `${theme.fg("dim", t("Total:"))} ${stats.totalMessages}\n`;
3988
+ info += `${theme.fg("dim", t("User:"))} ${stats.userMessages}\n`;
3989
+ info += `${theme.fg("dim", t("Assistant:"))} ${stats.assistantMessages}\n`;
3990
+ info += `${theme.fg("dim", t("Tools:"))} ${t("{calls} calls, {results} results", {
3991
+ calls: stats.toolCalls,
3992
+ results: stats.toolResults,
3993
+ })}\n\n`;
3994
+ info += `${theme.bold(t("Tokens"))}\n`;
3922
3995
  // "Input" is the full prompt volume. With cache activity, split it into
3923
3996
  // cached (served from cache) vs uncached (everything else) - the only
3924
3997
  // provider-independent split. Cache writes, where reported, are a detail
3925
3998
  // of the uncached portion.
3926
3999
  const { input, cacheRead, cacheWrite } = stats.tokens;
3927
4000
  const promptTokens = input + cacheRead + cacheWrite;
3928
- info += `${theme.fg("dim", "Input:")} ${promptTokens.toLocaleString()}\n`;
4001
+ info += `${theme.fg("dim", t("Input:"))} ${promptTokens.toLocaleString()}\n`;
3929
4002
  if (promptTokens > 0 && (cacheRead > 0 || cacheWrite > 0)) {
3930
4003
  const hitRate = theme.fg("dim", `(${((cacheRead / promptTokens) * 100).toFixed(1)}%)`);
3931
- info += ` ${theme.fg("dim", "Cached:")} ${cacheRead.toLocaleString()} ${hitRate}\n`;
3932
- const written = cacheWrite > 0 ? ` ${theme.fg("dim", `(${cacheWrite.toLocaleString()} written to cache)`)}` : "";
3933
- info += ` ${theme.fg("dim", "Uncached:")} ${(input + cacheWrite).toLocaleString()}${written}\n`;
4004
+ info += ` ${theme.fg("dim", t("Cached:"))} ${cacheRead.toLocaleString()} ${hitRate}\n`;
4005
+ const written = cacheWrite > 0
4006
+ ? ` ${theme.fg("dim", t("({count} written to cache)", { count: cacheWrite.toLocaleString() }))}`
4007
+ : "";
4008
+ info += ` ${theme.fg("dim", t("Uncached:"))} ${(input + cacheWrite).toLocaleString()}${written}\n`;
3934
4009
  }
3935
- info += `${theme.fg("dim", "Output:")} ${stats.tokens.output.toLocaleString()}\n`;
3936
- info += `${theme.fg("dim", "Total:")} ${stats.tokens.total.toLocaleString()}\n`;
4010
+ info += `${theme.fg("dim", t("Output:"))} ${stats.tokens.output.toLocaleString()}\n`;
4011
+ info += `${theme.fg("dim", t("Total:"))} ${stats.tokens.total.toLocaleString()}\n`;
3937
4012
  // 双维度统计(用户裁决 2026-09-25):总计之外按供应商/模型分桶——缓存读/写、
3938
4013
  // 命中率、费用逐桶可见。此前该拆分门控在 cost>0 且多桶才渲染,单价为 0 的
3939
4014
  // 自定义供应商(如自建代理)永远看不到。
3940
4015
  if (usageBreakdown.length > 0) {
3941
- info += `\n${theme.bold("By Provider/Model")}\n`;
4016
+ info += `\n${theme.bold(t("By Provider/Model"))}\n`;
3942
4017
  for (const entry of usageBreakdown) {
3943
4018
  const bucket = entry.totals;
3944
4019
  const promptBucket = bucket.input + bucket.cacheRead + bucket.cacheWrite;
3945
4020
  let line = ` ${theme.bold(entry.key)}`;
3946
4021
  if (promptBucket > 0) {
3947
- line += `\n ${theme.fg("dim", "Input:")} ${promptBucket.toLocaleString()}`;
4022
+ line += `\n ${theme.fg("dim", t("Input:"))} ${promptBucket.toLocaleString()}`;
3948
4023
  if (bucket.cacheRead > 0 || bucket.cacheWrite > 0) {
3949
4024
  const rate = promptBucket > 0 ? ((bucket.cacheRead / promptBucket) * 100).toFixed(1) : "0.0";
3950
- line += ` ${theme.fg("dim", `(cache ${rate}%, W ${bucket.cacheWrite.toLocaleString()})`)}`;
4025
+ line += ` ${theme.fg("dim", t("(cache {rate}%, W {written})", { rate, written: bucket.cacheWrite.toLocaleString() }))}`;
3951
4026
  }
3952
4027
  }
3953
4028
  if (bucket.output > 0)
3954
- line += `\n ${theme.fg("dim", "Output:")} ${bucket.output.toLocaleString()}`;
4029
+ line += `\n ${theme.fg("dim", t("Output:"))} ${bucket.output.toLocaleString()}`;
3955
4030
  if (entry.cost > 0)
3956
4031
  line += ` ${theme.fg("dim", `$${entry.cost.toFixed(3)}`)}`;
3957
4032
  info += `${line}\n`;
3958
4033
  }
3959
4034
  }
3960
4035
  if (stats.cost > 0 || cacheWaste.missedTokens > 0) {
3961
- info += `\n${theme.bold("Cost")}\n`;
3962
- info += `${theme.fg("dim", "Total:")} $${stats.cost.toFixed(3)}`;
4036
+ info += `\n${theme.bold(t("Cost"))}\n`;
4037
+ info += `${theme.fg("dim", t("Total:"))} $${stats.cost.toFixed(3)}`;
3963
4038
  if (usageBreakdown.length > 1) {
3964
4039
  for (const entry of usageBreakdown) {
3965
- info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", `(${formatTokens(entry.tokens)} tokens)`)}`;
4040
+ info += `\n ${theme.fg("dim", `${entry.key}:`)} $${entry.cost.toFixed(3)} ${theme.fg("dim", t("({tokens} tokens)", { tokens: formatTokens(entry.tokens) }))}`;
3966
4041
  }
3967
4042
  }
3968
4043
  if (cacheWaste.missedTokens > 0) {
3969
- const missLabel = cacheWaste.missCount === 1 ? "1 miss" : `${cacheWaste.missCount} misses`;
3970
- const detail = `${cacheWaste.missedTokens.toLocaleString()} tokens, ${missLabel}`;
4044
+ const missLabel = cacheWaste.missCount === 1
4045
+ ? t("{count} miss", { count: cacheWaste.missCount })
4046
+ : t("{count} misses", { count: cacheWaste.missCount });
4047
+ const detail = t("{tokens} tokens, {misses}", {
4048
+ tokens: cacheWaste.missedTokens.toLocaleString(),
4049
+ misses: missLabel,
4050
+ });
3971
4051
  info +=
3972
4052
  cacheWaste.missedCost >= 0.0001
3973
- ? `\n${theme.fg("dim", "Cache Re-billed:")} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
3974
- : `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
4053
+ ? `\n${theme.fg("dim", t("Cache Re-billed:"))} $${cacheWaste.missedCost.toFixed(3)} ${theme.fg("dim", `(${detail})`)}`
4054
+ : `\n${theme.fg("dim", t("Cache Re-billed:"))} ${detail}`;
3975
4055
  }
3976
4056
  }
3977
4057
  this.chatContainer.addChild(new Spacer(1));
@@ -3981,14 +4061,14 @@ export class InteractiveMode {
3981
4061
  handleMetricsCommand(turnsArg) {
3982
4062
  const provider = this.options.getMetrics;
3983
4063
  if (!provider) {
3984
- this.showWarning("Metrics are not available: the observability plugin is not mounted in this session");
4064
+ this.showWarning(t("Metrics are not available: the observability plugin is not mounted in this session"));
3985
4065
  return;
3986
4066
  }
3987
4067
  let windowTurns;
3988
4068
  if (turnsArg !== undefined) {
3989
4069
  const parsed = Number.parseInt(turnsArg, 10);
3990
4070
  if (!Number.isSafeInteger(parsed) || parsed < 1) {
3991
- this.showWarning(`Invalid turns: ${turnsArg}. Usage: /metrics [turns]`);
4071
+ this.showWarning(t("Invalid turns: {turns}. Usage: /metrics [turns]", { turns: turnsArg }));
3992
4072
  return;
3993
4073
  }
3994
4074
  windowTurns = parsed;
@@ -3997,7 +4077,7 @@ export class InteractiveMode {
3997
4077
  try {
3998
4078
  const result = provider({ windowTurns });
3999
4079
  if (result === undefined) {
4000
- this.showWarning("Metrics are not available: the observability plugin is not mounted in this session");
4080
+ this.showWarning(t("Metrics are not available: the observability plugin is not mounted in this session"));
4001
4081
  return;
4002
4082
  }
4003
4083
  snapshot = result;
@@ -4018,10 +4098,10 @@ export class InteractiveMode {
4018
4098
  .reverse()
4019
4099
  .map((e) => normalizeChangelogLinks(e.content, e))
4020
4100
  .join("\n\n")
4021
- : "No changelog entries found.";
4101
+ : t("No changelog entries found.");
4022
4102
  this.chatContainer.addChild(new Spacer(1));
4023
4103
  this.chatContainer.addChild(new DynamicBorder());
4024
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
4104
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", t("What's New"))), 1, 0));
4025
4105
  this.chatContainer.addChild(new Spacer(1));
4026
4106
  this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1, this.getMarkdownThemeWithSettings()));
4027
4107
  this.chatContainer.addChild(new DynamicBorder());
@@ -4043,7 +4123,7 @@ export class InteractiveMode {
4043
4123
  const section = (title, rows) => {
4044
4124
  if (rows.length === 0)
4045
4125
  return "";
4046
- let table = `\n**${title}**\n| Command | Description |\n|---------|-------------|\n`;
4126
+ let table = `\n**${title}**\n| ${t("Command")} | ${t("Description")} |\n|---------|-------------|\n`;
4047
4127
  for (const row of rows) {
4048
4128
  const command = row.hint ? `\`/${row.name} ${row.hint}\`` : `\`/${row.name}\``;
4049
4129
  table += `| ${command} | ${row.description ?? ""} |\n`;
@@ -4064,13 +4144,13 @@ export class InteractiveMode {
4064
4144
  name: `skill:${skill.name}`,
4065
4145
  description: skill.description,
4066
4146
  }));
4067
- const help = section("Built-in commands", builtinRows) +
4068
- section("Prompt templates", promptRows) +
4069
- section("Skills", skillRows) +
4070
- "\nType `/` for autocomplete. Use `/hotkeys` for keyboard shortcuts.";
4147
+ const help = section(t("Built-in commands"), builtinRows) +
4148
+ section(t("Prompt templates"), promptRows) +
4149
+ section(t("Skills"), skillRows) +
4150
+ `\n${t("Type `/` for autocomplete. Use `/hotkeys` for keyboard shortcuts.")}`;
4071
4151
  this.chatContainer.addChild(new Spacer(1));
4072
4152
  this.chatContainer.addChild(new DynamicBorder());
4073
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Available Commands")), 1, 0));
4153
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", t("Available Commands"))), 1, 0));
4074
4154
  this.chatContainer.addChild(new Markdown(help.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
4075
4155
  this.chatContainer.addChild(new DynamicBorder());
4076
4156
  this.ui.requestRender();
@@ -4118,68 +4198,70 @@ export class InteractiveMode {
4118
4198
  const pasteImage = this.getAppKeyDisplay("app.clipboard.pasteImage");
4119
4199
  // Iron law (2026-10-01): these shipped defaults were cleared in favor of
4120
4200
  // the /model command; the row only appears when a user re-configures a key.
4121
- const selectModelRow = selectModel ? `| \`${selectModel}\` | Open model selector |\n` : "";
4201
+ const selectModelRow = selectModel ? `| \`${selectModel}\` | ${t("Open model selector")} |\n` : "";
4122
4202
  // Iron law (2026-10-02 复审): ctrl+g/ctrl+x stay bound only for the
4123
4203
  // components without a command channel — the main editor ignores them
4124
4204
  // (/editor and /copy are its single entries), so the rows say where
4125
4205
  // each key actually acts.
4126
- const copyMessageRow = copyMessage ? `| \`${copyMessage}\` | Copy selection in /tree |\n` : "";
4206
+ const copyMessageRow = copyMessage ? `| \`${copyMessage}\` | ${t("Copy selection in /tree")} |\n` : "";
4127
4207
  const externalEditorRow = externalEditor
4128
- ? `| \`${externalEditor}\` | External editor (inside dialog inputs) |\n`
4208
+ ? `| \`${externalEditor}\` | ${t("External editor (inside dialog inputs)")} |\n`
4129
4209
  : "";
4130
4210
  // Iron law (2026-10-01): the message queue is the /queue and /dequeue
4131
4211
  // commands' feature; rows only appear when a user re-configures a key.
4132
- const followUpRow = followUp ? `| \`${followUp}\` | Queue follow-up message |\n` : "";
4133
- const dequeueRow = dequeue ? `| \`${dequeue}\` | Restore queued messages |\n` : "";
4134
- const cycleThinkingRow = cycleThinkingLevel ? `| \`${cycleThinkingLevel}\` | Cycle thinking level |\n` : "";
4212
+ const followUpRow = followUp ? `| \`${followUp}\` | ${t("Queue follow-up message")} |\n` : "";
4213
+ const dequeueRow = dequeue ? `| \`${dequeue}\` | ${t("Restore queued messages")} |\n` : "";
4214
+ const cycleThinkingRow = cycleThinkingLevel
4215
+ ? `| \`${cycleThinkingLevel}\` | ${t("Cycle thinking level")} |\n`
4216
+ : "";
4135
4217
  const cycleModelsRow = cycleModelForward || cycleModelBackward
4136
- ? `| \`${cycleModelForward}\` / \`${cycleModelBackward}\` | Cycle models |\n`
4218
+ ? `| \`${cycleModelForward}\` / \`${cycleModelBackward}\` | ${t("Cycle models")} |\n`
4137
4219
  : "";
4138
4220
  // Suspend has no default key on native Windows; hide the row there.
4139
- const suspendRow = suspend ? `| \`${suspend}\` | Suspend to background |\n` : "";
4221
+ const suspendRow = suspend ? `| \`${suspend}\` | ${t("Suspend to background")} |\n` : "";
4140
4222
  const hotkeys = `
4141
- **Navigation**
4142
- | Key | Action |
4223
+ **${t("Navigation")}**
4224
+ | ${t("Key")} | ${t("Action")} |
4143
4225
  |-----|--------|
4144
- | \`${cursorUp}\` / \`${cursorDown}\` / \`${cursorLeft}\` / \`${cursorRight}\` | Move cursor / browse history |
4145
- | \`${cursorWordLeft}\` / \`${cursorWordRight}\` | Move by word |
4146
- | \`${cursorLineStart}\` | Start of line |
4147
- | \`${cursorLineEnd}\` | End of line |
4148
- | \`${jumpForward}\` | Jump forward to character |
4149
- | \`${jumpBackward}\` | Jump backward to character |
4150
- | \`${pageUp}\` / \`${pageDown}\` | Scroll by page |
4226
+ | \`${cursorUp}\` / \`${cursorDown}\` / \`${cursorLeft}\` / \`${cursorRight}\` | ${t("Move cursor / browse history")} |
4227
+ | \`${cursorWordLeft}\` / \`${cursorWordRight}\` | ${t("Move by word")} |
4228
+ | \`${cursorLineStart}\` | ${t("Start of line")} |
4229
+ | \`${cursorLineEnd}\` | ${t("End of line")} |
4230
+ | \`${jumpForward}\` | ${t("Jump forward to character")} |
4231
+ | \`${jumpBackward}\` | ${t("Jump backward to character")} |
4232
+ | \`${pageUp}\` / \`${pageDown}\` | ${t("Scroll by page")} |
4151
4233
 
4152
- **Editing**
4153
- | Key | Action |
4234
+ **${t("Editing")}**
4235
+ | ${t("Key")} | ${t("Action")} |
4154
4236
  |-----|--------|
4155
- | \`${submit}\` | Send message |
4156
- | \`${newLine}\` | New line${process.platform === "win32" ? " (Ctrl+Enter on Windows Terminal)" : ""} |
4157
- | \`${deleteWordBackward}\` | Delete word backwards |
4158
- | \`${deleteWordForward}\` | Delete word forwards |
4159
- | \`${deleteToLineStart}\` | Delete to start of line |
4160
- | \`${deleteToLineEnd}\` | Delete to end of line |
4161
- | \`${yank}\` | Paste the most-recently-deleted text |
4162
- | \`${yankPop}\` | Cycle through the deleted text after pasting |
4163
- | \`${undo}\` | Undo |
4237
+ | \`${submit}\` | ${t("Send message")} |
4238
+ | \`${newLine}\` | ${process.platform === "win32" ? t("New line (Ctrl+Enter on Windows Terminal)") : t("New line")} |
4239
+ | \`${deleteWordBackward}\` | ${t("Delete word backwards")} |
4240
+ | \`${deleteWordForward}\` | ${t("Delete word forwards")} |
4241
+ | \`${deleteToLineStart}\` | ${t("Delete to start of line")} |
4242
+ | \`${deleteToLineEnd}\` | ${t("Delete to end of line")} |
4243
+ | \`${yank}\` | ${t("Paste the most-recently-deleted text")} |
4244
+ | \`${yankPop}\` | ${t("Cycle through the deleted text after pasting")} |
4245
+ | \`${undo}\` | ${t("Undo")} |
4164
4246
 
4165
- **Other**
4166
- | Key | Action |
4247
+ **${t("Other")}**
4248
+ | ${t("Key")} | ${t("Action")} |
4167
4249
  |-----|--------|
4168
- | \`${tab}\` | Path completion / accept autocomplete |
4169
- | \`${interrupt}\` | Cancel autocomplete / abort streaming |
4170
- | \`${clear}\` | Clear editor (first) / exit (second) |
4171
- | \`${exit}\` | Exit (when editor is empty) |
4172
- ${suspendRow}${cycleThinkingRow}${cycleModelsRow}${selectModelRow}| \`${expandTools}\` | Toggle tool output expansion |
4173
- | \`${toggleThinking}\` | Toggle thinking block visibility |
4250
+ | \`${tab}\` | ${t("Path completion / accept autocomplete")} |
4251
+ | \`${interrupt}\` | ${t("Cancel autocomplete / abort streaming")} |
4252
+ | \`${clear}\` | ${t("Clear editor (first) / exit (second)")} |
4253
+ | \`${exit}\` | ${t("Exit (when editor is empty)")} |
4254
+ ${suspendRow}${cycleThinkingRow}${cycleModelsRow}${selectModelRow}| \`${expandTools}\` | ${t("Toggle tool output expansion")} |
4255
+ | \`${toggleThinking}\` | ${t("Toggle thinking block visibility")} |
4174
4256
  ${externalEditorRow}${copyMessageRow}${followUpRow}${dequeueRow}
4175
- | \`${pasteImage}\` | Paste image or text from clipboard |
4176
- | \`/\` | Slash commands |
4177
- | \`!\` | Run bash command |
4178
- | \`!!\` | Run bash command (excluded from context) |
4257
+ | \`${pasteImage}\` | ${t("Paste image or text from clipboard")} |
4258
+ | \`/\` | ${t("Slash commands")} |
4259
+ | \`!\` | ${t("Run bash command")} |
4260
+ | \`!!\` | ${t("Run bash command (excluded from context)")} |
4179
4261
  `;
4180
4262
  this.chatContainer.addChild(new Spacer(1));
4181
4263
  this.chatContainer.addChild(new DynamicBorder());
4182
- this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0));
4264
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", t("Keyboard Shortcuts"))), 1, 0));
4183
4265
  this.chatContainer.addChild(new Spacer(1));
4184
4266
  this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, this.getMarkdownThemeWithSettings()));
4185
4267
  this.chatContainer.addChild(new DynamicBorder());
@@ -4193,7 +4275,7 @@ ${externalEditorRow}${copyMessageRow}${followUpRow}${dequeueRow}
4193
4275
  return;
4194
4276
  }
4195
4277
  this.chatContainer.addChild(new Spacer(1));
4196
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
4278
+ this.chatContainer.addChild(new Text(`${theme.fg("accent", t("✓ New session started"))}`, 1, 1));
4197
4279
  this.ui.requestRender();
4198
4280
  }
4199
4281
  catch (error) {
@@ -4206,18 +4288,18 @@ ${externalEditorRow}${copyMessageRow}${followUpRow}${dequeueRow}
4206
4288
  const allLines = this.ui.render(width);
4207
4289
  const debugLogPath = getDebugLogPath();
4208
4290
  const debugData = [
4209
- `Debug output at ${new Date().toISOString()}`,
4210
- `Terminal: ${width}x${height}`,
4211
- `Total lines: ${allLines.length}`,
4291
+ t("Debug output at {date}", { date: new Date().toISOString() }),
4292
+ t("Terminal: {columns}x{rows}", { columns: width, rows: height }),
4293
+ t("Total lines: {count}", { count: allLines.length }),
4212
4294
  "",
4213
- "=== All rendered lines with visible widths ===",
4295
+ t("=== All rendered lines with visible widths ==="),
4214
4296
  ...allLines.map((line, idx) => {
4215
4297
  const vw = visibleWidth(line);
4216
4298
  const escaped = JSON.stringify(line);
4217
4299
  return `[${idx}] (w=${vw}) ${escaped}`;
4218
4300
  }),
4219
4301
  "",
4220
- "=== Agent messages (JSONL) ===",
4302
+ t("=== Agent messages (JSONL) ==="),
4221
4303
  ...this.facade
4222
4304
  .getSessionAPI()
4223
4305
  .getMessages()
@@ -4227,7 +4309,7 @@ ${externalEditorRow}${copyMessageRow}${followUpRow}${dequeueRow}
4227
4309
  fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
4228
4310
  fs.writeFileSync(debugLogPath, debugData);
4229
4311
  this.chatContainer.addChild(new Spacer(1));
4230
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ Debug log written")}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
4312
+ this.chatContainer.addChild(new Text(`${theme.fg("accent", t("✓ Debug log written"))}\n${theme.fg("muted", debugLogPath)}`, 1, 1));
4231
4313
  this.ui.requestRender();
4232
4314
  }
4233
4315
  handleArminSaysHi() {
@@ -4277,7 +4359,9 @@ ${externalEditorRow}${copyMessageRow}${followUpRow}${dequeueRow}
4277
4359
  if (this.bashComponent) {
4278
4360
  this.bashComponent.setComplete(undefined, false);
4279
4361
  }
4280
- this.showError(`Bash command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
4362
+ this.showError(t("Bash command failed: {error}", {
4363
+ error: error instanceof Error ? error.message : t("Unknown error"),
4364
+ }));
4281
4365
  }
4282
4366
  this.bashComponent = undefined;
4283
4367
  this.ui.requestRender();