@humain/terminal 0.0.1 → 0.0.3-beta.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 (688) hide show
  1. package/CHANGELOG.md +271 -9
  2. package/README.md +143 -119
  3. package/dist/cli/args.d.ts +4 -2
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +42 -37
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-check.d.ts +19 -0
  8. package/dist/cli/auth-check.d.ts.map +1 -0
  9. package/dist/cli/auth-check.js +50 -0
  10. package/dist/cli/auth-check.js.map +1 -0
  11. package/dist/cli/auth-command.d.ts +24 -0
  12. package/dist/cli/auth-command.d.ts.map +1 -0
  13. package/dist/cli/auth-command.js +103 -0
  14. package/dist/cli/auth-command.js.map +1 -0
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js +2 -2
  17. package/dist/cli/config-selector.js.map +1 -1
  18. package/dist/cli/credential-print.d.ts +13 -0
  19. package/dist/cli/credential-print.d.ts.map +1 -0
  20. package/dist/cli/credential-print.js +76 -0
  21. package/dist/cli/credential-print.js.map +1 -0
  22. package/dist/cli/experimental/auth.d.ts +16 -0
  23. package/dist/cli/experimental/auth.d.ts.map +1 -0
  24. package/dist/cli/experimental/auth.js +13 -0
  25. package/dist/cli/experimental/auth.js.map +1 -0
  26. package/dist/cli/experimental/cli.d.ts +6 -0
  27. package/dist/cli/experimental/cli.d.ts.map +1 -0
  28. package/dist/cli/experimental/cli.js +5 -0
  29. package/dist/cli/experimental/cli.js.map +1 -0
  30. package/dist/cli/experimental/command-options.d.ts +17 -0
  31. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  32. package/dist/cli/experimental/command-options.js +35 -0
  33. package/dist/cli/experimental/command-options.js.map +1 -0
  34. package/dist/cli/experimental/command.d.ts +63 -0
  35. package/dist/cli/experimental/command.d.ts.map +1 -0
  36. package/dist/cli/experimental/command.js +130 -0
  37. package/dist/cli/experimental/command.js.map +1 -0
  38. package/dist/cli/experimental/commands/client.d.ts +13 -0
  39. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  40. package/dist/cli/experimental/commands/client.js +25 -0
  41. package/dist/cli/experimental/commands/client.js.map +1 -0
  42. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  43. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/pi.js +28 -0
  45. package/dist/cli/experimental/commands/pi.js.map +1 -0
  46. package/dist/cli/experimental/commands/server.d.ts +13 -0
  47. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  48. package/dist/cli/experimental/commands/server.js +25 -0
  49. package/dist/cli/experimental/commands/server.js.map +1 -0
  50. package/dist/cli/experimental/transport-address.d.ts +10 -0
  51. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  52. package/dist/cli/experimental/transport-address.js +38 -0
  53. package/dist/cli/experimental/transport-address.js.map +1 -0
  54. package/dist/cli/list-models.d.ts +1 -1
  55. package/dist/cli/list-models.d.ts.map +1 -1
  56. package/dist/cli/list-models.js +2 -2
  57. package/dist/cli/list-models.js.map +1 -1
  58. package/dist/cli/startup-ui.d.ts +1 -1
  59. package/dist/cli/startup-ui.d.ts.map +1 -1
  60. package/dist/cli/startup-ui.js +2 -2
  61. package/dist/cli/startup-ui.js.map +1 -1
  62. package/dist/client/index.d.ts +3 -0
  63. package/dist/client/index.d.ts.map +1 -0
  64. package/dist/client/index.js +3 -0
  65. package/dist/client/index.js.map +1 -0
  66. package/dist/client/remote-session.d.ts +53 -0
  67. package/dist/client/remote-session.d.ts.map +1 -0
  68. package/dist/client/remote-session.js +340 -0
  69. package/dist/client/remote-session.js.map +1 -0
  70. package/dist/client/transcript.d.ts +12 -0
  71. package/dist/client/transcript.d.ts.map +1 -0
  72. package/dist/client/transcript.js +98 -0
  73. package/dist/client/transcript.js.map +1 -0
  74. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  75. package/dist/core/agent-session-runtime.js +3 -0
  76. package/dist/core/agent-session-runtime.js.map +1 -1
  77. package/dist/core/agent-session-services.d.ts +1 -0
  78. package/dist/core/agent-session-services.d.ts.map +1 -1
  79. package/dist/core/agent-session-services.js +1 -0
  80. package/dist/core/agent-session-services.js.map +1 -1
  81. package/dist/core/agent-session.d.ts +2 -11
  82. package/dist/core/agent-session.d.ts.map +1 -1
  83. package/dist/core/agent-session.js +85 -76
  84. package/dist/core/agent-session.js.map +1 -1
  85. package/dist/core/auth-storage.d.ts +25 -9
  86. package/dist/core/auth-storage.d.ts.map +1 -1
  87. package/dist/core/auth-storage.js +237 -39
  88. package/dist/core/auth-storage.js.map +1 -1
  89. package/dist/core/extensions/index.d.ts +1 -1
  90. package/dist/core/extensions/index.d.ts.map +1 -1
  91. package/dist/core/extensions/index.js.map +1 -1
  92. package/dist/core/extensions/loader.d.ts.map +1 -1
  93. package/dist/core/extensions/loader.js +60 -41
  94. package/dist/core/extensions/loader.js.map +1 -1
  95. package/dist/core/extensions/runner.d.ts +3 -1
  96. package/dist/core/extensions/runner.d.ts.map +1 -1
  97. package/dist/core/extensions/runner.js +10 -0
  98. package/dist/core/extensions/runner.js.map +1 -1
  99. package/dist/core/extensions/types.d.ts +34 -4
  100. package/dist/core/extensions/types.d.ts.map +1 -1
  101. package/dist/core/extensions/types.js.map +1 -1
  102. package/dist/core/footer-data-provider.d.ts +10 -0
  103. package/dist/core/footer-data-provider.d.ts.map +1 -1
  104. package/dist/core/footer-data-provider.js +1 -1
  105. package/dist/core/footer-data-provider.js.map +1 -1
  106. package/dist/core/http-dispatcher.d.ts.map +1 -1
  107. package/dist/core/http-dispatcher.js +5 -0
  108. package/dist/core/http-dispatcher.js.map +1 -1
  109. package/dist/core/keybindings.d.ts +45 -5
  110. package/dist/core/keybindings.d.ts.map +1 -1
  111. package/dist/core/keybindings.js.map +1 -1
  112. package/dist/core/model-config.d.ts +29 -5
  113. package/dist/core/model-config.d.ts.map +1 -1
  114. package/dist/core/model-config.js +4 -0
  115. package/dist/core/model-config.js.map +1 -1
  116. package/dist/core/model-registry.d.ts +5 -3
  117. package/dist/core/model-registry.d.ts.map +1 -1
  118. package/dist/core/model-registry.js +13 -10
  119. package/dist/core/model-registry.js.map +1 -1
  120. package/dist/core/model-resolver.d.ts +4 -3
  121. package/dist/core/model-resolver.d.ts.map +1 -1
  122. package/dist/core/model-resolver.js +42 -10
  123. package/dist/core/model-resolver.js.map +1 -1
  124. package/dist/core/model-runtime.d.ts +32 -13
  125. package/dist/core/model-runtime.d.ts.map +1 -1
  126. package/dist/core/model-runtime.js +233 -73
  127. package/dist/core/model-runtime.js.map +1 -1
  128. package/dist/core/models-store.d.ts +12 -7
  129. package/dist/core/models-store.d.ts.map +1 -1
  130. package/dist/core/models-store.js +83 -14
  131. package/dist/core/models-store.js.map +1 -1
  132. package/dist/core/package-manager.d.ts +6 -3
  133. package/dist/core/package-manager.d.ts.map +1 -1
  134. package/dist/core/package-manager.js +93 -67
  135. package/dist/core/package-manager.js.map +1 -1
  136. package/dist/core/pi-manifest.d.ts +8 -0
  137. package/dist/core/pi-manifest.d.ts.map +1 -0
  138. package/dist/core/pi-manifest.js +28 -0
  139. package/dist/core/pi-manifest.js.map +1 -0
  140. package/dist/core/provider-composer.d.ts +4 -1
  141. package/dist/core/provider-composer.d.ts.map +1 -1
  142. package/dist/core/provider-composer.js +36 -15
  143. package/dist/core/provider-composer.js.map +1 -1
  144. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  145. package/dist/core/remote-catalog-provider.js +73 -67
  146. package/dist/core/remote-catalog-provider.js.map +1 -1
  147. package/dist/core/resource-loader.d.ts +15 -0
  148. package/dist/core/resource-loader.d.ts.map +1 -1
  149. package/dist/core/resource-loader.js +64 -10
  150. package/dist/core/resource-loader.js.map +1 -1
  151. package/dist/core/runtime-credentials.d.ts +5 -5
  152. package/dist/core/runtime-credentials.d.ts.map +1 -1
  153. package/dist/core/runtime-credentials.js +11 -8
  154. package/dist/core/runtime-credentials.js.map +1 -1
  155. package/dist/core/sdk.d.ts +1 -1
  156. package/dist/core/sdk.d.ts.map +1 -1
  157. package/dist/core/sdk.js +2 -2
  158. package/dist/core/sdk.js.map +1 -1
  159. package/dist/core/session-manager.d.ts.map +1 -1
  160. package/dist/core/session-manager.js +3 -1
  161. package/dist/core/session-manager.js.map +1 -1
  162. package/dist/core/settings-manager.d.ts +12 -0
  163. package/dist/core/settings-manager.d.ts.map +1 -1
  164. package/dist/core/settings-manager.js +40 -16
  165. package/dist/core/settings-manager.js.map +1 -1
  166. package/dist/core/system-prompt.d.ts.map +1 -1
  167. package/dist/core/system-prompt.js +8 -0
  168. package/dist/core/system-prompt.js.map +1 -1
  169. package/dist/core/tools/bash.d.ts +5 -1
  170. package/dist/core/tools/bash.d.ts.map +1 -1
  171. package/dist/core/tools/bash.js +16 -15
  172. package/dist/core/tools/bash.js.map +1 -1
  173. package/dist/core/tools/edit.d.ts +4 -0
  174. package/dist/core/tools/edit.d.ts.map +1 -1
  175. package/dist/core/tools/edit.js +11 -7
  176. package/dist/core/tools/edit.js.map +1 -1
  177. package/dist/core/tools/find.d.ts +7 -0
  178. package/dist/core/tools/find.d.ts.map +1 -1
  179. package/dist/core/tools/find.js +16 -19
  180. package/dist/core/tools/find.js.map +1 -1
  181. package/dist/core/tools/grep.d.ts +4 -0
  182. package/dist/core/tools/grep.d.ts.map +1 -1
  183. package/dist/core/tools/grep.js +5 -1
  184. package/dist/core/tools/grep.js.map +1 -1
  185. package/dist/core/tools/ls.d.ts +4 -0
  186. package/dist/core/tools/ls.d.ts.map +1 -1
  187. package/dist/core/tools/ls.js +5 -1
  188. package/dist/core/tools/ls.js.map +1 -1
  189. package/dist/core/tools/read.d.ts +4 -0
  190. package/dist/core/tools/read.d.ts.map +1 -1
  191. package/dist/core/tools/read.js +7 -3
  192. package/dist/core/tools/read.js.map +1 -1
  193. package/dist/core/tools/write.d.ts +4 -0
  194. package/dist/core/tools/write.d.ts.map +1 -1
  195. package/dist/core/tools/write.js +6 -2
  196. package/dist/core/tools/write.js.map +1 -1
  197. package/dist/extensions/llama/index.d.ts.map +1 -1
  198. package/dist/extensions/llama/index.js +11 -2
  199. package/dist/extensions/llama/index.js.map +1 -1
  200. package/dist/extensions/llama/provider.d.ts.map +1 -1
  201. package/dist/extensions/llama/provider.js +22 -8
  202. package/dist/extensions/llama/provider.js.map +1 -1
  203. package/dist/humain/agent-execution-protocol.d.ts +218 -0
  204. package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
  205. package/dist/humain/agent-execution-protocol.js +204 -0
  206. package/dist/humain/agent-execution-protocol.js.map +1 -0
  207. package/dist/humain/agent-execution-runtime.d.ts +35 -0
  208. package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
  209. package/dist/humain/agent-execution-runtime.js +170 -0
  210. package/dist/humain/agent-execution-runtime.js.map +1 -0
  211. package/dist/humain/index.d.ts.map +1 -1
  212. package/dist/humain/index.js +8 -7
  213. package/dist/humain/index.js.map +1 -1
  214. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  215. package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
  216. package/dist/humain/mcp-adapter/vendor/README.md +733 -0
  217. package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
  218. package/dist/humain/mcp-adapter/vendor/agent-dir.ts +60 -0
  219. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
  220. package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
  221. package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
  222. package/dist/humain/mcp-adapter/vendor/cli.js +209 -0
  223. package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
  224. package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
  225. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
  226. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +604 -0
  227. package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
  228. package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
  229. package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
  230. package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
  231. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
  232. package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
  233. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +15923 -0
  234. package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
  235. package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
  236. package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
  237. package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
  238. package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
  239. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
  240. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
  241. package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
  242. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
  243. package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
  244. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
  245. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
  246. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
  247. package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
  248. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
  249. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +666 -0
  250. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
  251. package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
  252. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +353 -0
  253. package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
  254. package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
  255. package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
  256. package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
  257. package/dist/humain/mcp-adapter/vendor/package.json +178 -0
  258. package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
  259. package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
  260. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
  261. package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
  262. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
  263. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
  264. package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
  265. package/dist/humain/mcp-adapter/vendor/server-manager.ts +1124 -0
  266. package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
  267. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
  268. package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
  269. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
  270. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +276 -0
  271. package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
  272. package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
  273. package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
  274. package/dist/humain/mcp-adapter/vendor/types.ts +859 -0
  275. package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
  276. package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
  277. package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
  278. package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
  279. package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
  280. package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
  281. package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
  282. package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
  283. package/dist/humain/mcp-adapter.d.ts +3 -0
  284. package/dist/humain/mcp-adapter.d.ts.map +1 -0
  285. package/dist/humain/mcp-adapter.js +5 -0
  286. package/dist/humain/mcp-adapter.js.map +1 -0
  287. package/dist/humain/pi-agent-execution-host.d.ts +34 -0
  288. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
  289. package/dist/humain/pi-agent-execution-host.js +77 -0
  290. package/dist/humain/pi-agent-execution-host.js.map +1 -0
  291. package/dist/humain/web-access/host.d.ts +4 -0
  292. package/dist/humain/web-access/host.d.ts.map +1 -0
  293. package/dist/humain/web-access/host.js +3 -0
  294. package/dist/humain/web-access/host.js.map +1 -0
  295. package/dist/humain/web-access/index.d.ts +3 -0
  296. package/dist/humain/web-access/index.d.ts.map +1 -0
  297. package/dist/humain/web-access/index.js +5 -0
  298. package/dist/humain/web-access/index.js.map +1 -0
  299. package/dist/humain/web-access/vendor/activity.d.ts +34 -0
  300. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
  301. package/dist/humain/web-access/vendor/activity.js +68 -0
  302. package/dist/humain/web-access/vendor/activity.js.map +1 -0
  303. package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
  304. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
  305. package/dist/humain/web-access/vendor/anysearch.js +167 -0
  306. package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
  307. package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
  308. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
  309. package/dist/humain/web-access/vendor/bocha.js +219 -0
  310. package/dist/humain/web-access/vendor/bocha.js.map +1 -0
  311. package/dist/humain/web-access/vendor/brave.d.ts +4 -0
  312. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
  313. package/dist/humain/web-access/vendor/brave.js +194 -0
  314. package/dist/humain/web-access/vendor/brave.js.map +1 -0
  315. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
  316. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
  317. package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
  318. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
  319. package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
  320. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
  321. package/dist/humain/web-access/vendor/brightdata.js +519 -0
  322. package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
  323. package/dist/humain/web-access/vendor/chrome-cookies.d.ts +10 -0
  324. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
  325. package/dist/humain/web-access/vendor/chrome-cookies.js +438 -0
  326. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
  327. package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
  328. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
  329. package/dist/humain/web-access/vendor/content-find.js +117 -0
  330. package/dist/humain/web-access/vendor/content-find.js.map +1 -0
  331. package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
  332. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
  333. package/dist/humain/web-access/vendor/credential-source.js +151 -0
  334. package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
  335. package/dist/humain/web-access/vendor/curator-page.d.ts +29 -0
  336. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
  337. package/dist/humain/web-access/vendor/curator-page.js +3554 -0
  338. package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
  339. package/dist/humain/web-access/vendor/curator-server.d.ts +93 -0
  340. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
  341. package/dist/humain/web-access/vendor/curator-server.js +688 -0
  342. package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
  343. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
  344. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
  345. package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
  346. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
  347. package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
  348. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
  349. package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
  350. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
  351. package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
  352. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
  353. package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
  354. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
  355. package/dist/humain/web-access/vendor/exa.d.ts +10 -0
  356. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
  357. package/dist/humain/web-access/vendor/exa.js +426 -0
  358. package/dist/humain/web-access/vendor/exa.js.map +1 -0
  359. package/dist/humain/web-access/vendor/extract.d.ts +46 -0
  360. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
  361. package/dist/humain/web-access/vendor/extract.js +1064 -0
  362. package/dist/humain/web-access/vendor/extract.js.map +1 -0
  363. package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
  364. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
  365. package/dist/humain/web-access/vendor/feature-config.js +27 -0
  366. package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
  367. package/dist/humain/web-access/vendor/fetch-params.d.ts +25 -0
  368. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
  369. package/dist/humain/web-access/vendor/fetch-params.js +57 -0
  370. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
  371. package/dist/humain/web-access/vendor/firecrawl.d.ts +12 -0
  372. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
  373. package/dist/humain/web-access/vendor/firecrawl.js +239 -0
  374. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
  375. package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
  376. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
  377. package/dist/humain/web-access/vendor/gemini-api.js +230 -0
  378. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
  379. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
  380. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
  381. package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
  382. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
  383. package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
  384. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
  385. package/dist/humain/web-access/vendor/gemini-search.js +814 -0
  386. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
  387. package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
  388. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
  389. package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
  390. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
  391. package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
  392. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
  393. package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
  394. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
  395. package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
  396. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
  397. package/dist/humain/web-access/vendor/gemini-web.js +385 -0
  398. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
  399. package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
  400. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
  401. package/dist/humain/web-access/vendor/github-api.js +160 -0
  402. package/dist/humain/web-access/vendor/github-api.js.map +1 -0
  403. package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
  404. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
  405. package/dist/humain/web-access/vendor/github-extract.js +635 -0
  406. package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
  407. package/dist/humain/web-access/vendor/index.d.ts +4 -0
  408. package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
  409. package/dist/humain/web-access/vendor/index.js +3002 -0
  410. package/dist/humain/web-access/vendor/index.js.map +1 -0
  411. package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
  412. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
  413. package/dist/humain/web-access/vendor/jina-search.js +255 -0
  414. package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
  415. package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
  416. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
  417. package/dist/humain/web-access/vendor/kagi.js +262 -0
  418. package/dist/humain/web-access/vendor/kagi.js.map +1 -0
  419. package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
  420. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
  421. package/dist/humain/web-access/vendor/ollama.js +216 -0
  422. package/dist/humain/web-access/vendor/ollama.js.map +1 -0
  423. package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
  424. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
  425. package/dist/humain/web-access/vendor/openai-search.js +459 -0
  426. package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
  427. package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
  428. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
  429. package/dist/humain/web-access/vendor/page-query.js +79 -0
  430. package/dist/humain/web-access/vendor/page-query.js.map +1 -0
  431. package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
  432. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
  433. package/dist/humain/web-access/vendor/parallel.js +343 -0
  434. package/dist/humain/web-access/vendor/parallel.js.map +1 -0
  435. package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
  436. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
  437. package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
  438. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
  439. package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
  440. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
  441. package/dist/humain/web-access/vendor/perplexity.js +159 -0
  442. package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
  443. package/dist/humain/web-access/vendor/querit.d.ts +10 -0
  444. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
  445. package/dist/humain/web-access/vendor/querit.js +335 -0
  446. package/dist/humain/web-access/vendor/querit.js.map +1 -0
  447. package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
  448. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
  449. package/dist/humain/web-access/vendor/render-search-error.js +130 -0
  450. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
  451. package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
  452. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
  453. package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
  454. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
  455. package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
  456. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
  457. package/dist/humain/web-access/vendor/search1api.js +251 -0
  458. package/dist/humain/web-access/vendor/search1api.js.map +1 -0
  459. package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
  460. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
  461. package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
  462. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
  463. package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
  464. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
  465. package/dist/humain/web-access/vendor/searxng.js +238 -0
  466. package/dist/humain/web-access/vendor/searxng.js.map +1 -0
  467. package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
  468. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
  469. package/dist/humain/web-access/vendor/serpbase.js +211 -0
  470. package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
  471. package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
  472. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
  473. package/dist/humain/web-access/vendor/serpdive.js +267 -0
  474. package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
  475. package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
  476. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
  477. package/dist/humain/web-access/vendor/source-check.js +205 -0
  478. package/dist/humain/web-access/vendor/source-check.js.map +1 -0
  479. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
  480. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
  481. package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
  482. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
  483. package/dist/humain/web-access/vendor/storage.d.ts +55 -0
  484. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
  485. package/dist/humain/web-access/vendor/storage.js +485 -0
  486. package/dist/humain/web-access/vendor/storage.js.map +1 -0
  487. package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
  488. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
  489. package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
  490. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
  491. package/dist/humain/web-access/vendor/summary-review.d.ts +24 -0
  492. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
  493. package/dist/humain/web-access/vendor/summary-review.js +341 -0
  494. package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
  495. package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
  496. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
  497. package/dist/humain/web-access/vendor/tavily.js +194 -0
  498. package/dist/humain/web-access/vendor/tavily.js.map +1 -0
  499. package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
  500. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
  501. package/dist/humain/web-access/vendor/tinyfish.js +331 -0
  502. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
  503. package/dist/humain/web-access/vendor/utils.d.ts +20 -0
  504. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
  505. package/dist/humain/web-access/vendor/utils.js +91 -0
  506. package/dist/humain/web-access/vendor/utils.js.map +1 -0
  507. package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
  508. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
  509. package/dist/humain/web-access/vendor/video-extract.js +335 -0
  510. package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
  511. package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
  512. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
  513. package/dist/humain/web-access/vendor/xai-search.js +331 -0
  514. package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
  515. package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
  516. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
  517. package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
  518. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
  519. package/dist/index.d.ts +7 -4
  520. package/dist/index.d.ts.map +1 -1
  521. package/dist/index.js +5 -2
  522. package/dist/index.js.map +1 -1
  523. package/dist/main.d.ts +2 -2
  524. package/dist/main.d.ts.map +1 -1
  525. package/dist/main.js +194 -84
  526. package/dist/main.js.map +1 -1
  527. package/dist/modes/agent-exec-mode.d.ts +14 -0
  528. package/dist/modes/agent-exec-mode.d.ts.map +1 -0
  529. package/dist/modes/agent-exec-mode.js +92 -0
  530. package/dist/modes/agent-exec-mode.js.map +1 -0
  531. package/dist/modes/index.d.ts +4 -2
  532. package/dist/modes/index.d.ts.map +1 -1
  533. package/dist/modes/index.js +2 -1
  534. package/dist/modes/index.js.map +1 -1
  535. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  536. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  537. package/dist/modes/interactive/components/assistant-message.js +13 -4
  538. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  539. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  540. package/dist/modes/interactive/components/custom-editor.js +7 -0
  541. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  542. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  543. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  544. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  545. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  546. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  547. package/dist/modes/interactive/components/footer.js +1 -1
  548. package/dist/modes/interactive/components/footer.js.map +1 -1
  549. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  550. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  551. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  552. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  553. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  554. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  555. package/dist/modes/interactive/components/mermaid.js +75 -0
  556. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  557. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  558. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  559. package/dist/modes/interactive/components/model-selector.js +20 -5
  560. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  561. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  562. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  563. package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
  564. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  565. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  566. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  567. package/dist/modes/interactive/components/settings-selector.js +30 -0
  568. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  569. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  570. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  571. package/dist/modes/interactive/components/user-message.js +9 -2
  572. package/dist/modes/interactive/components/user-message.js.map +1 -1
  573. package/dist/modes/interactive/interactive-mode.d.ts +45 -9
  574. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  575. package/dist/modes/interactive/interactive-mode.js +601 -217
  576. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  577. package/dist/modes/interactive/theme/dark.json +1 -0
  578. package/dist/modes/interactive/theme/light.json +1 -0
  579. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  580. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  581. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  582. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  583. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  584. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  585. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  586. package/dist/modes/interactive/theme/theme.js +24 -6
  587. package/dist/modes/interactive/theme/theme.js.map +1 -1
  588. package/dist/modes/json-event.d.ts +28 -0
  589. package/dist/modes/json-event.d.ts.map +1 -0
  590. package/dist/modes/json-event.js +12 -0
  591. package/dist/modes/json-event.js.map +1 -0
  592. package/dist/modes/print-mode.d.ts.map +1 -1
  593. package/dist/modes/print-mode.js +12 -2
  594. package/dist/modes/print-mode.js.map +1 -1
  595. package/dist/modes/rpc/rpc-client.d.ts +12 -5
  596. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  597. package/dist/modes/rpc/rpc-client.js +55 -1
  598. package/dist/modes/rpc/rpc-client.js.map +1 -1
  599. package/dist/modes/rpc/rpc-mode.d.ts +1 -1
  600. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  601. package/dist/modes/rpc/rpc-mode.js +26 -3
  602. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  603. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  604. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  605. package/dist/modes/rpc/rpc-types.js.map +1 -1
  606. package/dist/package-manager-cli.d.ts.map +1 -1
  607. package/dist/package-manager-cli.js +11 -9
  608. package/dist/package-manager-cli.js.map +1 -1
  609. package/dist/rpc-entry.d.ts.map +1 -1
  610. package/dist/rpc-entry.js +3 -2
  611. package/dist/rpc-entry.js.map +1 -1
  612. package/dist/server/create-harness.d.ts +26 -0
  613. package/dist/server/create-harness.d.ts.map +1 -0
  614. package/dist/server/create-harness.js +104 -0
  615. package/dist/server/create-harness.js.map +1 -0
  616. package/dist/utils/abort.d.ts +5 -0
  617. package/dist/utils/abort.d.ts.map +1 -0
  618. package/dist/utils/abort.js +48 -0
  619. package/dist/utils/abort.js.map +1 -0
  620. package/dist/utils/clipboard.d.ts +1 -1
  621. package/dist/utils/clipboard.d.ts.map +1 -1
  622. package/dist/utils/clipboard.js +22 -2
  623. package/dist/utils/clipboard.js.map +1 -1
  624. package/dist/utils/management-http.d.ts +23 -0
  625. package/dist/utils/management-http.d.ts.map +1 -0
  626. package/dist/utils/management-http.js +50 -0
  627. package/dist/utils/management-http.js.map +1 -0
  628. package/dist/utils/paths.d.ts +3 -0
  629. package/dist/utils/paths.d.ts.map +1 -1
  630. package/dist/utils/paths.js +23 -1
  631. package/dist/utils/paths.js.map +1 -1
  632. package/dist/utils/tool-result-images.d.ts +19 -0
  633. package/dist/utils/tool-result-images.d.ts.map +1 -0
  634. package/dist/utils/tool-result-images.js +45 -0
  635. package/dist/utils/tool-result-images.js.map +1 -0
  636. package/dist/utils/tools-manager.d.ts.map +1 -1
  637. package/dist/utils/tools-manager.js +13 -25
  638. package/dist/utils/tools-manager.js.map +1 -1
  639. package/dist/utils/version-check.d.ts +4 -0
  640. package/dist/utils/version-check.d.ts.map +1 -1
  641. package/dist/utils/version-check.js +23 -5
  642. package/dist/utils/version-check.js.map +1 -1
  643. package/docs/compaction.md +2 -2
  644. package/docs/custom-provider.md +16 -8
  645. package/docs/extensions.md +33 -6
  646. package/docs/humain-terminal.md +21 -1
  647. package/docs/json.md +24 -19
  648. package/docs/keybindings.md +46 -14
  649. package/docs/models.md +32 -11
  650. package/docs/providers.md +10 -1
  651. package/docs/quickstart.md +39 -37
  652. package/docs/rpc.md +31 -11
  653. package/docs/sdk.md +21 -2
  654. package/docs/security.md +21 -21
  655. package/docs/session-format.md +15 -13
  656. package/docs/settings.md +4 -1
  657. package/docs/themes.md +5 -3
  658. package/docs/usage.md +7 -0
  659. package/examples/extensions/custom-compaction.ts +3 -18
  660. package/examples/extensions/custom-provider-anthropic/index.ts +13 -3
  661. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  662. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  663. package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
  664. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  665. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  666. package/examples/extensions/gondolin/package-lock.json +2 -2
  667. package/examples/extensions/gondolin/package.json +1 -1
  668. package/examples/extensions/handoff.ts +4 -13
  669. package/examples/extensions/qna.ts +5 -9
  670. package/examples/extensions/sandbox/package-lock.json +2 -2
  671. package/examples/extensions/sandbox/package.json +1 -1
  672. package/examples/extensions/summarize.ts +9 -20
  673. package/examples/extensions/with-deps/package-lock.json +2 -2
  674. package/examples/extensions/with-deps/package.json +1 -1
  675. package/examples/rpc-extension-ui.ts +11 -2
  676. package/examples/sdk/02-custom-model.ts +2 -3
  677. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  678. package/examples/sdk/12-full-control.ts +3 -1
  679. package/examples/sdk/README.md +1 -1
  680. package/npm-shrinkwrap.json +2779 -543
  681. package/package.json +42 -13
  682. package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
  683. package/src/humain/mcp-adapter/upstream.json +7 -0
  684. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  685. package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
  686. package/src/humain/web-access/UPSTREAM.md +17 -0
  687. package/src/humain/web-access/upstream.json +23 -0
  688. package/src/humain/web-access/vendor/LICENSE +21 -0
