@sammorrowdrums/mcpi 0.70.9 → 0.85.0-bootstrap.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 (888) hide show
  1. package/CHANGELOG.md +1621 -0
  2. package/LICENSE +21 -0
  3. package/README.md +196 -141
  4. package/dist/bun/cli.d.ts.map +1 -1
  5. package/dist/bun/cli.js +4 -0
  6. package/dist/bun/cli.js.map +1 -1
  7. package/dist/bun/register-bedrock.d.ts.map +1 -1
  8. package/dist/bun/register-bedrock.js +1 -1
  9. package/dist/bun/register-bedrock.js.map +1 -1
  10. package/dist/bun/restore-sandbox-env.d.ts +17 -0
  11. package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
  12. package/dist/bun/restore-sandbox-env.js +36 -0
  13. package/dist/bun/restore-sandbox-env.js.map +1 -0
  14. package/dist/cli/args.d.ts +9 -2
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +116 -16
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/cli/auth-check.d.ts +19 -0
  19. package/dist/cli/auth-check.d.ts.map +1 -0
  20. package/dist/cli/auth-check.js +50 -0
  21. package/dist/cli/auth-check.js.map +1 -0
  22. package/dist/cli/auth-command.d.ts +24 -0
  23. package/dist/cli/auth-command.d.ts.map +1 -0
  24. package/dist/cli/auth-command.js +103 -0
  25. package/dist/cli/auth-command.js.map +1 -0
  26. package/dist/cli/config-selector.d.ts +6 -4
  27. package/dist/cli/config-selector.d.ts.map +1 -1
  28. package/dist/cli/config-selector.js +4 -4
  29. package/dist/cli/config-selector.js.map +1 -1
  30. package/dist/cli/credential-print.d.ts +13 -0
  31. package/dist/cli/credential-print.d.ts.map +1 -0
  32. package/dist/cli/credential-print.js +76 -0
  33. package/dist/cli/credential-print.js.map +1 -0
  34. package/dist/cli/experimental/auth.d.ts +16 -0
  35. package/dist/cli/experimental/auth.d.ts.map +1 -0
  36. package/dist/cli/experimental/auth.js +13 -0
  37. package/dist/cli/experimental/auth.js.map +1 -0
  38. package/dist/cli/experimental/cli.d.ts +6 -0
  39. package/dist/cli/experimental/cli.d.ts.map +1 -0
  40. package/dist/cli/experimental/cli.js +5 -0
  41. package/dist/cli/experimental/cli.js.map +1 -0
  42. package/dist/cli/experimental/command-options.d.ts +17 -0
  43. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  44. package/dist/cli/experimental/command-options.js +35 -0
  45. package/dist/cli/experimental/command-options.js.map +1 -0
  46. package/dist/cli/experimental/command.d.ts +63 -0
  47. package/dist/cli/experimental/command.d.ts.map +1 -0
  48. package/dist/cli/experimental/command.js +130 -0
  49. package/dist/cli/experimental/command.js.map +1 -0
  50. package/dist/cli/experimental/commands/client.d.ts +13 -0
  51. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  52. package/dist/cli/experimental/commands/client.js +25 -0
  53. package/dist/cli/experimental/commands/client.js.map +1 -0
  54. package/dist/cli/experimental/commands/mcpi.d.ts +15 -0
  55. package/dist/cli/experimental/commands/mcpi.d.ts.map +1 -0
  56. package/dist/cli/experimental/commands/mcpi.js +28 -0
  57. package/dist/cli/experimental/commands/mcpi.js.map +1 -0
  58. package/dist/cli/experimental/commands/server.d.ts +13 -0
  59. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  60. package/dist/cli/experimental/commands/server.js +25 -0
  61. package/dist/cli/experimental/commands/server.js.map +1 -0
  62. package/dist/cli/experimental/transport-address.d.ts +10 -0
  63. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  64. package/dist/cli/experimental/transport-address.js +38 -0
  65. package/dist/cli/experimental/transport-address.js.map +1 -0
  66. package/dist/cli/file-processor.d.ts.map +1 -1
  67. package/dist/cli/file-processor.js +13 -26
  68. package/dist/cli/file-processor.js.map +1 -1
  69. package/dist/cli/initial-message.d.ts +1 -1
  70. package/dist/cli/initial-message.d.ts.map +1 -1
  71. package/dist/cli/initial-message.js.map +1 -1
  72. package/dist/cli/list-models.d.ts +2 -2
  73. package/dist/cli/list-models.d.ts.map +1 -1
  74. package/dist/cli/list-models.js +4 -4
  75. package/dist/cli/list-models.js.map +1 -1
  76. package/dist/cli/project-trust.d.ts +10 -0
  77. package/dist/cli/project-trust.d.ts.map +1 -0
  78. package/dist/cli/project-trust.js +48 -0
  79. package/dist/cli/project-trust.js.map +1 -0
  80. package/dist/cli/session-picker.d.ts +3 -2
  81. package/dist/cli/session-picker.d.ts.map +1 -1
  82. package/dist/cli/session-picker.js +5 -4
  83. package/dist/cli/session-picker.js.map +1 -1
  84. package/dist/cli/startup-ui.d.ts +20 -0
  85. package/dist/cli/startup-ui.d.ts.map +1 -0
  86. package/dist/cli/startup-ui.js +184 -0
  87. package/dist/cli/startup-ui.js.map +1 -0
  88. package/dist/cli.d.ts.map +1 -1
  89. package/dist/cli.js +6 -3
  90. package/dist/cli.js.map +1 -1
  91. package/dist/client/index.d.ts +3 -0
  92. package/dist/client/index.d.ts.map +1 -0
  93. package/dist/client/index.js +3 -0
  94. package/dist/client/index.js.map +1 -0
  95. package/dist/client/remote-session.d.ts +53 -0
  96. package/dist/client/remote-session.d.ts.map +1 -0
  97. package/dist/client/remote-session.js +340 -0
  98. package/dist/client/remote-session.js.map +1 -0
  99. package/dist/client/transcript.d.ts +12 -0
  100. package/dist/client/transcript.d.ts.map +1 -0
  101. package/dist/client/transcript.js +98 -0
  102. package/dist/client/transcript.js.map +1 -0
  103. package/dist/config.d.ts +34 -12
  104. package/dist/config.d.ts.map +1 -1
  105. package/dist/config.js +312 -61
  106. package/dist/config.js.map +1 -1
  107. package/dist/core/agent-session-runtime.d.ts +11 -9
  108. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  109. package/dist/core/agent-session-runtime.js +16 -7
  110. package/dist/core/agent-session-runtime.js.map +1 -1
  111. package/dist/core/agent-session-services.d.ts +13 -12
  112. package/dist/core/agent-session-services.d.ts.map +1 -1
  113. package/dist/core/agent-session-services.js +34 -14
  114. package/dist/core/agent-session-services.js.map +1 -1
  115. package/dist/core/agent-session.d.ts +110 -53
  116. package/dist/core/agent-session.d.ts.map +1 -1
  117. package/dist/core/agent-session.js +658 -488
  118. package/dist/core/agent-session.js.map +1 -1
  119. package/dist/core/auth-guidance.d.ts.map +1 -1
  120. package/dist/core/auth-guidance.js.map +1 -1
  121. package/dist/core/auth-storage.d.ts +35 -104
  122. package/dist/core/auth-storage.d.ts.map +1 -1
  123. package/dist/core/auth-storage.js +272 -286
  124. package/dist/core/auth-storage.js.map +1 -1
  125. package/dist/core/bash-executor.d.ts +1 -1
  126. package/dist/core/bash-executor.d.ts.map +1 -1
  127. package/dist/core/bash-executor.js +11 -8
  128. package/dist/core/bash-executor.js.map +1 -1
  129. package/dist/core/cache-stats.d.ts +49 -0
  130. package/dist/core/cache-stats.d.ts.map +1 -0
  131. package/dist/core/cache-stats.js +101 -0
  132. package/dist/core/cache-stats.js.map +1 -0
  133. package/dist/core/compaction/branch-summarization.d.ts +16 -6
  134. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  135. package/dist/core/compaction/branch-summarization.js +13 -10
  136. package/dist/core/compaction/branch-summarization.js.map +1 -1
  137. package/dist/core/compaction/compaction.d.ts +25 -9
  138. package/dist/core/compaction/compaction.d.ts.map +1 -1
  139. package/dist/core/compaction/compaction.js +163 -133
  140. package/dist/core/compaction/compaction.js.map +1 -1
  141. package/dist/core/compaction/index.d.ts +3 -3
  142. package/dist/core/compaction/index.d.ts.map +1 -1
  143. package/dist/core/compaction/index.js.map +1 -1
  144. package/dist/core/compaction/utils.d.ts +3 -3
  145. package/dist/core/compaction/utils.d.ts.map +1 -1
  146. package/dist/core/compaction/utils.js +7 -18
  147. package/dist/core/compaction/utils.js.map +1 -1
  148. package/dist/core/defaults.d.ts +1 -1
  149. package/dist/core/defaults.d.ts.map +1 -1
  150. package/dist/core/defaults.js.map +1 -1
  151. package/dist/core/env-overlay.d.ts +21 -0
  152. package/dist/core/env-overlay.d.ts.map +1 -0
  153. package/dist/core/env-overlay.js +25 -0
  154. package/dist/core/env-overlay.js.map +1 -0
  155. package/dist/core/exec.d.ts +8 -1
  156. package/dist/core/exec.d.ts.map +1 -1
  157. package/dist/core/exec.js +7 -1
  158. package/dist/core/exec.js.map +1 -1
  159. package/dist/core/experimental.d.ts +6 -0
  160. package/dist/core/experimental.d.ts.map +1 -0
  161. package/dist/core/experimental.js +8 -0
  162. package/dist/core/experimental.js.map +1 -0
  163. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  164. package/dist/core/export-html/ansi-to-html.js +1 -1
  165. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  166. package/dist/core/export-html/index.d.ts +2 -2
  167. package/dist/core/export-html/index.d.ts.map +1 -1
  168. package/dist/core/export-html/index.js +8 -6
  169. package/dist/core/export-html/index.js.map +1 -1
  170. package/dist/core/export-html/template.css +53 -4
  171. package/dist/core/export-html/template.js +129 -35
  172. package/dist/core/export-html/tool-renderer.d.ts +2 -8
  173. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  174. package/dist/core/export-html/tool-renderer.js +15 -2
  175. package/dist/core/export-html/tool-renderer.js.map +1 -1
  176. package/dist/core/export-html/vendor/marked.min.js +75 -3
  177. package/dist/core/extensions/index.d.ts +8 -8
  178. package/dist/core/extensions/index.d.ts.map +1 -1
  179. package/dist/core/extensions/index.js.map +1 -1
  180. package/dist/core/extensions/loader.d.ts +5 -7
  181. package/dist/core/extensions/loader.d.ts.map +1 -1
  182. package/dist/core/extensions/loader.js +160 -87
  183. package/dist/core/extensions/loader.js.map +1 -1
  184. package/dist/core/extensions/runner.d.ts +32 -13
  185. package/dist/core/extensions/runner.d.ts.map +1 -1
  186. package/dist/core/extensions/runner.js +192 -4
  187. package/dist/core/extensions/runner.js.map +1 -1
  188. package/dist/core/extensions/types.d.ts +217 -69
  189. package/dist/core/extensions/types.d.ts.map +1 -1
  190. package/dist/core/extensions/types.js.map +1 -1
  191. package/dist/core/extensions/wrapper.d.ts +3 -3
  192. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  193. package/dist/core/extensions/wrapper.js +22 -3
  194. package/dist/core/extensions/wrapper.js.map +1 -1
  195. package/dist/core/footer-data-provider.d.ts +12 -0
  196. package/dist/core/footer-data-provider.d.ts.map +1 -1
  197. package/dist/core/footer-data-provider.js +30 -2
  198. package/dist/core/footer-data-provider.js.map +1 -1
  199. package/dist/core/http-dispatcher.d.ts +22 -0
  200. package/dist/core/http-dispatcher.d.ts.map +1 -0
  201. package/dist/core/http-dispatcher.js +96 -0
  202. package/dist/core/http-dispatcher.js.map +1 -0
  203. package/dist/core/index.d.ts +9 -8
  204. package/dist/core/index.d.ts.map +1 -1
  205. package/dist/core/index.js +1 -0
  206. package/dist/core/index.js.map +1 -1
  207. package/dist/core/keybindings.d.ts +79 -10
  208. package/dist/core/keybindings.d.ts.map +1 -1
  209. package/dist/core/keybindings.js +11 -10
  210. package/dist/core/keybindings.js.map +1 -1
  211. package/dist/core/messages.d.ts +2 -2
  212. package/dist/core/messages.d.ts.map +1 -1
  213. package/dist/core/messages.js.map +1 -1
  214. package/dist/core/model-config.d.ts +571 -0
  215. package/dist/core/model-config.d.ts.map +1 -0
  216. package/dist/core/model-config.js +254 -0
  217. package/dist/core/model-config.js.map +1 -0
  218. package/dist/core/model-registry.d.ts +23 -110
  219. package/dist/core/model-registry.d.ts.map +1 -1
  220. package/dist/core/model-registry.js +65 -616
  221. package/dist/core/model-registry.js.map +1 -1
  222. package/dist/core/model-resolver.d.ts +20 -7
  223. package/dist/core/model-resolver.d.ts.map +1 -1
  224. package/dist/core/model-resolver.js +139 -43
  225. package/dist/core/model-resolver.js.map +1 -1
  226. package/dist/core/model-runtime.d.ts +100 -0
  227. package/dist/core/model-runtime.d.ts.map +1 -0
  228. package/dist/core/model-runtime.js +602 -0
  229. package/dist/core/model-runtime.js.map +1 -0
  230. package/dist/core/models-store.d.ts +22 -0
  231. package/dist/core/models-store.d.ts.map +1 -0
  232. package/dist/core/models-store.js +113 -0
  233. package/dist/core/models-store.js.map +1 -0
  234. package/dist/core/output-guard.d.ts +1 -0
  235. package/dist/core/output-guard.d.ts.map +1 -1
  236. package/dist/core/output-guard.js +52 -22
  237. package/dist/core/output-guard.js.map +1 -1
  238. package/dist/core/package-manager.d.ts +21 -4
  239. package/dist/core/package-manager.d.ts.map +1 -1
  240. package/dist/core/package-manager.js +428 -191
  241. package/dist/core/package-manager.js.map +1 -1
  242. package/dist/core/pi-manifest.d.ts +8 -0
  243. package/dist/core/pi-manifest.d.ts.map +1 -0
  244. package/dist/core/pi-manifest.js +25 -0
  245. package/dist/core/pi-manifest.js.map +1 -0
  246. package/dist/core/project-trust.d.ts +15 -0
  247. package/dist/core/project-trust.d.ts.map +1 -0
  248. package/dist/core/project-trust.js +59 -0
  249. package/dist/core/project-trust.js.map +1 -0
  250. package/dist/core/prompt-templates.d.ts +4 -2
  251. package/dist/core/prompt-templates.d.ts.map +1 -1
  252. package/dist/core/prompt-templates.js +36 -50
  253. package/dist/core/prompt-templates.js.map +1 -1
  254. package/dist/core/provider-attribution.d.ts +4 -0
  255. package/dist/core/provider-attribution.d.ts.map +1 -0
  256. package/dist/core/provider-attribution.js +72 -0
  257. package/dist/core/provider-attribution.js.map +1 -0
  258. package/dist/core/provider-composer.d.ts +58 -0
  259. package/dist/core/provider-composer.d.ts.map +1 -0
  260. package/dist/core/provider-composer.js +396 -0
  261. package/dist/core/provider-composer.js.map +1 -0
  262. package/dist/core/radius.d.ts +2 -0
  263. package/dist/core/radius.d.ts.map +1 -0
  264. package/dist/core/radius.js +2 -0
  265. package/dist/core/radius.js.map +1 -0
  266. package/dist/core/remote-catalog-provider.d.ts +17 -0
  267. package/dist/core/remote-catalog-provider.d.ts.map +1 -0
  268. package/dist/core/remote-catalog-provider.js +137 -0
  269. package/dist/core/remote-catalog-provider.js.map +1 -0
  270. package/dist/core/resolve-config-value.d.ts +13 -6
  271. package/dist/core/resolve-config-value.d.ts.map +1 -1
  272. package/dist/core/resolve-config-value.js +143 -22
  273. package/dist/core/resolve-config-value.js.map +1 -1
  274. package/dist/core/resource-loader.d.ts +40 -12
  275. package/dist/core/resource-loader.d.ts.map +1 -1
  276. package/dist/core/resource-loader.js +236 -87
  277. package/dist/core/resource-loader.js.map +1 -1
  278. package/dist/core/runtime-credentials.d.ts +15 -0
  279. package/dist/core/runtime-credentials.d.ts.map +1 -0
  280. package/dist/core/runtime-credentials.js +39 -0
  281. package/dist/core/runtime-credentials.js.map +1 -0
  282. package/dist/core/sdk.d.ts +26 -25
  283. package/dist/core/sdk.d.ts.map +1 -1
  284. package/dist/core/sdk.js +56 -49
  285. package/dist/core/sdk.js.map +1 -1
  286. package/dist/core/session-manager.d.ts +42 -19
  287. package/dist/core/session-manager.d.ts.map +1 -1
  288. package/dist/core/session-manager.js +454 -223
  289. package/dist/core/session-manager.js.map +1 -1
  290. package/dist/core/settings-manager.d.ts +77 -8
  291. package/dist/core/settings-manager.d.ts.map +1 -1
  292. package/dist/core/settings-manager.js +255 -67
  293. package/dist/core/settings-manager.js.map +1 -1
  294. package/dist/core/skills.d.ts +2 -2
  295. package/dist/core/skills.d.ts.map +1 -1
  296. package/dist/core/skills.js +12 -34
  297. package/dist/core/skills.js.map +1 -1
  298. package/dist/core/slash-commands.d.ts +2 -1
  299. package/dist/core/slash-commands.d.ts.map +1 -1
  300. package/dist/core/slash-commands.js +4 -3
  301. package/dist/core/slash-commands.js.map +1 -1
  302. package/dist/core/source-info.d.ts +1 -1
  303. package/dist/core/source-info.d.ts.map +1 -1
  304. package/dist/core/source-info.js.map +1 -1
  305. package/dist/core/system-prompt.d.ts +1 -1
  306. package/dist/core/system-prompt.d.ts.map +1 -1
  307. package/dist/core/system-prompt.js +15 -25
  308. package/dist/core/system-prompt.js.map +1 -1
  309. package/dist/core/telemetry.d.ts +7 -1
  310. package/dist/core/telemetry.d.ts.map +1 -1
  311. package/dist/core/telemetry.js +7 -1
  312. package/dist/core/telemetry.js.map +1 -1
  313. package/dist/core/timings.d.ts +5 -3
  314. package/dist/core/timings.d.ts.map +1 -1
  315. package/dist/core/timings.js +26 -16
  316. package/dist/core/timings.js.map +1 -1
  317. package/dist/core/tools/bash.d.ts +11 -7
  318. package/dist/core/tools/bash.d.ts.map +1 -1
  319. package/dist/core/tools/bash.js +220 -188
  320. package/dist/core/tools/bash.js.map +1 -1
  321. package/dist/core/tools/edit-diff.d.ts +26 -5
  322. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  323. package/dist/core/tools/edit-diff.js +110 -23
  324. package/dist/core/tools/edit-diff.js.map +1 -1
  325. package/dist/core/tools/edit.d.ts +11 -5
  326. package/dist/core/tools/edit.d.ts.map +1 -1
  327. package/dist/core/tools/edit.js +67 -100
  328. package/dist/core/tools/edit.js.map +1 -1
  329. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  330. package/dist/core/tools/file-mutation-queue.js +27 -12
  331. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  332. package/dist/core/tools/find.d.ts +10 -3
  333. package/dist/core/tools/find.d.ts.map +1 -1
  334. package/dist/core/tools/find.js +41 -37
  335. package/dist/core/tools/find.js.map +1 -1
  336. package/dist/core/tools/grep.d.ts +7 -3
  337. package/dist/core/tools/grep.d.ts.map +1 -1
  338. package/dist/core/tools/grep.js +12 -8
  339. package/dist/core/tools/grep.js.map +1 -1
  340. package/dist/core/tools/index.d.ts +18 -18
  341. package/dist/core/tools/index.d.ts.map +1 -1
  342. package/dist/core/tools/index.js.map +1 -1
  343. package/dist/core/tools/ls.d.ts +7 -3
  344. package/dist/core/tools/ls.d.ts.map +1 -1
  345. package/dist/core/tools/ls.js +17 -15
  346. package/dist/core/tools/ls.js.map +1 -1
  347. package/dist/core/tools/output-accumulator.d.ts +52 -0
  348. package/dist/core/tools/output-accumulator.d.ts.map +1 -0
  349. package/dist/core/tools/output-accumulator.js +184 -0
  350. package/dist/core/tools/output-accumulator.js.map +1 -0
  351. package/dist/core/tools/path-utils.d.ts +2 -0
  352. package/dist/core/tools/path-utils.d.ts.map +1 -1
  353. package/dist/core/tools/path-utils.js +39 -21
  354. package/dist/core/tools/path-utils.js.map +1 -1
  355. package/dist/core/tools/read.d.ts +7 -3
  356. package/dist/core/tools/read.d.ts.map +1 -1
  357. package/dist/core/tools/read.js +101 -51
  358. package/dist/core/tools/read.js.map +1 -1
  359. package/dist/core/tools/render-utils.d.ts +5 -2
  360. package/dist/core/tools/render-utils.d.ts.map +1 -1
  361. package/dist/core/tools/render-utils.js +18 -2
  362. package/dist/core/tools/render-utils.js.map +1 -1
  363. package/dist/core/tools/tool-definition-wrapper.d.ts +2 -2
  364. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  365. package/dist/core/tools/tool-definition-wrapper.js +3 -3
  366. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  367. package/dist/core/tools/truncate.d.ts.map +1 -1
  368. package/dist/core/tools/truncate.js +12 -2
  369. package/dist/core/tools/truncate.js.map +1 -1
  370. package/dist/core/tools/write.d.ts +6 -2
  371. package/dist/core/tools/write.d.ts.map +1 -1
  372. package/dist/core/tools/write.js +35 -45
  373. package/dist/core/tools/write.js.map +1 -1
  374. package/dist/core/trust-manager.d.ts +36 -0
  375. package/dist/core/trust-manager.d.ts.map +1 -0
  376. package/dist/core/trust-manager.js +202 -0
  377. package/dist/core/trust-manager.js.map +1 -0
  378. package/dist/core/usage-totals.d.ts +19 -0
  379. package/dist/core/usage-totals.d.ts.map +1 -0
  380. package/dist/core/usage-totals.js +52 -0
  381. package/dist/core/usage-totals.js.map +1 -0
  382. package/dist/extensions/index.d.ts +3 -0
  383. package/dist/extensions/index.d.ts.map +1 -0
  384. package/dist/extensions/index.js +3 -0
  385. package/dist/extensions/index.js.map +1 -0
  386. package/dist/extensions/llama/client.d.ts +61 -0
  387. package/dist/extensions/llama/client.d.ts.map +1 -0
  388. package/dist/extensions/llama/client.js +302 -0
  389. package/dist/extensions/llama/client.js.map +1 -0
  390. package/dist/extensions/llama/huggingface.d.ts +23 -0
  391. package/dist/extensions/llama/huggingface.d.ts.map +1 -0
  392. package/dist/extensions/llama/huggingface.js +141 -0
  393. package/dist/extensions/llama/huggingface.js.map +1 -0
  394. package/dist/extensions/llama/index.d.ts +3 -0
  395. package/dist/extensions/llama/index.d.ts.map +1 -0
  396. package/dist/extensions/llama/index.js +217 -0
  397. package/dist/extensions/llama/index.js.map +1 -0
  398. package/dist/extensions/llama/provider.d.ts +10 -0
  399. package/dist/extensions/llama/provider.d.ts.map +1 -0
  400. package/dist/extensions/llama/provider.js +121 -0
  401. package/dist/extensions/llama/provider.js.map +1 -0
  402. package/dist/extensions/llama/ui.d.ts +42 -0
  403. package/dist/extensions/llama/ui.d.ts.map +1 -0
  404. package/dist/extensions/llama/ui.js +416 -0
  405. package/dist/extensions/llama/ui.js.map +1 -0
  406. package/dist/index.d.ts +34 -27
  407. package/dist/index.d.ts.map +1 -1
  408. package/dist/index.js +11 -5
  409. package/dist/index.js.map +1 -1
  410. package/dist/main.d.ts +2 -2
  411. package/dist/main.d.ts.map +1 -1
  412. package/dist/main.js +311 -101
  413. package/dist/main.js.map +1 -1
  414. package/dist/migrations.d.ts +5 -5
  415. package/dist/migrations.d.ts.map +1 -1
  416. package/dist/migrations.js +10 -10
  417. package/dist/migrations.js.map +1 -1
  418. package/dist/modes/index.d.ts +6 -5
  419. package/dist/modes/index.d.ts.map +1 -1
  420. package/dist/modes/index.js.map +1 -1
  421. package/dist/modes/interactive/components/armin.d.ts +1 -1
  422. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  423. package/dist/modes/interactive/components/armin.js.map +1 -1
  424. package/dist/modes/interactive/components/assistant-message.d.ts +8 -3
  425. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  426. package/dist/modes/interactive/components/assistant-message.js +55 -26
  427. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  428. package/dist/modes/interactive/components/bash-execution.d.ts +2 -2
  429. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/bash-execution.js +4 -4
  431. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  432. package/dist/modes/interactive/components/bordered-loader.d.ts +2 -2
  433. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/bordered-loader.js +1 -1
  435. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  436. package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -2
  437. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  439. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  440. package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -2
  441. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  443. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  444. package/dist/modes/interactive/components/config-selector.d.ts +37 -6
  445. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  446. package/dist/modes/interactive/components/config-selector.js +318 -34
  447. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  448. package/dist/modes/interactive/components/countdown-timer.d.ts +3 -3
  449. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/countdown-timer.js +2 -2
  451. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  452. package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
  453. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  454. package/dist/modes/interactive/components/custom-editor.js +9 -2
  455. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  456. package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  457. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
  458. package/dist/modes/interactive/components/custom-entry.js +52 -0
  459. package/dist/modes/interactive/components/custom-entry.js.map +1 -0
  460. package/dist/modes/interactive/components/custom-message.d.ts +6 -4
  461. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/custom-message.js +11 -3
  463. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  464. package/dist/modes/interactive/components/daxnuts.d.ts +1 -1
  465. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  466. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  467. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/diff.js.map +1 -1
  469. package/dist/modes/interactive/components/dynamic-border.d.ts +1 -1
  470. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  472. package/dist/modes/interactive/components/extension-editor.d.ts +5 -4
  473. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/extension-editor.js +19 -32
  475. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  476. package/dist/modes/interactive/components/extension-input.d.ts +1 -1
  477. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  478. package/dist/modes/interactive/components/extension-input.js +1 -1
  479. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  480. package/dist/modes/interactive/components/extension-selector.d.ts +3 -1
  481. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  482. package/dist/modes/interactive/components/extension-selector.js +7 -2
  483. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  484. package/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  485. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
  486. package/dist/modes/interactive/components/first-time-setup.js +103 -0
  487. package/dist/modes/interactive/components/first-time-setup.js.map +1 -0
  488. package/dist/modes/interactive/components/footer.d.ts +9 -4
  489. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  490. package/dist/modes/interactive/components/footer.js +52 -31
  491. package/dist/modes/interactive/components/footer.js.map +1 -1
  492. package/dist/modes/interactive/components/index.d.ts +33 -31
  493. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  494. package/dist/modes/interactive/components/index.js +2 -0
  495. package/dist/modes/interactive/components/index.js.map +1 -1
  496. package/dist/modes/interactive/components/keybinding-hints.d.ts +6 -1
  497. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  498. package/dist/modes/interactive/components/keybinding-hints.js +20 -6
  499. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  500. package/dist/modes/interactive/components/login-dialog.d.ts +12 -6
  501. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  502. package/dist/modes/interactive/components/login-dialog.js +46 -17
  503. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  504. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  505. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  506. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  507. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  508. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  509. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  510. package/dist/modes/interactive/components/mermaid.js +75 -0
  511. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  512. package/dist/modes/interactive/components/model-selector.d.ts +13 -6
  513. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  514. package/dist/modes/interactive/components/model-selector.js +92 -44
  515. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  516. package/dist/modes/interactive/components/oauth-selector.d.ts +7 -4
  517. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/oauth-selector.js +32 -28
  519. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  520. package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -1
  521. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  522. package/dist/modes/interactive/components/scoped-models-selector.js +52 -14
  523. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  524. package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
  525. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  526. package/dist/modes/interactive/components/session-selector-search.js +1 -1
  527. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  528. package/dist/modes/interactive/components/session-selector.d.ts +4 -5
  529. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  530. package/dist/modes/interactive/components/session-selector.js +18 -16
  531. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  532. package/dist/modes/interactive/components/settings-selector.d.ts +23 -2
  533. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  534. package/dist/modes/interactive/components/settings-selector.js +322 -22
  535. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  536. package/dist/modes/interactive/components/show-images-selector.d.ts +1 -1
  537. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  538. package/dist/modes/interactive/components/show-images-selector.js +1 -1
  539. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  540. package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -2
  541. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  542. package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
  543. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  544. package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
  545. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
  546. package/dist/modes/interactive/components/status-indicator.js +60 -0
  547. package/dist/modes/interactive/components/status-indicator.js.map +1 -0
  548. package/dist/modes/interactive/components/theme-selector.d.ts +1 -1
  549. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  550. package/dist/modes/interactive/components/theme-selector.js +1 -1
  551. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  552. package/dist/modes/interactive/components/thinking-selector.d.ts +2 -2
  553. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  554. package/dist/modes/interactive/components/thinking-selector.js +3 -2
  555. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  556. package/dist/modes/interactive/components/tool-execution.d.ts +2 -2
  557. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  558. package/dist/modes/interactive/components/tool-execution.js +33 -2
  559. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  560. package/dist/modes/interactive/components/tree-selector.d.ts +7 -2
  561. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  562. package/dist/modes/interactive/components/tree-selector.js +179 -26
  563. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  564. package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  565. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  566. package/dist/modes/interactive/components/trust-selector.js +91 -0
  567. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  568. package/dist/modes/interactive/components/user-message-selector.d.ts +1 -1
  569. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  570. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  571. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  572. package/dist/modes/interactive/components/user-message.d.ts +9 -3
  573. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  574. package/dist/modes/interactive/components/user-message.js +26 -6
  575. package/dist/modes/interactive/components/user-message.js.map +1 -1
  576. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  577. package/dist/modes/interactive/components/visual-truncate.js +1 -1
  578. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  579. package/dist/modes/interactive/external-editor.d.ts +12 -0
  580. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  581. package/dist/modes/interactive/external-editor.js +37 -0
  582. package/dist/modes/interactive/external-editor.js.map +1 -0
  583. package/dist/modes/interactive/interactive-mode.d.ts +104 -26
  584. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  585. package/dist/modes/interactive/interactive-mode.js +1565 -692
  586. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  587. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  588. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  589. package/dist/modes/interactive/model-catalog-refresh.js +34 -0
  590. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  591. package/dist/modes/interactive/model-search.d.ts +12 -0
  592. package/dist/modes/interactive/model-search.d.ts.map +1 -0
  593. package/dist/modes/interactive/model-search.js +15 -0
  594. package/dist/modes/interactive/model-search.js.map +1 -0
  595. package/dist/modes/interactive/theme/dark.json +10 -5
  596. package/dist/modes/interactive/theme/light.json +10 -5
  597. package/dist/modes/interactive/theme/theme-controller.d.ts +40 -0
  598. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
  599. package/dist/modes/interactive/theme/theme-controller.js +125 -0
  600. package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
  601. package/dist/modes/interactive/theme/theme-schema.json +22 -5
  602. package/dist/modes/interactive/theme/theme.d.ts +48 -7
  603. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  604. package/dist/modes/interactive/theme/theme.js +194 -76
  605. package/dist/modes/interactive/theme/theme.js.map +1 -1
  606. package/dist/modes/json-event.d.ts +31 -0
  607. package/dist/modes/json-event.d.ts.map +1 -0
  608. package/dist/modes/json-event.js +15 -0
  609. package/dist/modes/json-event.js.map +1 -0
  610. package/dist/modes/print-mode.d.ts +3 -3
  611. package/dist/modes/print-mode.d.ts.map +1 -1
  612. package/dist/modes/print-mode.js +16 -5
  613. package/dist/modes/print-mode.js.map +1 -1
  614. package/dist/modes/rpc/rpc-client.d.ts +33 -10
  615. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  616. package/dist/modes/rpc/rpc-client.js +89 -11
  617. package/dist/modes/rpc/rpc-client.js.map +1 -1
  618. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  619. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  620. package/dist/modes/rpc/rpc-mode.js +69 -9
  621. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  622. package/dist/modes/rpc/rpc-types.d.ts +43 -5
  623. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  624. package/dist/modes/rpc/rpc-types.js.map +1 -1
  625. package/dist/package-manager-cli.d.ts +6 -2
  626. package/dist/package-manager-cli.d.ts.map +1 -1
  627. package/dist/package-manager-cli.js +527 -25
  628. package/dist/package-manager-cli.js.map +1 -1
  629. package/dist/path-migration.d.ts +13 -0
  630. package/dist/path-migration.d.ts.map +1 -0
  631. package/dist/path-migration.js +52 -0
  632. package/dist/path-migration.js.map +1 -0
  633. package/dist/rpc-entry.d.ts +3 -0
  634. package/dist/rpc-entry.d.ts.map +1 -0
  635. package/dist/rpc-entry.js +11 -0
  636. package/dist/rpc-entry.js.map +1 -0
  637. package/dist/server/create-harness.d.ts +26 -0
  638. package/dist/server/create-harness.d.ts.map +1 -0
  639. package/dist/server/create-harness.js +106 -0
  640. package/dist/server/create-harness.js.map +1 -0
  641. package/dist/utils/abort.d.ts +5 -0
  642. package/dist/utils/abort.d.ts.map +1 -0
  643. package/dist/utils/abort.js +48 -0
  644. package/dist/utils/abort.js.map +1 -0
  645. package/dist/utils/ansi.d.ts +2 -0
  646. package/dist/utils/ansi.d.ts.map +1 -0
  647. package/dist/utils/ansi.js +52 -0
  648. package/dist/utils/ansi.js.map +1 -0
  649. package/dist/utils/changelog.d.ts +2 -1
  650. package/dist/utils/changelog.d.ts.map +1 -1
  651. package/dist/utils/changelog.js +85 -0
  652. package/dist/utils/changelog.js.map +1 -1
  653. package/dist/utils/child-process.d.ts +12 -5
  654. package/dist/utils/child-process.d.ts.map +1 -1
  655. package/dist/utils/child-process.js +33 -5
  656. package/dist/utils/child-process.js.map +1 -1
  657. package/dist/utils/clipboard-image.d.ts.map +1 -1
  658. package/dist/utils/clipboard-image.js +4 -4
  659. package/dist/utils/clipboard-image.js.map +1 -1
  660. package/dist/utils/clipboard-native.d.ts +4 -1
  661. package/dist/utils/clipboard-native.d.ts.map +1 -1
  662. package/dist/utils/clipboard-native.js +14 -8
  663. package/dist/utils/clipboard-native.js.map +1 -1
  664. package/dist/utils/clipboard.d.ts +2 -0
  665. package/dist/utils/clipboard.d.ts.map +1 -1
  666. package/dist/utils/clipboard.js +129 -46
  667. package/dist/utils/clipboard.js.map +1 -1
  668. package/dist/utils/deprecation.d.ts +4 -0
  669. package/dist/utils/deprecation.d.ts.map +1 -0
  670. package/dist/utils/deprecation.js +13 -0
  671. package/dist/utils/deprecation.js.map +1 -0
  672. package/dist/utils/exif-orientation.d.ts +1 -1
  673. package/dist/utils/exif-orientation.d.ts.map +1 -1
  674. package/dist/utils/exif-orientation.js.map +1 -1
  675. package/dist/utils/git.d.ts.map +1 -1
  676. package/dist/utils/git.js +54 -22
  677. package/dist/utils/git.js.map +1 -1
  678. package/dist/utils/html.d.ts +7 -0
  679. package/dist/utils/html.d.ts.map +1 -0
  680. package/dist/utils/html.js +40 -0
  681. package/dist/utils/html.js.map +1 -0
  682. package/dist/utils/image-convert.d.ts +1 -0
  683. package/dist/utils/image-convert.d.ts.map +1 -1
  684. package/dist/utils/image-convert.js +21 -15
  685. package/dist/utils/image-convert.js.map +1 -1
  686. package/dist/utils/image-process.d.ts +18 -0
  687. package/dist/utils/image-process.d.ts.map +1 -0
  688. package/dist/utils/image-process.js +83 -0
  689. package/dist/utils/image-process.js.map +1 -0
  690. package/dist/utils/image-resize-core.d.ts +30 -0
  691. package/dist/utils/image-resize-core.d.ts.map +1 -0
  692. package/dist/utils/image-resize-core.js +124 -0
  693. package/dist/utils/image-resize-core.js.map +1 -0
  694. package/dist/utils/image-resize-worker.d.ts +2 -0
  695. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  696. package/dist/utils/image-resize-worker.js +31 -0
  697. package/dist/utils/image-resize-worker.js.map +1 -0
  698. package/dist/utils/image-resize.d.ts +7 -27
  699. package/dist/utils/image-resize.d.ts.map +1 -1
  700. package/dist/utils/image-resize.js +75 -115
  701. package/dist/utils/image-resize.js.map +1 -1
  702. package/dist/utils/json.d.ts +3 -0
  703. package/dist/utils/json.d.ts.map +1 -0
  704. package/dist/utils/json.js +7 -0
  705. package/dist/utils/json.js.map +1 -0
  706. package/dist/utils/management-http.d.ts +23 -0
  707. package/dist/utils/management-http.d.ts.map +1 -0
  708. package/dist/utils/management-http.js +50 -0
  709. package/dist/utils/management-http.js.map +1 -0
  710. package/dist/utils/mime.d.ts +1 -0
  711. package/dist/utils/mime.d.ts.map +1 -1
  712. package/dist/utils/mime.js +100 -16
  713. package/dist/utils/mime.js.map +1 -1
  714. package/dist/utils/open-browser.d.ts +9 -0
  715. package/dist/utils/open-browser.d.ts.map +1 -0
  716. package/dist/utils/open-browser.js +22 -0
  717. package/dist/utils/open-browser.js.map +1 -0
  718. package/dist/utils/paths.d.ts +28 -1
  719. package/dist/utils/paths.d.ts.map +1 -1
  720. package/dist/utils/paths.js +97 -2
  721. package/dist/utils/paths.js.map +1 -1
  722. package/dist/utils/pi-user-agent.d.ts +2 -0
  723. package/dist/utils/pi-user-agent.d.ts.map +1 -0
  724. package/dist/utils/pi-user-agent.js +5 -0
  725. package/dist/utils/pi-user-agent.js.map +1 -0
  726. package/dist/utils/shell.d.ts +1 -0
  727. package/dist/utils/shell.d.ts.map +1 -1
  728. package/dist/utils/shell.js +18 -6
  729. package/dist/utils/shell.js.map +1 -1
  730. package/dist/utils/syntax-highlight.d.ts +12 -0
  731. package/dist/utils/syntax-highlight.d.ts.map +1 -0
  732. package/dist/utils/syntax-highlight.js +118 -0
  733. package/dist/utils/syntax-highlight.js.map +1 -0
  734. package/dist/utils/tool-result-images.d.ts +19 -0
  735. package/dist/utils/tool-result-images.d.ts.map +1 -0
  736. package/dist/utils/tool-result-images.js +45 -0
  737. package/dist/utils/tool-result-images.js.map +1 -0
  738. package/dist/utils/tools-manager.d.ts +10 -1
  739. package/dist/utils/tools-manager.d.ts.map +1 -1
  740. package/dist/utils/tools-manager.js +105 -36
  741. package/dist/utils/tools-manager.js.map +1 -1
  742. package/dist/utils/version-check.d.ts +19 -0
  743. package/dist/utils/version-check.d.ts.map +1 -0
  744. package/dist/utils/version-check.js +85 -0
  745. package/dist/utils/version-check.js.map +1 -0
  746. package/dist/utils/windows-self-update.d.ts +3 -0
  747. package/dist/utils/windows-self-update.d.ts.map +1 -0
  748. package/dist/utils/windows-self-update.js +77 -0
  749. package/dist/utils/windows-self-update.js.map +1 -0
  750. package/docs/compaction.md +39 -32
  751. package/docs/containerization.md +113 -0
  752. package/docs/custom-provider.md +212 -75
  753. package/docs/development.md +9 -9
  754. package/docs/docs.json +156 -0
  755. package/docs/environment-variables.md +186 -0
  756. package/docs/extensions.md +652 -140
  757. package/docs/index.md +81 -0
  758. package/docs/json.md +26 -15
  759. package/docs/keybindings.md +60 -21
  760. package/docs/llama-cpp.md +99 -0
  761. package/docs/models.md +168 -34
  762. package/docs/packages.md +46 -36
  763. package/docs/prompt-templates.md +13 -5
  764. package/docs/providers.md +147 -26
  765. package/docs/quickstart.md +167 -0
  766. package/docs/rpc.md +218 -36
  767. package/docs/sdk.md +190 -125
  768. package/docs/security.md +59 -0
  769. package/docs/{session.md → session-format.md} +48 -22
  770. package/docs/sessions.md +145 -0
  771. package/docs/settings.md +130 -25
  772. package/docs/shell-aliases.md +2 -2
  773. package/docs/skills.md +13 -14
  774. package/docs/terminal-setup.md +73 -16
  775. package/docs/termux.md +10 -10
  776. package/docs/themes.md +41 -16
  777. package/docs/tmux.md +6 -4
  778. package/docs/tui.md +85 -61
  779. package/docs/usage.md +302 -0
  780. package/docs/windows.md +2 -2
  781. package/examples/README.md +1 -1
  782. package/examples/extensions/README.md +12 -9
  783. package/examples/extensions/bash-spawn-hook.ts +2 -2
  784. package/examples/extensions/border-status-editor.ts +145 -0
  785. package/examples/extensions/built-in-tool-renderer.ts +2 -2
  786. package/examples/extensions/claude-rules.ts +1 -1
  787. package/examples/extensions/commands.ts +1 -1
  788. package/examples/extensions/custom-compaction.ts +6 -16
  789. package/examples/extensions/custom-footer.ts +1 -1
  790. package/examples/extensions/custom-header.ts +7 -7
  791. package/examples/extensions/custom-provider-anthropic/index.ts +15 -8
  792. package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
  793. package/examples/extensions/custom-provider-anthropic/package.json +3 -3
  794. package/examples/extensions/custom-provider-gitlab-duo/index.ts +65 -9
  795. package/examples/extensions/custom-provider-gitlab-duo/package.json +2 -2
  796. package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
  797. package/examples/extensions/doom-overlay/README.md +1 -1
  798. package/examples/extensions/doom-overlay/doom-component.ts +4 -4
  799. package/examples/extensions/doom-overlay/doom-keys.ts +1 -1
  800. package/examples/extensions/doom-overlay/index.ts +5 -5
  801. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  802. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  803. package/examples/extensions/entry-renderer.ts +41 -0
  804. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  805. package/examples/extensions/github-issue-autocomplete.ts +2 -2
  806. package/examples/extensions/gondolin/index.ts +531 -0
  807. package/examples/extensions/gondolin/package-lock.json +185 -0
  808. package/examples/extensions/gondolin/package.json +19 -0
  809. package/examples/extensions/handoff.ts +50 -14
  810. package/examples/extensions/hidden-thinking-label.ts +1 -1
  811. package/examples/extensions/inline-bash.ts +2 -2
  812. package/examples/extensions/input-transform-streaming.ts +39 -0
  813. package/examples/extensions/input-transform.ts +2 -2
  814. package/examples/extensions/interactive-shell.ts +2 -2
  815. package/examples/extensions/kimi-deferred-tools.ts +61 -0
  816. package/examples/extensions/mac-system-theme.ts +2 -2
  817. package/examples/extensions/message-renderer.ts +3 -3
  818. package/examples/extensions/minimal-mode.ts +2 -2
  819. package/examples/extensions/modal-editor.ts +2 -2
  820. package/examples/extensions/model-status.ts +1 -1
  821. package/examples/extensions/notify.ts +3 -3
  822. package/examples/extensions/overlay-qa-tests.ts +242 -140
  823. package/examples/extensions/overlay-test.ts +9 -6
  824. package/examples/extensions/pirate.ts +1 -1
  825. package/examples/extensions/plan-mode/README.md +3 -2
  826. package/examples/extensions/plan-mode/index.ts +90 -40
  827. package/examples/extensions/preset.ts +16 -10
  828. package/examples/extensions/project-trust.ts +64 -0
  829. package/examples/extensions/prompt-customizer.ts +1 -1
  830. package/examples/extensions/provider-payload.ts +5 -5
  831. package/examples/extensions/qna.ts +4 -8
  832. package/examples/extensions/question.ts +41 -19
  833. package/examples/extensions/questionnaire.ts +50 -29
  834. package/examples/extensions/rainbow-editor.ts +1 -1
  835. package/examples/extensions/reload-runtime.ts +2 -2
  836. package/examples/extensions/rpc-demo.ts +1 -1
  837. package/examples/extensions/sandbox/index.ts +9 -9
  838. package/examples/extensions/sandbox/package-lock.json +7 -7
  839. package/examples/extensions/sandbox/package.json +3 -3
  840. package/examples/extensions/shutdown-command.ts +5 -5
  841. package/examples/extensions/snake.ts +2 -2
  842. package/examples/extensions/space-invaders.ts +2 -2
  843. package/examples/extensions/ssh.ts +2 -2
  844. package/examples/extensions/structured-output.ts +1 -1
  845. package/examples/extensions/subagent/README.md +18 -13
  846. package/examples/extensions/subagent/agents.ts +42 -11
  847. package/examples/extensions/subagent/index.ts +76 -30
  848. package/examples/extensions/summarize.ts +12 -19
  849. package/examples/extensions/tic-tac-toe.ts +2 -2
  850. package/examples/extensions/titlebar-spinner.ts +3 -3
  851. package/examples/extensions/todo.ts +2 -2
  852. package/examples/extensions/tool-override.ts +1 -1
  853. package/examples/extensions/tools.ts +7 -2
  854. package/examples/extensions/truncated-tool.ts +2 -2
  855. package/examples/extensions/with-deps/package-lock.json +4 -4
  856. package/examples/extensions/with-deps/package.json +4 -4
  857. package/examples/extensions/working-indicator.ts +4 -4
  858. package/examples/extensions/working-message-test.ts +1 -1
  859. package/examples/rpc-extension-ui.ts +11 -2
  860. package/examples/sdk/01-minimal.ts +15 -11
  861. package/examples/sdk/02-custom-model.ts +18 -18
  862. package/examples/sdk/03-custom-prompt.ts +25 -17
  863. package/examples/sdk/04-skills.ts +3 -3
  864. package/examples/sdk/05-tools.ts +8 -4
  865. package/examples/sdk/06-extensions.ts +13 -9
  866. package/examples/sdk/07-context-files.ts +2 -2
  867. package/examples/sdk/08-prompt-templates.ts +3 -3
  868. package/examples/sdk/09-api-keys-and-oauth.ts +19 -33
  869. package/examples/sdk/10-settings.ts +4 -4
  870. package/examples/sdk/11-sessions.ts +4 -0
  871. package/examples/sdk/12-full-control.ts +22 -21
  872. package/examples/sdk/README.md +23 -30
  873. package/npm-shrinkwrap.json +1818 -0
  874. package/package.json +117 -99
  875. package/dist/modes/interactive/assets/clankolas.png +0 -0
  876. package/dist/modes/interactive/components/auth-selector-status.d.ts +0 -20
  877. package/dist/modes/interactive/components/auth-selector-status.d.ts.map +0 -1
  878. package/dist/modes/interactive/components/auth-selector-status.js +0 -23
  879. package/dist/modes/interactive/components/auth-selector-status.js.map +0 -1
  880. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
  881. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  882. package/dist/modes/interactive/components/earendil-announcement.js +0 -40
  883. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  884. package/docs/images/exy.png +0 -0
  885. package/docs/tree.md +0 -233
  886. package/examples/extensions/antigravity-image-gen.ts +0 -418
  887. package/examples/extensions/custom-provider-qwen-cli/index.ts +0 -345
  888. package/examples/extensions/custom-provider-qwen-cli/package.json +0 -16
