indusagi-coding-agent 0.1.46 → 0.1.48

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 (452) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/command-line/args.js +1 -1
  3. package/dist/command-line/args.js.map +1 -1
  4. package/dist/command-line/login-handler.d.ts.map +1 -1
  5. package/dist/command-line/login-handler.js +3 -1
  6. package/dist/command-line/login-handler.js.map +1 -1
  7. package/dist/command-line/session-picker.d.ts.map +1 -1
  8. package/dist/command-line/session-picker.js +26 -48
  9. package/dist/command-line/session-picker.js.map +1 -1
  10. package/dist/config.js +1 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/helpers/open-auth-url.d.ts +2 -0
  13. package/dist/helpers/open-auth-url.d.ts.map +1 -0
  14. package/dist/helpers/open-auth-url.js +54 -0
  15. package/dist/helpers/open-auth-url.js.map +1 -0
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2 -2
  19. package/dist/index.js.map +1 -1
  20. package/dist/interfaces/index.d.ts +1 -1
  21. package/dist/interfaces/index.d.ts.map +1 -1
  22. package/dist/interfaces/index.js +1 -1
  23. package/dist/interfaces/index.js.map +1 -1
  24. package/dist/interfaces/react-ink/adapters/command-router.d.ts +19 -0
  25. package/dist/interfaces/react-ink/adapters/command-router.d.ts.map +1 -0
  26. package/dist/interfaces/react-ink/adapters/command-router.js +674 -0
  27. package/dist/interfaces/react-ink/adapters/command-router.js.map +1 -0
  28. package/dist/interfaces/react-ink/adapters/session-events.d.ts +5 -0
  29. package/dist/interfaces/react-ink/adapters/session-events.d.ts.map +1 -0
  30. package/dist/interfaces/react-ink/adapters/session-events.js +76 -0
  31. package/dist/interfaces/react-ink/adapters/session-events.js.map +1 -0
  32. package/dist/interfaces/react-ink/adapters/session-history.d.ts +14 -0
  33. package/dist/interfaces/react-ink/adapters/session-history.d.ts.map +1 -0
  34. package/dist/interfaces/react-ink/adapters/session-history.js +83 -0
  35. package/dist/interfaces/react-ink/adapters/session-history.js.map +1 -0
  36. package/dist/interfaces/react-ink/adapters/tool-state.d.ts +4 -0
  37. package/dist/interfaces/react-ink/adapters/tool-state.d.ts.map +1 -0
  38. package/dist/interfaces/react-ink/adapters/tool-state.js +67 -0
  39. package/dist/interfaces/react-ink/adapters/tool-state.js.map +1 -0
  40. package/dist/interfaces/react-ink/components/AppShell.d.ts +17 -0
  41. package/dist/interfaces/react-ink/components/AppShell.d.ts.map +1 -0
  42. package/dist/interfaces/react-ink/components/AppShell.js +1465 -0
  43. package/dist/interfaces/react-ink/components/AppShell.js.map +1 -0
  44. package/dist/interfaces/react-ink/components/ChangelogBlock.d.ts +9 -0
  45. package/dist/interfaces/react-ink/components/ChangelogBlock.d.ts.map +1 -0
  46. package/dist/interfaces/react-ink/components/ChangelogBlock.js +58 -0
  47. package/dist/interfaces/react-ink/components/ChangelogBlock.js.map +1 -0
  48. package/dist/interfaces/react-ink/components/DisplayBlockView.d.ts +9 -0
  49. package/dist/interfaces/react-ink/components/DisplayBlockView.d.ts.map +1 -0
  50. package/dist/interfaces/react-ink/components/DisplayBlockView.js +11 -0
  51. package/dist/interfaces/react-ink/components/DisplayBlockView.js.map +1 -0
  52. package/dist/interfaces/react-ink/components/Footer.d.ts +11 -0
  53. package/dist/interfaces/react-ink/components/Footer.d.ts.map +1 -0
  54. package/dist/interfaces/react-ink/components/Footer.js +18 -0
  55. package/dist/interfaces/react-ink/components/Footer.js.map +1 -0
  56. package/dist/interfaces/react-ink/components/Header.d.ts +14 -0
  57. package/dist/interfaces/react-ink/components/Header.d.ts.map +1 -0
  58. package/dist/interfaces/react-ink/components/Header.js +24 -0
  59. package/dist/interfaces/react-ink/components/Header.js.map +1 -0
  60. package/dist/interfaces/react-ink/components/MessageList.d.ts +14 -0
  61. package/dist/interfaces/react-ink/components/MessageList.d.ts.map +1 -0
  62. package/dist/interfaces/react-ink/components/MessageList.js +43 -0
  63. package/dist/interfaces/react-ink/components/MessageList.js.map +1 -0
  64. package/dist/interfaces/react-ink/components/MessageRow.d.ts +13 -0
  65. package/dist/interfaces/react-ink/components/MessageRow.d.ts.map +1 -0
  66. package/dist/interfaces/react-ink/components/MessageRow.js +35 -0
  67. package/dist/interfaces/react-ink/components/MessageRow.js.map +1 -0
  68. package/dist/interfaces/react-ink/components/PromptInput.d.ts +35 -0
  69. package/dist/interfaces/react-ink/components/PromptInput.d.ts.map +1 -0
  70. package/dist/interfaces/react-ink/components/PromptInput.js +319 -0
  71. package/dist/interfaces/react-ink/components/PromptInput.js.map +1 -0
  72. package/dist/interfaces/react-ink/components/StartupDiagnosticsBlock.d.ts +9 -0
  73. package/dist/interfaces/react-ink/components/StartupDiagnosticsBlock.d.ts.map +1 -0
  74. package/dist/interfaces/react-ink/components/StartupDiagnosticsBlock.js +14 -0
  75. package/dist/interfaces/react-ink/components/StartupDiagnosticsBlock.js.map +1 -0
  76. package/dist/interfaces/react-ink/components/StatusLine.d.ts +10 -0
  77. package/dist/interfaces/react-ink/components/StatusLine.d.ts.map +1 -0
  78. package/dist/interfaces/react-ink/components/StatusLine.js +39 -0
  79. package/dist/interfaces/react-ink/components/StatusLine.js.map +1 -0
  80. package/dist/interfaces/react-ink/components/TaskPanel.d.ts +10 -0
  81. package/dist/interfaces/react-ink/components/TaskPanel.d.ts.map +1 -0
  82. package/dist/interfaces/react-ink/components/TaskPanel.js +23 -0
  83. package/dist/interfaces/react-ink/components/TaskPanel.js.map +1 -0
  84. package/dist/interfaces/react-ink/components/ToolEventBlock.d.ts +18 -0
  85. package/dist/interfaces/react-ink/components/ToolEventBlock.d.ts.map +1 -0
  86. package/dist/interfaces/react-ink/components/ToolEventBlock.js +61 -0
  87. package/dist/interfaces/react-ink/components/ToolEventBlock.js.map +1 -0
  88. package/dist/interfaces/react-ink/components/dialogs/DialogFrame.d.ts +9 -0
  89. package/dist/interfaces/react-ink/components/dialogs/DialogFrame.d.ts.map +1 -0
  90. package/dist/interfaces/react-ink/components/dialogs/DialogFrame.js +6 -0
  91. package/dist/interfaces/react-ink/components/dialogs/DialogFrame.js.map +1 -0
  92. package/dist/interfaces/react-ink/components/dialogs/LoginDialog.d.ts +15 -0
  93. package/dist/interfaces/react-ink/components/dialogs/LoginDialog.d.ts.map +1 -0
  94. package/dist/interfaces/react-ink/components/dialogs/LoginDialog.js +10 -0
  95. package/dist/interfaces/react-ink/components/dialogs/LoginDialog.js.map +1 -0
  96. package/dist/interfaces/react-ink/components/dialogs/ModelDialog.d.ts +10 -0
  97. package/dist/interfaces/react-ink/components/dialogs/ModelDialog.d.ts.map +1 -0
  98. package/dist/interfaces/react-ink/components/dialogs/ModelDialog.js +64 -0
  99. package/dist/interfaces/react-ink/components/dialogs/ModelDialog.js.map +1 -0
  100. package/dist/interfaces/react-ink/components/dialogs/OAuthDialog.d.ts +10 -0
  101. package/dist/interfaces/react-ink/components/dialogs/OAuthDialog.d.ts.map +1 -0
  102. package/dist/interfaces/react-ink/components/dialogs/OAuthDialog.js +24 -0
  103. package/dist/interfaces/react-ink/components/dialogs/OAuthDialog.js.map +1 -0
  104. package/dist/interfaces/react-ink/components/dialogs/ScopedModelsDialog.d.ts +10 -0
  105. package/dist/interfaces/react-ink/components/dialogs/ScopedModelsDialog.d.ts.map +1 -0
  106. package/dist/interfaces/react-ink/components/dialogs/ScopedModelsDialog.js +95 -0
  107. package/dist/interfaces/react-ink/components/dialogs/ScopedModelsDialog.js.map +1 -0
  108. package/dist/interfaces/react-ink/components/dialogs/SelectableDialog.d.ts +17 -0
  109. package/dist/interfaces/react-ink/components/dialogs/SelectableDialog.d.ts.map +1 -0
  110. package/dist/interfaces/react-ink/components/dialogs/SelectableDialog.js +66 -0
  111. package/dist/interfaces/react-ink/components/dialogs/SelectableDialog.js.map +1 -0
  112. package/dist/interfaces/react-ink/components/dialogs/SessionDialog.d.ts +11 -0
  113. package/dist/interfaces/react-ink/components/dialogs/SessionDialog.d.ts.map +1 -0
  114. package/dist/interfaces/react-ink/components/dialogs/SessionDialog.js +10 -0
  115. package/dist/interfaces/react-ink/components/dialogs/SessionDialog.js.map +1 -0
  116. package/dist/interfaces/react-ink/components/dialogs/SettingsDialog.d.ts +15 -0
  117. package/dist/interfaces/react-ink/components/dialogs/SettingsDialog.d.ts.map +1 -0
  118. package/dist/interfaces/react-ink/components/dialogs/SettingsDialog.js +79 -0
  119. package/dist/interfaces/react-ink/components/dialogs/SettingsDialog.js.map +1 -0
  120. package/dist/interfaces/react-ink/components/dialogs/StartupSessionPicker.d.ts +10 -0
  121. package/dist/interfaces/react-ink/components/dialogs/StartupSessionPicker.d.ts.map +1 -0
  122. package/dist/interfaces/react-ink/components/dialogs/StartupSessionPicker.js +99 -0
  123. package/dist/interfaces/react-ink/components/dialogs/StartupSessionPicker.js.map +1 -0
  124. package/dist/interfaces/react-ink/components/dialogs/ThemeDialog.d.ts +8 -0
  125. package/dist/interfaces/react-ink/components/dialogs/ThemeDialog.d.ts.map +1 -0
  126. package/dist/interfaces/react-ink/components/dialogs/ThemeDialog.js +7 -0
  127. package/dist/interfaces/react-ink/components/dialogs/ThemeDialog.js.map +1 -0
  128. package/dist/interfaces/react-ink/components/dialogs/TreeDialog.d.ts +9 -0
  129. package/dist/interfaces/react-ink/components/dialogs/TreeDialog.d.ts.map +1 -0
  130. package/dist/interfaces/react-ink/components/dialogs/TreeDialog.js +7 -0
  131. package/dist/interfaces/react-ink/components/dialogs/TreeDialog.js.map +1 -0
  132. package/dist/interfaces/react-ink/components/dialogs/UserMessageDialog.d.ts +9 -0
  133. package/dist/interfaces/react-ink/components/dialogs/UserMessageDialog.d.ts.map +1 -0
  134. package/dist/interfaces/react-ink/components/dialogs/UserMessageDialog.js +7 -0
  135. package/dist/interfaces/react-ink/components/dialogs/UserMessageDialog.js.map +1 -0
  136. package/dist/interfaces/react-ink/components/extensions/ExtensionComponentHost.d.ts +30 -0
  137. package/dist/interfaces/react-ink/components/extensions/ExtensionComponentHost.d.ts.map +1 -0
  138. package/dist/interfaces/react-ink/components/extensions/ExtensionComponentHost.js +106 -0
  139. package/dist/interfaces/react-ink/components/extensions/ExtensionComponentHost.js.map +1 -0
  140. package/dist/interfaces/react-ink/components/extensions/ExtensionDialogs.d.ts +20 -0
  141. package/dist/interfaces/react-ink/components/extensions/ExtensionDialogs.d.ts.map +1 -0
  142. package/dist/interfaces/react-ink/components/extensions/ExtensionDialogs.js +144 -0
  143. package/dist/interfaces/react-ink/components/extensions/ExtensionDialogs.js.map +1 -0
  144. package/dist/interfaces/react-ink/components/messages/AssistantMessage.d.ts +12 -0
  145. package/dist/interfaces/react-ink/components/messages/AssistantMessage.d.ts.map +1 -0
  146. package/dist/interfaces/react-ink/components/messages/AssistantMessage.js +20 -0
  147. package/dist/interfaces/react-ink/components/messages/AssistantMessage.js.map +1 -0
  148. package/dist/interfaces/react-ink/components/messages/BashMessage.d.ts +9 -0
  149. package/dist/interfaces/react-ink/components/messages/BashMessage.d.ts.map +1 -0
  150. package/dist/interfaces/react-ink/components/messages/BashMessage.js +11 -0
  151. package/dist/interfaces/react-ink/components/messages/BashMessage.js.map +1 -0
  152. package/dist/interfaces/react-ink/components/messages/BranchSummaryMessage.d.ts +9 -0
  153. package/dist/interfaces/react-ink/components/messages/BranchSummaryMessage.d.ts.map +1 -0
  154. package/dist/interfaces/react-ink/components/messages/BranchSummaryMessage.js +6 -0
  155. package/dist/interfaces/react-ink/components/messages/BranchSummaryMessage.js.map +1 -0
  156. package/dist/interfaces/react-ink/components/messages/CompactionMessage.d.ts +9 -0
  157. package/dist/interfaces/react-ink/components/messages/CompactionMessage.d.ts.map +1 -0
  158. package/dist/interfaces/react-ink/components/messages/CompactionMessage.js +6 -0
  159. package/dist/interfaces/react-ink/components/messages/CompactionMessage.js.map +1 -0
  160. package/dist/interfaces/react-ink/components/messages/CustomMessage.d.ts +10 -0
  161. package/dist/interfaces/react-ink/components/messages/CustomMessage.d.ts.map +1 -0
  162. package/dist/interfaces/react-ink/components/messages/CustomMessage.js +9 -0
  163. package/dist/interfaces/react-ink/components/messages/CustomMessage.js.map +1 -0
  164. package/dist/interfaces/react-ink/components/messages/SkillInvocationMessage.d.ts +8 -0
  165. package/dist/interfaces/react-ink/components/messages/SkillInvocationMessage.d.ts.map +1 -0
  166. package/dist/interfaces/react-ink/components/messages/SkillInvocationMessage.js +10 -0
  167. package/dist/interfaces/react-ink/components/messages/SkillInvocationMessage.js.map +1 -0
  168. package/dist/interfaces/react-ink/components/messages/ToolCallMessage.d.ts +9 -0
  169. package/dist/interfaces/react-ink/components/messages/ToolCallMessage.d.ts.map +1 -0
  170. package/dist/interfaces/react-ink/components/messages/ToolCallMessage.js +8 -0
  171. package/dist/interfaces/react-ink/components/messages/ToolCallMessage.js.map +1 -0
  172. package/dist/interfaces/react-ink/components/messages/ToolResultBlock.d.ts +12 -0
  173. package/dist/interfaces/react-ink/components/messages/ToolResultBlock.d.ts.map +1 -0
  174. package/dist/interfaces/react-ink/components/messages/ToolResultBlock.js +8 -0
  175. package/dist/interfaces/react-ink/components/messages/ToolResultBlock.js.map +1 -0
  176. package/dist/interfaces/react-ink/components/messages/UserMessage.d.ts +10 -0
  177. package/dist/interfaces/react-ink/components/messages/UserMessage.d.ts.map +1 -0
  178. package/dist/interfaces/react-ink/components/messages/UserMessage.js +7 -0
  179. package/dist/interfaces/react-ink/components/messages/UserMessage.js.map +1 -0
  180. package/dist/interfaces/react-ink/hooks/use-agent-session.d.ts +8 -0
  181. package/dist/interfaces/react-ink/hooks/use-agent-session.d.ts.map +1 -0
  182. package/dist/interfaces/react-ink/hooks/use-agent-session.js +34 -0
  183. package/dist/interfaces/react-ink/hooks/use-agent-session.js.map +1 -0
  184. package/dist/interfaces/react-ink/hooks/use-app-keybindings.d.ts +12 -0
  185. package/dist/interfaces/react-ink/hooks/use-app-keybindings.d.ts.map +1 -0
  186. package/dist/interfaces/react-ink/hooks/use-app-keybindings.js +17 -0
  187. package/dist/interfaces/react-ink/hooks/use-app-keybindings.js.map +1 -0
  188. package/dist/interfaces/react-ink/hooks/use-footer-data.d.ts +7 -0
  189. package/dist/interfaces/react-ink/hooks/use-footer-data.d.ts.map +1 -0
  190. package/dist/interfaces/react-ink/hooks/use-footer-data.js +17 -0
  191. package/dist/interfaces/react-ink/hooks/use-footer-data.js.map +1 -0
  192. package/dist/interfaces/react-ink/hooks/use-prompt-submit.d.ts +17 -0
  193. package/dist/interfaces/react-ink/hooks/use-prompt-submit.d.ts.map +1 -0
  194. package/dist/interfaces/react-ink/hooks/use-prompt-submit.js +66 -0
  195. package/dist/interfaces/react-ink/hooks/use-prompt-submit.js.map +1 -0
  196. package/dist/interfaces/react-ink/hooks/use-session-history.d.ts +8 -0
  197. package/dist/interfaces/react-ink/hooks/use-session-history.d.ts.map +1 -0
  198. package/dist/interfaces/react-ink/hooks/use-session-history.js +8 -0
  199. package/dist/interfaces/react-ink/hooks/use-session-history.js.map +1 -0
  200. package/dist/interfaces/react-ink/index.d.ts +8 -0
  201. package/dist/interfaces/react-ink/index.d.ts.map +1 -0
  202. package/dist/interfaces/react-ink/index.js +8 -0
  203. package/dist/interfaces/react-ink/index.js.map +1 -0
  204. package/dist/interfaces/react-ink/interactive-mode.d.ts +24 -0
  205. package/dist/interfaces/react-ink/interactive-mode.d.ts.map +1 -0
  206. package/dist/interfaces/react-ink/interactive-mode.js +57 -0
  207. package/dist/interfaces/react-ink/interactive-mode.js.map +1 -0
  208. package/dist/interfaces/react-ink/render-root.d.ts +19 -0
  209. package/dist/interfaces/react-ink/render-root.d.ts.map +1 -0
  210. package/dist/interfaces/react-ink/render-root.js +6 -0
  211. package/dist/interfaces/react-ink/render-root.js.map +1 -0
  212. package/dist/interfaces/react-ink/state/reducer.d.ts +51 -0
  213. package/dist/interfaces/react-ink/state/reducer.d.ts.map +1 -0
  214. package/dist/interfaces/react-ink/state/reducer.js +122 -0
  215. package/dist/interfaces/react-ink/state/reducer.js.map +1 -0
  216. package/dist/interfaces/react-ink/state/store.d.ts +4 -0
  217. package/dist/interfaces/react-ink/state/store.d.ts.map +1 -0
  218. package/dist/interfaces/react-ink/state/store.js +5 -0
  219. package/dist/interfaces/react-ink/state/store.js.map +1 -0
  220. package/dist/interfaces/react-ink/state/ui-state.d.ts +5 -0
  221. package/dist/interfaces/react-ink/state/ui-state.d.ts.map +1 -0
  222. package/dist/interfaces/react-ink/state/ui-state.js +20 -0
  223. package/dist/interfaces/react-ink/state/ui-state.js.map +1 -0
  224. package/dist/interfaces/react-ink/theme-adapter.d.ts +4 -0
  225. package/dist/interfaces/react-ink/theme-adapter.d.ts.map +1 -0
  226. package/dist/interfaces/react-ink/theme-adapter.js +15 -0
  227. package/dist/interfaces/react-ink/theme-adapter.js.map +1 -0
  228. package/dist/interfaces/react-ink/types.d.ts +51 -0
  229. package/dist/interfaces/react-ink/types.d.ts.map +1 -0
  230. package/dist/interfaces/react-ink/types.js +2 -0
  231. package/dist/interfaces/react-ink/types.js.map +1 -0
  232. package/dist/interfaces/react-ink/utils/changelog.d.ts +7 -0
  233. package/dist/interfaces/react-ink/utils/changelog.d.ts.map +1 -0
  234. package/dist/interfaces/react-ink/utils/changelog.js +40 -0
  235. package/dist/interfaces/react-ink/utils/changelog.js.map +1 -0
  236. package/dist/interfaces/react-ink/utils/key-data.d.ts +22 -0
  237. package/dist/interfaces/react-ink/utils/key-data.d.ts.map +1 -0
  238. package/dist/interfaces/react-ink/utils/key-data.js +123 -0
  239. package/dist/interfaces/react-ink/utils/key-data.js.map +1 -0
  240. package/dist/interfaces/react-ink/utils/message-groups.d.ts +26 -0
  241. package/dist/interfaces/react-ink/utils/message-groups.d.ts.map +1 -0
  242. package/dist/interfaces/react-ink/utils/message-groups.js +230 -0
  243. package/dist/interfaces/react-ink/utils/message-groups.js.map +1 -0
  244. package/dist/interfaces/react-ink/utils/prompt-autocomplete.d.ts +20 -0
  245. package/dist/interfaces/react-ink/utils/prompt-autocomplete.d.ts.map +1 -0
  246. package/dist/interfaces/react-ink/utils/prompt-autocomplete.js +46 -0
  247. package/dist/interfaces/react-ink/utils/prompt-autocomplete.js.map +1 -0
  248. package/dist/interfaces/react-ink/utils/selection-dialog.d.ts +3 -0
  249. package/dist/interfaces/react-ink/utils/selection-dialog.d.ts.map +1 -0
  250. package/dist/interfaces/react-ink/utils/selection-dialog.js +18 -0
  251. package/dist/interfaces/react-ink/utils/selection-dialog.js.map +1 -0
  252. package/dist/interfaces/react-ink/utils/session-actions.d.ts +10 -0
  253. package/dist/interfaces/react-ink/utils/session-actions.d.ts.map +1 -0
  254. package/dist/interfaces/react-ink/utils/session-actions.js +66 -0
  255. package/dist/interfaces/react-ink/utils/session-actions.js.map +1 -0
  256. package/dist/interfaces/react-ink/utils/slash-commands.d.ts +10 -0
  257. package/dist/interfaces/react-ink/utils/slash-commands.d.ts.map +1 -0
  258. package/dist/interfaces/react-ink/utils/slash-commands.js +111 -0
  259. package/dist/interfaces/react-ink/utils/slash-commands.js.map +1 -0
  260. package/dist/interfaces/react-ink/utils/startup-diagnostics.d.ts +7 -0
  261. package/dist/interfaces/react-ink/utils/startup-diagnostics.d.ts.map +1 -0
  262. package/dist/interfaces/react-ink/utils/startup-diagnostics.js +111 -0
  263. package/dist/interfaces/react-ink/utils/startup-diagnostics.js.map +1 -0
  264. package/dist/interfaces/react-ink/utils/tool-display.d.ts +22 -0
  265. package/dist/interfaces/react-ink/utils/tool-display.d.ts.map +1 -0
  266. package/dist/interfaces/react-ink/utils/tool-display.js +349 -0
  267. package/dist/interfaces/react-ink/utils/tool-display.js.map +1 -0
  268. package/dist/interfaces/service-api/rpc-mode.js +1 -1
  269. package/dist/interfaces/service-api/rpc-mode.js.map +1 -1
  270. package/dist/interfaces/{terminal-ui/theme → theme}/dark.json +1 -1
  271. package/dist/interfaces/{terminal-ui/theme → theme}/light.json +1 -1
  272. package/dist/interfaces/theme/theme.d.ts.map +1 -0
  273. package/dist/interfaces/{terminal-ui/theme → theme}/theme.js +1 -1
  274. package/dist/interfaces/theme/theme.js.map +1 -0
  275. package/dist/main.js +1 -1
  276. package/dist/main.js.map +1 -1
  277. package/dist/runtime/agent-session.js +1 -1
  278. package/dist/runtime/agent-session.js.map +1 -1
  279. package/dist/runtime/html-export/index.js +1 -1
  280. package/dist/runtime/html-export/index.js.map +1 -1
  281. package/dist/runtime/html-export/index.ts +1 -2
  282. package/dist/runtime/html-export/tool-renderer.d.ts +1 -1
  283. package/dist/runtime/html-export/tool-renderer.d.ts.map +1 -1
  284. package/dist/runtime/html-export/tool-renderer.ts +1 -1
  285. package/dist/runtime/plugins/runner.js +1 -1
  286. package/dist/runtime/plugins/runner.js.map +1 -1
  287. package/dist/runtime/plugins/types.d.ts +1 -1
  288. package/dist/runtime/plugins/types.d.ts.map +1 -1
  289. package/dist/runtime/resource-loader.d.ts +1 -1
  290. package/dist/runtime/resource-loader.d.ts.map +1 -1
  291. package/dist/runtime/resource-loader.js +1 -1
  292. package/dist/runtime/resource-loader.js.map +1 -1
  293. package/dist/runtime/system-prompt.js +1 -1
  294. package/dist/runtime/system-prompt.js.map +1 -1
  295. package/dist/runtime/tooling/composio-compat.d.ts +169 -0
  296. package/dist/runtime/tooling/composio-compat.d.ts.map +1 -0
  297. package/dist/runtime/tooling/composio-compat.js +163 -0
  298. package/dist/runtime/tooling/composio-compat.js.map +1 -0
  299. package/dist/runtime/tooling/index.d.ts +12 -25
  300. package/dist/runtime/tooling/index.d.ts.map +1 -1
  301. package/dist/runtime/tooling/index.js +3 -3
  302. package/dist/runtime/tooling/index.js.map +1 -1
  303. package/guides/INDUSVX_OBSERVE_FULL_INTEGRATION_REPORT.md +2 -2
  304. package/package.json +9 -5
  305. package/dist/interfaces/induscode-ui-delegate.d.ts +0 -3
  306. package/dist/interfaces/induscode-ui-delegate.d.ts.map +0 -1
  307. package/dist/interfaces/induscode-ui-delegate.js +0 -148
  308. package/dist/interfaces/induscode-ui-delegate.js.map +0 -1
  309. package/dist/interfaces/terminal-ui/components/armin.d.ts +0 -19
  310. package/dist/interfaces/terminal-ui/components/armin.d.ts.map +0 -1
  311. package/dist/interfaces/terminal-ui/components/armin.js +0 -280
  312. package/dist/interfaces/terminal-ui/components/armin.js.map +0 -1
  313. package/dist/interfaces/terminal-ui/components/assistant-message.d.ts +0 -13
  314. package/dist/interfaces/terminal-ui/components/assistant-message.d.ts.map +0 -1
  315. package/dist/interfaces/terminal-ui/components/assistant-message.js +0 -95
  316. package/dist/interfaces/terminal-ui/components/assistant-message.js.map +0 -1
  317. package/dist/interfaces/terminal-ui/components/bash-execution.d.ts +0 -24
  318. package/dist/interfaces/terminal-ui/components/bash-execution.d.ts.map +0 -1
  319. package/dist/interfaces/terminal-ui/components/bash-execution.js +0 -135
  320. package/dist/interfaces/terminal-ui/components/bash-execution.js.map +0 -1
  321. package/dist/interfaces/terminal-ui/components/bordered-loader.d.ts +0 -14
  322. package/dist/interfaces/terminal-ui/components/bordered-loader.d.ts.map +0 -1
  323. package/dist/interfaces/terminal-ui/components/bordered-loader.js +0 -78
  324. package/dist/interfaces/terminal-ui/components/bordered-loader.js.map +0 -1
  325. package/dist/interfaces/terminal-ui/components/branch-summary-message.d.ts +0 -16
  326. package/dist/interfaces/terminal-ui/components/branch-summary-message.d.ts.map +0 -1
  327. package/dist/interfaces/terminal-ui/components/branch-summary-message.js +0 -55
  328. package/dist/interfaces/terminal-ui/components/branch-summary-message.js.map +0 -1
  329. package/dist/interfaces/terminal-ui/components/compaction-summary-message.d.ts +0 -16
  330. package/dist/interfaces/terminal-ui/components/compaction-summary-message.d.ts.map +0 -1
  331. package/dist/interfaces/terminal-ui/components/compaction-summary-message.js +0 -60
  332. package/dist/interfaces/terminal-ui/components/compaction-summary-message.js.map +0 -1
  333. package/dist/interfaces/terminal-ui/components/config-selector.d.ts +0 -71
  334. package/dist/interfaces/terminal-ui/components/config-selector.d.ts.map +0 -1
  335. package/dist/interfaces/terminal-ui/components/config-selector.js +0 -459
  336. package/dist/interfaces/terminal-ui/components/config-selector.js.map +0 -1
  337. package/dist/interfaces/terminal-ui/components/countdown-timer.d.ts +0 -10
  338. package/dist/interfaces/terminal-ui/components/countdown-timer.d.ts.map +0 -1
  339. package/dist/interfaces/terminal-ui/components/countdown-timer.js +0 -42
  340. package/dist/interfaces/terminal-ui/components/countdown-timer.js.map +0 -1
  341. package/dist/interfaces/terminal-ui/components/custom-editor.d.ts +0 -17
  342. package/dist/interfaces/terminal-ui/components/custom-editor.d.ts.map +0 -1
  343. package/dist/interfaces/terminal-ui/components/custom-editor.js +0 -72
  344. package/dist/interfaces/terminal-ui/components/custom-editor.js.map +0 -1
  345. package/dist/interfaces/terminal-ui/components/custom-message.d.ts +0 -19
  346. package/dist/interfaces/terminal-ui/components/custom-message.d.ts.map +0 -1
  347. package/dist/interfaces/terminal-ui/components/custom-message.js +0 -71
  348. package/dist/interfaces/terminal-ui/components/custom-message.js.map +0 -1
  349. package/dist/interfaces/terminal-ui/components/diff.d.ts +0 -9
  350. package/dist/interfaces/terminal-ui/components/diff.d.ts.map +0 -1
  351. package/dist/interfaces/terminal-ui/components/diff.js +0 -126
  352. package/dist/interfaces/terminal-ui/components/diff.js.map +0 -1
  353. package/dist/interfaces/terminal-ui/components/dynamic-border.d.ts +0 -20
  354. package/dist/interfaces/terminal-ui/components/dynamic-border.d.ts.map +0 -1
  355. package/dist/interfaces/terminal-ui/components/dynamic-border.js +0 -40
  356. package/dist/interfaces/terminal-ui/components/dynamic-border.js.map +0 -1
  357. package/dist/interfaces/terminal-ui/components/extension-editor.d.ts +0 -13
  358. package/dist/interfaces/terminal-ui/components/extension-editor.d.ts.map +0 -1
  359. package/dist/interfaces/terminal-ui/components/extension-editor.js +0 -94
  360. package/dist/interfaces/terminal-ui/components/extension-editor.js.map +0 -1
  361. package/dist/interfaces/terminal-ui/components/extension-input.d.ts +0 -18
  362. package/dist/interfaces/terminal-ui/components/extension-input.d.ts.map +0 -1
  363. package/dist/interfaces/terminal-ui/components/extension-input.js +0 -72
  364. package/dist/interfaces/terminal-ui/components/extension-input.js.map +0 -1
  365. package/dist/interfaces/terminal-ui/components/extension-selector.d.ts +0 -19
  366. package/dist/interfaces/terminal-ui/components/extension-selector.d.ts.map +0 -1
  367. package/dist/interfaces/terminal-ui/components/extension-selector.js +0 -93
  368. package/dist/interfaces/terminal-ui/components/extension-selector.js.map +0 -1
  369. package/dist/interfaces/terminal-ui/components/footer.d.ts +0 -17
  370. package/dist/interfaces/terminal-ui/components/footer.d.ts.map +0 -1
  371. package/dist/interfaces/terminal-ui/components/footer.js +0 -160
  372. package/dist/interfaces/terminal-ui/components/footer.js.map +0 -1
  373. package/dist/interfaces/terminal-ui/components/index.d.ts +0 -80
  374. package/dist/interfaces/terminal-ui/components/index.d.ts.map +0 -1
  375. package/dist/interfaces/terminal-ui/components/index.js +0 -74
  376. package/dist/interfaces/terminal-ui/components/index.js.map +0 -1
  377. package/dist/interfaces/terminal-ui/components/keybinding-hints.d.ts +0 -23
  378. package/dist/interfaces/terminal-ui/components/keybinding-hints.d.ts.map +0 -1
  379. package/dist/interfaces/terminal-ui/components/keybinding-hints.js +0 -54
  380. package/dist/interfaces/terminal-ui/components/keybinding-hints.js.map +0 -1
  381. package/dist/interfaces/terminal-ui/components/login-dialog.d.ts +0 -29
  382. package/dist/interfaces/terminal-ui/components/login-dialog.d.ts.map +0 -1
  383. package/dist/interfaces/terminal-ui/components/login-dialog.js +0 -143
  384. package/dist/interfaces/terminal-ui/components/login-dialog.js.map +0 -1
  385. package/dist/interfaces/terminal-ui/components/model-selector.d.ts +0 -43
  386. package/dist/interfaces/terminal-ui/components/model-selector.d.ts.map +0 -1
  387. package/dist/interfaces/terminal-ui/components/model-selector.js +0 -201
  388. package/dist/interfaces/terminal-ui/components/model-selector.js.map +0 -1
  389. package/dist/interfaces/terminal-ui/components/oauth-selector.d.ts +0 -75
  390. package/dist/interfaces/terminal-ui/components/oauth-selector.d.ts.map +0 -1
  391. package/dist/interfaces/terminal-ui/components/oauth-selector.js +0 -374
  392. package/dist/interfaces/terminal-ui/components/oauth-selector.js.map +0 -1
  393. package/dist/interfaces/terminal-ui/components/scoped-models-selector.d.ts +0 -39
  394. package/dist/interfaces/terminal-ui/components/scoped-models-selector.d.ts.map +0 -1
  395. package/dist/interfaces/terminal-ui/components/scoped-models-selector.js +0 -242
  396. package/dist/interfaces/terminal-ui/components/scoped-models-selector.js.map +0 -1
  397. package/dist/interfaces/terminal-ui/components/session-selector-search.d.ts +0 -21
  398. package/dist/interfaces/terminal-ui/components/session-selector-search.d.ts.map +0 -1
  399. package/dist/interfaces/terminal-ui/components/session-selector-search.js +0 -135
  400. package/dist/interfaces/terminal-ui/components/session-selector-search.js.map +0 -1
  401. package/dist/interfaces/terminal-ui/components/session-selector.d.ts +0 -85
  402. package/dist/interfaces/terminal-ui/components/session-selector.d.ts.map +0 -1
  403. package/dist/interfaces/terminal-ui/components/session-selector.js +0 -688
  404. package/dist/interfaces/terminal-ui/components/session-selector.js.map +0 -1
  405. package/dist/interfaces/terminal-ui/components/settings-selector.d.ts +0 -49
  406. package/dist/interfaces/terminal-ui/components/settings-selector.d.ts.map +0 -1
  407. package/dist/interfaces/terminal-ui/components/settings-selector.js +0 -159
  408. package/dist/interfaces/terminal-ui/components/settings-selector.js.map +0 -1
  409. package/dist/interfaces/terminal-ui/components/show-images-selector.d.ts +0 -10
  410. package/dist/interfaces/terminal-ui/components/show-images-selector.d.ts.map +0 -1
  411. package/dist/interfaces/terminal-ui/components/show-images-selector.js +0 -32
  412. package/dist/interfaces/terminal-ui/components/show-images-selector.js.map +0 -1
  413. package/dist/interfaces/terminal-ui/components/skill-invocation-message.d.ts +0 -17
  414. package/dist/interfaces/terminal-ui/components/skill-invocation-message.d.ts.map +0 -1
  415. package/dist/interfaces/terminal-ui/components/skill-invocation-message.js +0 -55
  416. package/dist/interfaces/terminal-ui/components/skill-invocation-message.js.map +0 -1
  417. package/dist/interfaces/terminal-ui/components/theme-selector.d.ts +0 -11
  418. package/dist/interfaces/terminal-ui/components/theme-selector.d.ts.map +0 -1
  419. package/dist/interfaces/terminal-ui/components/theme-selector.js +0 -39
  420. package/dist/interfaces/terminal-ui/components/theme-selector.js.map +0 -1
  421. package/dist/interfaces/terminal-ui/components/thinking-selector.d.ts +0 -11
  422. package/dist/interfaces/terminal-ui/components/thinking-selector.d.ts.map +0 -1
  423. package/dist/interfaces/terminal-ui/components/thinking-selector.js +0 -45
  424. package/dist/interfaces/terminal-ui/components/thinking-selector.js.map +0 -1
  425. package/dist/interfaces/terminal-ui/components/tool-execution.d.ts +0 -72
  426. package/dist/interfaces/terminal-ui/components/tool-execution.d.ts.map +0 -1
  427. package/dist/interfaces/terminal-ui/components/tool-execution.js +0 -1162
  428. package/dist/interfaces/terminal-ui/components/tool-execution.js.map +0 -1
  429. package/dist/interfaces/terminal-ui/components/tree-selector.d.ts +0 -62
  430. package/dist/interfaces/terminal-ui/components/tree-selector.d.ts.map +0 -1
  431. package/dist/interfaces/terminal-ui/components/tree-selector.js +0 -886
  432. package/dist/interfaces/terminal-ui/components/tree-selector.js.map +0 -1
  433. package/dist/interfaces/terminal-ui/components/user-message-selector.d.ts +0 -24
  434. package/dist/interfaces/terminal-ui/components/user-message-selector.d.ts.map +0 -1
  435. package/dist/interfaces/terminal-ui/components/user-message-selector.js +0 -99
  436. package/dist/interfaces/terminal-ui/components/user-message-selector.js.map +0 -1
  437. package/dist/interfaces/terminal-ui/components/user-message.d.ts +0 -193
  438. package/dist/interfaces/terminal-ui/components/user-message.d.ts.map +0 -1
  439. package/dist/interfaces/terminal-ui/components/user-message.js +0 -201
  440. package/dist/interfaces/terminal-ui/components/user-message.js.map +0 -1
  441. package/dist/interfaces/terminal-ui/components/visual-truncate.d.ts +0 -12
  442. package/dist/interfaces/terminal-ui/components/visual-truncate.d.ts.map +0 -1
  443. package/dist/interfaces/terminal-ui/components/visual-truncate.js +0 -25
  444. package/dist/interfaces/terminal-ui/components/visual-truncate.js.map +0 -1
  445. package/dist/interfaces/terminal-ui/interactive-mode.d.ts +0 -1941
  446. package/dist/interfaces/terminal-ui/interactive-mode.d.ts.map +0 -1
  447. package/dist/interfaces/terminal-ui/interactive-mode.js +0 -5940
  448. package/dist/interfaces/terminal-ui/interactive-mode.js.map +0 -1
  449. package/dist/interfaces/terminal-ui/theme/theme.d.ts.map +0 -1
  450. package/dist/interfaces/terminal-ui/theme/theme.js.map +0 -1
  451. /package/dist/interfaces/{terminal-ui/theme → theme}/theme-schema.json +0 -0
  452. /package/dist/interfaces/{terminal-ui/theme → theme}/theme.d.ts +0 -0
