@openeryc/pi-coding-agent 0.75.26 → 0.75.28

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 (313) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cli/config-selector.d.ts +1 -13
  3. package/dist/cli/config-selector.d.ts.map +1 -1
  4. package/dist/cli/config-selector.js +4 -29
  5. package/dist/cli/config-selector.js.map +1 -1
  6. package/dist/cli/list-models.d.ts.map +1 -1
  7. package/dist/cli/list-models.js +1 -1
  8. package/dist/cli/list-models.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +0 -2
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +12 -20
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  14. package/dist/core/export-html/tool-renderer.js.map +1 -1
  15. package/dist/core/extensions/loader.d.ts.map +1 -1
  16. package/dist/core/extensions/loader.js +1 -1
  17. package/dist/core/extensions/loader.js.map +1 -1
  18. package/dist/core/extensions/runner.d.ts +1 -1
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +1 -1
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +1 -1
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/keybindings.d.ts +7 -135
  26. package/dist/core/keybindings.d.ts.map +1 -1
  27. package/dist/core/keybindings.js +1 -1
  28. package/dist/core/keybindings.js.map +1 -1
  29. package/dist/core/mcp/client.d.ts +30 -11
  30. package/dist/core/mcp/client.d.ts.map +1 -1
  31. package/dist/core/mcp/client.js +55 -110
  32. package/dist/core/mcp/client.js.map +1 -1
  33. package/dist/core/mcp/index.d.ts +1 -3
  34. package/dist/core/mcp/index.d.ts.map +1 -1
  35. package/dist/core/mcp/index.js.map +1 -1
  36. package/dist/core/mcp/manager.d.ts +3 -9
  37. package/dist/core/mcp/manager.d.ts.map +1 -1
  38. package/dist/core/mcp/manager.js +71 -105
  39. package/dist/core/mcp/manager.js.map +1 -1
  40. package/dist/core/tools/bash.d.ts.map +1 -1
  41. package/dist/core/tools/bash.js +1 -1
  42. package/dist/core/tools/bash.js.map +1 -1
  43. package/dist/core/tools/edit.d.ts +1 -1
  44. package/dist/core/tools/edit.d.ts.map +1 -1
  45. package/dist/core/tools/edit.js +1 -1
  46. package/dist/core/tools/edit.js.map +1 -1
  47. package/dist/core/tools/find.d.ts.map +1 -1
  48. package/dist/core/tools/find.js +1 -1
  49. package/dist/core/tools/find.js.map +1 -1
  50. package/dist/core/tools/grep.d.ts.map +1 -1
  51. package/dist/core/tools/grep.js +1 -1
  52. package/dist/core/tools/grep.js.map +1 -1
  53. package/dist/core/tools/index.d.ts +3 -1
  54. package/dist/core/tools/index.d.ts.map +1 -1
  55. package/dist/core/tools/index.js +27 -1
  56. package/dist/core/tools/index.js.map +1 -1
  57. package/dist/core/tools/ls.d.ts.map +1 -1
  58. package/dist/core/tools/ls.js +1 -1
  59. package/dist/core/tools/ls.js.map +1 -1
  60. package/dist/core/tools/read.d.ts.map +1 -1
  61. package/dist/core/tools/read.js +1 -1
  62. package/dist/core/tools/read.js.map +1 -1
  63. package/dist/core/tools/render-utils.d.ts.map +1 -1
  64. package/dist/core/tools/render-utils.js +1 -1
  65. package/dist/core/tools/render-utils.js.map +1 -1
  66. package/dist/core/tools/web-fetch.d.ts +15 -0
  67. package/dist/core/tools/web-fetch.d.ts.map +1 -0
  68. package/dist/core/tools/web-fetch.js +52 -0
  69. package/dist/core/tools/web-fetch.js.map +1 -0
  70. package/dist/core/tools/web-search.d.ts +18 -0
  71. package/dist/core/tools/web-search.d.ts.map +1 -0
  72. package/dist/core/tools/web-search.js +83 -0
  73. package/dist/core/tools/web-search.js.map +1 -0
  74. package/dist/core/tools/write.d.ts.map +1 -1
  75. package/dist/core/tools/write.js +1 -1
  76. package/dist/core/tools/write.js.map +1 -1
  77. package/dist/core/tui-stubs.d.ts +95 -0
  78. package/dist/core/tui-stubs.d.ts.map +1 -0
  79. package/dist/core/tui-stubs.js +90 -0
  80. package/dist/core/tui-stubs.js.map +1 -0
  81. package/dist/index.d.ts +5 -3
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +7 -5
  84. package/dist/index.js.map +1 -1
  85. package/dist/main.d.ts.map +1 -1
  86. package/dist/main.js +92 -106
  87. package/dist/main.js.map +1 -1
  88. package/dist/modes/index.d.ts +0 -4
  89. package/dist/modes/index.d.ts.map +1 -1
  90. package/dist/modes/index.js +0 -4
  91. package/dist/modes/index.js.map +1 -1
  92. package/dist/modes/interactive/components/diff.d.ts +1 -8
  93. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  94. package/dist/modes/interactive/components/diff.js +2 -131
  95. package/dist/modes/interactive/components/diff.js.map +1 -1
  96. package/dist/modes/interactive/components/keybinding-hints.d.ts +2 -12
  97. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  98. package/dist/modes/interactive/components/keybinding-hints.js +4 -33
  99. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  100. package/dist/modes/interactive/components/visual-truncate.d.ts +1 -19
  101. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  102. package/dist/modes/interactive/components/visual-truncate.js +4 -31
  103. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  104. package/dist/modes/interactive/theme/theme.d.ts +27 -89
  105. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  106. package/dist/modes/interactive/theme/theme.js +44 -992
  107. package/dist/modes/interactive/theme/theme.js.map +1 -1
  108. package/dist/package-manager-cli.d.ts.map +1 -1
  109. package/dist/package-manager-cli.js +1 -1
  110. package/dist/package-manager-cli.js.map +1 -1
  111. package/npm-shrinkwrap.json +240 -246
  112. package/package.json +6 -7
  113. package/dist/cli/session-picker.d.ts +0 -9
  114. package/dist/cli/session-picker.d.ts.map +0 -1
  115. package/dist/cli/session-picker.js +0 -35
  116. package/dist/cli/session-picker.js.map +0 -1
  117. package/dist/core/mcp/types.d.ts +0 -86
  118. package/dist/core/mcp/types.d.ts.map +0 -1
  119. package/dist/core/mcp/types.js +0 -8
  120. package/dist/core/mcp/types.js.map +0 -1
  121. package/dist/modes/interactive/assets/clankolas.png +0 -0
  122. package/dist/modes/interactive/components/armin.d.ts +0 -34
  123. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  124. package/dist/modes/interactive/components/armin.js +0 -333
  125. package/dist/modes/interactive/components/armin.js.map +0 -1
  126. package/dist/modes/interactive/components/assistant-message.d.ts +0 -20
  127. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  128. package/dist/modes/interactive/components/assistant-message.js +0 -121
  129. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  130. package/dist/modes/interactive/components/bash-execution.d.ts +0 -34
  131. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  132. package/dist/modes/interactive/components/bash-execution.js +0 -175
  133. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  134. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
  135. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  136. package/dist/modes/interactive/components/bordered-loader.js +0 -54
  137. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  138. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
  139. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  140. package/dist/modes/interactive/components/branch-summary-message.js +0 -44
  141. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  142. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
  143. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  144. package/dist/modes/interactive/components/compaction-summary-message.js +0 -45
  145. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  146. package/dist/modes/interactive/components/config-selector.d.ts +0 -71
  147. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  148. package/dist/modes/interactive/components/config-selector.js +0 -506
  149. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  150. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
  151. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  152. package/dist/modes/interactive/components/countdown-timer.js +0 -33
  153. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  154. package/dist/modes/interactive/components/custom-editor.d.ts +0 -21
  155. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  156. package/dist/modes/interactive/components/custom-editor.js +0 -70
  157. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  158. package/dist/modes/interactive/components/custom-message.d.ts +0 -20
  159. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  160. package/dist/modes/interactive/components/custom-message.js +0 -79
  161. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  162. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  163. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  164. package/dist/modes/interactive/components/daxnuts.js +0 -140
  165. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  166. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
  167. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  168. package/dist/modes/interactive/components/dynamic-border.js +0 -21
  169. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  170. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
  171. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  172. package/dist/modes/interactive/components/earendil-announcement.js +0 -40
  173. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  174. package/dist/modes/interactive/components/extension-editor.d.ts +0 -20
  175. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  176. package/dist/modes/interactive/components/extension-editor.js +0 -119
  177. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  178. package/dist/modes/interactive/components/extension-input.d.ts +0 -23
  179. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  180. package/dist/modes/interactive/components/extension-input.js +0 -61
  181. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  182. package/dist/modes/interactive/components/extension-selector.d.ts +0 -26
  183. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  184. package/dist/modes/interactive/components/extension-selector.js +0 -83
  185. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  186. package/dist/modes/interactive/components/footer.d.ts +0 -27
  187. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  188. package/dist/modes/interactive/components/footer.js +0 -201
  189. package/dist/modes/interactive/components/footer.js.map +0 -1
  190. package/dist/modes/interactive/components/index.d.ts +0 -32
  191. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  192. package/dist/modes/interactive/components/index.js +0 -33
  193. package/dist/modes/interactive/components/index.js.map +0 -1
  194. package/dist/modes/interactive/components/login-dialog.d.ts +0 -46
  195. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  196. package/dist/modes/interactive/components/login-dialog.js +0 -160
  197. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  198. package/dist/modes/interactive/components/model-selector.d.ts +0 -47
  199. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  200. package/dist/modes/interactive/components/model-selector.js +0 -278
  201. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  202. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -31
  203. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  204. package/dist/modes/interactive/components/oauth-selector.js +0 -165
  205. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  206. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -42
  207. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  208. package/dist/modes/interactive/components/scoped-models-selector.js +0 -290
  209. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  210. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
  211. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  212. package/dist/modes/interactive/components/session-selector-search.js +0 -155
  213. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  214. package/dist/modes/interactive/components/session-selector.d.ts +0 -96
  215. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  216. package/dist/modes/interactive/components/session-selector.js +0 -861
  217. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  218. package/dist/modes/interactive/components/settings-selector.d.ts +0 -69
  219. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  220. package/dist/modes/interactive/components/settings-selector.js +0 -390
  221. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  222. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
  223. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  224. package/dist/modes/interactive/components/show-images-selector.js +0 -39
  225. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  226. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
  227. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  228. package/dist/modes/interactive/components/skill-invocation-message.js +0 -47
  229. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  230. package/dist/modes/interactive/components/theme-selector.d.ts +0 -11
  231. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  232. package/dist/modes/interactive/components/theme-selector.js +0 -50
  233. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  234. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
  235. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  236. package/dist/modes/interactive/components/thinking-selector.js +0 -51
  237. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  238. package/dist/modes/interactive/components/tool-execution.d.ts +0 -63
  239. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  240. package/dist/modes/interactive/components/tool-execution.js +0 -295
  241. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  242. package/dist/modes/interactive/components/tree-selector.d.ts +0 -89
  243. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  244. package/dist/modes/interactive/components/tree-selector.js +0 -1093
  245. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  246. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
  247. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  248. package/dist/modes/interactive/components/user-message-selector.js +0 -114
  249. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  250. package/dist/modes/interactive/components/user-message.d.ts +0 -10
  251. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  252. package/dist/modes/interactive/components/user-message.js +0 -29
  253. package/dist/modes/interactive/components/user-message.js.map +0 -1
  254. package/dist/modes/interactive/interactive-mode.d.ts +0 -375
  255. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  256. package/dist/modes/interactive/interactive-mode.js +0 -4799
  257. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  258. package/dist/modes/interactive/theme/dark.json +0 -86
  259. package/dist/modes/interactive/theme/light.json +0 -85
  260. package/dist/modes/interactive/theme/theme-schema.json +0 -335
  261. package/examples/extensions/border-status-editor.ts +0 -150
  262. package/examples/extensions/built-in-tool-renderer.ts +0 -249
  263. package/examples/extensions/custom-footer.ts +0 -64
  264. package/examples/extensions/custom-header.ts +0 -73
  265. package/examples/extensions/custom-provider-anthropic/index.ts +0 -604
  266. package/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
  267. package/examples/extensions/custom-provider-anthropic/package.json +0 -19
  268. package/examples/extensions/custom-provider-gitlab-duo/index.ts +0 -349
  269. package/examples/extensions/custom-provider-gitlab-duo/package.json +0 -16
  270. package/examples/extensions/custom-provider-gitlab-duo/test.ts +0 -82
  271. package/examples/extensions/doom-overlay/README.md +0 -46
  272. package/examples/extensions/doom-overlay/doom/build/doom.js +0 -21
  273. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  274. package/examples/extensions/doom-overlay/doom/build.sh +0 -152
  275. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +0 -72
  276. package/examples/extensions/doom-overlay/doom-component.ts +0 -132
  277. package/examples/extensions/doom-overlay/doom-engine.ts +0 -173
  278. package/examples/extensions/doom-overlay/doom-keys.ts +0 -104
  279. package/examples/extensions/doom-overlay/index.ts +0 -74
  280. package/examples/extensions/doom-overlay/wad-finder.ts +0 -51
  281. package/examples/extensions/github-issue-autocomplete.ts +0 -185
  282. package/examples/extensions/handoff.ts +0 -191
  283. package/examples/extensions/interactive-shell.ts +0 -196
  284. package/examples/extensions/message-renderer.ts +0 -59
  285. package/examples/extensions/minimal-mode.ts +0 -426
  286. package/examples/extensions/modal-editor.ts +0 -85
  287. package/examples/extensions/overlay-qa-tests.ts +0 -1379
  288. package/examples/extensions/overlay-test.ts +0 -153
  289. package/examples/extensions/plan-mode/index.ts +0 -340
  290. package/examples/extensions/preset.ts +0 -430
  291. package/examples/extensions/qna.ts +0 -122
  292. package/examples/extensions/question.ts +0 -264
  293. package/examples/extensions/questionnaire.ts +0 -427
  294. package/examples/extensions/rainbow-editor.ts +0 -88
  295. package/examples/extensions/sandbox/index.ts +0 -321
  296. package/examples/extensions/sandbox/package-lock.json +0 -92
  297. package/examples/extensions/sandbox/package.json +0 -19
  298. package/examples/extensions/snake.ts +0 -343
  299. package/examples/extensions/space-invaders.ts +0 -560
  300. package/examples/extensions/ssh.ts +0 -220
  301. package/examples/extensions/status-line.ts +0 -32
  302. package/examples/extensions/structured-output.ts +0 -65
  303. package/examples/extensions/subagent/index.ts +0 -1009
  304. package/examples/extensions/summarize.ts +0 -206
  305. package/examples/extensions/tic-tac-toe.ts +0 -1008
  306. package/examples/extensions/todo.ts +0 -297
  307. package/examples/extensions/tools.ts +0 -141
  308. package/examples/extensions/truncated-tool.ts +0 -195
  309. package/examples/extensions/with-deps/index.ts +0 -32
  310. package/examples/extensions/with-deps/package-lock.json +0 -31
  311. package/examples/extensions/with-deps/package.json +0 -22
  312. package/examples/extensions/working-indicator.ts +0 -123
  313. package/examples/rpc-extension-ui.ts +0 -632