@@ -6,10 +6,11 @@ import * as crypto from "node:crypto";
6
6
  import * as fs from "node:fs";
7
7
  import * as os from "node:os";
8
8
  import * as path from "node:path";
9
- import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
9
+ import * as TuiLayouts from "@earendil-works/pi-tui";
10
+ import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
10
11
  import chalk from "chalk";
11
12
  import { spawn, spawnSync } from "child_process";
12
- import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, ENV_OFFLINE, getAgentDir, getAuthPath, getChangelogUrl, getDebugLogPath, getDocsPath, getInstallTelemetryUrl, getShareViewerUrl, VERSION, } from "../../config.js";
13
+ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
13
14
  import { parseSkillBlock } from "../../core/agent-session.js";
14
15
  import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
15
16
  import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
@@ -17,7 +18,8 @@ import { FooterDataProvider } from "../../core/footer-data-provider.js";
17
18
  import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
18
19
  import { KeybindingsManager } from "../../core/keybindings.js";
19
20
  import { createCompactionSummaryMessage } from "../../core/messages.js";
20
- import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, resolveModelScopeWithDiagnostics, } from "../../core/model-resolver.js";
21
+ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScopeFromModels, } from "../../core/model-resolver.js";
22
+ import { CredentialSynchronizationError } from "../../core/model-runtime.js";
21
23
  import { DefaultPackageManager } from "../../core/package-manager.js";