@@ -0,0 +1,1465 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { spawnSync } from "node:child_process";
3
+ import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { useEffect, useMemo, useReducer, useRef, useState } from "react";
7
+ import { Box, Text, useApp } from "ink";
8
+ import { matchesKey } from "indusagi/tui";
9
+ import { Footer, LoginDialog, MessageList, ModelDialog, OAuthDialog, ScopedModelsDialog, SessionDialog, SettingsDialog, StatusLine, TaskPanel, ThemeDialog, TreeDialog, UserMessageDialog, } from "indusagi/react-ink";
10
+ import { APP_NAME, VERSION, getAuthPath } from "../../../config.js";
11
+ import { extensionForImageMimeType, readClipboardImage } from "../../../helpers/clipboard-image.js";
12
+ import { openAuthUrl } from "../../../helpers/open-auth-url.js";
13
+ import { KeybindingsManager } from "../../../runtime/keybindings.js";
14
+ import { resolveModelScope } from "../../../runtime/model-resolver.js";
15
+ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getThemeByName, setTheme, setThemeInstance, theme as extensionTheme, Theme, } from "../../theme/theme.js";
16
+ import { flattenSessionTree, listAllSessions, listCurrentSessions, listUserMessages } from "../adapters/session-history.js";
17
+ import { uiReducer } from "../state/reducer.js";
18
+ import { createUiStore } from "../state/store.js";
19
+ import { createThemeAdapter } from "../theme-adapter.js";
20
+ import { deleteSessionAtPath, renameSessionAtPath } from "../utils/session-actions.js";
21
+ import { Header } from "./Header.js";
22
+ import { PromptInput } from "./PromptInput.js";
23
+ import { useAgentSession } from "../hooks/use-agent-session.js";
24
+ import { useAppKeybindings } from "../hooks/use-app-keybindings.js";
25
+ import { useFooterData } from "../hooks/use-footer-data.js";
26
+ import { usePromptSubmit } from "../hooks/use-prompt-submit.js";
27
+ import { createExtensionTuiBridge, createHostedExtensionComponent, createHostedExtensionComponentFromParts, ExtensionComponentHost, } from "./extensions/ExtensionComponentHost.js";
28
+ import { ExtensionSelectDialog, ExtensionTextDialog } from "./extensions/ExtensionDialogs.js";
29
+ function truncateWidgetLines(lines, maxLines = 10) {
30
+ if (lines.length <= maxLines) {
31
+ return lines;
32
+ }
33
+ return [...lines.slice(0, maxLines), `... ${lines.length - maxLines} more line(s)`];
34
+ }
35
+ function renderTextLines(lines, prefix) {
36
+ if (lines.length === 0) {
37
+ return null;
38
+ }
39
+ return (_jsx(Box, { flexDirection: "column", children: lines.map((line, index) => (_jsx(Text, { children: line.length > 0 ? line : " " }, `${prefix}:${index}`))) }));
40
+ }
41
+ function writeTerminalTitle(title) {
42
+ if (!process.stdout.isTTY) {
43
+ return;
44
+ }
45
+ process.stdout.write(`\u001B]0;${title}\u0007`);
46
+ }
47
+ function buildSettingsItems(session, state, onRefresh, setError) {
48
+ const booleanValues = ["enabled", "disabled"];
49
+ const visibilityValues = ["visible", "hidden"];
50
+ return [
51
+ {
52
+ id: "autocompact",
53
+ label: "Auto-compact",
54
+ description: "Automatically compact conversation context when it grows too large.",
55
+ value: session.autoCompactionEnabled ? "enabled" : "disabled",
56
+ values: booleanValues,
57
+ onChange: (value) => {
58
+ session.setAutoCompactionEnabled(value === "enabled");
59
+ onRefresh();
60
+ },
61
+ },
62
+ {
63
+ id: "images",
64
+ label: "Show images",
65
+ description: "Render inline image placeholders and image content in the UI.",
66
+ value: state.showImages ? "enabled" : "disabled",
67
+ values: booleanValues,
68
+ onChange: (value) => {
69
+ session.settingsManager.setShowImages(value === "enabled");
70
+ onRefresh();
71
+ },
72
+ },
73
+ {
74
+ id: "image-resize",
75
+ label: "Auto-resize images",
76
+ description: "Resize large images before sending them to providers.",
77
+ value: session.settingsManager.getImageAutoResize() ? "enabled" : "disabled",
78
+ values: booleanValues,
79
+ onChange: (value) => {
80
+ session.settingsManager.setImageAutoResize(value === "enabled");
81
+ onRefresh();
82
+ },
83
+ },
84
+ {
85
+ id: "block-images",
86
+ label: "Block images",
87
+ description: "Prevent images from being sent to model providers.",
88
+ value: session.settingsManager.getBlockImages() ? "enabled" : "disabled",
89
+ values: booleanValues,
90
+ onChange: (value) => {
91
+ session.settingsManager.setBlockImages(value === "enabled");
92
+ onRefresh();
93
+ },
94
+ },
95
+ {
96
+ id: "skills",
97
+ label: "Skill commands",
98
+ description: "Register skills as /skill:name slash commands.",
99
+ value: session.settingsManager.getEnableSkillCommands() ? "enabled" : "disabled",
100
+ values: booleanValues,
101
+ onChange: (value) => {
102
+ session.settingsManager.setEnableSkillCommands(value === "enabled");
103
+ onRefresh();
104
+ },
105
+ },
106
+ {
107
+ id: "steering-mode",
108
+ label: "Steering mode",
109
+ description: "Choose whether queued steering messages are delivered one-by-one or all at once.",
110
+ value: session.steeringMode,
111
+ values: ["one-at-a-time", "all"],
112
+ onChange: (value) => {
113
+ session.setSteeringMode(value);
114
+ onRefresh();
115
+ },
116
+ },
117
+ {
118
+ id: "follow-up-mode",
119
+ label: "Follow-up mode",
120
+ description: "Choose whether queued follow-up messages are delivered one-by-one or all at once.",
121
+ value: session.followUpMode,
122
+ values: ["one-at-a-time", "all"],
123
+ onChange: (value) => {
124
+ session.setFollowUpMode(value);
125
+ onRefresh();
126
+ },
127
+ },
128
+ {
129
+ id: "thinking-level",
130
+ label: "Thinking level",
131
+ description: "Control reasoning depth for models that support thinking.",
132
+ value: session.thinkingLevel,
133
+ values: session.getAvailableThinkingLevels(),
134
+ onChange: (value) => {
135
+ session.setThinkingLevel(value);
136
+ onRefresh();
137
+ },
138
+ },
139
+ {
140
+ id: "theme",
141
+ label: "Theme",
142
+ description: "Choose the color theme for the interface.",
143
+ value: session.settingsManager.getTheme() ?? state.themeName,
144
+ values: getAvailableThemes(),
145
+ onChange: (value) => {
146
+ const result = setTheme(value, true);
147
+ if (!result.success) {
148
+ setError(result.error ?? `Unable to load theme "${value}".`);
149
+ return;
150
+ }
151
+ session.settingsManager.setTheme(value);
152
+ onRefresh();
153
+ },
154
+ },
155
+ {
156
+ id: "thinking-blocks",
157
+ label: "Thinking blocks",
158
+ description: "Show or hide thinking blocks inside assistant responses.",
159
+ value: state.showThinking ? "visible" : "hidden",
160
+ values: visibilityValues,
161
+ onChange: (value) => {
162
+ session.settingsManager.setHideThinkingBlock(value === "hidden");
163
+ onRefresh();
164
+ },
165
+ },
166
+ {
167
+ id: "collapse-changelog",
168
+ label: "Collapse changelog",
169
+ description: "Prefer a condensed changelog after updates.",
170
+ value: session.settingsManager.getCollapseChangelog() ? "enabled" : "disabled",
171
+ values: booleanValues,
172
+ onChange: (value) => {
173
+ session.settingsManager.setCollapseChangelog(value === "enabled");
174
+ onRefresh();
175
+ },
176
+ },
177
+ {
178
+ id: "quiet-startup",
179
+ label: "Quiet startup",
180
+ description: "Reduce startup noise and status output when the app launches.",
181
+ value: session.settingsManager.getQuietStartup() ? "enabled" : "disabled",
182
+ values: booleanValues,
183
+ onChange: (value) => {
184
+ session.settingsManager.setQuietStartup(value === "enabled");
185
+ onRefresh();
186
+ },
187
+ },
188
+ {
189
+ id: "double-escape",
190
+ label: "Double-escape action",
191
+ description: "Choose what happens when Escape is pressed twice with an empty prompt.",
192
+ value: session.settingsManager.getDoubleEscapeAction(),
193
+ values: ["tree", "fork"],
194
+ onChange: (value) => {
195
+ session.settingsManager.setDoubleEscapeAction(value);
196
+ onRefresh();
197
+ },
198
+ },
199
+ {
200
+ id: "cursor",
201
+ label: "Hardware cursor",
202
+ description: "Show the terminal cursor while keeping IME-friendly positioning.",
203
+ value: session.settingsManager.getShowHardwareCursor() ? "enabled" : "disabled",
204
+ values: booleanValues,
205
+ onChange: (value) => {
206
+ session.settingsManager.setShowHardwareCursor(value === "enabled");
207
+ onRefresh();
208
+ },
209
+ },
210
+ {
211
+ id: "editor-padding",
212
+ label: "Editor padding",
213
+ description: "Horizontal padding for the prompt editor.",
214
+ value: String(session.settingsManager.getEditorPaddingX()),
215
+ values: ["0", "1", "2", "3"],
216
+ onChange: (value) => {
217
+ session.settingsManager.setEditorPaddingX(Number.parseInt(value, 10));
218
+ onRefresh();
219
+ },
220
+ },
221
+ ];
222
+ }
223
+ export function AppShell({ context, footerDataProvider, initialImages, initialMessage, initialMessages, startupChangelog, startupDiagnostics, startupNotices, verbose, }) {
224
+ const { exit } = useApp();
225
+ const keybindings = useMemo(() => KeybindingsManager.create(), []);
226
+ const [state, dispatch] = useReducer(uiReducer, context.session, createUiStore);
227
+ const overlayRef = useRef(state.overlay);
228
+ const oauthResolverRef = useRef(null);
229
+ const startupRanRef = useRef(false);
230
+ const displayBlockIdRef = useRef(0);
231
+ const [terminalRows, setTerminalRows] = useState(process.stdout.rows ?? 40);
232
+ const [terminalColumns, setTerminalColumns] = useState(process.stdout.columns ?? 80);
233
+ const [displayBlocks, setDisplayBlocks] = useState([]);
234
+ const [extensionHeader, setExtensionHeader] = useState(null);
235
+ const [extensionFooter, setExtensionFooter] = useState(null);
236
+ const [extensionWidgetsAbove, setExtensionWidgetsAbove] = useState(() => new Map());
237
+ const [extensionWidgetsBelow, setExtensionWidgetsBelow] = useState(() => new Map());
238
+ const [extensionOverlayState, setExtensionOverlayState] = useState({ kind: "none" });
239
+ const [extensionEditor, setExtensionEditor] = useState(null);
240
+ const [extensionWorkingMessage, setExtensionWorkingMessage] = useState();
241
+ const [toolOutputExpanded, setToolOutputExpanded] = useState(false);
242
+ const [compactionQueuedMessages, setCompactionQueuedMessages] = useState([]);
243
+ const [currentSessions, setCurrentSessions] = useState([]);
244
+ const [layoutEpoch, setLayoutEpoch] = useState(0);
245
+ const [startupDismissed, setStartupDismissed] = useState(context.session.messages.length > 0);
246
+ const extensionOverlayRef = useRef({ kind: "none" });
247
+ const extensionUiContextRef = useRef(undefined);
248
+ const inputRef = useRef(state.input);
249
+ const customTerminalTitleRef = useRef(null);
250
+ const setStatus = (text, kind = "info") => {
251
+ dispatch({ type: "set-status", status: { text, kind } });
252
+ };
253
+ const setError = (text) => {
254
+ dispatch({ type: "set-status", status: { text, kind: "error" } });
255
+ };
256
+ const clearStatus = () => {
257
+ dispatch({ type: "set-status", status: undefined });
258
+ };
259
+ const setOverlay = (overlay) => {
260
+ dispatch({ type: "set-overlay", overlay });
261
+ };
262
+ const closeOverlay = () => {
263
+ oauthResolverRef.current = null;
264
+ dispatch({ type: "close-overlay" });
265
+ };
266
+ const setInput = (value, cursorOffset) => {
267
+ dispatch({ type: "set-input", value, cursorOffset });
268
+ };
269
+ inputRef.current = state.input;
270
+ const appendDisplayBlock = (block) => {
271
+ const timestamp = Date.now();
272
+ displayBlockIdRef.current += 1;
273
+ setDisplayBlocks((current) => [
274
+ ...current,
275
+ {
276
+ ...block,
277
+ id: `${block.kind}:${timestamp}:${displayBlockIdRef.current}`,
278
+ timestamp,
279
+ },
280
+ ]);
281
+ };
282
+ const handleExit = () => {
283
+ context.requestExit();
284
+ exit();
285
+ };
286
+ const isExtensionCommand = (text) => {
287
+ if (!text.startsWith("/")) {
288
+ return false;
289
+ }
290
+ const extensionRunner = context.session.extensionRunner;
291
+ if (!extensionRunner) {
292
+ return false;
293
+ }
294
+ const spaceIndex = text.indexOf(" ");
295
+ const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
296
+ return Boolean(extensionRunner.getCommand(commandName));
297
+ };
298
+ const flushCompactionQueueRef = useRef(null);
299
+ const { snapshot, toolExecutions, refresh } = useAgentSession(context.session, (status) => {
300
+ dispatch({ type: "set-status", status });
301
+ }, (event) => {
302
+ if (event.type === "session_compact") {
303
+ void flushCompactionQueueRef.current?.();
304
+ }
305
+ if (event.type === "auto_compaction_end" && !event.aborted && event.result) {
306
+ void flushCompactionQueueRef.current?.();
307
+ }
308
+ });
309
+ useEffect(() => {
310
+ dispatch({ type: "set-tool-executions", toolExecutions });
311
+ }, [toolExecutions]);
312
+ const refreshSessionView = () => {
313
+ dispatch({ type: "set-tool-executions", toolExecutions: {} });
314
+ refresh();
315
+ };
316
+ const resetSessionView = () => {
317
+ setDisplayBlocks([]);
318
+ refreshSessionView();
319
+ };
320
+ const triggerFooterRefresh = () => {
321
+ dispatch({ type: "footer-tick" });
322
+ };
323
+ const pendingMessages = [
324
+ ...context.session.getSteeringMessages().map((text, index) => ({
325
+ id: `session-steer-${index}-${text}`,
326
+ mode: "steer",
327
+ text,
328
+ source: "session",
329
+ })),
330
+ ...context.session.getFollowUpMessages().map((text, index) => ({
331
+ id: `session-follow-${index}-${text}`,
332
+ mode: "followUp",
333
+ text,
334
+ source: "session",
335
+ })),
336
+ ...compactionQueuedMessages.map((message) => ({
337
+ id: message.id,
338
+ mode: message.mode,
339
+ text: message.text,
340
+ source: "compaction",
341
+ })),
342
+ ];
343
+ const restoreQueuedMessagesToPrompt = (options) => {
344
+ const { steering, followUp } = context.session.clearQueue();
345
+ const queuedMessages = [
346
+ ...steering,
347
+ ...followUp,
348
+ ...compactionQueuedMessages.map((message) => message.text),
349
+ ];
350
+ setCompactionQueuedMessages([]);
351
+ if (queuedMessages.length === 0) {
352
+ if (options?.abort) {
353
+ void context.session.abort();
354
+ }
355
+ return 0;
356
+ }
357
+ const combinedText = [...queuedMessages, options?.currentText ?? state.input]
358
+ .filter((value) => value.trim().length > 0)
359
+ .join("\n\n");
360
+ setInput(combinedText);
361
+ if (options?.abort) {
362
+ void context.session.abort();
363
+ }
364
+ return queuedMessages.length;
365
+ };
366
+ const queueCompactionMessage = (text, mode) => {
367
+ setCompactionQueuedMessages((current) => [
368
+ ...current,
369
+ {
370
+ id: `${mode}:${Date.now()}:${current.length}`,
371
+ text,
372
+ mode,
373
+ },
374
+ ]);
375
+ };
376
+ const flushCompactionQueue = async () => {
377
+ if (compactionQueuedMessages.length === 0) {
378
+ return;
379
+ }
380
+ const queuedMessages = [...compactionQueuedMessages];
381
+ setCompactionQueuedMessages([]);
382
+ const restoreQueue = (error) => {
383
+ setCompactionQueuedMessages(queuedMessages);
384
+ setError(`Failed to send queued message${queuedMessages.length === 1 ? "" : "s"}: ${error instanceof Error ? error.message : String(error)}`);
385
+ };
386
+ try {
387
+ const firstPromptIndex = queuedMessages.findIndex((message) => !isExtensionCommand(message.text));
388
+ if (firstPromptIndex === -1) {
389
+ for (const message of queuedMessages) {
390
+ await context.session.prompt(message.text);
391
+ }
392
+ return;
393
+ }
394
+ for (const message of queuedMessages.slice(0, firstPromptIndex)) {
395
+ await context.session.prompt(message.text);
396
+ }
397
+ const firstPrompt = queuedMessages[firstPromptIndex];
398
+ const rest = queuedMessages.slice(firstPromptIndex + 1);
399
+ await context.session.prompt(firstPrompt.text);
400
+ for (const message of rest) {
401
+ if (isExtensionCommand(message.text)) {
402
+ await context.session.prompt(message.text);
403
+ continue;
404
+ }
405
+ await context.session.prompt(message.text, {
406
+ streamingBehavior: message.mode === "followUp" ? "followUp" : "steer",
407
+ });
408
+ }
409
+ setStatus(`Flushed ${queuedMessages.length} queued message${queuedMessages.length === 1 ? "" : "s"} after compaction.`, "success");
410
+ }
411
+ catch (error) {
412
+ restoreQueue(error);
413
+ }
414
+ };
415
+ flushCompactionQueueRef.current = flushCompactionQueue;
416
+ const cycleModel = async (direction) => {
417
+ try {
418
+ const result = await context.session.cycleModel(direction);
419
+ if (!result) {
420
+ setStatus(context.session.scopedModels.length > 0 ? "Only one model in scope." : "Only one model available.", "warning");
421
+ return;
422
+ }
423
+ refresh();
424
+ setStatus(`Switched to ${result.model.provider}/${result.model.id}.`, "success");
425
+ }
426
+ catch (error) {
427
+ setError(error instanceof Error ? error.message : String(error));
428
+ }
429
+ };
430
+ const toggleThinkingVisibility = () => {
431
+ const nextShowThinking = !state.showThinking;
432
+ context.session.settingsManager.setHideThinkingBlock(!nextShowThinking);
433
+ dispatch({ type: "set-show-thinking", value: nextShowThinking });
434
+ setStatus(`Thinking blocks ${nextShowThinking ? "visible" : "hidden"}.`, "success");
435
+ };
436
+ const toggleToolOutputExpansion = () => {
437
+ setToolOutputExpanded((current) => {
438
+ const next = !current;
439
+ setStatus(`Tool outputs ${next ? "expanded" : "collapsed"}.`, "success");
440
+ return next;
441
+ });
442
+ };
443
+ const openExternalEditor = async () => {
444
+ const editorCommand = process.env.VISUAL || process.env.EDITOR;
445
+ if (!editorCommand) {
446
+ setStatus("Set $VISUAL or $EDITOR to use the external editor shortcut.", "warning");
447
+ return;
448
+ }
449
+ const tempFile = join(tmpdir(), `indusagi-editor-${Date.now()}.md`);
450
+ const currentText = state.input;
451
+ try {
452
+ writeFileSync(tempFile, currentText, "utf-8");
453
+ process.stdout.write("\u001B[?25h");
454
+ const [editor, ...editorArgs] = editorCommand.split(" ").filter(Boolean);
455
+ const result = spawnSync(editor, [...editorArgs, tempFile], {
456
+ stdio: "inherit",
457
+ });
458
+ if (result.status === 0) {
459
+ const nextText = readFileSync(tempFile, "utf-8").replace(/\n$/, "");
460
+ setInput(nextText, nextText.length);
461
+ setStatus("Updated prompt from external editor.", "success");
462
+ }
463
+ }
464
+ catch (error) {
465
+ setError(`External editor failed: ${error instanceof Error ? error.message : String(error)}`);
466
+ }
467
+ finally {
468
+ try {
469
+ unlinkSync(tempFile);
470
+ }
471
+ catch { }
472
+ process.stdout.write("\u001B[?25l");
473
+ }
474
+ };
475
+ const dequeueQueuedMessages = () => {
476
+ const restored = restoreQueuedMessagesToPrompt();
477
+ if (restored === 0) {
478
+ setStatus("No queued messages to restore.", "warning");
479
+ return;
480
+ }
481
+ setStatus(`Restored ${restored} queued message${restored === 1 ? "" : "s"} to the prompt.`, "success");
482
+ };
483
+ const pasteClipboardImage = async () => {
484
+ try {
485
+ const image = await readClipboardImage();
486
+ if (!image) {
487
+ setStatus("No image was found in the clipboard.", "warning");
488
+ return;
489
+ }
490
+ const extension = extensionForImageMimeType(image.mimeType) ?? "png";
491
+ const filePath = join(tmpdir(), `indusagi-clipboard-${crypto.randomUUID()}.${extension}`);
492
+ writeFileSync(filePath, Buffer.from(image.bytes));
493
+ const nextValue = state.input.length > 0 && !/\s$/.test(state.input)
494
+ ? `${state.input} ${filePath}`
495
+ : `${state.input}${filePath}`;
496
+ setInput(nextValue, nextValue.length);
497
+ setStatus("Inserted clipboard image path into the prompt.", "success");
498
+ }
499
+ catch (error) {
500
+ setStatus(`Unable to paste clipboard image: ${error instanceof Error ? error.message : String(error)}`, "warning");
501
+ }
502
+ };
503
+ const suspendTerminal = () => {
504
+ if (process.platform === "win32") {
505
+ setStatus("Suspend is not available on Windows terminals.", "warning");
506
+ return;
507
+ }
508
+ process.once("SIGCONT", () => {
509
+ refresh();
510
+ triggerFooterRefresh();
511
+ setStatus("Resumed terminal session.", "success");
512
+ });
513
+ process.stdout.write("\u001B[?25h");
514
+ process.kill(0, "SIGTSTP");
515
+ };
516
+ const restoreDefaultTerminalTitle = () => {
517
+ customTerminalTitleRef.current = null;
518
+ const sessionName = context.session.sessionManager.getSessionName();
519
+ writeTerminalTitle(sessionName ? `${APP_NAME} ${VERSION} - ${sessionName}` : `${APP_NAME} ${VERSION}`);
520
+ };
521
+ const cancelExtensionOverlay = () => {
522
+ const current = extensionOverlayRef.current;
523
+ switch (current.kind) {
524
+ case "select":
525
+ current.resolve(undefined);
526
+ break;
527
+ case "confirm":
528
+ current.resolve(false);
529
+ break;
530
+ case "input":
531
+ case "editor":
532
+ current.resolve(undefined);
533
+ break;
534
+ case "custom":
535
+ current.cancel();
536
+ break;
537
+ case "none":
538
+ break;
539
+ }
540
+ setExtensionOverlayState({ kind: "none" });
541
+ };
542
+ const resetExtensionUi = () => {
543
+ cancelExtensionOverlay();
544
+ setExtensionEditor(null);
545
+ setExtensionHeader(null);
546
+ setExtensionFooter(null);
547
+ setExtensionWidgetsAbove(new Map());
548
+ setExtensionWidgetsBelow(new Map());
549
+ setExtensionWorkingMessage(undefined);
550
+ footerDataProvider.clearExtensionStatuses();
551
+ triggerFooterRefresh();
552
+ restoreDefaultTerminalTitle();
553
+ };
554
+ useEffect(() => {
555
+ overlayRef.current = state.overlay;
556
+ }, [state.overlay]);
557
+ useEffect(() => {
558
+ extensionOverlayRef.current = extensionOverlayState;
559
+ }, [extensionOverlayState]);
560
+ useEffect(() => {
561
+ const onResize = () => {
562
+ setTerminalRows(process.stdout.rows ?? 40);
563
+ setTerminalColumns(process.stdout.columns ?? 80);
564
+ };
565
+ process.stdout.on("resize", onResize);
566
+ return () => {
567
+ process.stdout.off("resize", onResize);
568
+ };
569
+ }, []);
570
+ const footerData = useFooterData(footerDataProvider, state.footerTick);
571
+ const theme = createThemeAdapter(state.themeName);
572
+ const showStartupDiagnostics = !startupDismissed;
573
+ const previousStartupDiagnosticsRef = useRef(showStartupDiagnostics);
574
+ function handleOAuthOverlayChange(partial) {
575
+ const current = overlayRef.current;
576
+ if (current.kind !== "oauth")
577
+ return;
578
+ setOverlay({ ...current, ...partial });
579
+ }
580
+ async function startOAuthLogin(provider) {
581
+ setOverlay({
582
+ kind: "oauth",
583
+ providerId: provider.id,
584
+ providerName: provider.label,
585
+ mode: "oauth",
586
+ inputLabel: "Authorization code",
587
+ inputValue: "",
588
+ accountId: "default",
589
+ accountName: "Default",
590
+ progress: `Credentials will be saved to ${getAuthPath()}.`,
591
+ });
592
+ try {
593
+ await context.session.modelRegistry.authStorage.login(provider.id, {
594
+ onAuth: (authInfo) => {
595
+ const opened = openAuthUrl(authInfo.url);
596
+ handleOAuthOverlayChange({
597
+ authInfo,
598
+ progress: opened
599
+ ? "Opened the login URL in Chrome. Complete login there, then paste the code if prompted."
600
+ : "Open the URL in your browser, then paste the code.",
601
+ });
602
+ },
603
+ onPrompt: (prompt) => new Promise((resolve) => {
604
+ oauthResolverRef.current = resolve;
605
+ handleOAuthOverlayChange({ prompt, inputLabel: prompt.message, inputValue: "" });
606
+ }),
607
+ onManualCodeInput: () => new Promise((resolve) => {
608
+ oauthResolverRef.current = resolve;
609
+ handleOAuthOverlayChange({
610
+ prompt: { message: "Paste the authorization code:" },
611
+ inputLabel: "Authorization code",
612
+ inputValue: "",
613
+ });
614
+ }),
615
+ onProgress: (message) => {
616
+ handleOAuthOverlayChange({ progress: message });
617
+ },
618
+ }, "default", "Default");
619
+ context.session.modelRegistry.refresh();
620
+ closeOverlay();
621
+ refresh();
622
+ setStatus(`Logged in to ${provider.id}.`, "success");
623
+ }
624
+ catch (error) {
625
+ closeOverlay();
626
+ setError(error instanceof Error ? error.message : String(error));
627
+ }
628
+ }
629
+ const { submitPrompt } = usePromptSubmit({
630
+ session: context.session,
631
+ dispatch,
632
+ routerContext: {
633
+ setStatus,
634
+ setError,
635
+ clearStatus,
636
+ setOverlay,
637
+ closeOverlay,
638
+ setInput,
639
+ appendDisplayBlock,
640
+ startOAuthLogin,
641
+ resetSessionView,
642
+ refreshSessionView,
643
+ onBeforeReload: resetExtensionUi,
644
+ onExit: handleExit,
645
+ },
646
+ onAfterSubmit: refresh,
647
+ onQueueDuringCompaction: queueCompactionMessage,
648
+ onShouldRunDuringCompaction: isExtensionCommand,
649
+ });
650
+ const submitPromptRef = useRef(submitPrompt);
651
+ const submitPromptWithStartupDismiss = async (input, mode = "followUp") => {
652
+ if (!startupDismissed && input.trim().length > 0) {
653
+ setStartupDismissed(true);
654
+ }
655
+ await submitPrompt(input, mode);
656
+ };
657
+ submitPromptRef.current = submitPromptWithStartupDismiss;
658
+ const handleExtensionShortcutKeyData = async (data) => {
659
+ const extensionRunner = context.session.extensionRunner;
660
+ if (!extensionRunner) {
661
+ return false;
662
+ }
663
+ const shortcuts = extensionRunner.getShortcuts(keybindings.getEffectiveConfig());
664
+ if (shortcuts.size === 0) {
665
+ return false;
666
+ }
667
+ const shortcutContext = {
668
+ ui: extensionUiContextRef.current ?? {
669
+ select: async () => undefined,
670
+ confirm: async () => false,
671
+ input: async () => undefined,
672
+ notify: () => { },
673
+ setStatus: () => { },
674
+ setWorkingMessage: () => { },
675
+ setWidget: () => { },
676
+ setFooter: () => { },
677
+ setHeader: () => { },
678
+ setTitle: () => { },
679
+ custom: async () => undefined,
680
+ setEditorText: () => { },
681
+ getEditorText: () => inputRef.current,
682
+ editor: async () => undefined,
683
+ setEditorComponent: () => { },
684
+ get theme() {
685
+ return extensionTheme;
686
+ },
687
+ getAllThemes: () => [],
688
+ getTheme: () => undefined,
689
+ setTheme: () => ({ success: false, error: "Extension UI is not ready yet." }),
690
+ },
691
+ hasUI: true,
692
+ cwd: process.cwd(),
693
+ sessionManager: context.session.sessionManager,
694
+ modelRegistry: context.session.modelRegistry,
695
+ model: context.session.model,
696
+ isIdle: () => !context.session.isStreaming,
697
+ abort: () => {
698
+ void context.session.abort();
699
+ },
700
+ hasPendingMessages: () => context.session.pendingMessageCount > 0,
701
+ shutdown: handleExit,
702
+ getContextUsage: () => context.session.getContextUsage(),
703
+ compact: (options) => {
704
+ void (async () => {
705
+ try {
706
+ const result = await context.session.compact(options?.customInstructions);
707
+ refreshSessionView();
708
+ options?.onComplete?.(result);
709
+ }
710
+ catch (error) {
711
+ const resolvedError = error instanceof Error ? error : new Error(String(error));
712
+ options?.onError?.(resolvedError);
713
+ }
714
+ })();
715
+ },
716
+ };
717
+ for (const [shortcutKey, shortcut] of shortcuts) {
718
+ if (!matchesKey(data, shortcutKey)) {
719
+ continue;
720
+ }
721
+ try {
722
+ await Promise.resolve(shortcut.handler(shortcutContext));
723
+ }
724
+ catch (error) {
725
+ setError(`Shortcut handler error: ${error instanceof Error ? error.message : String(error)}`);
726
+ }
727
+ return true;
728
+ }
729
+ return false;
730
+ };
731
+ useEffect(() => {
732
+ if (customTerminalTitleRef.current) {
733
+ return;
734
+ }
735
+ restoreDefaultTerminalTitle();
736
+ }, [snapshot.sessionName]);
737
+ useEffect(() => {
738
+ if (extensionOverlayState.kind === "none") {
739
+ return;
740
+ }
741
+ const timeoutAt = extensionOverlayState.kind === "select" ||
742
+ extensionOverlayState.kind === "confirm" ||
743
+ extensionOverlayState.kind === "input" ||
744
+ extensionOverlayState.kind === "editor"
745
+ ? extensionOverlayState.timeoutAt
746
+ : undefined;
747
+ if (!timeoutAt) {
748
+ return;
749
+ }
750
+ const remaining = timeoutAt - Date.now();
751
+ if (remaining <= 0) {
752
+ cancelExtensionOverlay();
753
+ return;
754
+ }
755
+ const timer = setTimeout(() => {
756
+ cancelExtensionOverlay();
757
+ }, remaining);
758
+ return () => {
759
+ clearTimeout(timer);
760
+ };
761
+ }, [extensionOverlayState]);
762
+ useEffect(() => {
763
+ if (!extensionEditor) {
764
+ return;
765
+ }
766
+ if (extensionEditor.component.getText() !== state.input) {
767
+ extensionEditor.component.setText(state.input);
768
+ extensionEditor.bridge.requestRender?.();
769
+ }
770
+ }, [extensionEditor, state.input]);
771
+ useEffect(() => {
772
+ const buildExtensionUiContext = () => ({
773
+ select: (title, options, opts) => new Promise((resolve) => {
774
+ if (opts?.signal?.aborted) {
775
+ resolve(undefined);
776
+ return;
777
+ }
778
+ const finalize = (() => {
779
+ let settled = false;
780
+ return (value) => {
781
+ if (settled) {
782
+ return;
783
+ }
784
+ settled = true;
785
+ opts?.signal?.removeEventListener("abort", onAbort);
786
+ setExtensionOverlayState({ kind: "none" });
787
+ resolve(value);
788
+ };
789
+ })();
790
+ const onAbort = () => {
791
+ finalize(undefined);
792
+ };
793
+ cancelExtensionOverlay();
794
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
795
+ setExtensionOverlayState({
796
+ kind: "select",
797
+ title,
798
+ options,
799
+ timeoutAt: opts?.timeout ? Date.now() + opts.timeout : undefined,
800
+ resolve: finalize,
801
+ });
802
+ }),
803
+ confirm: (title, message, opts) => new Promise((resolve) => {
804
+ if (opts?.signal?.aborted) {
805
+ resolve(false);
806
+ return;
807
+ }
808
+ const finalize = (() => {
809
+ let settled = false;
810
+ return (value) => {
811
+ if (settled) {
812
+ return;
813
+ }
814
+ settled = true;
815
+ opts?.signal?.removeEventListener("abort", onAbort);
816
+ setExtensionOverlayState({ kind: "none" });
817
+ resolve(value);
818
+ };
819
+ })();
820
+ const onAbort = () => {
821
+ finalize(false);
822
+ };
823
+ cancelExtensionOverlay();
824
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
825
+ setExtensionOverlayState({
826
+ kind: "confirm",
827
+ title,
828
+ message,
829
+ timeoutAt: opts?.timeout ? Date.now() + opts.timeout : undefined,
830
+ resolve: finalize,
831
+ });
832
+ }),
833
+ input: (title, placeholder, opts) => new Promise((resolve) => {
834
+ if (opts?.signal?.aborted) {
835
+ resolve(undefined);
836
+ return;
837
+ }
838
+ const finalize = (() => {
839
+ let settled = false;
840
+ return (value) => {
841
+ if (settled) {
842
+ return;
843
+ }
844
+ settled = true;
845
+ opts?.signal?.removeEventListener("abort", onAbort);
846
+ setExtensionOverlayState({ kind: "none" });
847
+ resolve(value);
848
+ };
849
+ })();
850
+ const onAbort = () => {
851
+ finalize(undefined);
852
+ };
853
+ cancelExtensionOverlay();
854
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
855
+ setExtensionOverlayState({
856
+ kind: "input",
857
+ title,
858
+ placeholder,
859
+ timeoutAt: opts?.timeout ? Date.now() + opts.timeout : undefined,
860
+ resolve: finalize,
861
+ });
862
+ }),
863
+ notify: (message, type) => {
864
+ if (type === "error") {
865
+ setError(message);
866
+ return;
867
+ }
868
+ if (type === "warning") {
869
+ setStatus(message, "warning");
870
+ return;
871
+ }
872
+ setStatus(message, "info");
873
+ },
874
+ setStatus: (key, text) => {
875
+ footerDataProvider.setExtensionStatus(key, text);
876
+ triggerFooterRefresh();
877
+ },
878
+ setWorkingMessage: (message) => {
879
+ setExtensionWorkingMessage(message);
880
+ },
881
+ setWidget: (key, content, options) => {
882
+ const placement = options?.placement ?? "aboveEditor";
883
+ const updateMap = placement === "belowEditor" ? setExtensionWidgetsBelow : setExtensionWidgetsAbove;
884
+ const clearOtherMap = placement === "belowEditor" ? setExtensionWidgetsAbove : setExtensionWidgetsBelow;
885
+ clearOtherMap((current) => {
886
+ if (!current.has(key)) {
887
+ return current;
888
+ }
889
+ const next = new Map(current);
890
+ next.delete(key);
891
+ return next;
892
+ });
893
+ updateMap((current) => {
894
+ const next = new Map(current);
895
+ if (content === undefined) {
896
+ next.delete(key);
897
+ return next;
898
+ }
899
+ if (Array.isArray(content)) {
900
+ next.set(key, { kind: "lines", lines: truncateWidgetLines(content) });
901
+ return next;
902
+ }
903
+ try {
904
+ next.set(key, {
905
+ kind: "component",
906
+ hosted: createHostedExtensionComponent((tui) => content(tui, extensionTheme)),
907
+ });
908
+ }
909
+ catch (error) {
910
+ setError(`Failed to render extension widget "${key}": ${error instanceof Error ? error.message : String(error)}`);
911
+ }
912
+ return next;
913
+ });
914
+ },
915
+ setFooter: (factory) => {
916
+ if (!factory) {
917
+ setExtensionFooter(null);
918
+ return;
919
+ }
920
+ try {
921
+ setExtensionFooter(createHostedExtensionComponent((tui) => factory(tui, extensionTheme, footerDataProvider)));
922
+ }
923
+ catch (error) {
924
+ setError(`Failed to render extension footer: ${error instanceof Error ? error.message : String(error)}`);
925
+ }
926
+ },
927
+ setHeader: (factory) => {
928
+ if (!factory) {
929
+ setExtensionHeader(null);
930
+ return;
931
+ }
932
+ try {
933
+ setExtensionHeader(createHostedExtensionComponent((tui) => factory(tui, extensionTheme)));
934
+ }
935
+ catch (error) {
936
+ setError(`Failed to render extension header: ${error instanceof Error ? error.message : String(error)}`);
937
+ }
938
+ },
939
+ setTitle: (title) => {
940
+ customTerminalTitleRef.current = title;
941
+ writeTerminalTitle(title);
942
+ },
943
+ custom: async (factory, options) => new Promise((resolve, reject) => {
944
+ let overlayHandleHidden = false;
945
+ const finish = (() => {
946
+ let settled = false;
947
+ return (value) => {
948
+ if (settled) {
949
+ return;
950
+ }
951
+ settled = true;
952
+ setExtensionOverlayState({ kind: "none" });
953
+ resolve(value);
954
+ };
955
+ })();
956
+ const cancel = () => {
957
+ setExtensionOverlayState({ kind: "none" });
958
+ resolve(undefined);
959
+ };
960
+ cancelExtensionOverlay();
961
+ const bridge = createExtensionTuiBridge();
962
+ Promise.resolve(factory(bridge, extensionTheme, keybindings, finish))
963
+ .then((component) => {
964
+ const hosted = createHostedExtensionComponentFromParts(component, bridge);
965
+ const handle = {
966
+ hide: () => {
967
+ overlayHandleHidden = true;
968
+ setExtensionOverlayState((current) => current.kind === "custom"
969
+ ? { ...current, hidden: true }
970
+ : current);
971
+ },
972
+ setHidden: (hidden) => {
973
+ overlayHandleHidden = hidden;
974
+ setExtensionOverlayState((current) => current.kind === "custom"
975
+ ? { ...current, hidden }
976
+ : current);
977
+ },
978
+ isHidden: () => overlayHandleHidden,
979
+ };
980
+ options?.onHandle?.(handle);
981
+ setExtensionOverlayState({
982
+ kind: "custom",
983
+ hosted,
984
+ mode: options?.overlay === true ? "overlay" : "inline",
985
+ hidden: false,
986
+ cancel: () => {
987
+ cancel();
988
+ },
989
+ });
990
+ })
991
+ .catch((error) => {
992
+ setExtensionOverlayState({ kind: "none" });
993
+ reject(error);
994
+ });
995
+ }),
996
+ setEditorText: (text) => {
997
+ setInput(text);
998
+ },
999
+ getEditorText: () => inputRef.current,
1000
+ editor: (title, prefill) => new Promise((resolve) => {
1001
+ const finalize = (() => {
1002
+ let settled = false;
1003
+ return (value) => {
1004
+ if (settled) {
1005
+ return;
1006
+ }
1007
+ settled = true;
1008
+ setExtensionOverlayState({ kind: "none" });
1009
+ resolve(value);
1010
+ };
1011
+ })();
1012
+ cancelExtensionOverlay();
1013
+ setExtensionOverlayState({
1014
+ kind: "editor",
1015
+ title,
1016
+ prefill,
1017
+ resolve: finalize,
1018
+ });
1019
+ }),
1020
+ setEditorComponent: (factory) => {
1021
+ if (!factory) {
1022
+ setExtensionEditor(null);
1023
+ return;
1024
+ }
1025
+ try {
1026
+ const hosted = createHostedExtensionComponent((tui) => {
1027
+ const editor = factory(tui, getEditorTheme(), keybindings);
1028
+ editor.onSubmit = (text) => {
1029
+ void submitPromptRef.current(text, "steer");
1030
+ };
1031
+ editor.onChange = (text) => {
1032
+ dispatch({ type: "set-input", value: text, cursorOffset: text.length });
1033
+ };
1034
+ editor.setText(inputRef.current);
1035
+ return editor;
1036
+ });
1037
+ setExtensionEditor(hosted);
1038
+ }
1039
+ catch (error) {
1040
+ setError(`Failed to enable extension editor: ${error instanceof Error ? error.message : String(error)}`);
1041
+ }
1042
+ },
1043
+ get theme() {
1044
+ return extensionTheme;
1045
+ },
1046
+ getAllThemes: () => getAvailableThemesWithPaths(),
1047
+ getTheme: (name) => getThemeByName(name),
1048
+ setTheme: (themeOrName) => {
1049
+ if (themeOrName instanceof Theme) {
1050
+ setThemeInstance(themeOrName);
1051
+ if (themeOrName.name) {
1052
+ context.session.settingsManager.setTheme(themeOrName.name);
1053
+ dispatch({ type: "set-theme-name", themeName: themeOrName.name });
1054
+ }
1055
+ triggerFooterRefresh();
1056
+ refresh();
1057
+ return { success: true };
1058
+ }
1059
+ const result = setTheme(themeOrName, true);
1060
+ if (result.success) {
1061
+ context.session.settingsManager.setTheme(themeOrName);
1062
+ dispatch({ type: "set-theme-name", themeName: themeOrName });
1063
+ triggerFooterRefresh();
1064
+ refresh();
1065
+ }
1066
+ return result;
1067
+ },
1068
+ });
1069
+ const uiContext = buildExtensionUiContext();
1070
+ extensionUiContextRef.current = uiContext;
1071
+ void context.session.bindExtensions({
1072
+ uiContext,
1073
+ commandContextActions: {
1074
+ waitForIdle: () => context.session.agent.waitForIdle(),
1075
+ newSession: async (options) => {
1076
+ const started = await context.session.newSession({ parentSession: options?.parentSession });
1077
+ if (!started) {
1078
+ return { cancelled: true };
1079
+ }
1080
+ if (options?.setup) {
1081
+ await options.setup(context.session.sessionManager);
1082
+ }
1083
+ resetSessionView();
1084
+ setInput("");
1085
+ setStatus("New session started.", "success");
1086
+ return { cancelled: false };
1087
+ },
1088
+ fork: async (entryId) => {
1089
+ const result = await context.session.fork(entryId);
1090
+ if (result.cancelled) {
1091
+ return { cancelled: true };
1092
+ }
1093
+ resetSessionView();
1094
+ setInput(result.selectedText);
1095
+ setStatus("Forked to new session.", "success");
1096
+ return { cancelled: false };
1097
+ },
1098
+ navigateTree: async (targetId, options) => {
1099
+ const result = await context.session.navigateTree(targetId, {
1100
+ summarize: options?.summarize,
1101
+ customInstructions: options?.customInstructions,
1102
+ replaceInstructions: options?.replaceInstructions,
1103
+ label: options?.label,
1104
+ });
1105
+ if (result.cancelled) {
1106
+ return { cancelled: true };
1107
+ }
1108
+ resetSessionView();
1109
+ if (result.editorText) {
1110
+ setInput(result.editorText);
1111
+ }
1112
+ setStatus("Navigated to selected point.", "success");
1113
+ return { cancelled: false };
1114
+ },
1115
+ },
1116
+ shutdownHandler: handleExit,
1117
+ onError: (error) => {
1118
+ setError(`Extension error in ${error.extensionPath}: ${error.error}`);
1119
+ },
1120
+ onHookError: (error) => {
1121
+ setError(`Hook error in ${error.hookPath}: ${error.error}`);
1122
+ },
1123
+ });
1124
+ return () => {
1125
+ resetExtensionUi();
1126
+ };
1127
+ }, [context.session, footerDataProvider, keybindings]);
1128
+ useEffect(() => {
1129
+ if (startupRanRef.current)
1130
+ return;
1131
+ startupRanRef.current = true;
1132
+ void (async () => {
1133
+ try {
1134
+ if (initialMessage) {
1135
+ setStatus("Sending startup prompt...", "busy");
1136
+ await context.session.prompt(initialMessage, { images: initialImages });
1137
+ }
1138
+ if (initialMessages) {
1139
+ for (const message of initialMessages) {
1140
+ await context.session.prompt(message);
1141
+ }
1142
+ }
1143
+ if (initialMessage || (initialMessages && initialMessages.length > 0)) {
1144
+ setStatus("Startup prompt completed.", "success");
1145
+ }
1146
+ }
1147
+ catch (error) {
1148
+ setError(error instanceof Error ? error.message : String(error));
1149
+ }
1150
+ finally {
1151
+ refresh();
1152
+ }
1153
+ })();
1154
+ }, [context.session, initialImages, initialMessage, initialMessages, refresh]);
1155
+ const extensionUiActive = Boolean(extensionEditor) ||
1156
+ (extensionOverlayState.kind !== "none" &&
1157
+ !(extensionOverlayState.kind === "custom" && extensionOverlayState.hidden));
1158
+ useAppKeybindings({
1159
+ session: context.session,
1160
+ overlayActive: state.overlay.kind !== "none" || extensionUiActive,
1161
+ onExit: handleExit,
1162
+ onOpenSettings: () => setOverlay({ kind: "settings" }),
1163
+ onOpenResume: () => {
1164
+ setOverlay({ kind: "session" });
1165
+ },
1166
+ onStatus: setStatus,
1167
+ });
1168
+ useEffect(() => {
1169
+ if (state.overlay.kind !== "session") {
1170
+ return;
1171
+ }
1172
+ let cancelled = false;
1173
+ void listCurrentSessions(context.session)
1174
+ .then((sessions) => {
1175
+ if (!cancelled) {
1176
+ setCurrentSessions(sessions);
1177
+ }
1178
+ })
1179
+ .catch((error) => {
1180
+ if (!cancelled) {
1181
+ setError(error instanceof Error ? error.message : String(error));
1182
+ }
1183
+ });
1184
+ return () => {
1185
+ cancelled = true;
1186
+ };
1187
+ }, [context.session, state.overlay.kind]);
1188
+ const settingsItems = useMemo(() => buildSettingsItems(context.session, state, () => dispatch({ type: "footer-tick" }), setError), [context.session, state]);
1189
+ const maxItems = Math.max(10, terminalRows - (state.overlay.kind === "none" ? 14 : 24));
1190
+ const effectiveStatus = state.status ??
1191
+ (extensionWorkingMessage &&
1192
+ (snapshot.isStreaming || snapshot.isCompacting || snapshot.isBashRunning || snapshot.pendingToolCallCount > 0)
1193
+ ? { kind: "busy", text: extensionWorkingMessage }
1194
+ : undefined);
1195
+ let overlay = null;
1196
+ let extensionOverlay = null;
1197
+ switch (state.overlay.kind) {
1198
+ case "settings":
1199
+ overlay = (_jsx(SettingsDialog, { items: settingsItems, onClose: closeOverlay }));
1200
+ break;
1201
+ case "model":
1202
+ overlay = (_jsx(ModelDialog, { models: context.session.modelRegistry.getAvailable(), onClose: closeOverlay, onSelect: async (model) => {
1203
+ try {
1204
+ await context.session.setModel(model);
1205
+ closeOverlay();
1206
+ refresh();
1207
+ setStatus(`Model set to ${model.provider}/${model.id}.`, "success");
1208
+ }
1209
+ catch (error) {
1210
+ setError(error instanceof Error ? error.message : String(error));
1211
+ }
1212
+ }, search: state.overlay.search }));
1213
+ break;
1214
+ case "scopedModels":
1215
+ const scopedModelsOverlay = state.overlay;
1216
+ overlay = (_jsx(ScopedModelsDialog, { models: scopedModelsOverlay.models, onClose: closeOverlay, onSave: async (selectedIds) => {
1217
+ try {
1218
+ const allIds = scopedModelsOverlay.models.map((model) => `${model.provider}/${model.id}`);
1219
+ if (selectedIds.length === 0 || selectedIds.length === allIds.length) {
1220
+ context.session.settingsManager.setEnabledModels(undefined);
1221
+ context.session.setScopedModels([]);
1222
+ closeOverlay();
1223
+ refresh();
1224
+ setStatus("Scoped model filter cleared. Ctrl+P will cycle all available models.", "success");
1225
+ return;
1226
+ }
1227
+ const resolved = await resolveModelScope(selectedIds, context.session.modelRegistry);
1228
+ context.session.settingsManager.setEnabledModels(selectedIds);
1229
+ context.session.setScopedModels(resolved.map((entry) => ({
1230
+ model: entry.model,
1231
+ thinkingLevel: entry.thinkingLevel ?? context.session.thinkingLevel,
1232
+ })));
1233
+ closeOverlay();
1234
+ refresh();
1235
+ setStatus(`Scoped model cycling to ${selectedIds.length} model(s).`, "success");
1236
+ }
1237
+ catch (error) {
1238
+ setError(error instanceof Error ? error.message : String(error));
1239
+ }
1240
+ }, selectedIds: scopedModelsOverlay.selectedIds }));
1241
+ break;
1242
+ case "theme":
1243
+ overlay = (_jsx(ThemeDialog, { themes: getAvailableThemes(), onClose: closeOverlay, onSelect: (themeName) => {
1244
+ const result = setTheme(themeName, true);
1245
+ if (!result.success) {
1246
+ setError(result.error ?? `Unable to load theme "${themeName}".`);
1247
+ return;
1248
+ }
1249
+ context.session.settingsManager.setTheme(themeName);
1250
+ dispatch({ type: "set-theme-name", themeName });
1251
+ dispatch({ type: "footer-tick" });
1252
+ closeOverlay();
1253
+ setStatus(`Theme set to ${themeName}.`, "success");
1254
+ } }));
1255
+ break;
1256
+ case "session":
1257
+ overlay = (_jsx(SessionDialog, { onClose: closeOverlay, currentSessionPath: context.session.sessionFile, onDeleteSession: async (item) => {
1258
+ try {
1259
+ if (item.path === context.session.sessionFile) {
1260
+ setStatus("Cannot delete the current active session from the picker.", "warning");
1261
+ return;
1262
+ }
1263
+ await deleteSessionAtPath(item.path);
1264
+ setCurrentSessions((sessions) => sessions.filter((session) => session.path !== item.path));
1265
+ setStatus("Deleted session.", "success");
1266
+ }
1267
+ catch (error) {
1268
+ setError(error instanceof Error ? error.message : String(error));
1269
+ }
1270
+ }, onLoadAllSessions: (onProgress) => listAllSessions(onProgress), onRenameSession: async (item, name) => {
1271
+ try {
1272
+ const resolvedName = await renameSessionAtPath(item.path, name);
1273
+ setCurrentSessions((sessions) => sessions.map((session) => session.path === item.path
1274
+ ? { ...session, name: resolvedName, modified: new Date(), lastModified: Date.now() }
1275
+ : session));
1276
+ if (item.path === context.session.sessionFile)
1277
+ refresh();
1278
+ setStatus(`Renamed session to ${resolvedName}.`, "success");
1279
+ }
1280
+ catch (error) {
1281
+ setError(error instanceof Error ? error.message : String(error));
1282
+ }
1283
+ }, onSelect: async (item) => {
1284
+ try {
1285
+ await context.session.switchSession(item.path);
1286
+ closeOverlay();
1287
+ resetSessionView();
1288
+ setStatus("Resumed session.", "success");
1289
+ }
1290
+ catch (error) {
1291
+ setError(error instanceof Error ? error.message : String(error));
1292
+ }
1293
+ }, currentSessions: currentSessions }));
1294
+ break;
1295
+ case "tree":
1296
+ overlay = (_jsx(TreeDialog, { items: state.overlay.items, onClose: closeOverlay, onSelect: async (item) => {
1297
+ if (!item.id) {
1298
+ setError("Navigation before the first message is not supported yet.");
1299
+ return;
1300
+ }
1301
+ try {
1302
+ const result = await context.session.navigateTree(item.id);
1303
+ closeOverlay();
1304
+ resetSessionView();
1305
+ if (result.editorText) {
1306
+ setInput(result.editorText);
1307
+ }
1308
+ setStatus("Navigated to the selected point.", "success");
1309
+ }
1310
+ catch (error) {
1311
+ setError(error instanceof Error ? error.message : String(error));
1312
+ }
1313
+ } }));
1314
+ break;
1315
+ case "userMessage":
1316
+ overlay = (_jsx(UserMessageDialog, { items: state.overlay.items, onClose: closeOverlay, onSelect: async (item) => {
1317
+ try {
1318
+ const result = await context.session.fork(item.entryId);
1319
+ closeOverlay();
1320
+ resetSessionView();
1321
+ if (!result.cancelled) {
1322
+ setInput(result.selectedText);
1323
+ setStatus("Forked to a new session branch.", "success");
1324
+ }
1325
+ }
1326
+ catch (error) {
1327
+ setError(error instanceof Error ? error.message : String(error));
1328
+ }
1329
+ } }));
1330
+ break;
1331
+ case "login":
1332
+ overlay = (_jsx(LoginDialog, { mode: "login", onClose: closeOverlay, onSelect: async (provider) => {
1333
+ if (provider.authKind === "oauth") {
1334
+ await startOAuthLogin(provider);
1335
+ return;
1336
+ }
1337
+ setOverlay({
1338
+ kind: "oauth",
1339
+ providerId: provider.id,
1340
+ providerName: provider.label,
1341
+ mode: "apiKey",
1342
+ inputLabel: `API key for ${provider.id}`,
1343
+ inputValue: "",
1344
+ accountId: "default",
1345
+ accountName: "Default",
1346
+ progress: `Credentials will be saved to ${getAuthPath()}.`,
1347
+ });
1348
+ }, providers: state.overlay.providers }));
1349
+ break;
1350
+ case "logout":
1351
+ overlay = (_jsx(LoginDialog, { mode: "logout", accounts: state.overlay.accounts, onClose: closeOverlay, onSelect: (account) => {
1352
+ context.session.modelRegistry.authStorage.logout(account.provider, account.accountId);
1353
+ context.session.modelRegistry.refresh();
1354
+ closeOverlay();
1355
+ refresh();
1356
+ setStatus(`Removed saved credential ${account.label}.`, "success");
1357
+ } }));
1358
+ break;
1359
+ case "oauth":
1360
+ const oauthState = state.overlay;
1361
+ overlay = (_jsx(OAuthDialog, { state: oauthState, onChange: handleOAuthOverlayChange, onClose: closeOverlay, onSubmit: async () => {
1362
+ if (oauthResolverRef.current) {
1363
+ const resolve = oauthResolverRef.current;
1364
+ oauthResolverRef.current = null;
1365
+ const value = oauthState.inputValue;
1366
+ handleOAuthOverlayChange({ inputValue: "", prompt: undefined });
1367
+ resolve(value);
1368
+ return;
1369
+ }
1370
+ if (oauthState.mode === "apiKey") {
1371
+ const value = oauthState.inputValue.trim();
1372
+ if (!value) {
1373
+ setError("API key cannot be empty.");
1374
+ return;
1375
+ }
1376
+ context.session.modelRegistry.authStorage.set(oauthState.providerId, "default", {
1377
+ type: "api_key",
1378
+ key: value,
1379
+ accountId: "default",
1380
+ accountName: "Default",
1381
+ });
1382
+ context.session.modelRegistry.refresh();
1383
+ closeOverlay();
1384
+ refresh();
1385
+ setStatus(`Saved API key for ${oauthState.providerId}.`, "success");
1386
+ }
1387
+ } }));
1388
+ break;
1389
+ case "none":
1390
+ break;
1391
+ }
1392
+ switch (extensionOverlayState.kind) {
1393
+ case "select":
1394
+ extensionOverlay = (_jsx(ExtensionSelectDialog, { onClose: () => extensionOverlayState.resolve(undefined), onSelect: (value) => extensionOverlayState.resolve(value), options: extensionOverlayState.options, timeoutAt: extensionOverlayState.timeoutAt, title: extensionOverlayState.title }));
1395
+ break;
1396
+ case "confirm":
1397
+ extensionOverlay = (_jsx(ExtensionSelectDialog, { onClose: () => extensionOverlayState.resolve(false), onSelect: (value) => extensionOverlayState.resolve(value === "Yes"), options: ["Yes", "No"], timeoutAt: extensionOverlayState.timeoutAt, title: `${extensionOverlayState.title}\n${extensionOverlayState.message}` }));
1398
+ break;
1399
+ case "input":
1400
+ extensionOverlay = (_jsx(ExtensionTextDialog, { onClose: () => extensionOverlayState.resolve(undefined), onSubmit: (value) => extensionOverlayState.resolve(value), placeholder: extensionOverlayState.placeholder, timeoutAt: extensionOverlayState.timeoutAt, title: extensionOverlayState.title }));
1401
+ break;
1402
+ case "editor":
1403
+ extensionOverlay = (_jsx(ExtensionTextDialog, { multiline: true, onClose: () => extensionOverlayState.resolve(undefined), onSubmit: (value) => extensionOverlayState.resolve(value), prefill: extensionOverlayState.prefill, timeoutAt: extensionOverlayState.timeoutAt, title: extensionOverlayState.title }));
1404
+ break;
1405
+ case "custom":
1406
+ if (extensionOverlayState.mode === "overlay" && !extensionOverlayState.hidden) {
1407
+ extensionOverlay = (_jsx(ExtensionComponentHost, { active: true, hosted: extensionOverlayState.hosted, width: terminalColumns }));
1408
+ }
1409
+ break;
1410
+ case "none":
1411
+ break;
1412
+ }
1413
+ useEffect(() => {
1414
+ if (!startupDismissed && snapshot.messages.length > 0) {
1415
+ setStartupDismissed(true);
1416
+ }
1417
+ }, [snapshot.messages.length, startupDismissed]);
1418
+ useEffect(() => {
1419
+ const nextShowThinking = !context.session.settingsManager.getHideThinkingBlock();
1420
+ const nextShowImages = context.session.settingsManager.getShowImages();
1421
+ const nextThemeName = context.session.settingsManager.getTheme() ?? "dark";
1422
+ if (state.showThinking !== nextShowThinking) {
1423
+ dispatch({ type: "set-show-thinking", value: nextShowThinking });
1424
+ }
1425
+ if (state.showImages !== nextShowImages) {
1426
+ dispatch({ type: "set-show-images", value: nextShowImages });
1427
+ }
1428
+ if (state.themeName !== nextThemeName) {
1429
+ dispatch({ type: "set-theme-name", themeName: nextThemeName });
1430
+ }
1431
+ }, [context.session, state.footerTick, state.showImages, state.showThinking, state.themeName]);
1432
+ useEffect(() => {
1433
+ if (previousStartupDiagnosticsRef.current && !showStartupDiagnostics && process.stdout.isTTY) {
1434
+ process.stdout.write("\u001B[2J\u001B[3J\u001B[H");
1435
+ setLayoutEpoch((current) => current + 1);
1436
+ }
1437
+ previousStartupDiagnosticsRef.current = showStartupDiagnostics;
1438
+ }, [showStartupDiagnostics]);
1439
+ return (_jsxs(Box, { flexDirection: "column", children: [extensionHeader ? (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(ExtensionComponentHost, { hosted: extensionHeader, width: terminalColumns }) })) : (_jsx(Header, { collapseChangelog: context.session.settingsManager.getCollapseChangelog(), sessionName: snapshot.sessionName, showBranding: Boolean(verbose) || !context.session.settingsManager.getQuietStartup(), startupChangelog: startupChangelog, startupDiagnostics: showStartupDiagnostics ? startupDiagnostics : undefined, startupNotices: startupNotices, theme: theme })), _jsx(MessageList, { displayBlocks: displayBlocks, expandToolOutputs: toolOutputExpanded, maxItems: maxItems, messages: snapshot.messages, showImages: state.showImages, showThinking: state.showThinking, theme: theme }), _jsx(TaskPanel, { expandToolOutputs: toolOutputExpanded, pendingMessages: pendingMessages, snapshot: snapshot, theme: theme, toolExecutions: state.toolExecutions }), _jsx(StatusLine, { snapshot: snapshot, status: effectiveStatus, theme: theme }), Array.from(extensionWidgetsAbove.entries()).map(([key, widget]) => widget.kind === "lines" ? (_jsx(Box, { marginTop: 1, children: renderTextLines(widget.lines, `widget-above:${key}`) }, `widget-above:${key}`)) : (_jsx(Box, { marginTop: 1, children: _jsx(ExtensionComponentHost, { hosted: widget.hosted, maxLines: 10, width: terminalColumns }) }, `widget-above:${key}`))), extensionEditor ? (_jsx(Box, { marginTop: 1, children: _jsx(ExtensionComponentHost, { active: true, hosted: extensionEditor, onKeyData: handleExtensionShortcutKeyData, width: terminalColumns }) })) : extensionOverlayState.kind === "custom" &&
1440
+ extensionOverlayState.mode === "inline" &&
1441
+ !extensionOverlayState.hidden ? (_jsx(Box, { marginTop: 1, children: _jsx(ExtensionComponentHost, { active: true, hosted: extensionOverlayState.hosted, width: terminalColumns }) })) : (_jsx(PromptInput, { cursorOffset: state.cursorOffset, disabled: state.overlay.kind !== "none" || extensionUiActive, dispatch: dispatch, input: state.input, keybindings: keybindings, onCancelActiveWork: async (kind) => {
1442
+ if (kind === "bash") {
1443
+ context.session.abortBash();
1444
+ setStatus("Cancelled bash command.", "warning");
1445
+ return;
1446
+ }
1447
+ if (context.session.isCompacting) {
1448
+ context.session.abortCompaction();
1449
+ setStatus("Cancelling compaction...", "warning");
1450
+ return;
1451
+ }
1452
+ const restored = restoreQueuedMessagesToPrompt({ abort: true });
1453
+ refresh();
1454
+ if (restored > 0) {
1455
+ setStatus(`Cancelled active work and restored ${restored} queued message${restored === 1 ? "" : "s"}.`, "warning");
1456
+ }
1457
+ else {
1458
+ setStatus("Cancelled active work.", "warning");
1459
+ }
1460
+ }, onCycleModel: cycleModel, onDequeue: dequeueQueuedMessages, onExit: handleExit, onExternalEditor: openExternalEditor, onKeyData: handleExtensionShortcutKeyData, onOpenModelSelector: () => setOverlay({ kind: "model" }), onOpenFork: () => setOverlay({ kind: "userMessage", items: listUserMessages(context.session) }), onOpenTree: () => setOverlay({ kind: "tree", items: flattenSessionTree(context.session) }), onPasteClipboardImage: pasteClipboardImage, onStatus: setStatus, onSubmit: (value) => submitPromptWithStartupDismiss(value ?? state.input, "steer"), onSubmitFollowUp: (value) => submitPromptWithStartupDismiss(value ?? state.input, "followUp"), onSubmitSteer: (value) => submitPromptWithStartupDismiss(value ?? state.input, "steer"), onSuspend: suspendTerminal, onThinkingLevelChange: (level) => {
1461
+ refresh();
1462
+ setStatus(`Thinking level: ${level}`, "success");
1463
+ }, onToggleThinkingVisibility: toggleThinkingVisibility, onToggleToolExpansion: toggleToolOutputExpansion, session: context.session, theme: theme })), Array.from(extensionWidgetsBelow.entries()).map(([key, widget]) => widget.kind === "lines" ? (_jsx(Box, { marginTop: 1, children: renderTextLines(widget.lines, `widget-below:${key}`) }, `widget-below:${key}`)) : (_jsx(Box, { marginTop: 1, children: _jsx(ExtensionComponentHost, { hosted: widget.hosted, maxLines: 10, width: terminalColumns }) }, `widget-below:${key}`))), extensionFooter ? (_jsx(ExtensionComponentHost, { hosted: extensionFooter, width: terminalColumns })) : (_jsx(Footer, { availableProviderCount: footerData.availableProviderCount, branch: footerData.branch, extensionStatuses: footerData.extensionStatuses, snapshot: snapshot, theme: theme })), overlay, extensionOverlay, state.overlay.kind === "none" && extensionOverlayState.kind === "none" ? null : (_jsx(Text, { children: theme.muted("Dialogs pause typing in the main prompt until they close.") }))] }, layoutEpoch));
1464
+ }
1465
+ //# sourceMappingURL=AppShell.js.map