@@ -1 +1 @@
1
- {"version":3,"file":"extension-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAgC,KAAK,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAMzF,MAAM,WAAW,wBAAwB;IACxC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,0BAA2B,SAAQ,SAAS;IACxD,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA6B;IAE9C,YACC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAClC,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,CAAC,EAAE,wBAAwB,EA2C/B;IAED,OAAO,CAAC,UAAU;IAWlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAcjC;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@mariozechner/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { CountdownTimer } from \"./countdown-timer.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.js\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: string[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: string[],\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst text = isSelected\n\t\t\t\t? theme.fg(\"accent\", \"→ \") + theme.fg(\"accent\", this.options[i])\n\t\t\t\t: ` ${theme.fg(\"text\", this.options[i])}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
1
+ {"version":3,"file":"extension-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAgC,KAAK,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAM7F,MAAM,WAAW,wBAAwB;IACxC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACnC;AAED,qBAAa,0BAA2B,SAAQ,SAAS;IACxD,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,qBAAqB,CAA2B;IAExD,YACC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAClC,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,CAAC,EAAE,wBAAwB,EA4C/B;IAED,OAAO,CAAC,UAAU;IAWlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBjC;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@sammorrowdrums/mcpi-tui\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n\tonToggleToolsExpanded?: () => void;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: string[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\tprivate onToggleToolsExpanded: (() => void) | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: string[],\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.onToggleToolsExpanded = opts?.onToggleToolsExpanded;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst text = isSelected\n\t\t\t\t? theme.fg(\"accent\", \"→ \") + theme.fg(\"accent\", this.options[i])\n\t\t\t\t: ` ${theme.fg(\"text\", this.options[i])}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.tools.expand\")) {\n\t\t\tthis.onToggleToolsExpanded?.();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Generic selector component for extensions.
3
3
  * Displays a list of string options with keyboard navigation.
4
4
  */
5
- import { Container, getKeybindings, Spacer, Text } from "@mariozechner/pi-tui";
5
+ import { Container, getKeybindings, Spacer, Text } from "@sammorrowdrums/mcpi-tui";
6
6
  import { theme } from "../theme/theme.js";
7
7
  import { CountdownTimer } from "./countdown-timer.js";
8
8
  import { DynamicBorder } from "./dynamic-border.js";
@@ -16,11 +16,13 @@ export class ExtensionSelectorComponent extends Container {
16
16
  titleText;
17
17
  baseTitle;
18
18
  countdown;
19
+ onToggleToolsExpanded;
19
20
  constructor(title, options, onSelect, onCancel, opts) {
20
21
  super();
21
22
  this.options = options;
22
23
  this.onSelectCallback = onSelect;
23
24
  this.onCancelCallback = onCancel;
25
+ this.onToggleToolsExpanded = opts?.onToggleToolsExpanded;
24
26
  this.baseTitle = title;
25
27
  this.addChild(new DynamicBorder());
26
28
  this.addChild(new Spacer(1));
@@ -54,7 +56,10 @@ export class ExtensionSelectorComponent extends Container {
54
56
  }
55
57
  handleInput(keyData) {
56
58
  const kb = getKeybindings();
57
- if (kb.matches(keyData, "tui.select.up") || keyData === "k") {
59
+ if (kb.matches(keyData, "app.tools.expand")) {
60
+ this.onToggleToolsExpanded?.();
61
+ }
62
+ else if (kb.matches(keyData, "tui.select.up") || keyData === "k") {
58
63
  this.selectedIndex = Math.max(0, this.selectedIndex - 1);
59
64
  this.updateList();
60
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"extension-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@mariozechner/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { CountdownTimer } from \"./countdown-timer.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.js\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: string[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: string[],\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst text = isSelected\n\t\t\t\t? theme.fg(\"accent\", \"→ \") + theme.fg(\"accent\", this.options[i])\n\t\t\t\t: ` ${theme.fg(\"text\", this.options[i])}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
1
+ {"version":3,"file":"extension-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@sammorrowdrums/mcpi-tui\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n\tonToggleToolsExpanded?: () => void;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: string[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\tprivate onToggleToolsExpanded: (() => void) | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: string[],\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.onToggleToolsExpanded = opts?.onToggleToolsExpanded;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst text = isSelected\n\t\t\t\t? theme.fg(\"accent\", \"→ \") + theme.fg(\"accent\", this.options[i])\n\t\t\t\t: ` ${theme.fg(\"text\", this.options[i])}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.tools.expand\")) {\n\t\t\tthis.onToggleToolsExpanded?.();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { Container } from "@sammorrowdrums/mcpi-tui";
2
+ import { type TerminalTheme } from "../theme/theme.ts";
3
+ export interface FirstTimeSetupResult {
4
+ theme: TerminalTheme;
5
+ shareAnalytics: boolean;
6
+ }
7
+ export interface FirstTimeSetupOptions {
8
+ detectedTheme: TerminalTheme;
9
+ onThemePreview: (themeName: TerminalTheme) => void;
10
+ onSubmit: (result: FirstTimeSetupResult) => void;
11
+ onCancel: () => void;
12
+ }
13
+ /** First-time setup dialog: theme choice and analytics opt-in. */
14
+ export declare class FirstTimeSetupComponent extends Container {
15
+ private step;
16
+ private themeIndex;
17
+ private analyticsIndex;
18
+ private readonly options;
19
+ constructor(options: FirstTimeSetupOptions);
20
+ private update;
21
+ private addOptionList;
22
+ private moveSelection;
23
+ handleInput(keyData: string): void;
24
+ }
25
+ //# sourceMappingURL=first-time-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-time-setup.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/first-time-setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgC,MAAM,0BAA0B,CAAC;AAEnF,OAAO,EAAE,KAAK,aAAa,EAAS,MAAM,mBAAmB,CAAC;AAI9D,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACrC,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACrB;AAcD,kEAAkE;AAClE,qBAAa,uBAAwB,SAAQ,SAAS;IACrD,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAEhD,YAAY,OAAO,EAAE,qBAAqB,EAQzC;IAGD,OAAO,CAAC,MAAM;IAsDd,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,aAAa;IAarB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBjC;CACD","sourcesContent":["import { Container, getKeybindings, Spacer, Text } from \"@sammorrowdrums/mcpi-tui\";\nimport { APP_NAME } from \"../../../config.ts\";\nimport { type TerminalTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface FirstTimeSetupResult {\n\ttheme: TerminalTheme;\n\tshareAnalytics: boolean;\n}\n\nexport interface FirstTimeSetupOptions {\n\tdetectedTheme: TerminalTheme;\n\tonThemePreview: (themeName: TerminalTheme) => void;\n\tonSubmit: (result: FirstTimeSetupResult) => void;\n\tonCancel: () => void;\n}\n\nconst THEME_OPTIONS: Array<{ value: TerminalTheme; label: string }> = [\n\t{ value: \"dark\", label: \"Dark\" },\n\t{ value: \"light\", label: \"Light\" },\n];\n\nconst ANALYTICS_OPTIONS: Array<{ value: boolean; label: string }> = [\n\t{ value: true, label: \"Share anonymous usage data\" },\n\t{ value: false, label: \"Don't share\" },\n];\n\nconst SETUP_LOGO_LINES = [\"██████\", \"██ ██\", \"████ ██\", \"██ ██\"];\n\n/** First-time setup dialog: theme choice and analytics opt-in. */\nexport class FirstTimeSetupComponent extends Container {\n\tprivate step: \"theme\" | \"analytics\" = \"theme\";\n\tprivate themeIndex: number;\n\tprivate analyticsIndex = 0;\n\tprivate readonly options: FirstTimeSetupOptions;\n\n\tconstructor(options: FirstTimeSetupOptions) {\n\t\tsuper();\n\t\tthis.options = options;\n\t\tthis.themeIndex = Math.max(\n\t\t\t0,\n\t\t\tTHEME_OPTIONS.findIndex((option) => option.value === options.detectedTheme),\n\t\t);\n\t\tthis.update();\n\t}\n\n\t// Rebuild the whole dialog on every change so theme previews recolor all text.\n\tprivate update(): void {\n\t\tthis.clear();\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"accent\", SETUP_LOGO_LINES.join(\"\\n\")), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(theme.fg(\"accent\", theme.bold(`Welcome to ${APP_NAME}, the minimal coding agent.`)), 1, 0),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.step === \"theme\") {\n\t\t\tthis.addChild(new Text(theme.fg(\"text\", \"Pick a theme.\"), 1, 0));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", `Detected system appearance: ${this.options.detectedTheme}`), 1, 0));\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addOptionList(\n\t\t\t\tTHEME_OPTIONS.map((option) => option.label),\n\t\t\t\tthis.themeIndex,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(new Text(theme.fg(\"text\", \"Opt-in to anonymous usage data sharing?\"), 1, 0));\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"muted\",\n\t\t\t\t\t\t\"Opting in stores a tracking identifier in settings.json and enables anonymous\\nusage analytics. This helps us to better debug, reproduce, and resolve issues\\nand bugs within mcpi. You can observe what is shared using /privacy and make\\nchanges anytime in settings.json.\",\n\t\t\t\t\t),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addOptionList(\n\t\t\t\tANALYTICS_OPTIONS.map((option) => option.label),\n\t\t\t\tthis.analyticsIndex,\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", this.step === \"theme\" ? \"continue\" : \"finish\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"skip setup\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate addOptionList(labels: string[], selectedIndex: number): void {\n\t\tfor (let i = 0; i < labels.length; i++) {\n\t\t\tconst isSelected = i === selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst label = isSelected ? theme.fg(\"accent\", labels[i]) : theme.fg(\"text\", labels[i]);\n\t\t\tthis.addChild(new Text(`${prefix}${label}`, 1, 0));\n\t\t}\n\t}\n\n\tprivate moveSelection(delta: number): void {\n\t\tif (this.step === \"theme\") {\n\t\t\tconst next = Math.max(0, Math.min(THEME_OPTIONS.length - 1, this.themeIndex + delta));\n\t\t\tif (next !== this.themeIndex) {\n\t\t\t\tthis.themeIndex = next;\n\t\t\t\tthis.options.onThemePreview(THEME_OPTIONS[this.themeIndex].value);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.analyticsIndex = Math.max(0, Math.min(ANALYTICS_OPTIONS.length - 1, this.analyticsIndex + delta));\n\t\t}\n\t\tthis.update();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.moveSelection(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.moveSelection(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tif (this.step === \"theme\") {\n\t\t\t\tthis.step = \"analytics\";\n\t\t\t\tthis.update();\n\t\t\t} else {\n\t\t\t\tthis.options.onSubmit({\n\t\t\t\t\ttheme: THEME_OPTIONS[this.themeIndex].value,\n\t\t\t\t\tshareAnalytics: ANALYTICS_OPTIONS[this.analyticsIndex].value,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.options.onCancel();\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,103 @@
1
+ import { Container, getKeybindings, Spacer, Text } from "@sammorrowdrums/mcpi-tui";
2
+ import { APP_NAME } from "../../../config.js";
3
+ import { theme } from "../theme/theme.js";
4
+ import { DynamicBorder } from "./dynamic-border.js";
5
+ import { keyHint, rawKeyHint } from "./keybinding-hints.js";
6
+ const THEME_OPTIONS = [
7
+ { value: "dark", label: "Dark" },
8
+ { value: "light", label: "Light" },
9
+ ];
10
+ const ANALYTICS_OPTIONS = [
11
+ { value: true, label: "Share anonymous usage data" },
12
+ { value: false, label: "Don't share" },
13
+ ];
14
+ const SETUP_LOGO_LINES = ["██████", "██ ██", "████ ██", "██ ██"];
15
+ /** First-time setup dialog: theme choice and analytics opt-in. */
16
+ export class FirstTimeSetupComponent extends Container {
17
+ step = "theme";
18
+ themeIndex;
19
+ analyticsIndex = 0;
20
+ options;
21
+ constructor(options) {
22
+ super();
23
+ this.options = options;
24
+ this.themeIndex = Math.max(0, THEME_OPTIONS.findIndex((option) => option.value === options.detectedTheme));
25
+ this.update();
26
+ }
27
+ // Rebuild the whole dialog on every change so theme previews recolor all text.
28
+ update() {
29
+ this.clear();
30
+ this.addChild(new DynamicBorder());
31
+ this.addChild(new Spacer(1));
32
+ this.addChild(new Text(theme.fg("accent", SETUP_LOGO_LINES.join("\n")), 1, 0));
33
+ this.addChild(new Spacer(1));
34
+ this.addChild(new Text(theme.fg("accent", theme.bold(`Welcome to ${APP_NAME}, the minimal coding agent.`)), 1, 0));
35
+ this.addChild(new Spacer(1));
36
+ if (this.step === "theme") {
37
+ this.addChild(new Text(theme.fg("text", "Pick a theme."), 1, 0));
38
+ this.addChild(new Text(theme.fg("muted", `Detected system appearance: ${this.options.detectedTheme}`), 1, 0));
39
+ this.addChild(new Spacer(1));
40
+ this.addOptionList(THEME_OPTIONS.map((option) => option.label), this.themeIndex);
41
+ }
42
+ else {
43
+ this.addChild(new Text(theme.fg("text", "Opt-in to anonymous usage data sharing?"), 1, 0));
44
+ this.addChild(new Text(theme.fg("muted", "Opting in stores a tracking identifier in settings.json and enables anonymous\nusage analytics. This helps us to better debug, reproduce, and resolve issues\nand bugs within mcpi. You can observe what is shared using /privacy and make\nchanges anytime in settings.json."), 1, 0));
45
+ this.addChild(new Spacer(1));
46
+ this.addOptionList(ANALYTICS_OPTIONS.map((option) => option.label), this.analyticsIndex);
47
+ }
48
+ this.addChild(new Spacer(1));
49
+ this.addChild(new Text(rawKeyHint("↑↓", "navigate") +
50
+ " " +
51
+ keyHint("tui.select.confirm", this.step === "theme" ? "continue" : "finish") +
52
+ " " +
53
+ keyHint("tui.select.cancel", "skip setup"), 1, 0));
54
+ this.addChild(new Spacer(1));
55
+ this.addChild(new DynamicBorder());
56
+ }
57
+ addOptionList(labels, selectedIndex) {
58
+ for (let i = 0; i < labels.length; i++) {
59
+ const isSelected = i === selectedIndex;
60
+ const prefix = isSelected ? theme.fg("accent", "→ ") : " ";
61
+ const label = isSelected ? theme.fg("accent", labels[i]) : theme.fg("text", labels[i]);
62
+ this.addChild(new Text(`${prefix}${label}`, 1, 0));
63
+ }
64
+ }
65
+ moveSelection(delta) {
66
+ if (this.step === "theme") {
67
+ const next = Math.max(0, Math.min(THEME_OPTIONS.length - 1, this.themeIndex + delta));
68
+ if (next !== this.themeIndex) {
69
+ this.themeIndex = next;
70
+ this.options.onThemePreview(THEME_OPTIONS[this.themeIndex].value);
71
+ }
72
+ }
73
+ else {
74
+ this.analyticsIndex = Math.max(0, Math.min(ANALYTICS_OPTIONS.length - 1, this.analyticsIndex + delta));
75
+ }
76
+ this.update();
77
+ }
78
+ handleInput(keyData) {
79
+ const kb = getKeybindings();
80
+ if (kb.matches(keyData, "tui.select.up") || keyData === "k") {
81
+ this.moveSelection(-1);
82
+ }
83
+ else if (kb.matches(keyData, "tui.select.down") || keyData === "j") {
84
+ this.moveSelection(1);
85
+ }
86
+ else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
87
+ if (this.step === "theme") {
88
+ this.step = "analytics";
89
+ this.update();
90
+ }
91
+ else {
92
+ this.options.onSubmit({
93
+ theme: THEME_OPTIONS[this.themeIndex].value,
94
+ shareAnalytics: ANALYTICS_OPTIONS[this.analyticsIndex].value,
95
+ });
96
+ }
97
+ }
98
+ else if (kb.matches(keyData, "tui.select.cancel")) {
99
+ this.options.onCancel();
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=first-time-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-time-setup.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/first-time-setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, getKeybindings, Spacer, Text } from \"@sammorrowdrums/mcpi-tui\";\nimport { APP_NAME } from \"../../../config.ts\";\nimport { type TerminalTheme, theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface FirstTimeSetupResult {\n\ttheme: TerminalTheme;\n\tshareAnalytics: boolean;\n}\n\nexport interface FirstTimeSetupOptions {\n\tdetectedTheme: TerminalTheme;\n\tonThemePreview: (themeName: TerminalTheme) => void;\n\tonSubmit: (result: FirstTimeSetupResult) => void;\n\tonCancel: () => void;\n}\n\nconst THEME_OPTIONS: Array<{ value: TerminalTheme; label: string }> = [\n\t{ value: \"dark\", label: \"Dark\" },\n\t{ value: \"light\", label: \"Light\" },\n];\n\nconst ANALYTICS_OPTIONS: Array<{ value: boolean; label: string }> = [\n\t{ value: true, label: \"Share anonymous usage data\" },\n\t{ value: false, label: \"Don't share\" },\n];\n\nconst SETUP_LOGO_LINES = [\"██████\", \"██ ██\", \"████ ██\", \"██ ██\"];\n\n/** First-time setup dialog: theme choice and analytics opt-in. */\nexport class FirstTimeSetupComponent extends Container {\n\tprivate step: \"theme\" | \"analytics\" = \"theme\";\n\tprivate themeIndex: number;\n\tprivate analyticsIndex = 0;\n\tprivate readonly options: FirstTimeSetupOptions;\n\n\tconstructor(options: FirstTimeSetupOptions) {\n\t\tsuper();\n\t\tthis.options = options;\n\t\tthis.themeIndex = Math.max(\n\t\t\t0,\n\t\t\tTHEME_OPTIONS.findIndex((option) => option.value === options.detectedTheme),\n\t\t);\n\t\tthis.update();\n\t}\n\n\t// Rebuild the whole dialog on every change so theme previews recolor all text.\n\tprivate update(): void {\n\t\tthis.clear();\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"accent\", SETUP_LOGO_LINES.join(\"\\n\")), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(theme.fg(\"accent\", theme.bold(`Welcome to ${APP_NAME}, the minimal coding agent.`)), 1, 0),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (this.step === \"theme\") {\n\t\t\tthis.addChild(new Text(theme.fg(\"text\", \"Pick a theme.\"), 1, 0));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", `Detected system appearance: ${this.options.detectedTheme}`), 1, 0));\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addOptionList(\n\t\t\t\tTHEME_OPTIONS.map((option) => option.label),\n\t\t\t\tthis.themeIndex,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.addChild(new Text(theme.fg(\"text\", \"Opt-in to anonymous usage data sharing?\"), 1, 0));\n\t\t\tthis.addChild(\n\t\t\t\tnew Text(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"muted\",\n\t\t\t\t\t\t\"Opting in stores a tracking identifier in settings.json and enables anonymous\\nusage analytics. This helps us to better debug, reproduce, and resolve issues\\nand bugs within mcpi. You can observe what is shared using /privacy and make\\nchanges anytime in settings.json.\",\n\t\t\t\t\t),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t);\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addOptionList(\n\t\t\t\tANALYTICS_OPTIONS.map((option) => option.label),\n\t\t\t\tthis.analyticsIndex,\n\t\t\t);\n\t\t}\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", this.step === \"theme\" ? \"continue\" : \"finish\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", \"skip setup\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate addOptionList(labels: string[], selectedIndex: number): void {\n\t\tfor (let i = 0; i < labels.length; i++) {\n\t\t\tconst isSelected = i === selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst label = isSelected ? theme.fg(\"accent\", labels[i]) : theme.fg(\"text\", labels[i]);\n\t\t\tthis.addChild(new Text(`${prefix}${label}`, 1, 0));\n\t\t}\n\t}\n\n\tprivate moveSelection(delta: number): void {\n\t\tif (this.step === \"theme\") {\n\t\t\tconst next = Math.max(0, Math.min(THEME_OPTIONS.length - 1, this.themeIndex + delta));\n\t\t\tif (next !== this.themeIndex) {\n\t\t\t\tthis.themeIndex = next;\n\t\t\t\tthis.options.onThemePreview(THEME_OPTIONS[this.themeIndex].value);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.analyticsIndex = Math.max(0, Math.min(ANALYTICS_OPTIONS.length - 1, this.analyticsIndex + delta));\n\t\t}\n\t\tthis.update();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.moveSelection(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.moveSelection(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tif (this.step === \"theme\") {\n\t\t\t\tthis.step = \"analytics\";\n\t\t\t\tthis.update();\n\t\t\t} else {\n\t\t\t\tthis.options.onSubmit({\n\t\t\t\t\ttheme: THEME_OPTIONS[this.themeIndex].value,\n\t\t\t\t\tshareAnalytics: ANALYTICS_OPTIONS[this.analyticsIndex].value,\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.options.onCancel();\n\t\t}\n\t}\n}\n"]}
@@ -1,14 +1,19 @@
1
- import { type Component } from "@mariozechner/pi-tui";
2
- import type { AgentSession } from "../../../core/agent-session.js";
3
- import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.js";
1
+ import { type Component } from "@sammorrowdrums/mcpi-tui";
2
+ import type { AgentSession } from "../../../core/agent-session.ts";
3
+ import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.ts";
4
+ /**
5
+ * Format token counts for compact footer display.
6
+ */
7
+ export declare function formatTokens(count: number): string;
8
+ export declare function formatCwdForFooter(cwd: string, home: string | undefined): string;
4
9
  /**
5
10
  * Footer component that shows pwd, token stats, and context usage.
6
11
  * Computes token/context stats from session, gets git branch and extension statuses from provider.
7
12
  */
8
13
  export declare class FooterComponent implements Component {
14
+ private autoCompactEnabled;
9
15
  private session;
10
16
  private footerData;
11
- private autoCompactEnabled;
12
17
  constructor(session: AgentSession, footerData: ReadonlyFooterDataProvider);
13
18
  setSession(session: AgentSession): void;
14
19
  setAutoCompactEnabled(enabled: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AA0BxF;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAI/C,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,UAAU;IAJnB,OAAO,CAAC,kBAAkB,CAAQ;IAElC,YACS,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,0BAA0B,EAC3C;IAEJ,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEtC;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED;;;OAGG;IACH,UAAU,IAAI,IAAI,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0J9B;CACD","sourcesContent":["import { type Component, truncateToWidth, visibleWidth } from \"@mariozechner/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.js\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts (similar to web-ui)\n */\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\n\tconstructor(\n\t\tprivate session: AgentSession,\n\t\tprivate footerData: ReadonlyFooterDataProvider,\n\t) {}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\ttotalInput += entry.message.usage.input;\n\t\t\t\ttotalOutput += entry.message.usage.output;\n\t\t\t\ttotalCacheRead += entry.message.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += entry.message.usage.cacheWrite;\n\t\t\t\ttotalCost += entry.message.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = this.session.sessionManager.getCwd();\n\t\tconst home = process.env.HOME || process.env.USERPROFILE;\n\t\tif (home && pwd.startsWith(home)) {\n\t\t\tpwd = `~${pwd.slice(home.length)}`;\n\t\t}\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (totalInput) statsParts.push(`↑${formatTokens(totalInput)}`);\n\t\tif (totalOutput) statsParts.push(`↓${formatTokens(totalOutput)}`);\n\t\tif (totalCacheRead) statsParts.push(`R${formatTokens(totalCacheRead)}`);\n\t\tif (totalCacheWrite) statsParts.push(`W${formatTokens(totalCacheWrite)}`);\n\n\t\t// Show cost with \"(sub)\" indicator if using OAuth subscription\n\t\tconst usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
1
+ {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,0BAA0B,CAAC;AACzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAgBxF;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYhF;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAA6B;IAE/C,YAAY,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B,EAGxE;IAED,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEtC;IAED,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE5C;IAED;;;OAGG;IACH,UAAU,IAAI,IAAI,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAEd;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgK9B;CACD","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@sammorrowdrums/mcpi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.session.modelRuntime.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
@@ -1,4 +1,7 @@
1
- import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
1
+ import { isAbsolute, relative, resolve, sep } from "node:path";
2
+ import { truncateToWidth, visibleWidth } from "@sammorrowdrums/mcpi-tui";
3
+ import { areExperimentalFeaturesEnabled } from "../../../core/experimental.js";
4
+ import { addUsageToTotals, createUsageTotals } from "../../../core/usage-totals.js";
2
5
  import { theme } from "../theme/theme.js";
3
6
  /**
4
7
  * Sanitize text for display in a single-line status.
@@ -12,9 +15,9 @@ function sanitizeStatusText(text) {
12
15
  .trim();
13
16
  }
14
17
  /**
15
- * Format token counts (similar to web-ui)
18
+ * Format token counts for compact footer display.
16
19
  */
17
- function formatTokens(count) {
20
+ export function formatTokens(count) {
18
21
  if (count < 1000)
19
22
  return count.toString();
20
23
  if (count < 10000)
@@ -25,14 +28,26 @@ function formatTokens(count) {
25
28
  return `${(count / 1000000).toFixed(1)}M`;
26
29
  return `${Math.round(count / 1000000)}M`;
27
30
  }
31
+ export function formatCwdForFooter(cwd, home) {
32
+ if (!home)
33
+ return cwd;
34
+ const resolvedCwd = resolve(cwd);
35
+ const resolvedHome = resolve(home);
36
+ const relativeToHome = relative(resolvedHome, resolvedCwd);
37
+ const isInsideHome = relativeToHome === "" ||
38
+ (relativeToHome !== ".." && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));
39
+ if (!isInsideHome)
40
+ return cwd;
41
+ return relativeToHome === "" ? "~" : `~${sep}${relativeToHome}`;
42
+ }
28
43
  /**
29
44
  * Footer component that shows pwd, token stats, and context usage.
30
45
  * Computes token/context stats from session, gets git branch and extension statuses from provider.
31
46
  */
32
47
  export class FooterComponent {
48
+ autoCompactEnabled = true;
33
49
  session;
34
50
  footerData;
35
- autoCompactEnabled = true;
36
51
  constructor(session, footerData) {
37
52
  this.session = session;
38
53
  this.footerData = footerData;
@@ -60,18 +75,20 @@ export class FooterComponent {
60
75
  render(width) {
61
76
  const state = this.session.state;
62
77
  // Calculate cumulative usage from ALL session entries (not just post-compaction messages)
63
- let totalInput = 0;
64
- let totalOutput = 0;
65
- let totalCacheRead = 0;
66
- let totalCacheWrite = 0;
67
- let totalCost = 0;
78
+ const usageTotals = createUsageTotals();
79
+ let latestCacheHitRate;
68
80
  for (const entry of this.session.sessionManager.getEntries()) {
69
81
  if (entry.type === "message" && entry.message.role === "assistant") {
70
- totalInput += entry.message.usage.input;
71
- totalOutput += entry.message.usage.output;
72
- totalCacheRead += entry.message.usage.cacheRead;
73
- totalCacheWrite += entry.message.usage.cacheWrite;
74
- totalCost += entry.message.usage.cost.total;
82
+ addUsageToTotals(usageTotals, entry.message.usage);
83
+ const latestPromptTokens = entry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;
84
+ latestCacheHitRate =
85
+ latestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;
86
+ }
87
+ else if (entry.type === "message" && entry.message.role === "toolResult" && entry.message.usage) {
88
+ addUsageToTotals(usageTotals, entry.message.usage);
89
+ }
90
+ else if ((entry.type === "branch_summary" || entry.type === "compaction") && entry.usage) {
91
+ addUsageToTotals(usageTotals, entry.usage);
75
92
  }
76
93
  }
77
94
  // Calculate context usage from session (handles compaction correctly).
@@ -81,11 +98,7 @@ export class FooterComponent {
81
98
  const contextPercentValue = contextUsage?.percent ?? 0;
82
99
  const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
83
100
  // Replace home directory with ~
84
- let pwd = this.session.sessionManager.getCwd();
85
- const home = process.env.HOME || process.env.USERPROFILE;
86
- if (home && pwd.startsWith(home)) {
87
- pwd = `~${pwd.slice(home.length)}`;
88
- }
101
+ let pwd = formatCwdForFooter(this.session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);
89
102
  // Add git branch if available
90
103
  const branch = this.footerData.getGitBranch();
91
104
  if (branch) {
@@ -98,18 +111,23 @@ export class FooterComponent {
98
111
  }
99
112
  // Build stats line
100
113
  const statsParts = [];
101
- if (totalInput)
102
- statsParts.push(`↑${formatTokens(totalInput)}`);
103
- if (totalOutput)
104
- statsParts.push(`↓${formatTokens(totalOutput)}`);
105
- if (totalCacheRead)
106
- statsParts.push(`R${formatTokens(totalCacheRead)}`);
107
- if (totalCacheWrite)
108
- statsParts.push(`W${formatTokens(totalCacheWrite)}`);
109
- // Show cost with "(sub)" indicator if using OAuth subscription
110
- const usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;
111
- if (totalCost || usingSubscription) {
112
- const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
114
+ if (usageTotals.input)
115
+ statsParts.push(`↑${formatTokens(usageTotals.input)}`);
116
+ if (usageTotals.output)
117
+ statsParts.push(`↓${formatTokens(usageTotals.output)}`);
118
+ if (usageTotals.cacheRead)
119
+ statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);
120
+ if (usageTotals.cacheWrite)
121
+ statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);
122
+ if ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {
123
+ statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);
124
+ }
125
+ // Kimi Coding is subscription-backed despite using API-key authentication.
126
+ const usingSubscription = state.model
127
+ ? state.model.provider === "kimi-coding" || this.session.modelRuntime.isUsingSubscription(state.model.provider)
128
+ : false;
129
+ if (usageTotals.cost || usingSubscription) {
130
+ const costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
113
131
  statsParts.push(costStr);
114
132
  }
115
133
  // Colorize context percentage based on usage
@@ -128,6 +146,9 @@ export class FooterComponent {
128
146
  contextPercentStr = contextPercentDisplay;
129
147
  }
130
148
  statsParts.push(contextPercentStr);
149
+ if (areExperimentalFeaturesEnabled()) {
150
+ statsParts.push(`${theme.fg("dim", "•")} ${theme.bold(theme.fg("warning", "xp"))}`);
151
+ }
131
152
  let statsLeft = statsParts.join(" ");
132
153
  // Add model name on the right side, plus thinking level if model supports it
133
154
  const modelName = state.model?.id || "no-model";
@@ -1 +1 @@
1
- {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, truncateToWidth, visibleWidth } from \"@mariozechner/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.js\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts (similar to web-ui)\n */\nfunction formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\n\tconstructor(\n\t\tprivate session: AgentSession,\n\t\tprivate footerData: ReadonlyFooterDataProvider,\n\t) {}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\ttotalInput += entry.message.usage.input;\n\t\t\t\ttotalOutput += entry.message.usage.output;\n\t\t\t\ttotalCacheRead += entry.message.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += entry.message.usage.cacheWrite;\n\t\t\t\ttotalCost += entry.message.usage.cost.total;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = this.session.sessionManager.getCwd();\n\t\tconst home = process.env.HOME || process.env.USERPROFILE;\n\t\tif (home && pwd.startsWith(home)) {\n\t\t\tpwd = `~${pwd.slice(home.length)}`;\n\t\t}\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (totalInput) statsParts.push(`↑${formatTokens(totalInput)}`);\n\t\tif (totalOutput) statsParts.push(`↓${formatTokens(totalOutput)}`);\n\t\tif (totalCacheRead) statsParts.push(`R${formatTokens(totalCacheRead)}`);\n\t\tif (totalCacheWrite) statsParts.push(`W${formatTokens(totalCacheWrite)}`);\n\n\t\t// Show cost with \"(sub)\" indicator if using OAuth subscription\n\t\tconst usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@sammorrowdrums/mcpi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport { areExperimentalFeaturesEnabled } from \"../../../core/experimental.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { addUsageToTotals, createUsageTotals } from \"../../../core/usage-totals.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for compact footer display.\n */\nexport function formatTokens(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate autoCompactEnabled = true;\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// Calculate cumulative usage from ALL session entries (not just post-compaction messages)\n\t\tconst usageTotals = createUsageTotals();\n\t\tlet latestCacheHitRate: number | undefined;\n\n\t\tfor (const entry of this.session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\n\t\t\t\tconst latestPromptTokens =\n\t\t\t\t\tentry.message.usage.input + entry.message.usage.cacheRead + entry.message.usage.cacheWrite;\n\t\t\t\tlatestCacheHitRate =\n\t\t\t\t\tlatestPromptTokens > 0 ? (entry.message.usage.cacheRead / latestPromptTokens) * 100 : undefined;\n\t\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.message.usage);\n\t\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\t\taddUsageToTotals(usageTotals, entry.usage);\n\t\t\t}\n\t\t}\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\n\t\t// Replace home directory with ~\n\t\tlet pwd = formatCwdForFooter(this.session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\n\t\t// Add git branch if available\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tpwd = `${pwd} (${branch})`;\n\t\t}\n\n\t\t// Add session name if set\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tpwd = `${pwd} • ${sessionName}`;\n\t\t}\n\n\t\t// Build stats line\n\t\tconst statsParts = [];\n\t\tif (usageTotals.input) statsParts.push(`↑${formatTokens(usageTotals.input)}`);\n\t\tif (usageTotals.output) statsParts.push(`↓${formatTokens(usageTotals.output)}`);\n\t\tif (usageTotals.cacheRead) statsParts.push(`R${formatTokens(usageTotals.cacheRead)}`);\n\t\tif (usageTotals.cacheWrite) statsParts.push(`W${formatTokens(usageTotals.cacheWrite)}`);\n\t\tif ((usageTotals.cacheRead > 0 || usageTotals.cacheWrite > 0) && latestCacheHitRate !== undefined) {\n\t\t\tstatsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.session.modelRuntime.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (usageTotals.cost || usingSubscription) {\n\t\t\tconst costStr = `$${usageTotals.cost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tstatsParts.push(costStr);\n\t\t}\n\n\t\t// Colorize context percentage based on usage\n\t\tlet contextPercentStr: string;\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst contextPercentDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `?/${formatTokens(contextWindow)}${autoIndicator}`\n\t\t\t\t: `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;\n\t\tif (contextPercentValue > 90) {\n\t\t\tcontextPercentStr = theme.fg(\"error\", contextPercentDisplay);\n\t\t} else if (contextPercentValue > 70) {\n\t\t\tcontextPercentStr = theme.fg(\"warning\", contextPercentDisplay);\n\t\t} else {\n\t\t\tcontextPercentStr = contextPercentDisplay;\n\t\t}\n\t\tstatsParts.push(contextPercentStr);\n\t\tif (areExperimentalFeaturesEnabled()) {\n\t\t\tstatsParts.push(`${theme.fg(\"dim\", \"•\")} ${theme.bold(theme.fg(\"warning\", \"xp\"))}`);\n\t\t}\n\n\t\tlet statsLeft = statsParts.join(\" \");\n\n\t\t// Add model name on the right side, plus thinking level if model supports it\n\t\tconst modelName = state.model?.id || \"no-model\";\n\n\t\tlet statsLeftWidth = visibleWidth(statsLeft);\n\n\t\t// If statsLeft is too wide, truncate it\n\t\tif (statsLeftWidth > width) {\n\t\t\tstatsLeft = truncateToWidth(statsLeft, width, \"...\");\n\t\t\tstatsLeftWidth = visibleWidth(statsLeft);\n\t\t}\n\n\t\t// Calculate available space for padding (minimum 2 spaces between stats and model)\n\t\tconst minPadding = 2;\n\n\t\t// Add thinking level indicator if model supports reasoning\n\t\tlet rightSideWithoutProvider = modelName;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\trightSideWithoutProvider =\n\t\t\t\tthinkingLevel === \"off\" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;\n\t\t}\n\n\t\t// Prepend the provider in parentheses if there are multiple providers and there's enough room\n\t\tlet rightSide = rightSideWithoutProvider;\n\t\tif (this.footerData.getAvailableProviderCount() > 1 && state.model) {\n\t\t\trightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;\n\t\t\tif (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {\n\t\t\t\t// Too wide, fall back\n\t\t\t\trightSide = rightSideWithoutProvider;\n\t\t\t}\n\t\t}\n\n\t\tconst rightSideWidth = visibleWidth(rightSide);\n\t\tconst totalNeeded = statsLeftWidth + minPadding + rightSideWidth;\n\n\t\tlet statsLine: string;\n\t\tif (totalNeeded <= width) {\n\t\t\t// Both fit - add padding to right-align model\n\t\t\tconst padding = \" \".repeat(width - statsLeftWidth - rightSideWidth);\n\t\t\tstatsLine = statsLeft + padding + rightSide;\n\t\t} else {\n\t\t\t// Need to truncate right side\n\t\t\tconst availableForRight = width - statsLeftWidth - minPadding;\n\t\t\tif (availableForRight > 0) {\n\t\t\t\tconst truncatedRight = truncateToWidth(rightSide, availableForRight, \"\");\n\t\t\t\tconst truncatedRightWidth = visibleWidth(truncatedRight);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));\n\t\t\t\tstatsLine = statsLeft + padding + truncatedRight;\n\t\t\t} else {\n\t\t\t\t// Not enough space for right side at all\n\t\t\t\tstatsLine = statsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Apply dim to each part separately. statsLeft may contain color codes (for context %)\n\t\t// that end with a reset, which would clear an outer dim wrapper. So we dim the parts\n\t\t// before and after the colored section independently.\n\t\tconst dimStatsLeft = theme.fg(\"dim\", statsLeft);\n\t\tconst remainder = statsLine.slice(statsLeft.length); // padding + rightSide\n\t\tconst dimRemainder = theme.fg(\"dim\", remainder);\n\n\t\tconst pwdLine = truncateToWidth(theme.fg(\"dim\", pwd), width, theme.fg(\"dim\", \"...\"));\n\t\tconst lines = [pwdLine, dimStatsLeft + dimRemainder];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}