22
24
  import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
23
25
  import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
@@ -29,6 +31,8 @@ import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelo
29
31
  import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
30
32
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
31
33
  import { parseGitUrl } from "../../utils/git.js";
34
+ import { openBrowser } from "../../utils/open-browser.js";
35
+ import { getCwdRelativePath } from "../../utils/paths.js";
32
36
  import { getPiUserAgent } from "../../utils/pi-user-agent.js";
33
37
  import { killTrackedDetachedChildren } from "../../utils/shell.js";
34
38
  import { ensureTool } from "../../utils/tools-manager.js";
@@ -44,12 +48,14 @@ import { CustomEntryComponent } from "./components/custom-entry.js";
44
48
  import { CustomMessageComponent } from "./components/custom-message.js";
45
49
  import { DaxnutsComponent } from "./components/daxnuts.js";
46
50
  import { DynamicBorder } from "./components/dynamic-border.js";
51
+ import { EarendilAnnouncementComponent } from "./components/earendil-announcement.js";
47
52
  import { ExtensionEditorComponent } from "./components/extension-editor.js";
48
53
  import { ExtensionInputComponent } from "./components/extension-input.js";
49
54
  import { ExtensionSelectorComponent } from "./components/extension-selector.js";
50
55
  import { FooterComponent, formatTokens } from "./components/footer.js";
51
56
  import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
52
57
  import { LoginDialogComponent } from "./components/login-dialog.js";
58
+ import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
53
59
  import { ModelSelectorComponent } from "./components/model-selector.js";
54
60
  import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
55
61
  import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
@@ -159,11 +165,58 @@ function formatLoginProviderCompletionDescription(provider) {
159
165
  const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
160
166
  return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
161
167
  }