@@ -1,201 +0,0 @@
1
- import { truncateToWidth, visibleWidth } from "@openeryc/pi-tui";
2
- import { theme } from "../theme/theme.js";
3
- /**
4
- * Sanitize text for display in a single-line status.
5
- * Removes newlines, tabs, carriage returns, and other control characters.
6
- */
7
- function sanitizeStatusText(text) {
8
- // Replace newlines, tabs, carriage returns with space, then collapse multiple spaces
9
- return text
10
- .replace(/[\r\n\t]/g, " ")
11
- .replace(/ +/g, " ")
12
- .trim();
13
- }
14
- /**
15
- * Format token counts for compact footer display.
16
- */
17
- function formatTokens(count) {
18
- if (count < 1000)
19
- return count.toString();
20
- if (count < 10000)
21
- return `${(count / 1000).toFixed(1)}k`;
22
- if (count < 1000000)
23
- return `${Math.round(count / 1000)}k`;
24
- if (count < 10000000)
25
- return `${(count / 1000000).toFixed(1)}M`;
26
- return `${Math.round(count / 1000000)}M`;
27
- }
28
- /**
29
- * Footer component that shows pwd, token stats, and context usage.
30
- * Computes token/context stats from session, gets git branch and extension statuses from provider.
31
- */
32
- export class FooterComponent {
33
- autoCompactEnabled = true;
34
- session;
35
- footerData;
36
- constructor(session, footerData) {
37
- this.session = session;
38
- this.footerData = footerData;
39
- }
40
- setSession(session) {
41
- this.session = session;
42
- }
43
- setAutoCompactEnabled(enabled) {
44
- this.autoCompactEnabled = enabled;
45
- }
46
- /**
47
- * No-op: git branch caching now handled by provider.
48
- * Kept for compatibility with existing call sites in interactive-mode.
49
- */
50
- invalidate() {
51
- // No-op: git branch is cached/invalidated by provider
52
- }
53
- /**
54
- * Clean up resources.
55
- * Git watcher cleanup now handled by provider.
56
- */
57
- dispose() {
58
- // Git watcher cleanup handled by provider
59
- }
60
- render(width) {
61
- const state = this.session.state;
62
- // 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;
68
- for (const entry of this.session.sessionManager.getEntries()) {
69
- 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;
75
- }
76
- }
77
- // Calculate context usage from session (handles compaction correctly).
78
- // After compaction, tokens are unknown until the next LLM response.
79
- const contextUsage = this.session.getContextUsage();
80
- const contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;
81
- const contextPercentValue = contextUsage?.percent ?? 0;
82
- const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
83
- // 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
- }
89
- // Add git branch if available
90
- const branch = this.footerData.getGitBranch();
91
- if (branch) {
92
- pwd = `${pwd} (${branch})`;
93
- }
94
- // Add session name if set
95
- const sessionName = this.session.sessionManager.getSessionName();
96
- if (sessionName) {
97
- pwd = `${pwd} • ${sessionName}`;
98
- }
99
- // Build stats line
100
- 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)" : ""}`;
113
- statsParts.push(costStr);
114
- }
115
- // Colorize context percentage based on usage
116
- let contextPercentStr;
117
- const autoIndicator = this.autoCompactEnabled ? " (auto)" : "";
118
- const contextPercentDisplay = contextPercent === "?"
119
- ? `?/${formatTokens(contextWindow)}${autoIndicator}`
120
- : `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;
121
- if (contextPercentValue > 90) {
122
- contextPercentStr = theme.fg("error", contextPercentDisplay);
123
- }
124
- else if (contextPercentValue > 70) {
125
- contextPercentStr = theme.fg("warning", contextPercentDisplay);
126
- }
127
- else {
128
- contextPercentStr = contextPercentDisplay;
129
- }
130
- statsParts.push(contextPercentStr);
131
- let statsLeft = statsParts.join(" ");
132
- // Add model name on the right side, plus thinking level if model supports it
133
- const modelName = state.model?.id || "no-model";
134
- let statsLeftWidth = visibleWidth(statsLeft);
135
- // If statsLeft is too wide, truncate it
136
- if (statsLeftWidth > width) {
137
- statsLeft = truncateToWidth(statsLeft, width, "...");
138
- statsLeftWidth = visibleWidth(statsLeft);
139
- }
140
- // Calculate available space for padding (minimum 2 spaces between stats and model)
141
- const minPadding = 2;
142
- // Add thinking level indicator if model supports reasoning
143
- let rightSideWithoutProvider = modelName;
144
- if (state.model?.reasoning) {
145
- const thinkingLevel = state.thinkingLevel || "off";
146
- rightSideWithoutProvider =
147
- thinkingLevel === "off" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;
148
- }
149
- // Prepend the provider in parentheses if there are multiple providers and there's enough room
150
- let rightSide = rightSideWithoutProvider;
151
- if (this.footerData.getAvailableProviderCount() > 1 && state.model) {
152
- rightSide = `(${state.model.provider}) ${rightSideWithoutProvider}`;
153
- if (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {
154
- // Too wide, fall back
155
- rightSide = rightSideWithoutProvider;
156
- }
157
- }
158
- const rightSideWidth = visibleWidth(rightSide);
159
- const totalNeeded = statsLeftWidth + minPadding + rightSideWidth;
160
- let statsLine;
161
- if (totalNeeded <= width) {
162
- // Both fit - add padding to right-align model
163
- const padding = " ".repeat(width - statsLeftWidth - rightSideWidth);
164
- statsLine = statsLeft + padding + rightSide;
165
- }
166
- else {
167
- // Need to truncate right side
168
- const availableForRight = width - statsLeftWidth - minPadding;
169
- if (availableForRight > 0) {
170
- const truncatedRight = truncateToWidth(rightSide, availableForRight, "");
171
- const truncatedRightWidth = visibleWidth(truncatedRight);
172
- const padding = " ".repeat(Math.max(0, width - statsLeftWidth - truncatedRightWidth));
173
- statsLine = statsLeft + padding + truncatedRight;
174
- }
175
- else {
176
- // Not enough space for right side at all
177
- statsLine = statsLeft;
178
- }
179
- }
180
- // Apply dim to each part separately. statsLeft may contain color codes (for context %)
181
- // that end with a reset, which would clear an outer dim wrapper. So we dim the parts
182
- // before and after the colored section independently.
183
- const dimStatsLeft = theme.fg("dim", statsLeft);
184
- const remainder = statsLine.slice(statsLeft.length); // padding + rightSide
185
- const dimRemainder = theme.fg("dim", remainder);
186
- const pwdLine = truncateToWidth(theme.fg("dim", pwd), width, theme.fg("dim", "..."));
187
- const lines = [pwdLine, dimStatsLeft + dimRemainder];
188
- // Add extension statuses on a single line, sorted by key alphabetically
189
- const extensionStatuses = this.footerData.getExtensionStatuses();
190
- if (extensionStatuses.size > 0) {
191
- const sortedStatuses = Array.from(extensionStatuses.entries())
192
- .sort(([a], [b]) => a.localeCompare(b))
193
- .map(([, text]) => sanitizeStatusText(text));
194
- const statusLine = sortedStatuses.join(" ");
195
- // Truncate to terminal width with dim ellipsis for consistency with footer style
196
- lines.push(truncateToWidth(statusLine, width, theme.fg("dim", "...")));
197
- }
198
- return lines;
199
- }
200
- }
201
- //# sourceMappingURL=footer.js.map
@@ -1 +0,0 @@
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 \"@openeryc/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.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 */\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\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\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,32 +0,0 @@
1
- export { ArminComponent } from "./armin.ts";
2
- export { AssistantMessageComponent } from "./assistant-message.ts";
3
- export { BashExecutionComponent } from "./bash-execution.ts";
4
- export { BorderedLoader } from "./bordered-loader.ts";
5
- export { BranchSummaryMessageComponent } from "./branch-summary-message.ts";
6
- export { CompactionSummaryMessageComponent } from "./compaction-summary-message.ts";
7
- export { CustomEditor } from "./custom-editor.ts";
8
- export { CustomMessageComponent } from "./custom-message.ts";
9
- export { DaxnutsComponent } from "./daxnuts.ts";
10
- export { type RenderDiffOptions, renderDiff } from "./diff.ts";
11
- export { DynamicBorder } from "./dynamic-border.ts";
12
- export { ExtensionEditorComponent } from "./extension-editor.ts";
13
- export { ExtensionInputComponent } from "./extension-input.ts";
14
- export { ExtensionSelectorComponent } from "./extension-selector.ts";
15
- export { FooterComponent } from "./footer.ts";
16
- export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.ts";
17
- export { LoginDialogComponent } from "./login-dialog.ts";
18
- export { ModelSelectorComponent } from "./model-selector.ts";
19
- export { OAuthSelectorComponent } from "./oauth-selector.ts";
20
- export { type ModelsCallbacks, type ModelsConfig, ScopedModelsSelectorComponent } from "./scoped-models-selector.ts";
21
- export { SessionSelectorComponent } from "./session-selector.ts";
22
- export { type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent } from "./settings-selector.ts";
23
- export { ShowImagesSelectorComponent } from "./show-images-selector.ts";
24
- export { SkillInvocationMessageComponent } from "./skill-invocation-message.ts";
25
- export { ThemeSelectorComponent } from "./theme-selector.ts";
26
- export { ThinkingSelectorComponent } from "./thinking-selector.ts";
27
- export { ToolExecutionComponent, type ToolExecutionOptions } from "./tool-execution.ts";
28
- export { TreeSelectorComponent } from "./tree-selector.ts";
29
- export { UserMessageComponent } from "./user-message.ts";
30
- export { UserMessageSelectorComponent } from "./user-message-selector.ts";
31
- export { truncateToVisualLines, type VisualTruncateResult } from "./visual-truncate.ts";
32
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["// UI Components for extensions\nexport { ArminComponent } from \"./armin.ts\";\nexport { AssistantMessageComponent } from \"./assistant-message.ts\";\nexport { BashExecutionComponent } from \"./bash-execution.ts\";\nexport { BorderedLoader } from \"./bordered-loader.ts\";\nexport { BranchSummaryMessageComponent } from \"./branch-summary-message.ts\";\nexport { CompactionSummaryMessageComponent } from \"./compaction-summary-message.ts\";\nexport { CustomEditor } from \"./custom-editor.ts\";\nexport { CustomMessageComponent } from \"./custom-message.ts\";\nexport { DaxnutsComponent } from \"./daxnuts.ts\";\nexport { type RenderDiffOptions, renderDiff } from \"./diff.ts\";\nexport { DynamicBorder } from \"./dynamic-border.ts\";\nexport { ExtensionEditorComponent } from \"./extension-editor.ts\";\nexport { ExtensionInputComponent } from \"./extension-input.ts\";\nexport { ExtensionSelectorComponent } from \"./extension-selector.ts\";\nexport { FooterComponent } from \"./footer.ts\";\nexport { keyHint, keyText, rawKeyHint } from \"./keybinding-hints.ts\";\nexport { LoginDialogComponent } from \"./login-dialog.ts\";\nexport { ModelSelectorComponent } from \"./model-selector.ts\";\nexport { OAuthSelectorComponent } from \"./oauth-selector.ts\";\nexport { type ModelsCallbacks, type ModelsConfig, ScopedModelsSelectorComponent } from \"./scoped-models-selector.ts\";\nexport { SessionSelectorComponent } from \"./session-selector.ts\";\nexport { type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent } from \"./settings-selector.ts\";\nexport { ShowImagesSelectorComponent } from \"./show-images-selector.ts\";\nexport { SkillInvocationMessageComponent } from \"./skill-invocation-message.ts\";\nexport { ThemeSelectorComponent } from \"./theme-selector.ts\";\nexport { ThinkingSelectorComponent } from \"./thinking-selector.ts\";\nexport { ToolExecutionComponent, type ToolExecutionOptions } from \"./tool-execution.ts\";\nexport { TreeSelectorComponent } from \"./tree-selector.ts\";\nexport { UserMessageComponent } from \"./user-message.ts\";\nexport { UserMessageSelectorComponent } from \"./user-message-selector.ts\";\nexport { truncateToVisualLines, type VisualTruncateResult } from \"./visual-truncate.ts\";\n"]}
@@ -1,33 +0,0 @@
1
- // UI Components for extensions
2
- export { ArminComponent } from "./armin.js";
3
- export { AssistantMessageComponent } from "./assistant-message.js";
4
- export { BashExecutionComponent } from "./bash-execution.js";
5
- export { BorderedLoader } from "./bordered-loader.js";
6
- export { BranchSummaryMessageComponent } from "./branch-summary-message.js";
7
- export { CompactionSummaryMessageComponent } from "./compaction-summary-message.js";
8
- export { CustomEditor } from "./custom-editor.js";
9
- export { CustomMessageComponent } from "./custom-message.js";
10
- export { DaxnutsComponent } from "./daxnuts.js";
11
- export { renderDiff } from "./diff.js";
12
- export { DynamicBorder } from "./dynamic-border.js";
13
- export { ExtensionEditorComponent } from "./extension-editor.js";
14
- export { ExtensionInputComponent } from "./extension-input.js";
15
- export { ExtensionSelectorComponent } from "./extension-selector.js";
16
- export { FooterComponent } from "./footer.js";
17
- export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.js";
18
- export { LoginDialogComponent } from "./login-dialog.js";
19
- export { ModelSelectorComponent } from "./model-selector.js";
20
- export { OAuthSelectorComponent } from "./oauth-selector.js";
21
- export { ScopedModelsSelectorComponent } from "./scoped-models-selector.js";
22
- export { SessionSelectorComponent } from "./session-selector.js";
23
- export { SettingsSelectorComponent } from "./settings-selector.js";
24
- export { ShowImagesSelectorComponent } from "./show-images-selector.js";
25
- export { SkillInvocationMessageComponent } from "./skill-invocation-message.js";
26
- export { ThemeSelectorComponent } from "./theme-selector.js";
27
- export { ThinkingSelectorComponent } from "./thinking-selector.js";
28
- export { ToolExecutionComponent } from "./tool-execution.js";
29
- export { TreeSelectorComponent } from "./tree-selector.js";
30
- export { UserMessageComponent } from "./user-message.js";
31
- export { UserMessageSelectorComponent } from "./user-message-selector.js";
32
- export { truncateToVisualLines } from "./visual-truncate.js";
33
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/index.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAA0B,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAA2C,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACrH,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAA+C,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAA6B,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAA6B,MAAM,sBAAsB,CAAC","sourcesContent":["// UI Components for extensions\nexport { ArminComponent } from \"./armin.ts\";\nexport { AssistantMessageComponent } from \"./assistant-message.ts\";\nexport { BashExecutionComponent } from \"./bash-execution.ts\";\nexport { BorderedLoader } from \"./bordered-loader.ts\";\nexport { BranchSummaryMessageComponent } from \"./branch-summary-message.ts\";\nexport { CompactionSummaryMessageComponent } from \"./compaction-summary-message.ts\";\nexport { CustomEditor } from \"./custom-editor.ts\";\nexport { CustomMessageComponent } from \"./custom-message.ts\";\nexport { DaxnutsComponent } from \"./daxnuts.ts\";\nexport { type RenderDiffOptions, renderDiff } from \"./diff.ts\";\nexport { DynamicBorder } from \"./dynamic-border.ts\";\nexport { ExtensionEditorComponent } from \"./extension-editor.ts\";\nexport { ExtensionInputComponent } from \"./extension-input.ts\";\nexport { ExtensionSelectorComponent } from \"./extension-selector.ts\";\nexport { FooterComponent } from \"./footer.ts\";\nexport { keyHint, keyText, rawKeyHint } from \"./keybinding-hints.ts\";\nexport { LoginDialogComponent } from \"./login-dialog.ts\";\nexport { ModelSelectorComponent } from \"./model-selector.ts\";\nexport { OAuthSelectorComponent } from \"./oauth-selector.ts\";\nexport { type ModelsCallbacks, type ModelsConfig, ScopedModelsSelectorComponent } from \"./scoped-models-selector.ts\";\nexport { SessionSelectorComponent } from \"./session-selector.ts\";\nexport { type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent } from \"./settings-selector.ts\";\nexport { ShowImagesSelectorComponent } from \"./show-images-selector.ts\";\nexport { SkillInvocationMessageComponent } from \"./skill-invocation-message.ts\";\nexport { ThemeSelectorComponent } from \"./theme-selector.ts\";\nexport { ThinkingSelectorComponent } from \"./thinking-selector.ts\";\nexport { ToolExecutionComponent, type ToolExecutionOptions } from \"./tool-execution.ts\";\nexport { TreeSelectorComponent } from \"./tree-selector.ts\";\nexport { UserMessageComponent } from \"./user-message.ts\";\nexport { UserMessageSelectorComponent } from \"./user-message-selector.ts\";\nexport { truncateToVisualLines, type VisualTruncateResult } from \"./visual-truncate.ts\";\n"]}
@@ -1,46 +0,0 @@
1
- import { Container, type Focusable, type TUI } from "@openeryc/pi-tui";
2
- /**
3
- * Login dialog component - replaces editor during OAuth login flow
4
- */
5
- export declare class LoginDialogComponent extends Container implements Focusable {
6
- private contentContainer;
7
- private input;
8
- private tui;
9
- private abortController;
10
- private inputResolver?;
11
- private inputRejecter?;
12
- private onComplete;
13
- private _focused;
14
- get focused(): boolean;
15
- set focused(value: boolean);
16
- constructor(tui: TUI, providerId: string, onComplete: (success: boolean, message?: string) => void, providerNameOverride?: string, titleOverride?: string);
17
- get signal(): AbortSignal;
18
- private cancel;
19
- /**
20
- * Called by onAuth callback - show URL and optional instructions
21
- */
22
- showAuth(url: string, instructions?: string): void;
23
- /**
24
- * Show input for manual code/URL entry (for callback server providers)
25
- */
26
- showManualInput(prompt: string): Promise<string>;
27
- /**
28
- * Called by onPrompt callback - show prompt and wait for input
29
- * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)
30
- */
31
- showPrompt(message: string, placeholder?: string): Promise<string>;
32
- /**
33
- * Show informational text without prompting for input.
34
- */
35
- showInfo(lines: string[]): void;
36
- /**
37
- * Show waiting message (for polling flows like GitHub Copilot)
38
- */
39
- showWaiting(message: string): void;
40
- /**
41
- * Called by onProgress callback
42
- */
43
- showProgress(message: string): void;
44
- handleInput(data: string): void;
45
- }
46
- //# sourceMappingURL=login-dialog.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"login-dialog.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/login-dialog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAuC,KAAK,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAM5G;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,SAAU,YAAW,SAAS;IACvE,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,aAAa,CAAC,CAA0B;IAChD,OAAO,CAAC,aAAa,CAAC,CAAyB;IAC/C,OAAO,CAAC,UAAU,CAA+C;IAGjE,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,YACC,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,EACxD,oBAAoB,CAAC,EAAE,MAAM,EAC7B,aAAa,CAAC,EAAE,MAAM,EAmCtB;IAED,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,OAAO,CAAC,MAAM;IAUd;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAoBjD;IAED;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW/C;IAED;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBjE;IAED;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAS9B;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKjC;IAED;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGlC;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAU9B;CACD","sourcesContent":["import { getOAuthProviders } from \"@openeryc/pi-ai/oauth\";\nimport { Container, type Focusable, getKeybindings, Input, Spacer, Text, type TUI } from \"@openeryc/pi-tui\";\nimport { exec } from \"child_process\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\n/**\n * Login dialog component - replaces editor during OAuth login flow\n */\nexport class LoginDialogComponent extends Container implements Focusable {\n\tprivate contentContainer: Container;\n\tprivate input: Input;\n\tprivate tui: TUI;\n\tprivate abortController = new AbortController();\n\tprivate inputResolver?: (value: string) => void;\n\tprivate inputRejecter?: (error: Error) => void;\n\tprivate onComplete: (success: boolean, message?: string) => void;\n\n\t// Focusable implementation - propagate to input for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tproviderId: string,\n\t\tonComplete: (success: boolean, message?: string) => void,\n\t\tproviderNameOverride?: string,\n\t\ttitleOverride?: string,\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.onComplete = onComplete;\n\n\t\tconst providerInfo = getOAuthProviders().find((p) => p.id === providerId);\n\t\tconst providerName = providerNameOverride || providerInfo?.name || providerId;\n\t\tconst title = titleOverride ?? `Login to ${providerName}`;\n\n\t\t// Top border\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\n\t\t// Dynamic content area\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Input (always present, used when needed)\n\t\tthis.input = new Input();\n\t\tthis.input.onSubmit = () => {\n\t\t\tif (this.inputResolver) {\n\t\t\t\tthis.inputResolver(this.input.getValue());\n\t\t\t\tthis.inputResolver = undefined;\n\t\t\t\tthis.inputRejecter = undefined;\n\t\t\t}\n\t\t};\n\t\tthis.input.onEscape = () => {\n\t\t\tthis.cancel();\n\t\t};\n\n\t\t// Bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.abortController.signal;\n\t}\n\n\tprivate cancel(): void {\n\t\tthis.abortController.abort();\n\t\tif (this.inputRejecter) {\n\t\t\tthis.inputRejecter(new Error(\"Login cancelled\"));\n\t\t\tthis.inputResolver = undefined;\n\t\t\tthis.inputRejecter = undefined;\n\t\t}\n\t\tthis.onComplete(false, \"Login cancelled\");\n\t}\n\n\t/**\n\t * Called by onAuth callback - show URL and optional instructions\n\t */\n\tshowAuth(url: string, instructions?: string): void {\n\t\tthis.contentContainer.clear();\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tconst linkedUrl = `\\x1b]8;;${url}\\x07${url}\\x1b]8;;\\x07`;\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"accent\", linkedUrl), 1, 0));\n\n\t\tconst clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n\t\tconst hyperlink = `\\x1b]8;;${url}\\x07${clickHint}\\x1b]8;;\\x07`;\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", hyperlink), 1, 0));\n\n\t\tif (instructions) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"warning\", instructions), 1, 0));\n\t\t}\n\n\t\t// Try to open browser\n\t\tconst openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n\t\texec(`${openCmd} \"${url}\"`);\n\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Show input for manual code/URL entry (for callback server providers)\n\t */\n\tshowManualInput(prompt: string): Promise<string> {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", prompt), 1, 0));\n\t\tthis.contentContainer.addChild(this.input);\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.inputResolver = resolve;\n\t\t\tthis.inputRejecter = reject;\n\t\t});\n\t}\n\n\t/**\n\t * Called by onPrompt callback - show prompt and wait for input\n\t * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)\n\t */\n\tshowPrompt(message: string, placeholder?: string): Promise<string> {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"text\", message), 1, 0));\n\t\tif (placeholder) {\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", `e.g., ${placeholder}`), 1, 0));\n\t\t}\n\t\tthis.contentContainer.addChild(this.input);\n\t\tthis.contentContainer.addChild(\n\t\t\tnew Text(\n\t\t\t\t`(${keyHint(\"tui.select.cancel\", \"to cancel,\")} ${keyHint(\"tui.select.confirm\", \"to submit\")})`,\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\tthis.input.setValue(\"\");\n\t\tthis.tui.requestRender();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.inputResolver = resolve;\n\t\t\tthis.inputRejecter = reject;\n\t\t});\n\t}\n\n\t/**\n\t * Show informational text without prompting for input.\n\t */\n\tshowInfo(lines: string[]): void {\n\t\tthis.contentContainer.clear();\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tfor (const line of lines) {\n\t\t\tthis.contentContainer.addChild(new Text(line, 1, 0));\n\t\t}\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to close\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Show waiting message (for polling flows like GitHub Copilot)\n\t */\n\tshowWaiting(message: string): void {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Called by onProgress callback\n\t */\n\tshowProgress(message: string): void {\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.cancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass to input\n\t\tthis.input.handleInput(data);\n\t}\n}\n"]}
@@ -1,160 +0,0 @@
1
- import { getOAuthProviders } from "@openeryc/pi-ai/oauth";
2
- import { Container, getKeybindings, Input, Spacer, Text } from "@openeryc/pi-tui";
3
- import { exec } from "child_process";
4
- import { theme } from "../theme/theme.js";
5
- import { DynamicBorder } from "./dynamic-border.js";
6
- import { keyHint } from "./keybinding-hints.js";
7
- /**
8
- * Login dialog component - replaces editor during OAuth login flow
9
- */
10
- export class LoginDialogComponent extends Container {
11
- contentContainer;
12
- input;
13
- tui;
14
- abortController = new AbortController();
15
- inputResolver;
16
- inputRejecter;
17
- onComplete;
18
- // Focusable implementation - propagate to input for IME cursor positioning
19
- _focused = false;
20
- get focused() {
21
- return this._focused;
22
- }
23
- set focused(value) {
24
- this._focused = value;
25
- this.input.focused = value;
26
- }
27
- constructor(tui, providerId, onComplete, providerNameOverride, titleOverride) {
28
- super();
29
- this.tui = tui;
30
- this.onComplete = onComplete;
31
- const providerInfo = getOAuthProviders().find((p) => p.id === providerId);
32
- const providerName = providerNameOverride || providerInfo?.name || providerId;
33
- const title = titleOverride ?? `Login to ${providerName}`;
34
- // Top border
35
- this.addChild(new DynamicBorder());
36
- // Title
37
- this.addChild(new Text(theme.fg("accent", theme.bold(title)), 1, 0));
38
- // Dynamic content area
39
- this.contentContainer = new Container();
40
- this.addChild(this.contentContainer);
41
- // Input (always present, used when needed)
42
- this.input = new Input();
43
- this.input.onSubmit = () => {
44
- if (this.inputResolver) {
45
- this.inputResolver(this.input.getValue());
46
- this.inputResolver = undefined;
47
- this.inputRejecter = undefined;
48
- }
49
- };
50
- this.input.onEscape = () => {
51
- this.cancel();
52
- };
53
- // Bottom border
54
- this.addChild(new DynamicBorder());
55
- }
56
- get signal() {
57
- return this.abortController.signal;
58
- }
59
- cancel() {
60
- this.abortController.abort();
61
- if (this.inputRejecter) {
62
- this.inputRejecter(new Error("Login cancelled"));
63
- this.inputResolver = undefined;
64
- this.inputRejecter = undefined;
65
- }
66
- this.onComplete(false, "Login cancelled");
67
- }
68
- /**
69
- * Called by onAuth callback - show URL and optional instructions
70
- */
71
- showAuth(url, instructions) {
72
- this.contentContainer.clear();
73
- this.contentContainer.addChild(new Spacer(1));
74
- const linkedUrl = `\x1b]8;;${url}\x07${url}\x1b]8;;\x07`;
75
- this.contentContainer.addChild(new Text(theme.fg("accent", linkedUrl), 1, 0));
76
- const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
77
- const hyperlink = `\x1b]8;;${url}\x07${clickHint}\x1b]8;;\x07`;
78
- this.contentContainer.addChild(new Text(theme.fg("dim", hyperlink), 1, 0));
79
- if (instructions) {
80
- this.contentContainer.addChild(new Spacer(1));
81
- this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));
82
- }
83
- // Try to open browser
84
- const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
85
- exec(`${openCmd} "${url}"`);
86
- this.tui.requestRender();
87
- }
88
- /**
89
- * Show input for manual code/URL entry (for callback server providers)
90
- */
91
- showManualInput(prompt) {
92
- this.contentContainer.addChild(new Spacer(1));
93
- this.contentContainer.addChild(new Text(theme.fg("dim", prompt), 1, 0));
94
- this.contentContainer.addChild(this.input);
95
- this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel")})`, 1, 0));
96
- this.tui.requestRender();
97
- return new Promise((resolve, reject) => {
98
- this.inputResolver = resolve;
99
- this.inputRejecter = reject;
100
- });
101
- }
102
- /**
103
- * Called by onPrompt callback - show prompt and wait for input
104
- * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)
105
- */
106
- showPrompt(message, placeholder) {
107
- this.contentContainer.addChild(new Spacer(1));
108
- this.contentContainer.addChild(new Text(theme.fg("text", message), 1, 0));
109
- if (placeholder) {
110
- this.contentContainer.addChild(new Text(theme.fg("dim", `e.g., ${placeholder}`), 1, 0));
111
- }
112
- this.contentContainer.addChild(this.input);
113
- this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel,")} ${keyHint("tui.select.confirm", "to submit")})`, 1, 0));
114
- this.input.setValue("");
115
- this.tui.requestRender();
116
- return new Promise((resolve, reject) => {
117
- this.inputResolver = resolve;
118
- this.inputRejecter = reject;
119
- });
120
- }
121
- /**
122
- * Show informational text without prompting for input.
123
- */
124
- showInfo(lines) {
125
- this.contentContainer.clear();
126
- this.contentContainer.addChild(new Spacer(1));
127
- for (const line of lines) {
128
- this.contentContainer.addChild(new Text(line, 1, 0));
129
- }
130
- this.contentContainer.addChild(new Spacer(1));
131
- this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to close")})`, 1, 0));
132
- this.tui.requestRender();
133
- }
134
- /**
135
- * Show waiting message (for polling flows like GitHub Copilot)
136
- */
137
- showWaiting(message) {
138
- this.contentContainer.addChild(new Spacer(1));
139
- this.contentContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
140
- this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel")})`, 1, 0));
141
- this.tui.requestRender();
142
- }
143
- /**
144
- * Called by onProgress callback
145
- */
146
- showProgress(message) {
147
- this.contentContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
148
- this.tui.requestRender();
149
- }
150
- handleInput(data) {
151
- const kb = getKeybindings();
152
- if (kb.matches(data, "tui.select.cancel")) {
153
- this.cancel();
154
- return;
155
- }
156
- // Pass to input
157
- this.input.handleInput(data);
158
- }
159
- }
160
- //# sourceMappingURL=login-dialog.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"login-dialog.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/login-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["import { getOAuthProviders } from \"@openeryc/pi-ai/oauth\";\nimport { Container, type Focusable, getKeybindings, Input, Spacer, Text, type TUI } from \"@openeryc/pi-tui\";\nimport { exec } from \"child_process\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint } from \"./keybinding-hints.ts\";\n\n/**\n * Login dialog component - replaces editor during OAuth login flow\n */\nexport class LoginDialogComponent extends Container implements Focusable {\n\tprivate contentContainer: Container;\n\tprivate input: Input;\n\tprivate tui: TUI;\n\tprivate abortController = new AbortController();\n\tprivate inputResolver?: (value: string) => void;\n\tprivate inputRejecter?: (error: Error) => void;\n\tprivate onComplete: (success: boolean, message?: string) => void;\n\n\t// Focusable implementation - propagate to input for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tproviderId: string,\n\t\tonComplete: (success: boolean, message?: string) => void,\n\t\tproviderNameOverride?: string,\n\t\ttitleOverride?: string,\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.onComplete = onComplete;\n\n\t\tconst providerInfo = getOAuthProviders().find((p) => p.id === providerId);\n\t\tconst providerName = providerNameOverride || providerInfo?.name || providerId;\n\t\tconst title = titleOverride ?? `Login to ${providerName}`;\n\n\t\t// Top border\n\t\tthis.addChild(new DynamicBorder());\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\n\t\t// Dynamic content area\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Input (always present, used when needed)\n\t\tthis.input = new Input();\n\t\tthis.input.onSubmit = () => {\n\t\t\tif (this.inputResolver) {\n\t\t\t\tthis.inputResolver(this.input.getValue());\n\t\t\t\tthis.inputResolver = undefined;\n\t\t\t\tthis.inputRejecter = undefined;\n\t\t\t}\n\t\t};\n\t\tthis.input.onEscape = () => {\n\t\t\tthis.cancel();\n\t\t};\n\n\t\t// Bottom border\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.abortController.signal;\n\t}\n\n\tprivate cancel(): void {\n\t\tthis.abortController.abort();\n\t\tif (this.inputRejecter) {\n\t\t\tthis.inputRejecter(new Error(\"Login cancelled\"));\n\t\t\tthis.inputResolver = undefined;\n\t\t\tthis.inputRejecter = undefined;\n\t\t}\n\t\tthis.onComplete(false, \"Login cancelled\");\n\t}\n\n\t/**\n\t * Called by onAuth callback - show URL and optional instructions\n\t */\n\tshowAuth(url: string, instructions?: string): void {\n\t\tthis.contentContainer.clear();\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tconst linkedUrl = `\\x1b]8;;${url}\\x07${url}\\x1b]8;;\\x07`;\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"accent\", linkedUrl), 1, 0));\n\n\t\tconst clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n\t\tconst hyperlink = `\\x1b]8;;${url}\\x07${clickHint}\\x1b]8;;\\x07`;\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", hyperlink), 1, 0));\n\n\t\tif (instructions) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"warning\", instructions), 1, 0));\n\t\t}\n\n\t\t// Try to open browser\n\t\tconst openCmd = process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n\t\texec(`${openCmd} \"${url}\"`);\n\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Show input for manual code/URL entry (for callback server providers)\n\t */\n\tshowManualInput(prompt: string): Promise<string> {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", prompt), 1, 0));\n\t\tthis.contentContainer.addChild(this.input);\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.inputResolver = resolve;\n\t\t\tthis.inputRejecter = reject;\n\t\t});\n\t}\n\n\t/**\n\t * Called by onPrompt callback - show prompt and wait for input\n\t * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)\n\t */\n\tshowPrompt(message: string, placeholder?: string): Promise<string> {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"text\", message), 1, 0));\n\t\tif (placeholder) {\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", `e.g., ${placeholder}`), 1, 0));\n\t\t}\n\t\tthis.contentContainer.addChild(this.input);\n\t\tthis.contentContainer.addChild(\n\t\t\tnew Text(\n\t\t\t\t`(${keyHint(\"tui.select.cancel\", \"to cancel,\")} ${keyHint(\"tui.select.confirm\", \"to submit\")})`,\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\n\t\tthis.input.setValue(\"\");\n\t\tthis.tui.requestRender();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.inputResolver = resolve;\n\t\t\tthis.inputRejecter = reject;\n\t\t});\n\t}\n\n\t/**\n\t * Show informational text without prompting for input.\n\t */\n\tshowInfo(lines: string[]): void {\n\t\tthis.contentContainer.clear();\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tfor (const line of lines) {\n\t\t\tthis.contentContainer.addChild(new Text(line, 1, 0));\n\t\t}\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to close\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Show waiting message (for polling flows like GitHub Copilot)\n\t */\n\tshowWaiting(message: string): void {\n\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n\t\tthis.contentContainer.addChild(new Text(`(${keyHint(\"tui.select.cancel\", \"to cancel\")})`, 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Called by onProgress callback\n\t */\n\tshowProgress(message: string): void {\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", message), 1, 0));\n\t\tthis.tui.requestRender();\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.cancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass to input\n\t\tthis.input.handleInput(data);\n\t}\n}\n"]}
@@ -1,47 +0,0 @@
1
- import { type Model } from "@openeryc/pi-ai";
2
- import { Container, type Focusable, Input, type TUI } from "@openeryc/pi-tui";
3
- import type { ModelRegistry } from "../../../core/model-registry.ts";
4
- import type { SettingsManager } from "../../../core/settings-manager.ts";
5
- interface ScopedModelItem {
6
- model: Model<any>;
7
- thinkingLevel?: string;
8
- }
9
- /**
10
- * Component that renders a model selector with search
11
- */
12
- export declare class ModelSelectorComponent extends Container implements Focusable {
13
- private searchInput;
14
- private _focused;
15
- get focused(): boolean;
16
- set focused(value: boolean);
17
- private listContainer;
18
- private allModels;
19
- private scopedModelItems;
20
- private activeModels;
21
- private filteredModels;
22
- private selectedIndex;
23
- private currentModel?;
24
- private settingsManager;
25
- private modelRegistry;
26
- private onSelectCallback;
27
- private onCancelCallback;
28
- private errorMessage?;
29
- private tui;
30
- private scopedModels;
31
- private scope;
32
- private scopeText?;
33
- private scopeHintText?;
34
- constructor(tui: TUI, currentModel: Model<any> | undefined, settingsManager: SettingsManager, modelRegistry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, onSelect: (model: Model<any>) => void, onCancel: () => void, initialSearchInput?: string);
35
- private loadModels;
36
- private sortModels;
37
- private getScopeText;
38
- private getScopeHintText;
39
- private setScope;
40
- private filterModels;
41
- private updateList;
42
- handleInput(keyData: string): void;
43
- private handleSelect;
44
- getSearchInput(): Input;
45
- }
46
- export {};
47
- //# sourceMappingURL=model-selector.d.ts.map