168
+ /** Composition root for selecting the interactive terminal renderer. */
169
+ export function createInteractiveTui(options) {
170
+ const terminal = options.terminal ?? new ProcessTerminal();
171
+ if (options.tuiMode === "fullscreen") {
172
+ return new TuiAltScreen(terminal, options.showHardwareCursor, options.logDirectory, {
173
+ openUrl: openBrowser,
174
+ onRightClickPaste: options.onRightClickPaste,
175
+ });
176
+ }
177
+ return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);
178
+ }
179
+ /** Stable reference for components while InteractiveMode replaces the active renderer. */
180
+ export function createInteractiveTuiReference(getTui) {
181
+ return new Proxy({}, {
182
+ get: (_target, property) => {
183
+ const tui = getTui();
184
+ const value = Reflect.get(tui, property, tui);
185
+ if (typeof value !== "function")
186
+ return value;
187
+ let methodTui = tui;
188
+ let method = value;
189
+ return (...args) => {
190
+ const currentTui = getTui();
191
+ if (currentTui !== methodTui) {
192
+ const currentMethod = Reflect.get(currentTui, property, currentTui);
193
+ if (typeof currentMethod !== "function") {
194
+ throw new TypeError(`TUI property ${String(property)} is not callable`);
195
+ }
196
+ methodTui = currentTui;
197
+ method = currentMethod;
198
+ }
199
+ return Reflect.apply(method, methodTui, args);
200
+ };
201
+ },
202
+ set: (_target, property, value) => {
203
+ const tui = getTui();
204
+ return Reflect.set(tui, property, value, tui);
205
+ },
206
+ has: (_target, property) => Reflect.has(getTui(), property),
207
+ getPrototypeOf: () => Reflect.getPrototypeOf(getTui()),
208
+ });
209
+ }
162
210
  export class InteractiveMode {
163
211
  runtimeHost;
212
+ renderer;
164
213
  ui;
214
+ mainScreenRenderState;
165
215
  loadedResourcesContainer;
166
216
  chatContainer;
217
+ documentContainer;
218
+ transcriptScrollView;
219
+ fullscreenLayoutRoot;
167
220
  pendingMessagesContainer;
168
221
  statusContainer;
169
222
  defaultEditor;
@@ -173,7 +226,10 @@ export class InteractiveMode {
173
226
  autocompleteProviderWrappers = [];
174
227
  fdPath;
175
228
  editorContainer;
229
+ activeSelectorToken;
230
+ activeSelectorDispose;
176
231
  footer;
232
+ footerContainer;
177
233
  footerDataProvider;
178
234
  // Stored so the same manager can be injected into custom editors, selectors, and extension UI.
179
235
  keybindings;
@@ -207,6 +263,10 @@ export class InteractiveMode {
207
263
  // Thinking block visibility state
208
264
  hideThinkingBlock = false;
209
265
  outputPad = 1;
266
+ mermaidMarkdownTransformer = createMermaidMarkdownTransformer({
267
+ getMode: () => this.settingsManager.getMermaidRenderingMode(),
268
+ theme,
269
+ });
210
270
  // Skill commands: command name -> skill file path
211
271
  skillCommands = new Map();
212
272
  // Agent subscription unsubscribe function
@@ -230,7 +290,7 @@ export class InteractiveMode {
230
290
  extensionSelector = undefined;
231
291
  extensionInput = undefined;
232
292
  extensionEditor = undefined;
233
- extensionTerminalInputUnsubscribers = new Set();
293
+ extensionTerminalInputSubscriptions = new Set();
234
294
  // Extension widgets (components rendered above/below the editor)
235
295
  extensionWidgetsAbove = new Map();
236
296
  extensionWidgetsBelow = new Map();
@@ -245,6 +305,9 @@ export class InteractiveMode {
245
305
  // Custom header from extension (undefined = use built-in header)
246
306
  customHeader = undefined;
247
307
  options;
308
+ onRightClickPaste = () => {
309
+ void this.handleRightClickPaste();
310
+ };
248
311
  autoTrustOnReloadCwd;
249
312
  themeController;
250
313
  // Convenience accessors
@@ -262,7 +325,8 @@ export class InteractiveMode {
262
325
  }
263
326
  constructor(runtimeHost, options = {}) {
264
327
  this.runtimeHost = runtimeHost;
265
- this.options = options;
328
+ const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
329
+ this.options = { ...options, tuiMode };
266
330
  this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
267
331
  this.runtimeHost.setBeforeSessionInvalidate(() => {
268
332
  this.resetExtensionUI();
@@ -271,11 +335,21 @@ export class InteractiveMode {
271
335
  await this.rebindCurrentSession({ renderBeforeBind: true });
272
336
  });
273
337
  this.version = VERSION;
274
- this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor(), getAgentDir());
338
+ this.renderer = createInteractiveTui({
339
+ tuiMode,
340
+ showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
341
+ logDirectory: getAgentDir(),
342
+ onRightClickPaste: this.onRightClickPaste,
343
+ });
344
+ this.ui = createInteractiveTuiReference(() => this.renderer);
275
345
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
276
346
  this.headerContainer = new Container();
277
347
  this.loadedResourcesContainer = new Container();
278
348
  this.chatContainer = new Container();
349
+ this.documentContainer = new Container();
350
+ this.documentContainer.addChild(this.headerContainer);
351
+ this.documentContainer.addChild(this.loadedResourcesContainer);
352
+ this.documentContainer.addChild(this.chatContainer);
279
353
  this.pendingMessagesContainer = new Container();
280
354
  this.statusContainer = new Container();
281
355
  this.widgetContainerAbove = new Container();
@@ -294,6 +368,8 @@ export class InteractiveMode {
294
368
  this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
295
369
  this.footer = new FooterComponent(this.session, this.footerDataProvider);
296
370
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
371
+ this.footerContainer = new Container();
372
+ this.footerContainer.addChild(this.footer);
297
373
  // Load hide thinking block setting
298
374
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
299
375
  this.outputPad = this.settingsManager.getOutputPad();
@@ -349,11 +425,10 @@ export class InteractiveMode {
349
425
  }));
350
426
  const modelCommand = slashCommands.find((command) => command.name === "model");
351
427
  if (modelCommand) {
352
- modelCommand.getArgumentCompletions = async (prefix) => {
353
- // Get available models (scoped or from registry)
428
+ modelCommand.getArgumentCompletions = (prefix) => {
354
429
  const models = this.session.scopedModels.length > 0
355
430
  ? this.session.scopedModels.map((s) => s.model)
356
- : await this.session.modelRuntime.getAvailable();
431
+ : this.session.modelRuntime.getAvailableSnapshot();
357
432
  if (models.length === 0)
358
433
  return null;
359
434
  // Create items with provider/id format
@@ -454,6 +529,73 @@ export class InteractiveMode {
454
529
  }
455
530
  this.chatContainer.addChild(new DynamicBorder());
456
531
  }
532
+ mountInteractiveTui(tui, components) {
533
+ for (const component of components)
534
+ tui.addChild(component);
535
+ if (TuiLayouts.isViewportTUI(tui)) {
536
+ if (!this.fullscreenLayoutRoot)
537
+ throw new Error("Fullscreen layout is not initialized");
538
+ tui.setLayoutRoot(this.fullscreenLayoutRoot);
539
+ }
540
+ }
541
+ stopInteractiveTui() {
542
+ if (this.renderer.mode === "fullscreen") {
543
+ while (this.renderer.hasOverlayEntries)
544
+ this.renderer.hideOverlay();
545
+ this.switchTuiMode("regular", false, false);
546
+ this.renderer.renderNow();
547
+ }
548
+ this.ui.stop();
549
+ }
550
+ switchTuiMode(mode, restoreProgress = true, startRenderer = true) {
551
+ const previousUi = this.renderer;
552
+ if (mode === previousUi.mode)
553
+ return true;
554
+ if (previousUi.hasOverlayEntries)
555
+ return false;
556
+ const components = [...previousUi.children];
557
+ const focus = previousUi.getFocusedComponent();
558
+ const terminal = previousUi.terminal;
559
+ const showHardwareCursor = previousUi.getShowHardwareCursor();
560
+ const clearOnShrink = previousUi.getClearOnShrink();
561
+ const onDebug = previousUi.onDebug;
562
+ if (previousUi instanceof TuiMainScreen) {
563
+ this.mainScreenRenderState = previousUi.captureRenderState();
564
+ }
565
+ previousUi.stop({ preserveScreen: true });
566
+ previousUi.setFocus(null);
567
+ previousUi.clear();
568
+ if (TuiLayouts.isViewportTUI(previousUi))
569
+ previousUi.setLayoutRoot(undefined);
570
+ const nextUi = createInteractiveTui({
571
+ tuiMode: mode,
572
+ showHardwareCursor,
573
+ logDirectory: getAgentDir(),
574
+ terminal,
575
+ onRightClickPaste: this.onRightClickPaste,
576
+ });
577
+ nextUi.setClearOnShrink(clearOnShrink);
578
+ nextUi.onDebug = onDebug;
579
+ if (nextUi instanceof TuiMainScreen && this.mainScreenRenderState) {
580
+ nextUi.restoreRenderState(this.mainScreenRenderState);
581
+ }
582
+ this.renderer = nextUi;
583
+ this.options.tuiMode = mode;
584
+ this.mountInteractiveTui(nextUi, components);
585
+ nextUi.invalidate();
586
+ nextUi.setFocus(focus);
587
+ if (!startRenderer)
588
+ return true;
589
+ nextUi.start();
590
+ this.themeController.rebindTui();
591
+ this.rebindExtensionTerminalInputListeners();
592
+ if (restoreProgress &&
593
+ this.settingsManager.getShowTerminalProgress() &&
594
+ (this.session.isStreaming || this.session.isCompacting)) {
595
+ terminal.setProgress(true);
596
+ }
597
+ return true;
598
+ }
457
599
  async init() {
458
600
  if (this.isInitialized)
459
601
  return;
@@ -477,18 +619,36 @@ export class InteractiveMode {
477
619
  : "";
478
620
  console.log(theme.fg("dim", `Model scope: ${modelList}${cycleHint}`));
479
621
  }
480
- // Add header container as first child. Populate it after applying theme settings.
481
- // Keep loaded resources before chat so restored session messages never precede them.
482
- this.ui.addChild(this.headerContainer);
483
- this.ui.addChild(this.loadedResourcesContainer);
484
- this.ui.addChild(this.chatContainer);
485
- this.ui.addChild(this.pendingMessagesContainer);
486
- this.ui.addChild(this.statusContainer);
622
+ // Keep one component tree and remount it when changing renderers.
487
623
  this.renderWidgets(); // Initialize with default spacer
488
- this.ui.addChild(this.widgetContainerAbove);
489
- this.ui.addChild(this.editorContainer);
490
- this.ui.addChild(this.widgetContainerBelow);
491
- this.ui.addChild(this.footer);
624
+ this.transcriptScrollView = new TuiLayouts.ScrollView(this.documentContainer, {
625
+ follow: "end",
626
+ primary: true,
627
+ overscroll: "chain",
628
+ scrollbar: this.settingsManager.getFullscreenScrollbar(),
629
+ scrollbarStyle: (text) => theme.bg("scrollbarThumb", text),
630
+ });
631
+ const dock = new TuiLayouts.VStack([
632
+ { component: this.pendingMessagesContainer, shrink: 1, minSize: 0 },
633
+ { component: this.statusContainer, shrink: 1, minSize: 0 },
634
+ { component: this.widgetContainerAbove, shrink: 1, minSize: 0 },
635
+ { component: this.editorContainer, shrink: 1, minSize: 3 },
636
+ { component: this.widgetContainerBelow, shrink: 1, minSize: 0 },
637
+ { component: this.footerContainer, shrink: 1, minSize: 1 },
638
+ ]);
639
+ this.fullscreenLayoutRoot = new TuiLayouts.VStack([
640
+ { component: this.transcriptScrollView, basis: 0, grow: 1, shrink: 1, minSize: 1 },
641
+ { component: dock, basis: "auto", grow: 0, shrink: 1, minSize: 1 },
642
+ ]);
643
+ this.mountInteractiveTui(this.renderer, [
644
+ this.documentContainer,
645
+ this.pendingMessagesContainer,
646
+ this.statusContainer,
647
+ this.widgetContainerAbove,
648
+ this.editorContainer,
649
+ this.widgetContainerBelow,
650
+ this.footerContainer,
651
+ ]);
492
652
  this.ui.setFocus(this.editor);
493
653
  this.setupKeyHandlers();
494
654
  this.setupEditorSubmitHandler();
@@ -498,7 +658,7 @@ export class InteractiveMode {
498
658
  await this.themeController.applyFromSettings();
499
659
  // Add header with keybindings from config (unless silenced)
500
660
  if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
501
- const logo = theme.fg("accent", APP_TITLE) + theme.fg("dim", ` v${this.version}`);
661
+ const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
502
662
  // Build startup instructions using keybinding hint helpers
503
663
  const hint = (keybinding, description) => keyHint(keybinding, description);
504
664
  const expandedInstructions = [
@@ -530,7 +690,7 @@ export class InteractiveMode {
530
690
  hint("app.tools.expand", "more"),
531
691
  ].join(theme.fg("muted", " · "));
532
692
  const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
533
- const onboarding = theme.fg("dim", `${APP_TITLE} can explain its own features, model profiles, and package resources.`);
693
+ const onboarding = theme.fg("dim", `Pi can explain its own features and look up its docs. Ask it how to use or extend Pi.`);
534
694
  this.builtInHeader = new ExpandableText(() => `${logo}\n${compactInstructions}\n${compactOnboarding}\n\n${onboarding}`, () => `${logo}\n${expandedInstructions}\n\n${onboarding}`, this.getStartupExpansionState(), 1, 0);
535
695
  // Setup UI layout
536
696
  this.headerContainer.addChild(new Spacer(1));
@@ -580,10 +740,13 @@ export class InteractiveMode {
580
740
  async run() {
581
741
  await this.init();
582
742
  if (!process.env.PI_OFFLINE) {
743
+ const controller = new AbortController();
744
+ const timeout = setTimeout(() => controller.abort(), 15_000);
583
745
  void this.session.modelRuntime
584
- .refresh()
746
+ .refresh({ signal: controller.signal })
585
747
  .then(() => this.updateAvailableProviderCount())
586
- .catch(() => { });
748
+ .catch(() => { })
749
+ .finally(() => clearTimeout(timeout));
587
750
  }
588
751
  // Start version check asynchronously
589
752
  checkForNewPiVersion(this.version).then((newRelease) => {
@@ -620,7 +783,7 @@ export class InteractiveMode {
620
783
  if (modelsJsonError) {
621
784
  this.showError(`models.json error: ${modelsJsonError}`);
622
785
  }
623
- if (modelFallbackMessage && !this.isNoModelsAvailableMessage(modelFallbackMessage)) {
786
+ if (modelFallbackMessage) {
624
787
  this.showWarning(modelFallbackMessage);
625
788
  }
626
789
  void this.maybeWarnAboutAnthropicSubscriptionAuth();
@@ -658,7 +821,7 @@ export class InteractiveMode {
658
821
  }
659
822
  }
660
823
  async checkForPackageUpdates() {
661
- if (process.env[ENV_OFFLINE]) {
824
+ if (process.env.PI_OFFLINE) {
662
825
  return [];
663
826
  }
664
827
  try {
@@ -711,7 +874,7 @@ export class InteractiveMode {
711
874
  return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
712
875
  }
713
876
  if (extendedKeysFormat === "xterm") {
714
- return `tmux extended-keys-format is xterm. ${APP_TITLE} works best with csi-u. Add \`set -g extended-keys-format csi-u\` to ~/.tmux.conf and restart tmux.`;
877
+ return "tmux extended-keys-format is xterm. Pi works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
715
878
  }
716
879
  return undefined;
717
880
  }
@@ -742,13 +905,13 @@ export class InteractiveMode {
742
905
  return undefined;
743
906
  }
744
907
  reportInstallTelemetry(version) {
745
- if (process.env[ENV_OFFLINE]) {
908
+ if (process.env.PI_OFFLINE) {
746
909
  return;
747
910
  }
748
911
  if (!isInstallTelemetryEnabled(this.settingsManager)) {
749
912
  return;
750
913
  }
751
- void fetch(getInstallTelemetryUrl(version), {
914
+ void fetch(`https://pi.dev/api/report-install?version=${encodeURIComponent(version)}`, {
752
915
  headers: {
753
916
  "User-Agent": getPiUserAgent(version),
754
917
  },
@@ -763,20 +926,6 @@ export class InteractiveMode {
763
926
  codeBlockIndent: this.settingsManager.getCodeBlockIndent(),
764
927
  };
765
928
  }
766
- isNoModelsAvailableMessage(message) {
767
- return message?.startsWith("No models available.") ?? false;
768
- }
769
- getNoModelsStartupNotice() {
770
- if (!this.isNoModelsAvailableMessage(this.options.modelFallbackMessage)) {
771
- return undefined;
772
- }
773
- return [
774
- theme.bold(theme.fg("warning", "Model setup required")),
775
- `${theme.fg("muted", "No models are available yet. Run ")}${theme.bold("/login")}${theme.fg("muted", " to add a provider.")}`,
776
- `${theme.fg("dim", "Then use ")}${theme.bold("/model")}${theme.fg("dim", " if you want to switch models.")}`,
777
- `${theme.fg("dim", "Docs: ")}${theme.fg("accent", "docs/providers.md")}${theme.fg("dim", ", ")}${theme.fg("accent", "docs/models.md")}`,
778
- ].join("\n");
779
- }
780
929
  // =========================================================================
781
930
  // Extension System
782
931
  // =========================================================================
@@ -794,6 +943,15 @@ export class InteractiveMode {
794
943
  result = result.replace(/\/index\.ts$/, "").replace(/\/index\.js$/, "");
795
944
  return result;
796
945
  }
946
+ formatContextPath(p) {
947
+ const cwd = path.resolve(this.sessionManager.getCwd());
948
+ const absolutePath = path.isAbsolute(p) ? path.resolve(p) : path.resolve(cwd, p);
949
+ const relativePath = getCwdRelativePath(absolutePath, cwd);
950
+ if (relativePath !== undefined) {
951
+ return relativePath;
952
+ }
953
+ return this.formatDisplayPath(absolutePath);
954
+ }
797
955
  getStartupExpansionState() {
798
956
  return this.options.verbose || this.toolOutputExpanded;
799
957
  }
@@ -830,43 +988,92 @@ export class InteractiveMode {
830
988
  }
831
989
  return this.formatDisplayPath(fullPath);
832
990
  }
833
- stripNpmPackageVersion(packageSpec) {
834
- if (packageSpec.startsWith("@")) {
835
- const versionStart = packageSpec.indexOf("@", packageSpec.indexOf("/") + 1);
836
- return versionStart === -1 ? packageSpec : packageSpec.slice(0, versionStart);
991
+ getCompactPathLabel(resourcePath, sourceInfo) {
992
+ const shortPath = this.getShortPath(resourcePath, sourceInfo);
993
+ const normalizedPath = shortPath.replace(/\\/g, "/");
994
+ const segments = normalizedPath.split("/").filter((segment) => segment.length > 0 && segment !== "~");
995
+ if (segments.length > 0) {
996
+ return segments[segments.length - 1];
837
997
  }
838
- const versionStart = packageSpec.indexOf("@");
839
- return versionStart === -1 ? packageSpec : packageSpec.slice(0, versionStart);
998
+ return shortPath;
840
999
  }
841
- stripLegacyPackagePrefix(packageName) {
842
- const scopedMatch = /^(@[^/]+)\/(.+)$/.exec(packageName);
843
- if (scopedMatch) {
844
- return `${scopedMatch[1]}/${this.stripLegacyPackagePrefix(scopedMatch[2])}`;
845
- }
846
- const sanitized = packageName.replace(/^pi[-_]/, "");
847
- return sanitized || packageName;
848
- }
849
- getPackageSourceName(source) {
1000
+ getCompactPackageSourceLabel(sourceInfo) {
1001
+ const source = sourceInfo?.source ?? "";
850
1002
  if (source.startsWith("npm:")) {
851
- return this.stripLegacyPackagePrefix(this.stripNpmPackageVersion(source.slice("npm:".length)));
1003
+ return source.slice("npm:".length) || source;
852
1004
  }
853
1005
  const gitSource = parseGitUrl(source);
854
- if (gitSource?.path) {
855
- return gitSource.path
856
- .split("/")
857
- .map((segment, index, segments) => index === segments.length - 1 ? this.stripLegacyPackagePrefix(segment) : segment)
858
- .join("/");
1006
+ if (gitSource) {
1007
+ return gitSource.path || source;
859
1008
  }
860
1009
  return source;
861
1010
  }
862
- getDisplaySourceLabel(source) {
863
- if (source.startsWith("npm:")) {
864
- return `npm:${this.getPackageSourceName(source)}`;
865
- }
866
- if (source.startsWith("git:")) {
867
- return `git:${this.getPackageSourceName(source)}`;
1011
+ getCompactExtensionLabel(resourcePath, sourceInfo) {
1012
+ if (!this.isPackageSource(sourceInfo)) {
1013
+ return this.getCompactPathLabel(resourcePath, sourceInfo);
1014
+ }
1015
+ const sourceLabel = this.getCompactPackageSourceLabel(sourceInfo);
1016
+ if (!sourceLabel) {
1017
+ return this.getCompactPathLabel(resourcePath, sourceInfo);
1018
+ }
1019
+ const shortPath = this.getShortPath(resourcePath, sourceInfo).replace(/\\/g, "/");
1020
+ const packagePath = shortPath.startsWith("extensions/") ? shortPath.slice("extensions/".length) : shortPath;
1021
+ const parsedPath = path.posix.parse(packagePath);
1022
+ if (parsedPath.name === "index") {
1023
+ return !parsedPath.dir || parsedPath.dir === "." ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;
1024
+ }
1025
+ return `${sourceLabel}:${packagePath}`;
1026
+ }
1027
+ getCompactDisplayPathSegments(resourcePath) {
1028
+ return this.formatDisplayPath(resourcePath)
1029
+ .replace(/\\/g, "/")
1030
+ .split("/")
1031
+ .filter((segment) => segment.length > 0 && segment !== "~");
1032
+ }
1033
+ getCompactNonPackageExtensionLabel(resourcePath, index, allPaths) {
1034
+ const segments = allPaths[index]?.segments;
1035
+ if (!segments || segments.length === 0) {
1036
+ return this.getCompactPathLabel(resourcePath);
1037
+ }
1038
+ for (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {
1039
+ const candidate = segments.slice(-segmentCount).join("/");
1040
+ const isUnique = allPaths.every((item, itemIndex) => {
1041
+ if (itemIndex === index) {
1042
+ return true;
1043
+ }
1044
+ return item.segments.slice(-segmentCount).join("/") !== candidate;
1045
+ });
1046
+ if (isUnique) {
1047
+ return candidate;
1048
+ }
868
1049
  }
869
- return source;
1050
+ return segments.join("/");
1051
+ }
1052
+ getCompactExtensionLabels(extensions) {
1053
+ const nonPackageExtensions = extensions
1054
+ .map((extension) => {
1055
+ const segments = this.getCompactDisplayPathSegments(extension.path);
1056
+ const lastSegment = segments[segments.length - 1];
1057
+ if (segments.length > 1 && (lastSegment === "index.ts" || lastSegment === "index.js")) {
1058
+ segments.pop();
1059
+ }
1060
+ return {
1061
+ path: extension.path,
1062
+ sourceInfo: extension.sourceInfo,
1063
+ segments,
1064
+ };
1065
+ })
1066
+ .filter((extension) => !this.isPackageSource(extension.sourceInfo));
1067
+ return extensions.map((extension) => {
1068
+ if (this.isPackageSource(extension.sourceInfo)) {
1069
+ return this.getCompactExtensionLabel(extension.path, extension.sourceInfo);
1070
+ }
1071
+ const nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);
1072
+ if (nonPackageIndex === -1) {
1073
+ return this.getCompactPathLabel(extension.path, extension.sourceInfo);
1074
+ }
1075
+ return this.getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);
1076
+ });
870
1077
  }
871
1078
  getDisplaySourceInfo(sourceInfo) {
872
1079
  const source = sourceInfo?.source ?? "local";
@@ -887,7 +1094,7 @@ export class InteractiveMode {
887
1094
  return { label: "path", scopeLabel: scope === "temporary" ? "temp" : undefined, color: "muted" };
888
1095
  }
889
1096
  const scopeLabel = scope === "user" ? "user" : scope === "project" ? "project" : scope === "temporary" ? "temp" : undefined;
890
- return { label: this.getDisplaySourceLabel(source), scopeLabel, color: "accent" };
1097
+ return { label: source, scopeLabel, color: "accent" };
891
1098
  }
892
1099
  getScopeGroup(sourceInfo) {
893
1100
  const source = sourceInfo?.source ?? "local";
@@ -935,7 +1142,7 @@ export class InteractiveMode {
935
1142
  }
936
1143
  const sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));
937
1144
  for (const [source, items] of sortedPackages) {
938
- lines.push(` ${theme.fg("mdLink", this.getDisplaySourceLabel(source))}`);
1145
+ lines.push(` ${theme.fg("mdLink", source)}`);
939
1146
  const sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));
940
1147
  for (const item of sortedPackagePaths) {
941
1148
  lines.push(theme.fg("dim", ` ${options.formatPackagePath(item, source)}`));
@@ -1011,24 +1218,22 @@ export class InteractiveMode {
1011
1218
  this.loadedResourcesContainer.clear();
1012
1219
  const showListing = options?.force || this.options.verbose || !this.settingsManager.getQuietStartup();
1013
1220
  const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
1014
- const noModelsStartupNotice = this.getNoModelsStartupNotice();
1015
- if (!showListing && !showDiagnostics && !noModelsStartupNotice) {
1221
+ if (!showListing && !showDiagnostics) {
1016
1222
  return;
1017
1223
  }
1018
1224
  const sectionHeader = (name, color = "mdHeading") => theme.fg(color, `[${name}]`);
1019
- const formatCountSummary = (count, singular, plural = `${singular}s`) => theme.fg("dim", ` ${count} ${count === 1 ? singular : plural}`);
1225
+ const formatCompactList = (items, options) => {
1226
+ const labels = items.map((item) => item.trim()).filter((item) => item.length > 0);
1227
+ if (options?.sort !== false) {
1228
+ labels.sort((a, b) => a.localeCompare(b));
1229
+ }
1230
+ return theme.fg("dim", ` ${labels.join(", ")}`);
1231
+ };
1020
1232
  const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
1021
1233
  const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, this.getStartupExpansionState(), 0, 0);
1022
1234
  this.loadedResourcesContainer.addChild(section);
1023
1235
  this.loadedResourcesContainer.addChild(new Spacer(1));
1024
1236
  };
1025
- if (noModelsStartupNotice) {
1026
- this.loadedResourcesContainer.addChild(new Spacer(1));
1027
- this.loadedResourcesContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
1028
- this.loadedResourcesContainer.addChild(new Text(noModelsStartupNotice, 1, 0));
1029
- this.loadedResourcesContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
1030
- this.loadedResourcesContainer.addChild(new Spacer(1));
1031
- }
1032
1237
  const skillsResult = this.session.resourceLoader.getSkills();
1033
1238
  const promptsResult = this.session.resourceLoader.getPrompts();
1034
1239
  const themesResult = this.session.resourceLoader.getThemes();
@@ -1062,13 +1267,18 @@ export class InteractiveMode {
1062
1267
  }
1063
1268
  }
1064
1269
  if (showListing) {
1065
- const contextFiles = this.session.resourceLoader.getAgentsFiles().agentsFiles;
1270
+ const systemPromptSource = this.session.resourceLoader.getSystemPromptSource();
1271
+ const contextFiles = [
1272
+ ...(systemPromptSource ? [systemPromptSource] : []),
1273
+ ...this.session.resourceLoader.getAppendSystemPromptSources(),
1274
+ ...this.session.resourceLoader.getAgentsFiles().agentsFiles,
1275
+ ];
1066
1276
  if (contextFiles.length > 0) {
1067
1277
  this.loadedResourcesContainer.addChild(new Spacer(1));
1068
1278
  const contextList = contextFiles
1069
1279
  .map((f) => theme.fg("dim", ` ${this.formatDisplayPath(f.path)}`))
1070
1280
  .join("\n");
1071
- const contextCompactList = formatCountSummary(contextFiles.length, "context file");
1281
+ const contextCompactList = formatCompactList(contextFiles.map((contextFile) => this.formatContextPath(contextFile.path)), { sort: false });
1072
1282
  addLoadedSection("Context", contextCompactList, contextList);
1073
1283
  }
1074
1284
  const skills = skillsResult.skills;
@@ -1078,7 +1288,7 @@ export class InteractiveMode {
1078
1288
  formatPath: (item) => this.formatDisplayPath(item.path),
1079
1289
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1080
1290
  });
1081
- const skillCompactList = formatCountSummary(skills.length, "skill");
1291
+ const skillCompactList = formatCompactList(skills.map((skill) => skill.name));
1082
1292
  addLoadedSection("Skills", skillCompactList, skillList);
1083
1293
  }
1084
1294
  const templates = this.session.promptTemplates;
@@ -1095,7 +1305,7 @@ export class InteractiveMode {
1095
1305
  return template ? `/${template.name}` : this.formatDisplayPath(item.path);
1096
1306
  },
1097
1307
  });
1098
- const promptCompactList = formatCountSummary(templates.length, "prompt");
1308
+ const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));
1099
1309
  addLoadedSection("Prompts", promptCompactList, templateList);
1100
1310
  }
1101
1311
  if (extensions.length > 0) {
@@ -1104,7 +1314,7 @@ export class InteractiveMode {
1104
1314
  formatPath: (item) => this.formatExtensionDisplayPath(item.path),
1105
1315
  formatPackagePath: (item) => this.formatExtensionDisplayPath(this.getShortPath(item.path, item.sourceInfo)),
1106
1316
  });
1107
- const extensionCompactList = formatCountSummary(extensions.length, "extension");
1317
+ const extensionCompactList = formatCompactList(this.getCompactExtensionLabels(extensions));
1108
1318
  addLoadedSection("Extensions", extensionCompactList, extList, "mdHeading");
1109
1319
  }
1110
1320
  // Show loaded themes (excluding built-in)
@@ -1119,7 +1329,7 @@ export class InteractiveMode {
1119
1329
  formatPath: (item) => this.formatDisplayPath(item.path),
1120
1330
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
1121
1331
  });
1122
- const themeCompactList = formatCountSummary(customThemes.length, "theme");
1332
+ const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? this.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
1123
1333
  addLoadedSection("Themes", themeCompactList, themeList);
1124
1334
  }
1125
1335
  }
@@ -1239,8 +1449,12 @@ export class InteractiveMode {
1239
1449
  this.showLoadedResources({ force: false, showDiagnosticsWhenQuiet: true });
1240
1450
  this.showStartupNoticesIfNeeded();
1241
1451
  }
1452
+ applyFullscreenScrollbarSetting() {
1453
+ this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
1454
+ }
1242
1455
  applyRuntimeSettings() {
1243
1456
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
1457
+ this.applyFullscreenScrollbarSetting();
1244
1458
  this.footer.setSession(this.session);
1245
1459
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
1246
1460
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
@@ -1262,16 +1476,19 @@ export class InteractiveMode {
1262
1476
  }
1263
1477
  }
1264
1478
  async rebindCurrentSession(options = {}) {
1479
+ const session = this.session;
1265
1480
  this.unsubscribe?.();
1266
1481
  this.unsubscribe = undefined;
1267
1482
  this.applyRuntimeSettings();
1268
1483
  if (options.renderBeforeBind) {
1269
1484
  this.renderCurrentSessionState();
1270
1485
  this.subscribeToAgent();
1271
- await this.bindCurrentSessionExtensions();
1272
1486
  }
1273
- else {
1274
- await this.bindCurrentSessionExtensions();
1487
+ await this.bindCurrentSessionExtensions();
1488
+ if (this.session !== session) {
1489
+ return;
1490
+ }
1491
+ if (!options.renderBeforeBind) {
1275
1492
  this.subscribeToAgent();
1276
1493
  }
1277
1494
  await this.updateAvailableProviderCount();
@@ -1301,6 +1518,9 @@ export class InteractiveMode {
1301
1518
  getRegisteredToolDefinition(toolName) {
1302
1519
  return this.session.getToolDefinition(toolName);
1303
1520
  }
1521
+ getMarkdownTransformers() {
1522
+ return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
1523
+ }
1304
1524
  /**
1305
1525
  * Set up keyboard shortcuts registered by extensions.
1306
1526
  */
@@ -1317,6 +1537,7 @@ export class InteractiveMode {
1317
1537
  sessionManager: this.sessionManager,
1318
1538
  modelRegistry: extensionRunner.getModelRegistry(),
1319
1539
  model: this.session.model,
1540
+ scopedModels: this.session.scopedModels,
1320
1541
  thinkingLevel: this.session.thinkingLevel,
1321
1542
  isIdle: () => this.session.isIdle,
1322
1543
  isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
@@ -1379,7 +1600,7 @@ export class InteractiveMode {
1379
1600
  this.activeStatusIndicator?.dispose();
1380
1601
  this.activeStatusIndicator = undefined;
1381
1602
  this.statusContainer.clear();
1382
- if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
1603
+ if (hadActiveStatusIndicator && this.options.tuiMode === "regular" && this.ui.getClearOnShrink()) {
1383
1604
  this.statusContainer.addChild(this.idleStatus);
1384
1605
  }
1385
1606
  }
@@ -1527,22 +1748,16 @@ export class InteractiveMode {
1527
1748
  if (this.customFooter?.dispose) {
1528
1749
  this.customFooter.dispose();
1529
1750
  }
1530
- // Remove current footer from UI
1531
- if (this.customFooter) {
1532
- this.ui.removeChild(this.customFooter);
1533
- }
1534
- else {
1535
- this.ui.removeChild(this.footer);
1536
- }
1751
+ this.footerContainer.clear();
1537
1752
  if (factory) {
1538
1753
  // Create and add custom footer, passing the data provider
1539
1754
  this.customFooter = factory(this.ui, theme, this.footerDataProvider);
1540
- this.ui.addChild(this.customFooter);
1755
+ this.footerContainer.addChild(this.customFooter);
1541
1756
  }
1542
1757
  else {
1543
1758
  // Restore built-in footer
1544
1759
  this.customFooter = undefined;
1545
- this.ui.addChild(this.footer);
1760
+ this.footerContainer.addChild(this.footer);
1546
1761
  }
1547
1762
  this.ui.requestRender();
1548
1763
  }
@@ -1588,18 +1803,23 @@ export class InteractiveMode {
1588
1803
  this.ui.requestRender();
1589
1804
  }
1590
1805
  addExtensionTerminalInputListener(handler) {
1591
- const unsubscribe = this.ui.addInputListener(handler);
1592
- this.extensionTerminalInputUnsubscribers.add(unsubscribe);
1806
+ const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };
1807
+ this.extensionTerminalInputSubscriptions.add(subscription);
1593
1808
  return () => {
1594
- unsubscribe();
1595
- this.extensionTerminalInputUnsubscribers.delete(unsubscribe);
1809
+ subscription.unsubscribe();
1810
+ this.extensionTerminalInputSubscriptions.delete(subscription);
1596
1811
  };
1597
1812
  }
1598
- clearExtensionTerminalInputListeners() {
1599
- for (const unsubscribe of this.extensionTerminalInputUnsubscribers) {
1600
- unsubscribe();
1813
+ rebindExtensionTerminalInputListeners() {
1814
+ for (const subscription of this.extensionTerminalInputSubscriptions) {
1815
+ subscription.unsubscribe();
1816
+ subscription.unsubscribe = this.ui.addInputListener(subscription.handler);
1601
1817
  }
1602
- this.extensionTerminalInputUnsubscribers.clear();
1818
+ }
1819
+ clearExtensionTerminalInputListeners() {
1820
+ for (const subscription of this.extensionTerminalInputSubscriptions)
1821
+ subscription.unsubscribe();
1822
+ this.extensionTerminalInputSubscriptions.clear();
1603
1823
  }
1604
1824
  /**
1605
1825
  * Create the ExtensionUIContext for extensions.
@@ -1694,6 +1914,7 @@ export class InteractiveMode {
1694
1914
  this.hideExtensionSelector();
1695
1915
  resolve(undefined);
1696
1916
  }, { tui: this.ui, timeout: opts?.timeout, onToggleToolsExpanded: () => this.toggleToolOutputExpansion() });
1917
+ this.disposeActiveSelector();
1697
1918
  this.editorContainer.clear();
1698
1919
  this.editorContainer.addChild(this.extensionSelector);
1699
1920
  this.ui.setFocus(this.extensionSelector);
@@ -1745,6 +1966,7 @@ export class InteractiveMode {
1745
1966
  this.hideExtensionInput();
1746
1967
  resolve(undefined);
1747
1968
  }, { tui: this.ui, timeout: opts?.timeout });
1969
+ this.disposeActiveSelector();
1748
1970
  this.editorContainer.clear();
1749
1971
  this.editorContainer.addChild(this.extensionInput);
1750
1972
  this.ui.setFocus(this.extensionInput);
@@ -1774,6 +1996,7 @@ export class InteractiveMode {
1774
1996
  this.hideExtensionEditor();
1775
1997
  resolve(undefined);
1776
1998
  }, undefined, this.settingsManager.getExternalEditorCommand());
1999
+ this.disposeActiveSelector();
1777
2000
  this.editorContainer.clear();
1778
2001
  this.editorContainer.addChild(this.extensionEditor);
1779
2002
  this.ui.setFocus(this.extensionEditor);
@@ -1798,6 +2021,7 @@ export class InteractiveMode {
1798
2021
  this.editorComponentFactory = factory;
1799
2022
  // Save text from current editor before switching
1800
2023
  const currentText = this.editor.getText();
2024
+ this.disposeActiveSelector();
1801
2025
  this.editorContainer.clear();
1802
2026
  if (factory) {
1803
2027
  // Create the custom editor with tui, theme, and keybindings
@@ -1814,6 +2038,9 @@ export class InteractiveMode {
1814
2038
  if (newEditor.setPaddingX !== undefined) {
1815
2039
  newEditor.setPaddingX(this.defaultEditor.getPaddingX());
1816
2040
  }
2041
+ if (newEditor.setAutocompleteMaxVisible !== undefined) {
2042
+ newEditor.setAutocompleteMaxVisible(this.defaultEditor.getAutocompleteMaxVisible());
2043
+ }
1817
2044
  // Set autocomplete if supported
1818
2045
  if (newEditor.setAutocompleteProvider && this.autocompleteProvider) {
1819
2046
  newEditor.setAutocompleteProvider(this.autocompleteProvider);
@@ -1918,6 +2145,7 @@ export class InteractiveMode {
1918
2145
  options?.onHandle?.(handle);
1919
2146
  }
1920
2147
  else {
2148
+ this.disposeActiveSelector();
1921
2149
  this.editorContainer.clear();
1922
2150
  this.editorContainer.addChild(component);
1923
2151
  this.ui.setFocus(component);
@@ -2004,7 +2232,7 @@ export class InteractiveMode {
2004
2232
  this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
2005
2233
  this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
2006
2234
  this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
2007
- this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
2235
+ this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true }));
2008
2236
  this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
2009
2237
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
2010
2238
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
@@ -2024,13 +2252,29 @@ export class InteractiveMode {
2024
2252
  void this.handleClipboardPaste();
2025
2253
  };
2026
2254
  }
2255
+ async handleRightClickPaste() {
2256
+ const target = this.renderer.getFocusedComponent();
2257
+ const handleInput = target?.handleInput;
2258
+ if (!target || !handleInput)
2259
+ return;
2260
+ try {
2261
+ const text = await readClipboardText();
2262
+ if (!text || this.renderer.getFocusedComponent() !== target)
2263
+ return;
2264
+ handleInput.call(target, `\x1b[200~${text}\x1b[201~`);
2265
+ this.ui.requestRender();
2266
+ }
2267
+ catch {
2268
+ // Silently ignore clipboard errors (may not have permission, etc.)
2269
+ }
2270
+ }
2027
2271
  async handleClipboardPaste() {
2028
2272
  try {
2029
2273
  const image = await readClipboardImage();
2030
2274
  if (image) {
2031
2275
  const tmpDir = os.tmpdir();
2032
2276
  const ext = extensionForImageMimeType(image.mimeType) ?? "png";
2033
- const fileName = `humain-terminal-clipboard-${crypto.randomUUID()}.${ext}`;
2277
+ const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
2034
2278
  const filePath = path.join(tmpDir, fileName);
2035
2279
  fs.writeFileSync(filePath, Buffer.from(image.bytes));
2036
2280
  this.editor.insertTextAtCursor?.(filePath);
@@ -2166,6 +2410,11 @@ export class InteractiveMode {
2166
2410
  this.editor.setText("");
2167
2411
  return;
2168
2412
  }
2413
+ if (text === "/dementedelves") {
2414
+ this.handleDementedDelves();
2415
+ this.editor.setText("");
2416
+ return;
2417
+ }
2169
2418
  if (text === "/resume") {
2170
2419
  this.showSessionSelector();
2171
2420
  this.editor.setText("");
@@ -2287,17 +2536,17 @@ export class InteractiveMode {
2287
2536
  this.ui.requestRender();
2288
2537
  }
2289
2538
  else if (event.message.role === "assistant") {
2290
- this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2539
+ this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2291
2540
  this.streamingMessage = event.message;
2292
2541
  this.chatContainer.addChild(this.streamingComponent);
2293
- this.streamingComponent.updateContent(this.streamingMessage);
2542
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2294
2543
  this.ui.requestRender();
2295
2544
  }
2296
2545
  break;
2297
2546
  case "message_update":
2298
2547
  if (this.streamingComponent && event.message.role === "assistant") {
2299
2548
  this.streamingMessage = event.message;
2300
- this.streamingComponent.updateContent(this.streamingMessage);
2549
+ this.streamingComponent.updateContent(this.streamingMessage, true);
2301
2550
  for (const content of this.streamingMessage.content) {
2302
2551
  if (content.type === "toolCall") {
2303
2552
  if (!this.pendingTools.has(content.id)) {
@@ -2334,7 +2583,7 @@ export class InteractiveMode {
2334
2583
  : "Operation aborted";
2335
2584
  this.streamingMessage.errorMessage = errorMessage;
2336
2585
  }
2337
- this.streamingComponent.updateContent(this.streamingMessage);
2586
+ this.streamingComponent.updateContent(this.streamingMessage, false);
2338
2587
  if (this.streamingMessage.stopReason === "aborted" || this.streamingMessage.stopReason === "error") {
2339
2588
  if (!errorMessage) {
2340
2589
  errorMessage = this.streamingMessage.errorMessage || "Error";
@@ -2608,12 +2857,12 @@ export class InteractiveMode {
2608
2857
  // Render user message separately if present
2609
2858
  if (skillBlock.userMessage) {
2610
2859
  this.chatContainer.addChild(new Spacer(1));
2611
- const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
2860
+ const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2612
2861
  this.chatContainer.addChild(userComponent);
2613
2862
  }
2614
2863
  }
2615
2864
  else {
2616
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
2865
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad, this.getMarkdownTransformers());
2617
2866
  this.chatContainer.addChild(userComponent);
2618
2867
  }
2619
2868
  if (options?.populateHistory) {
@@ -2623,7 +2872,7 @@ export class InteractiveMode {
2623
2872
  break;
2624
2873
  }
2625
2874
  case "assistant": {
2626
- const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2875
+ const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad, this.getMarkdownTransformers());
2627
2876
  this.chatContainer.addChild(assistantComponent);
2628
2877
  break;
2629
2878
  }
@@ -2775,7 +3024,7 @@ export class InteractiveMode {
2775
3024
  if (this.chatContainer.children.length > 0) {
2776
3025
  this.chatContainer.addChild(new Spacer(1));
2777
3026
  }
2778
- this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart ${APP_NAME}.`), 1, 0));
3027
+ this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart pi.`), 1, 0));
2779
3028
  }
2780
3029
  async getUserInput() {
2781
3030
  const queuedInput = this.pendingUserInputs.shift();
@@ -2888,7 +3137,7 @@ export class InteractiveMode {
2888
3137
  this.ui.stop();
2889
3138
  }
2890
3139
  catch { }
2891
- console.error(`${APP_NAME} exiting due to uncaughtException:`);
3140
+ console.error("pi exiting due to uncaughtException:");
2892
3141
  console.error(error);
2893
3142
  process.exit(1);
2894
3143
  }
@@ -2930,7 +3179,7 @@ export class InteractiveMode {
2930
3179
  this.signalCleanupHandlers.push(() => process.stderr.off("error", terminalErrorHandler));
2931
3180
  // Restore the terminal before the process dies on any uncaught throw.
2932
3181
  // Without this, an unhandled exception from extension code (or anywhere
2933
- // in the terminal agent) leaves the terminal in raw mode with no cursor.
3182
+ // in pi) leaves the terminal in raw mode with no cursor.
2934
3183
  const uncaughtExceptionHandler = (error) => this.uncaughtCrash(error);
2935
3184
  process.prependListener("uncaughtException", uncaughtExceptionHandler);
2936
3185
  this.signalCleanupHandlers.push(() => process.off("uncaughtException", uncaughtExceptionHandler));
@@ -3057,6 +3306,8 @@ export class InteractiveMode {
3057
3306
  this.setToolsExpanded(!this.toolOutputExpanded);
3058
3307
  }
3059
3308
  setToolsExpanded(expanded) {
3309
+ if (expanded === this.toolOutputExpanded)
3310
+ return;
3060
3311
  this.toolOutputExpanded = expanded;
3061
3312
  const activeHeader = this.customHeader ?? this.builtInHeader;
3062
3313
  if (isExpandable(activeHeader)) {
@@ -3069,7 +3320,7 @@ export class InteractiveMode {
3069
3320
  }
3070
3321
  }
3071
3322
  }
3072
- this.ui.requestRender();
3323
+ this.showStatus(`Tool output: ${expanded ? "expanded" : "collapsed"}`);
3073
3324
  }
3074
3325
  toggleThinkingBlockVisibility() {
3075
3326
  this.hideThinkingBlock = !this.hideThinkingBlock;
@@ -3112,7 +3363,7 @@ export class InteractiveMode {
3112
3363
  }
3113
3364
  showError(errorMessage) {
3114
3365
  this.chatContainer.addChild(new Spacer(1));
3115
- this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
3366
+ this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), this.outputPad, 0));
3116
3367
  this.ui.requestRender();
3117
3368
  }
3118
3369
  showWarning(warningMessage) {
@@ -3123,7 +3374,7 @@ export class InteractiveMode {
3123
3374
  showNewVersionNotification(release) {
3124
3375
  const action = theme.fg("accent", `${APP_NAME} update`);
3125
3376
  const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
3126
- const changelogUrl = getChangelogUrl();
3377
+ const changelogUrl = "https://pi.dev/changelog";
3127
3378
  const changelogLink = getCapabilities().hyperlinks
3128
3379
  ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3129
3380
  : theme.fg("accent", changelogUrl);
@@ -3322,25 +3573,43 @@ export class InteractiveMode {
3322
3573
  // =========================================================================
3323
3574
  // Selectors
3324
3575
  // =========================================================================
3576
+ disposeActiveSelector() {
3577
+ const dispose = this.activeSelectorDispose;
3578
+ this.activeSelectorToken = undefined;
3579
+ this.activeSelectorDispose = undefined;
3580
+ dispose?.();
3581
+ }
3325
3582
  /**
3326
3583
  * Shows a selector component in place of the editor.
3327
3584
  * @param create Factory that receives a `done` callback and returns the component and focus target
3328
3585
  */
3329
3586
  showSelector(create) {
3587
+ const token = {};
3588
+ let dispose;
3330
3589
  const done = () => {
3590
+ dispose?.();
3591
+ if (this.activeSelectorToken !== token)
3592
+ return;
3593
+ this.activeSelectorToken = undefined;
3594
+ this.activeSelectorDispose = undefined;
3331
3595
  this.editorContainer.clear();
3332
3596
  this.editorContainer.addChild(this.editor);
3333
3597
  this.ui.setFocus(this.editor);
3334
3598
  };
3335
- const { component, focus } = create(done);
3599
+ const created = create(done);
3600
+ dispose = created.dispose;
3601
+ this.disposeActiveSelector();
3602
+ this.activeSelectorToken = token;
3603
+ this.activeSelectorDispose = dispose;
3336
3604
  this.editorContainer.clear();
3337
- this.editorContainer.addChild(component);
3338
- this.ui.setFocus(focus);
3605
+ this.editorContainer.addChild(created.component);
3606
+ this.ui.setFocus(created.focus);
3339
3607
  this.ui.requestRender();
3340
3608
  }
3341
3609
  showSettingsSelector() {
3342
3610
  this.showSelector((done) => {
3343
- const selector = new SettingsSelectorComponent({
3611
+ let selector;
3612
+ selector = new SettingsSelectorComponent({
3344
3613
  autoCompact: this.session.autoCompactionEnabled,
3345
3614
  showImages: this.settingsManager.getShowImages(),
3346
3615
  imageWidthCells: this.settingsManager.getImageWidthCells(),
@@ -3357,6 +3626,7 @@ export class InteractiveMode {
3357
3626
  terminalTheme: this.themeController.getTerminalTheme(),
3358
3627
  availableThemes: getAvailableThemes(),
3359
3628
  hideThinkingBlock: this.hideThinkingBlock,
3629
+ mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
3360
3630
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
3361
3631
  enableInstallTelemetry: this.settingsManager.getEnableInstallTelemetry(),
3362
3632
  doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
@@ -3370,6 +3640,8 @@ export class InteractiveMode {
3370
3640
  quietStartup: this.settingsManager.getQuietStartup(),
3371
3641
  clearOnShrink: this.settingsManager.getClearOnShrink(),
3372
3642
  showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
3643
+ tuiMode: this.ui.mode,
3644
+ fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
3373
3645
  warnings: this.settingsManager.getWarnings(),
3374
3646
  }, {
3375
3647
  onAutoCompactChange: (enabled) => {
@@ -3438,6 +3710,11 @@ export class InteractiveMode {
3438
3710
  this.chatContainer.clear();
3439
3711
  this.rebuildChatFromMessages();
3440
3712
  },
3713
+ onMermaidRenderingModeChange: (mode) => {
3714
+ this.settingsManager.setMermaidRenderingMode(mode);
3715
+ this.chatContainer.invalidate();
3716
+ this.ui.requestRender();
3717
+ },
3441
3718
  onShowCacheMissNoticesChange: (shown) => {
3442
3719
  this.settingsManager.setShowCacheMissNotices(shown);
3443
3720
  this.rebuildChatFromMessages();
@@ -3507,6 +3784,21 @@ export class InteractiveMode {
3507
3784
  onShowTerminalProgressChange: (enabled) => {
3508
3785
  this.settingsManager.setShowTerminalProgress(enabled);
3509
3786
  },
3787
+ onTuiModeChange: (mode) => {
3788
+ if (!this.switchTuiMode(mode)) {
3789
+ selector?.getSettingsList().updateValue("tui-mode", this.ui.mode);
3790
+ this.showStatus("Close active overlays before changing TUI mode");
3791
+ return;
3792
+ }
3793
+ this.settingsManager.setTuiMode(mode);
3794
+ if (!this.activeStatusIndicator)
3795
+ this.statusContainer.clear();
3796
+ this.showStatus(`TUI mode: ${mode}`);
3797
+ },
3798
+ onFullscreenScrollbarChange: (mode) => {
3799
+ this.settingsManager.setFullscreenScrollbar(mode);
3800
+ this.applyFullscreenScrollbarSetting();
3801
+ },
3510
3802
  onWarningsChange: (warnings) => {
3511
3803
  this.settingsManager.setWarnings(warnings);
3512
3804
  },
@@ -3541,20 +3833,37 @@ export class InteractiveMode {
3541
3833
  this.showModelSelector(searchTerm);
3542
3834
  }
3543
3835
  async findExactModelMatch(searchTerm) {
3544
- const models = await this.getModelCandidates();
3545
- return findExactModelReferenceMatch(searchTerm, models);
3546
- }
3547
- async getModelCandidates() {
3548
- if (this.session.scopedModels.length > 0) {
3549
- return this.session.scopedModels.map((scoped) => scoped.model);
3550
- }
3836
+ const cachedModels = this.session.scopedModels.length > 0
3837
+ ? this.session.scopedModels.map((scoped) => scoped.model)
3838
+ : [...this.session.modelRuntime.getAvailableSnapshot()];
3839
+ const cachedMatch = findExactModelReferenceMatch(searchTerm, cachedModels);
3840
+ if (cachedMatch || this.session.scopedModels.length > 0)
3841
+ return cachedMatch;
3842
+ this.showStatus("Refreshing model catalogs…");
3843
+ const controller = new AbortController();
3844
+ let timedOut = false;
3845
+ const timeout = setTimeout(() => {
3846
+ timedOut = true;
3847
+ controller.abort();
3848
+ }, 15_000);
3551
3849
  try {
3552
- await this.session.modelRuntime.refresh();
3553
- return [...(await this.session.modelRuntime.getAvailable())];
3850
+ const result = await this.session.modelRuntime.refresh({ signal: controller.signal });
3851
+ if (result.aborted && timedOut) {
3852
+ this.showWarning("Model refresh timed out; searching cached models.");
3853
+ }
3854
+ else if (result.errors.size > 0) {
3855
+ this.showWarning(`Could not refresh ${[...result.errors.keys()].join(", ")}; searching cached models.`);
3856
+ }
3554
3857
  }
3555
- catch {
3556
- return [];
3858
+ catch (error) {
3859
+ this.showWarning(timedOut
3860
+ ? "Model refresh timed out; searching cached models."
3861
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`);
3862
+ }
3863
+ finally {
3864
+ clearTimeout(timeout);
3557
3865
  }
3866
+ return findExactModelReferenceMatch(searchTerm, [...this.session.modelRuntime.getAvailableSnapshot()]);
3558
3867
  }
3559
3868
  /** Update the footer's available provider count from the current snapshot without refreshing catalogs. */
3560
3869
  updateAvailableProviderCount() {
@@ -3626,7 +3935,7 @@ export class InteractiveMode {
3626
3935
  onSelect: (selection) => {
3627
3936
  trustStore.setMany(selection.updates);
3628
3937
  done();
3629
- this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart ${APP_NAME} for this to take effect.`);
3938
+ this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart pi for this to take effect.`);
3630
3939
  },
3631
3940
  onCancel: () => {
3632
3941
  done();
@@ -3656,73 +3965,67 @@ export class InteractiveMode {
3656
3965
  done();
3657
3966
  this.ui.requestRender();
3658
3967
  }, initialSearchInput);
3659
- return { component: selector, focus: selector };
3968
+ return { component: selector, focus: selector, dispose: () => selector.dispose() };
3660
3969
  });
3661
3970
  }
3662
- async showModelsSelector() {
3663
- // Get all available models
3664
- await this.session.modelRuntime.refresh();
3665
- const allModels = [...(await this.session.modelRuntime.getAvailable())];
3666
- const allModelIds = new Set(allModels.map((model) => `${model.provider}/${model.id}`));
3971
+ showModelsSelector() {
3972
+ let availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
3973
+ let availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
3667
3974
  const configuredPatterns = this.settingsManager.getEnabledModels();
3668
3975
  const sessionScopedModels = this.session.scopedModels;
3669
- if (allModels.length === 0 && !configuredPatterns?.length && sessionScopedModels.length === 0) {
3670
- this.showStatus("No models available");
3671
- return;
3672
- }
3673
- const configuredScope = configuredPatterns?.length
3674
- ? await resolveModelScopeWithDiagnostics(configuredPatterns, this.session.modelRuntime)
3675
- : undefined;
3676
- // Check if session has scoped models (from previous session-only changes or CLI --models)
3677
- const hasSessionScope = sessionScopedModels.length > 0;
3678
- // Build enabled model IDs from session state or settings
3679
- let currentEnabledIds = null;
3680
- if (hasSessionScope) {
3681
- // Use current session's scoped models
3682
- currentEnabledIds = sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3683
- }
3684
- else if (configuredScope) {
3685
- currentEnabledIds = configuredScope.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3686
- }
3687
- for (const diagnostic of configuredScope?.diagnostics ?? []) {
3688
- if (diagnostic.code !== "no-match")
3689
- continue;
3690
- currentEnabledIds ??= [];
3691
- if (!currentEnabledIds.includes(diagnostic.pattern))
3692
- currentEnabledIds.push(diagnostic.pattern);
3693
- }
3694
- // Helper to update session's scoped models (session-only, no persist)
3695
- const updateSessionModels = async (enabledIds) => {
3976
+ const configuredEnabledIds = (models) => {
3977
+ if (!configuredPatterns?.length)
3978
+ return null;
3979
+ const resolved = resolveModelScopeFromModels(configuredPatterns, models);
3980
+ const ids = resolved.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
3981
+ for (const diagnostic of resolved.diagnostics) {
3982
+ if (diagnostic.code === "no-match" && !ids.includes(diagnostic.pattern))
3983
+ ids.push(diagnostic.pattern);
3984
+ }
3985
+ return ids;
3986
+ };
3987
+ let currentEnabledIds = sessionScopedModels.length > 0
3988
+ ? sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`)
3989
+ : configuredEnabledIds(availableModels);
3990
+ let selectionChanged = false;
3991
+ const updateSessionModels = (enabledIds) => {
3696
3992
  currentEnabledIds = enabledIds === null ? null : [...enabledIds];
3697
- const hasEnabledAvailableModel = enabledIds?.some((id) => allModelIds.has(id)) ?? false;
3698
- const allAvailableModelsEnabled = enabledIds !== null && [...allModelIds].every((id) => enabledIds.includes(id));
3993
+ const hasEnabledAvailableModel = enabledIds?.some((id) => availableModelIds.has(id)) ?? false;
3994
+ const allAvailableModelsEnabled = enabledIds !== null && [...availableModelIds].every((id) => enabledIds.includes(id));
3699
3995
  if (enabledIds && hasEnabledAvailableModel && !allAvailableModelsEnabled) {
3700
- const newScopedModels = await resolveModelScope(enabledIds, this.session.modelRuntime);
3701
- this.session.setScopedModels(newScopedModels.map((sm) => ({
3702
- model: sm.model,
3703
- thinkingLevel: sm.thinkingLevel,
3996
+ const newScopedModels = resolveModelScopeFromModels(enabledIds, availableModels).scopedModels;
3997
+ this.session.setScopedModels(newScopedModels.map((scoped) => ({
3998
+ model: scoped.model,
3999
+ thinkingLevel: scoped.thinkingLevel,
3704
4000
  })));
3705
4001
  }
3706
4002
  else {
3707
- // All enabled or none enabled = no filter
3708
4003
  this.session.setScopedModels([]);
3709
4004
  }
3710
- await this.updateAvailableProviderCount();
4005
+ this.updateAvailableProviderCount();
3711
4006
  this.ui.requestRender();
3712
4007
  };
3713
4008
  this.showSelector((done) => {
4009
+ let disposed = false;
4010
+ let timedOut = false;
4011
+ const controller = new AbortController();
4012
+ const timeout = setTimeout(() => {
4013
+ timedOut = true;
4014
+ controller.abort();
4015
+ }, 15_000);
3714
4016
  const selector = new ScopedModelsSelectorComponent({
3715
- allModels,
4017
+ allModels: availableModels,
3716
4018
  enabledModelIds: currentEnabledIds,
4019
+ refreshStatus: "Refreshing model catalogs…",
3717
4020
  }, {
3718
- onChange: async (enabledIds) => {
3719
- await updateSessionModels(enabledIds);
4021
+ onChange: (enabledIds) => {
4022
+ selectionChanged = true;
4023
+ updateSessionModels(enabledIds);
3720
4024
  },
3721
4025
  onPersist: (enabledIds) => {
3722
- // Persist to settings
3723
4026
  const allEnabled = enabledIds !== null &&
3724
- enabledIds.length === allModels.length &&
3725
- enabledIds.every((id) => allModelIds.has(id));
4027
+ enabledIds.length === availableModels.length &&
4028
+ enabledIds.every((id) => availableModelIds.has(id));
3726
4029
  const newPatterns = enabledIds === null || allEnabled ? undefined : enabledIds;
3727
4030
  this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
3728
4031
  this.showStatus("Model selection saved to settings");
@@ -3732,7 +4035,51 @@ export class InteractiveMode {
3732
4035
  this.ui.requestRender();
3733
4036
  },
3734
4037
  });
3735
- return { component: selector, focus: selector };
4038
+ void this.session.modelRuntime
4039
+ .refresh({ signal: controller.signal })
4040
+ .then((result) => {
4041
+ if (disposed)
4042
+ return;
4043
+ availableModels = [...this.session.modelRuntime.getAvailableSnapshot()];
4044
+ availableModelIds = new Set(availableModels.map((model) => `${model.provider}/${model.id}`));
4045
+ if (!selectionChanged && sessionScopedModels.length === 0) {
4046
+ currentEnabledIds = configuredEnabledIds(availableModels);
4047
+ selector.updateModels(availableModels, currentEnabledIds);
4048
+ }
4049
+ else {
4050
+ selector.updateModels(availableModels);
4051
+ }
4052
+ if (currentEnabledIds !== null)
4053
+ updateSessionModels(currentEnabledIds);
4054
+ if (result.aborted && timedOut) {
4055
+ selector.setRefreshStatus("Model refresh timed out; showing cached models.", "warning");
4056
+ }
4057
+ else if (result.errors.size > 0) {
4058
+ selector.setRefreshStatus(`Could not refresh ${[...result.errors.keys()].join(", ")}; showing cached models.`, "warning");
4059
+ }
4060
+ else {
4061
+ selector.setRefreshStatus("Model catalogs refreshed.", "success");
4062
+ }
4063
+ this.ui.requestRender();
4064
+ })
4065
+ .catch((error) => {
4066
+ if (disposed)
4067
+ return;
4068
+ selector.setRefreshStatus(timedOut
4069
+ ? "Model refresh timed out; showing cached models."
4070
+ : `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`, "warning");
4071
+ this.ui.requestRender();
4072
+ })
4073
+ .finally(() => clearTimeout(timeout));
4074
+ return {
4075
+ component: selector,
4076
+ focus: selector,
4077
+ dispose: () => {
4078
+ disposed = true;
4079
+ clearTimeout(timeout);
4080
+ controller.abort();
4081
+ },
4082
+ };
3736
4083
  });
3737
4084
  }
3738
4085
  showUserMessageSelector() {
@@ -3794,7 +4141,7 @@ export class InteractiveMode {
3794
4141
  this.showSelector((done) => {
3795
4142
  const selector = new TreeSelectorComponent(tree, realLeafId, this.ui.terminal.rows, async (entryId) => {
3796
4143
  // Selecting the current leaf is a no-op (already there)
3797
- if (entryId === realLeafId) {
4144
+ if (entryId === this.sessionManager.getLeafId()) {
3798
4145
  done();
3799
4146
  this.showStatus("Already at this point");
3800
4147
  return;
@@ -3829,6 +4176,11 @@ export class InteractiveMode {
3829
4176
  break;
3830
4177
  }
3831
4178
  }
4179
+ // The user committed to navigating: stop the active response first.
4180
+ if (this.session.isStreaming) {
4181
+ this.restoreQueuedMessagesToEditor();
4182
+ await this.session.abort();
4183
+ }
3832
4184
  // Set up escape handler and status indicator if summarizing
3833
4185
  let showingSummaryIndicator = false;
3834
4186
  const originalOnEscape = this.defaultEditor.onEscape;
@@ -3989,7 +4341,7 @@ export class InteractiveMode {
3989
4341
  return options.sort((a, b) => a.name.localeCompare(b.name));
3990
4342
  }
3991
4343
  async getLogoutProviderOptions() {
3992
- return (await this.session.modelRuntime.listCredentials())
4344
+ return (await this.session.modelRuntime.listCredentials({ signal: AbortSignal.timeout(15_000) }))
3993
4345
  .map(({ providerId, type }) => ({
3994
4346
  id: providerId,
3995
4347
  name: this.session.modelRuntime.getProvider(providerId)?.name ?? providerId,
@@ -4007,7 +4359,6 @@ export class InteractiveMode {
4007
4359
  provider.name.toLowerCase() === normalizedProviderRef);
4008
4360
  }
4009
4361
  async handleLoginCommand(providerRef) {
4010
- await this.session.modelRuntime.getAvailable();
4011
4362
  if (!providerRef) {
4012
4363
  this.showLoginAuthTypeSelector();
4013
4364
  return;
@@ -4121,7 +4472,14 @@ export class InteractiveMode {
4121
4472
  this.showLoginAuthTypeSelector();
4122
4473
  return;
4123
4474
  }
4124
- const providerOptions = await this.getLogoutProviderOptions();
4475
+ let providerOptions;
4476
+ try {
4477
+ providerOptions = await this.getLogoutProviderOptions();
4478
+ }
4479
+ catch (error) {
4480
+ this.showError(`Could not read stored credentials: ${error instanceof Error ? error.message : String(error)}`);
4481
+ return;
4482
+ }
4125
4483
  if (providerOptions.length === 0) {
4126
4484
  this.showStatus("No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.");
4127
4485
  return;
@@ -4134,7 +4492,9 @@ export class InteractiveMode {
4134
4492
  return;
4135
4493
  }
4136
4494
  try {
4137
- await this.session.modelRuntime.logout(providerOption.id);
4495
+ await this.session.modelRuntime.logout(providerOption.id, {
4496
+ signal: AbortSignal.timeout(15_000),
4497
+ });
4138
4498
  await this.updateAvailableProviderCount();
4139
4499
  const message = providerOption.authType === "oauth"
4140
4500
  ? `Logged out of ${providerOption.name}`
@@ -4142,7 +4502,10 @@ export class InteractiveMode {
4142
4502
  this.showStatus(message);
4143
4503
  }
4144
4504
  catch (error) {
4145
- this.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
4505
+ const message = error instanceof Error ? error.message : String(error);
4506
+ this.showError(error instanceof CredentialSynchronizationError
4507
+ ? `Credentials removed for ${providerOption.name}, but local model state could not be synchronized: ${message}`
4508
+ : `Logout failed: ${message}`);
4146
4509
  }
4147
4510
  }, () => {
4148
4511
  done();
@@ -4152,12 +4515,11 @@ export class InteractiveMode {
4152
4515
  });
4153
4516
  }
4154
4517
  async completeProviderAuthentication(providerId, providerName, authType, previousModel) {
4155
- await this.session.modelRuntime.getAvailable();
4156
4518
  const actionLabel = authType === "oauth" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;
4157
4519
  let selectedModel;
4158
4520
  let selectionError;
4159
4521
  if (isUnknownModel(previousModel)) {
4160
- const availableModels = await this.session.modelRuntime.getAvailable();
4522
+ const availableModels = this.session.modelRuntime.getAvailableSnapshot();
4161
4523
  const providerModels = availableModels.filter((model) => model.provider === providerId);
4162
4524
  if (!hasDefaultModelProvider(providerId)) {
4163
4525
  selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
@@ -4200,6 +4562,25 @@ export class InteractiveMode {
4200
4562
  void this.maybeWarnAboutAnthropicSubscriptionAuth();
4201
4563
  }
4202
4564
  }
4565
+ const controller = new AbortController();
4566
+ const timeout = setTimeout(() => controller.abort(), 15_000);
4567
+ void this.session.modelRuntime
4568
+ .refresh({ providers: [providerId], signal: controller.signal })
4569
+ .then((result) => {
4570
+ if (result.aborted) {
4571
+ this.showWarning(`${actionLabel}, but its model catalog refresh timed out; using cached models.`);
4572
+ }
4573
+ else if (result.errors.size > 0) {
4574
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed; using cached models.`);
4575
+ }
4576
+ this.updateAvailableProviderCount();
4577
+ this.footer.invalidate();
4578
+ this.ui.requestRender();
4579
+ })
4580
+ .catch((error) => {
4581
+ this.showWarning(`${actionLabel}, but its model catalog could not be refreshed: ${error instanceof Error ? error.message : String(error)}`);
4582
+ })
4583
+ .finally(() => clearTimeout(timeout));
4203
4584
  }
4204
4585
  showAmbientAuthDialog(providerOption) {
4205
4586
  const restoreEditor = () => {
@@ -4245,7 +4626,10 @@ export class InteractiveMode {
4245
4626
  catch (error) {
4246
4627
  restoreEditor();
4247
4628
  const errorMsg = error instanceof Error ? error.message : String(error);
4248
- if (errorMsg !== "Login cancelled") {
4629
+ if (error instanceof CredentialSynchronizationError) {
4630
+ this.showError(`Saved API key for ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4631
+ }
4632
+ else if (errorMsg !== "Login cancelled") {
4249
4633
  this.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);
4250
4634
  }
4251
4635
  }
@@ -4348,7 +4732,10 @@ export class InteractiveMode {
4348
4732
  catch (error) {
4349
4733
  restoreEditor();
4350
4734
  const errorMsg = error instanceof Error ? error.message : String(error);
4351
- if (errorMsg !== "Login cancelled") {
4735
+ if (error instanceof CredentialSynchronizationError) {
4736
+ this.showError(`Logged in to ${providerName}, but local model state could not be synchronized: ${errorMsg}`);
4737
+ }
4738
+ else if (errorMsg !== "Login cancelled") {
4352
4739
  this.showError(`Failed to login to ${providerName}: ${errorMsg}`);
4353
4740
  }
4354
4741
  }
@@ -4399,7 +4786,6 @@ export class InteractiveMode {
4399
4786
  try {
4400
4787
  await this.session.reload({ beforeSessionStart: restoreChatBeforeSessionStart });
4401
4788
  restoreChatBeforeSessionStart();
4402
- configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
4403
4789
  this.keybindings.reload();
4404
4790
  const activeHeader = this.customHeader ?? this.builtInHeader;
4405
4791
  if (isExpandable(activeHeader)) {
@@ -4407,20 +4793,7 @@ export class InteractiveMode {
4407
4793
  }
4408
4794
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4409
4795
  await this.themeController.applyFromSettings();
4410
- const editorPaddingX = this.settingsManager.getEditorPaddingX();
4411
- const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
4412
- this.defaultEditor.setPaddingX(editorPaddingX);
4413
- this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
4414
- if (this.editor !== this.defaultEditor) {
4415
- this.editor.setPaddingX?.(editorPaddingX);
4416
- this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
4417
- }
4418
- this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
4419
- const clearOnShrink = this.settingsManager.getClearOnShrink();
4420
- this.ui.setClearOnShrink(clearOnShrink);
4421
- if (!clearOnShrink && !this.activeStatusIndicator) {
4422
- this.statusContainer.clear();
4423
- }
4796
+ this.applyRuntimeSettings();
4424
4797
  this.setupAutocompleteProvider();
4425
4798
  const runner = this.session.extensionRunner;
4426
4799
  this.setupExtensionShortcuts(runner);
@@ -4616,7 +4989,7 @@ export class InteractiveMode {
4616
4989
  }
4617
4990
  }
4618
4991
  }
4619
- async handleCopyCommand() {
4992
+ async handleCopyCommand(options = {}) {
4620
4993
  const text = this.session.getLastAssistantText();
4621
4994
  if (!text) {
4622
4995
  this.showError("No agent messages to copy yet.");
@@ -4624,7 +4997,12 @@ export class InteractiveMode {
4624
4997
  }
4625
4998
  try {
4626
4999
  await copyToClipboard(text);
4627
- this.showStatus("Copied last agent message to clipboard");
5000
+ if (options.flashConfirmation && this.ui instanceof TuiAltScreen) {
5001
+ this.ui.flash("Copied!");
5002
+ }
5003
+ else {
5004
+ this.showStatus("Copied last agent message to clipboard");
5005
+ }
4628
5006
  }
4629
5007
  catch (error) {
4630
5008
  this.showError(error instanceof Error ? error.message : String(error));
@@ -4897,6 +5275,11 @@ export class InteractiveMode {
4897
5275
  this.chatContainer.addChild(new ArminComponent(this.ui));
4898
5276
  this.ui.requestRender();
4899
5277
  }
5278
+ handleDementedDelves() {
5279
+ this.chatContainer.addChild(new Spacer(1));
5280
+ this.chatContainer.addChild(new EarendilAnnouncementComponent());
5281
+ this.ui.requestRender();
5282
+ }
4900
5283
  handleDaxnuts() {
4901
5284
  this.chatContainer.addChild(new Spacer(1));
4902
5285
  this.chatContainer.addChild(new DaxnutsComponent(this.ui));
@@ -4982,6 +5365,7 @@ export class InteractiveMode {
4982
5365
  }
4983
5366
  }
4984
5367
  stop() {
5368
+ this.disposeActiveSelector();
4985
5369
  if (this.settingsManager.getShowTerminalProgress()) {
4986
5370
  this.ui.terminal.setProgress(false);
4987
5371
  }
@@ -4994,7 +5378,7 @@ export class InteractiveMode {
4994
5378
  this.unsubscribe();
4995
5379
  }
4996
5380
  if (this.isInitialized) {
4997
- this.ui.stop();
5381
+ this.stopInteractiveTui();
4998
5382
  this.isInitialized = false;
4999
5383
  }
5000
5384
  this.unregisterSignalHandlers();