@openadapter/koda 1.0.0-beta.3

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 (357) hide show
  1. package/CHANGELOG.md +4448 -0
  2. package/README.md +665 -0
  3. package/dist/bun/cli.d.ts +2 -0
  4. package/dist/bun/cli.js +2 -0
  5. package/dist/bun/register-bedrock.d.ts +1 -0
  6. package/dist/bun/register-bedrock.js +1 -0
  7. package/dist/bun/restore-sandbox-env.d.ts +12 -0
  8. package/dist/bun/restore-sandbox-env.js +1 -0
  9. package/dist/cli/args.d.ts +55 -0
  10. package/dist/cli/args.js +167 -0
  11. package/dist/cli/config-selector.d.ts +13 -0
  12. package/dist/cli/config-selector.js +1 -0
  13. package/dist/cli/file-processor.d.ts +14 -0
  14. package/dist/cli/file-processor.js +7 -0
  15. package/dist/cli/import-sessions.d.ts +34 -0
  16. package/dist/cli/import-sessions.js +6 -0
  17. package/dist/cli/initial-message.d.ts +17 -0
  18. package/dist/cli/initial-message.js +1 -0
  19. package/dist/cli/list-models.d.ts +8 -0
  20. package/dist/cli/list-models.js +2 -0
  21. package/dist/cli/openadapter-setup.d.ts +29 -0
  22. package/dist/cli/openadapter-setup.js +3 -0
  23. package/dist/cli/session-picker.d.ts +8 -0
  24. package/dist/cli/session-picker.js +1 -0
  25. package/dist/cli.d.ts +2 -0
  26. package/dist/cli.js +2 -0
  27. package/dist/config.d.ts +92 -0
  28. package/dist/config.js +1 -0
  29. package/dist/core/agent-session-runtime.d.ts +116 -0
  30. package/dist/core/agent-session-runtime.js +1 -0
  31. package/dist/core/agent-session-services.d.ts +86 -0
  32. package/dist/core/agent-session-services.js +1 -0
  33. package/dist/core/agent-session.d.ts +747 -0
  34. package/dist/core/agent-session.js +32 -0
  35. package/dist/core/auth-guidance.d.ts +4 -0
  36. package/dist/core/auth-guidance.js +8 -0
  37. package/dist/core/auth-storage.d.ts +140 -0
  38. package/dist/core/auth-storage.js +1 -0
  39. package/dist/core/bash-executor.d.ts +31 -0
  40. package/dist/core/bash-executor.js +1 -0
  41. package/dist/core/compaction/branch-summarization.d.ts +89 -0
  42. package/dist/core/compaction/branch-summarization.js +38 -0
  43. package/dist/core/compaction/compaction.d.ts +120 -0
  44. package/dist/core/compaction/compaction.js +104 -0
  45. package/dist/core/compaction/index.d.ts +6 -0
  46. package/dist/core/compaction/index.js +1 -0
  47. package/dist/core/compaction/utils.d.ts +37 -0
  48. package/dist/core/compaction/utils.js +19 -0
  49. package/dist/core/defaults.d.ts +2 -0
  50. package/dist/core/defaults.js +1 -0
  51. package/dist/core/diagnostics.d.ts +14 -0
  52. package/dist/core/diagnostics.js +0 -0
  53. package/dist/core/event-bus.d.ts +8 -0
  54. package/dist/core/event-bus.js +1 -0
  55. package/dist/core/exec.d.ts +28 -0
  56. package/dist/core/exec.js +1 -0
  57. package/dist/core/export-html/ansi-to-html.d.ts +21 -0
  58. package/dist/core/export-html/ansi-to-html.js +1 -0
  59. package/dist/core/export-html/index.d.ts +36 -0
  60. package/dist/core/export-html/index.js +2 -0
  61. package/dist/core/export-html/template.css +1066 -0
  62. package/dist/core/export-html/template.html +55 -0
  63. package/dist/core/export-html/template.js +72 -0
  64. package/dist/core/export-html/tool-renderer.d.ts +33 -0
  65. package/dist/core/export-html/tool-renderer.js +1 -0
  66. package/dist/core/export-html/vendor/highlight.min.js +8 -0
  67. package/dist/core/export-html/vendor/marked.min.js +56 -0
  68. package/dist/core/extensions/index.d.ts +11 -0
  69. package/dist/core/extensions/index.js +1 -0
  70. package/dist/core/extensions/loader.d.ts +23 -0
  71. package/dist/core/extensions/loader.js +1 -0
  72. package/dist/core/extensions/runner.d.ts +160 -0
  73. package/dist/core/extensions/runner.js +1 -0
  74. package/dist/core/extensions/types.d.ts +1180 -0
  75. package/dist/core/extensions/types.js +1 -0
  76. package/dist/core/extensions/wrapper.d.ts +19 -0
  77. package/dist/core/extensions/wrapper.js +1 -0
  78. package/dist/core/footer-data-provider.d.ts +53 -0
  79. package/dist/core/footer-data-provider.js +1 -0
  80. package/dist/core/http-dispatcher.d.ts +20 -0
  81. package/dist/core/http-dispatcher.js +1 -0
  82. package/dist/core/index.d.ts +11 -0
  83. package/dist/core/index.js +1 -0
  84. package/dist/core/keybindings.d.ts +352 -0
  85. package/dist/core/keybindings.js +1 -0
  86. package/dist/core/messages.d.ts +76 -0
  87. package/dist/core/messages.js +17 -0
  88. package/dist/core/model-registry.d.ts +149 -0
  89. package/dist/core/model-registry.js +9 -0
  90. package/dist/core/model-resolver.d.ts +109 -0
  91. package/dist/core/model-resolver.js +1 -0
  92. package/dist/core/output-guard.d.ts +6 -0
  93. package/dist/core/output-guard.js +1 -0
  94. package/dist/core/package-manager.d.ts +203 -0
  95. package/dist/core/package-manager.js +3 -0
  96. package/dist/core/prompt-templates.d.ts +51 -0
  97. package/dist/core/prompt-templates.js +2 -0
  98. package/dist/core/provider-attribution.d.ts +3 -0
  99. package/dist/core/provider-attribution.js +1 -0
  100. package/dist/core/provider-display-names.d.ts +1 -0
  101. package/dist/core/provider-display-names.js +1 -0
  102. package/dist/core/resolve-config-value.d.ts +30 -0
  103. package/dist/core/resolve-config-value.js +1 -0
  104. package/dist/core/resource-loader.d.ts +193 -0
  105. package/dist/core/resource-loader.js +1 -0
  106. package/dist/core/sdk.d.ts +108 -0
  107. package/dist/core/sdk.js +1 -0
  108. package/dist/core/session-cwd.d.ts +18 -0
  109. package/dist/core/session-cwd.js +7 -0
  110. package/dist/core/session-manager.d.ts +331 -0
  111. package/dist/core/session-manager.js +11 -0
  112. package/dist/core/settings-manager.d.ts +265 -0
  113. package/dist/core/settings-manager.js +1 -0
  114. package/dist/core/skills.d.ts +59 -0
  115. package/dist/core/skills.js +4 -0
  116. package/dist/core/slash-commands.d.ts +13 -0
  117. package/dist/core/slash-commands.js +1 -0
  118. package/dist/core/source-info.d.ts +17 -0
  119. package/dist/core/source-info.js +1 -0
  120. package/dist/core/system-prompt.d.ts +27 -0
  121. package/dist/core/system-prompt.js +52 -0
  122. package/dist/core/telemetry.d.ts +2 -0
  123. package/dist/core/telemetry.js +1 -0
  124. package/dist/core/timings.d.ts +7 -0
  125. package/dist/core/timings.js +3 -0
  126. package/dist/core/tools/bash.d.ts +67 -0
  127. package/dist/core/tools/bash.js +18 -0
  128. package/dist/core/tools/edit-diff.d.ts +86 -0
  129. package/dist/core/tools/edit-diff.js +16 -0
  130. package/dist/core/tools/edit.d.ts +50 -0
  131. package/dist/core/tools/edit.js +2 -0
  132. package/dist/core/tools/file-mutation-queue.d.ts +5 -0
  133. package/dist/core/tools/file-mutation-queue.js +1 -0
  134. package/dist/core/tools/find.d.ts +34 -0
  135. package/dist/core/tools/find.js +13 -0
  136. package/dist/core/tools/grep.d.ts +36 -0
  137. package/dist/core/tools/grep.js +13 -0
  138. package/dist/core/tools/index.d.ts +39 -0
  139. package/dist/core/tools/index.js +1 -0
  140. package/dist/core/tools/ls.d.ts +36 -0
  141. package/dist/core/tools/ls.js +9 -0
  142. package/dist/core/tools/output-accumulator.d.ts +51 -0
  143. package/dist/core/tools/output-accumulator.js +4 -0
  144. package/dist/core/tools/path-utils.d.ts +9 -0
  145. package/dist/core/tools/path-utils.js +1 -0
  146. package/dist/core/tools/read.d.ts +34 -0
  147. package/dist/core/tools/read.js +22 -0
  148. package/dist/core/tools/render-utils.d.ts +23 -0
  149. package/dist/core/tools/render-utils.js +4 -0
  150. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -0
  151. package/dist/core/tools/tool-definition-wrapper.js +1 -0
  152. package/dist/core/tools/truncate.d.ts +69 -0
  153. package/dist/core/tools/truncate.js +5 -0
  154. package/dist/core/tools/write.d.ts +25 -0
  155. package/dist/core/tools/write.js +13 -0
  156. package/dist/index.d.ts +30 -0
  157. package/dist/index.js +1 -0
  158. package/dist/main.d.ts +11 -0
  159. package/dist/main.js +1 -0
  160. package/dist/migrations.d.ts +32 -0
  161. package/dist/migrations.js +8 -0
  162. package/dist/modes/index.d.ts +8 -0
  163. package/dist/modes/index.js +1 -0
  164. package/dist/modes/interactive/assets/clankolas.png +0 -0
  165. package/dist/modes/interactive/components/armin.d.ts +33 -0
  166. package/dist/modes/interactive/components/armin.js +1 -0
  167. package/dist/modes/interactive/components/assistant-message.d.ts +19 -0
  168. package/dist/modes/interactive/components/assistant-message.js +1 -0
  169. package/dist/modes/interactive/components/bash-execution.d.ts +33 -0
  170. package/dist/modes/interactive/components/bash-execution.js +13 -0
  171. package/dist/modes/interactive/components/bordered-loader.d.ts +15 -0
  172. package/dist/modes/interactive/components/bordered-loader.js +1 -0
  173. package/dist/modes/interactive/components/branch-summary-message.d.ts +15 -0
  174. package/dist/modes/interactive/components/branch-summary-message.js +3 -0
  175. package/dist/modes/interactive/components/compaction-summary-message.d.ts +15 -0
  176. package/dist/modes/interactive/components/compaction-summary-message.js +3 -0
  177. package/dist/modes/interactive/components/config-selector.d.ts +70 -0
  178. package/dist/modes/interactive/components/config-selector.js +1 -0
  179. package/dist/modes/interactive/components/countdown-timer.d.ts +13 -0
  180. package/dist/modes/interactive/components/countdown-timer.js +1 -0
  181. package/dist/modes/interactive/components/custom-editor.d.ts +20 -0
  182. package/dist/modes/interactive/components/custom-editor.js +1 -0
  183. package/dist/modes/interactive/components/custom-message.d.ts +19 -0
  184. package/dist/modes/interactive/components/custom-message.js +2 -0
  185. package/dist/modes/interactive/components/daxnuts.d.ts +22 -0
  186. package/dist/modes/interactive/components/daxnuts.js +1 -0
  187. package/dist/modes/interactive/components/diff.d.ts +11 -0
  188. package/dist/modes/interactive/components/diff.js +3 -0
  189. package/dist/modes/interactive/components/dynamic-border.d.ts +14 -0
  190. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  191. package/dist/modes/interactive/components/earendil-announcement.d.ts +4 -0
  192. package/dist/modes/interactive/components/earendil-announcement.js +1 -0
  193. package/dist/modes/interactive/components/extension-editor.d.ts +19 -0
  194. package/dist/modes/interactive/components/extension-editor.js +3 -0
  195. package/dist/modes/interactive/components/extension-input.d.ts +22 -0
  196. package/dist/modes/interactive/components/extension-input.js +2 -0
  197. package/dist/modes/interactive/components/extension-selector.d.ts +25 -0
  198. package/dist/modes/interactive/components/extension-selector.js +2 -0
  199. package/dist/modes/interactive/components/footer.d.ts +27 -0
  200. package/dist/modes/interactive/components/footer.js +1 -0
  201. package/dist/modes/interactive/components/index.d.ts +31 -0
  202. package/dist/modes/interactive/components/index.js +1 -0
  203. package/dist/modes/interactive/components/keybinding-hints.d.ts +12 -0
  204. package/dist/modes/interactive/components/keybinding-hints.js +1 -0
  205. package/dist/modes/interactive/components/login-dialog.d.ts +51 -0
  206. package/dist/modes/interactive/components/login-dialog.js +1 -0
  207. package/dist/modes/interactive/components/model-selector.d.ts +46 -0
  208. package/dist/modes/interactive/components/model-selector.js +2 -0
  209. package/dist/modes/interactive/components/oauth-selector.d.ts +30 -0
  210. package/dist/modes/interactive/components/oauth-selector.js +1 -0
  211. package/dist/modes/interactive/components/scoped-models-selector.d.ts +41 -0
  212. package/dist/modes/interactive/components/scoped-models-selector.js +1 -0
  213. package/dist/modes/interactive/components/session-selector-search.d.ts +22 -0
  214. package/dist/modes/interactive/components/session-selector-search.js +1 -0
  215. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  216. package/dist/modes/interactive/components/session-selector.js +2 -0
  217. package/dist/modes/interactive/components/settings-selector.d.ts +68 -0
  218. package/dist/modes/interactive/components/settings-selector.js +1 -0
  219. package/dist/modes/interactive/components/show-images-selector.d.ts +9 -0
  220. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  221. package/dist/modes/interactive/components/skill-invocation-message.d.ts +16 -0
  222. package/dist/modes/interactive/components/skill-invocation-message.js +3 -0
  223. package/dist/modes/interactive/components/theme-selector.d.ts +10 -0
  224. package/dist/modes/interactive/components/theme-selector.js +1 -0
  225. package/dist/modes/interactive/components/thinking-selector.d.ts +10 -0
  226. package/dist/modes/interactive/components/thinking-selector.js +1 -0
  227. package/dist/modes/interactive/components/tool-execution.d.ts +62 -0
  228. package/dist/modes/interactive/components/tool-execution.js +4 -0
  229. package/dist/modes/interactive/components/tree-selector.d.ts +88 -0
  230. package/dist/modes/interactive/components/tree-selector.js +1 -0
  231. package/dist/modes/interactive/components/user-message-selector.d.ts +29 -0
  232. package/dist/modes/interactive/components/user-message-selector.js +1 -0
  233. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  234. package/dist/modes/interactive/components/user-message.js +1 -0
  235. package/dist/modes/interactive/components/visual-truncate.d.ts +23 -0
  236. package/dist/modes/interactive/components/visual-truncate.js +1 -0
  237. package/dist/modes/interactive/interactive-mode.d.ts +417 -0
  238. package/dist/modes/interactive/interactive-mode.js +116 -0
  239. package/dist/modes/interactive/theme/dark.json +86 -0
  240. package/dist/modes/interactive/theme/light.json +85 -0
  241. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  242. package/dist/modes/interactive/theme/theme.d.ts +101 -0
  243. package/dist/modes/interactive/theme/theme.js +18 -0
  244. package/dist/modes/print-mode.d.ts +27 -0
  245. package/dist/modes/print-mode.js +4 -0
  246. package/dist/modes/rpc/jsonl.d.ts +16 -0
  247. package/dist/modes/rpc/jsonl.js +3 -0
  248. package/dist/modes/rpc/rpc-client.d.ts +226 -0
  249. package/dist/modes/rpc/rpc-client.js +1 -0
  250. package/dist/modes/rpc/rpc-mode.d.ts +19 -0
  251. package/dist/modes/rpc/rpc-mode.js +1 -0
  252. package/dist/modes/rpc/rpc-types.d.ts +419 -0
  253. package/dist/modes/rpc/rpc-types.js +0 -0
  254. package/dist/package-manager-cli.d.ts +3 -0
  255. package/dist/package-manager-cli.js +49 -0
  256. package/dist/utils/ansi.d.ts +1 -0
  257. package/dist/utils/ansi.js +1 -0
  258. package/dist/utils/auto-update.d.ts +13 -0
  259. package/dist/utils/auto-update.js +1 -0
  260. package/dist/utils/changelog.d.ts +20 -0
  261. package/dist/utils/changelog.js +4 -0
  262. package/dist/utils/child-process.d.ts +14 -0
  263. package/dist/utils/child-process.js +1 -0
  264. package/dist/utils/clipboard-image.d.ts +10 -0
  265. package/dist/utils/clipboard-image.js +1 -0
  266. package/dist/utils/clipboard-native.d.ts +9 -0
  267. package/dist/utils/clipboard-native.js +1 -0
  268. package/dist/utils/clipboard.d.ts +1 -0
  269. package/dist/utils/clipboard.js +1 -0
  270. package/dist/utils/deprecation.d.ts +3 -0
  271. package/dist/utils/deprecation.js +1 -0
  272. package/dist/utils/exif-orientation.d.ts +4 -0
  273. package/dist/utils/exif-orientation.js +1 -0
  274. package/dist/utils/frontmatter.d.ts +7 -0
  275. package/dist/utils/frontmatter.js +4 -0
  276. package/dist/utils/fs-watch.d.ts +4 -0
  277. package/dist/utils/fs-watch.js +1 -0
  278. package/dist/utils/git.d.ts +25 -0
  279. package/dist/utils/git.js +1 -0
  280. package/dist/utils/html.d.ts +6 -0
  281. package/dist/utils/html.js +1 -0
  282. package/dist/utils/image-convert.d.ts +8 -0
  283. package/dist/utils/image-convert.js +1 -0
  284. package/dist/utils/image-resize-core.d.ts +29 -0
  285. package/dist/utils/image-resize-core.js +1 -0
  286. package/dist/utils/image-resize-worker.d.ts +1 -0
  287. package/dist/utils/image-resize-worker.js +1 -0
  288. package/dist/utils/image-resize.d.ts +15 -0
  289. package/dist/utils/image-resize.js +1 -0
  290. package/dist/utils/json.d.ts +2 -0
  291. package/dist/utils/json.js +1 -0
  292. package/dist/utils/koda-user-agent.d.ts +1 -0
  293. package/dist/utils/koda-user-agent.js +1 -0
  294. package/dist/utils/mime.d.ts +2 -0
  295. package/dist/utils/mime.js +1 -0
  296. package/dist/utils/paths.d.ts +30 -0
  297. package/dist/utils/paths.js +1 -0
  298. package/dist/utils/photon.d.ts +20 -0
  299. package/dist/utils/photon.js +1 -0
  300. package/dist/utils/shell.d.ts +29 -0
  301. package/dist/utils/shell.js +8 -0
  302. package/dist/utils/sleep.d.ts +4 -0
  303. package/dist/utils/sleep.js +1 -0
  304. package/dist/utils/syntax-highlight.d.ts +11 -0
  305. package/dist/utils/syntax-highlight.js +2 -0
  306. package/dist/utils/tools-manager.d.ts +2 -0
  307. package/dist/utils/tools-manager.js +1 -0
  308. package/dist/utils/version-check.d.ts +14 -0
  309. package/dist/utils/version-check.js +1 -0
  310. package/dist/utils/windows-self-update.d.ts +2 -0
  311. package/dist/utils/windows-self-update.js +1 -0
  312. package/docs/compaction.md +394 -0
  313. package/docs/custom-provider.md +736 -0
  314. package/docs/development.md +71 -0
  315. package/docs/docs.json +148 -0
  316. package/docs/extensions.md +2626 -0
  317. package/docs/images/doom-extension.png +0 -0
  318. package/docs/images/exy.png +0 -0
  319. package/docs/images/interactive-mode.png +0 -0
  320. package/docs/images/tree-view.png +0 -0
  321. package/docs/index.md +80 -0
  322. package/docs/json.md +82 -0
  323. package/docs/keybindings.md +197 -0
  324. package/docs/models.md +493 -0
  325. package/docs/packages.md +226 -0
  326. package/docs/prompt-templates.md +88 -0
  327. package/docs/providers.md +253 -0
  328. package/docs/quickstart.md +165 -0
  329. package/docs/rpc.md +1408 -0
  330. package/docs/sdk.md +1137 -0
  331. package/docs/session-format.md +412 -0
  332. package/docs/sessions.md +145 -0
  333. package/docs/settings.md +281 -0
  334. package/docs/shell-aliases.md +13 -0
  335. package/docs/skills.md +231 -0
  336. package/docs/terminal-setup.md +114 -0
  337. package/docs/termux.md +127 -0
  338. package/docs/themes.md +295 -0
  339. package/docs/tmux.md +61 -0
  340. package/docs/tui.md +927 -0
  341. package/docs/usage.md +288 -0
  342. package/docs/windows.md +17 -0
  343. package/npm-shrinkwrap.json +1792 -0
  344. package/openadapter/extensions/koda-ask.js +12 -0
  345. package/openadapter/extensions/koda-bg.js +14 -0
  346. package/openadapter/extensions/koda-commands.mjs +15 -0
  347. package/openadapter/extensions/koda-help.js +8 -0
  348. package/openadapter/extensions/koda-memory.js +16 -0
  349. package/openadapter/extensions/koda-status.js +1 -0
  350. package/openadapter/extensions/koda-todo.js +4 -0
  351. package/openadapter/extensions/koda-vision.js +4 -0
  352. package/openadapter/extensions/koda-web.js +7 -0
  353. package/openadapter/setup.mjs +173 -0
  354. package/openadapter/skills/code-review/SKILL.md +22 -0
  355. package/openadapter/skills/debugging/SKILL.md +28 -0
  356. package/openadapter/skills/frontend/SKILL.md +38 -0
  357. package/package.json +108 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Simple text input component for extensions.
3
+ */
4
+ import { Container, type Focusable, type TUI } from "@openadapter/koda-tui";
5
+ export interface ExtensionInputOptions {
6
+ tui?: TUI;
7
+ timeout?: number;
8
+ }
9
+ export declare class ExtensionInputComponent extends Container implements Focusable {
10
+ private input;
11
+ private onSubmitCallback;
12
+ private onCancelCallback;
13
+ private titleText;
14
+ private baseTitle;
15
+ private countdown;
16
+ private _focused;
17
+ get focused(): boolean;
18
+ set focused(value: boolean);
19
+ constructor(title: string, _placeholder: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, opts?: ExtensionInputOptions);
20
+ handleInput(keyData: string): void;
21
+ dispose(): void;
22
+ }
@@ -0,0 +1,2 @@
1
+ var r=Object.defineProperty;var l=(s,t)=>r(s,"name",{value:t,configurable:!0});import{Container as C,getKeybindings as f,Input as p,Spacer as i,Text as c}from"@openadapter/koda-tui";import{theme as d}from"../theme/theme.js";import{CountdownTimer as b}from"./countdown-timer.js";import{DynamicBorder as o}from"./dynamic-border.js";import{keyHint as h}from"./keybinding-hints.js";class S extends C{static{l(this,"ExtensionInputComponent")}input;onSubmitCallback;onCancelCallback;titleText;baseTitle;countdown;_focused=!1;get focused(){return this._focused}set focused(t){this._focused=t,this.input.focused=t}constructor(t,n,a,u,e){super(),this.onSubmitCallback=a,this.onCancelCallback=u,this.baseTitle=t,this.addChild(new o),this.addChild(new i(1)),this.titleText=new c(d.fg("accent",t),1,0),this.addChild(this.titleText),this.addChild(new i(1)),e?.timeout&&e.timeout>0&&e.tui&&(this.countdown=new b(e.timeout,e.tui,m=>this.titleText.setText(d.fg("accent",`${this.baseTitle} (${m}s)`)),()=>this.onCancelCallback())),this.input=new p,this.addChild(this.input),this.addChild(new i(1)),this.addChild(new c(`${h("tui.select.confirm","submit")} ${h("tui.select.cancel","cancel")}`,1,0)),this.addChild(new i(1)),this.addChild(new o)}handleInput(t){const n=f();n.matches(t,"tui.select.confirm")||t===`
2
+ `?this.onSubmitCallback(this.input.getValue()):n.matches(t,"tui.select.cancel")?this.onCancelCallback():this.input.handleInput(t)}dispose(){this.countdown?.dispose()}}export{S as ExtensionInputComponent};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Generic selector component for extensions.
3
+ * Displays a list of string options with keyboard navigation.
4
+ */
5
+ import { Container, type TUI } from "@openadapter/koda-tui";
6
+ export interface ExtensionSelectorOptions {
7
+ tui?: TUI;
8
+ timeout?: number;
9
+ onToggleToolsExpanded?: () => void;
10
+ }
11
+ export declare class ExtensionSelectorComponent extends Container {
12
+ private options;
13
+ private selectedIndex;
14
+ private listContainer;
15
+ private onSelectCallback;
16
+ private onCancelCallback;
17
+ private titleText;
18
+ private baseTitle;
19
+ private countdown;
20
+ private onToggleToolsExpanded;
21
+ constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void, opts?: ExtensionSelectorOptions);
22
+ private updateList;
23
+ handleInput(keyData: string): void;
24
+ dispose(): void;
25
+ }
@@ -0,0 +1,2 @@
1
+ var p=Object.defineProperty;var c=(d,t)=>p(d,"name",{value:t,configurable:!0});import{Container as h,getKeybindings as x,Spacer as l,Text as o}from"@openadapter/koda-tui";import{theme as i}from"../theme/theme.js";import{CountdownTimer as u}from"./countdown-timer.js";import{DynamicBorder as a}from"./dynamic-border.js";import{keyHint as r,rawKeyHint as f}from"./keybinding-hints.js";class E extends h{static{c(this,"ExtensionSelectorComponent")}options;selectedIndex=0;listContainer;onSelectCallback;onCancelCallback;titleText;baseTitle;countdown;onToggleToolsExpanded;constructor(t,e,s,C,n){super(),this.options=e,this.onSelectCallback=s,this.onCancelCallback=C,this.onToggleToolsExpanded=n?.onToggleToolsExpanded,this.baseTitle=t,this.addChild(new a),this.addChild(new l(1)),this.titleText=new o(i.fg("accent",i.bold(t)),1,0),this.addChild(this.titleText),this.addChild(new l(1)),n?.timeout&&n.timeout>0&&n.tui&&(this.countdown=new u(n.timeout,n.tui,m=>this.titleText.setText(i.fg("accent",i.bold(`${this.baseTitle} (${m}s)`))),()=>this.onCancelCallback())),this.listContainer=new h,this.addChild(this.listContainer),this.addChild(new l(1)),this.addChild(new o(f("\u2191\u2193","navigate")+" "+r("tui.select.confirm","select")+" "+r("tui.select.cancel","cancel"),1,0)),this.addChild(new l(1)),this.addChild(new a),this.updateList()}updateList(){this.listContainer.clear();for(let t=0;t<this.options.length;t++){const s=t===this.selectedIndex?i.fg("accent","\u2192 ")+i.fg("accent",this.options[t]):` ${i.fg("text",this.options[t])}`;this.listContainer.addChild(new o(s,1,0))}}handleInput(t){const e=x();if(e.matches(t,"app.tools.expand"))this.onToggleToolsExpanded?.();else if(e.matches(t,"tui.select.up")||t==="k")this.selectedIndex=Math.max(0,this.selectedIndex-1),this.updateList();else if(e.matches(t,"tui.select.down")||t==="j")this.selectedIndex=Math.min(this.options.length-1,this.selectedIndex+1),this.updateList();else if(e.matches(t,"tui.select.confirm")||t===`
2
+ `){const s=this.options[this.selectedIndex];s&&this.onSelectCallback(s)}else e.matches(t,"tui.select.cancel")&&this.onCancelCallback()}dispose(){this.countdown?.dispose()}}export{E as ExtensionSelectorComponent};
@@ -0,0 +1,27 @@
1
+ import { type Component } from "@openadapter/koda-tui";
2
+ import type { AgentSession } from "../../../core/agent-session.ts";
3
+ import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.ts";
4
+ export declare function formatCwdForFooter(cwd: string, home: string | undefined): string;
5
+ /**
6
+ * Footer component that shows pwd, token stats, and context usage.
7
+ * Computes token/context stats from session, gets git branch and extension statuses from provider.
8
+ */
9
+ export declare class FooterComponent implements Component {
10
+ private autoCompactEnabled;
11
+ private session;
12
+ private footerData;
13
+ constructor(session: AgentSession, footerData: ReadonlyFooterDataProvider);
14
+ setSession(session: AgentSession): void;
15
+ setAutoCompactEnabled(enabled: boolean): void;
16
+ /**
17
+ * No-op: git branch caching now handled by provider.
18
+ * Kept for compatibility with existing call sites in interactive-mode.
19
+ */
20
+ invalidate(): void;
21
+ /**
22
+ * Clean up resources.
23
+ * Git watcher cleanup now handled by provider.
24
+ */
25
+ dispose(): void;
26
+ render(width: number): string[];
27
+ }
@@ -0,0 +1 @@
1
+ var q=Object.defineProperty;var u=(e,t)=>q(e,"name",{value:t,configurable:!0});import{isAbsolute as w,relative as J,resolve as U,sep as j}from"node:path";import{truncateToWidth as C,visibleWidth as p}from"@openadapter/koda-tui";import{theme as c}from"../theme/theme.js";function K(e){return e.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()}u(K,"sanitizeStatusText");function d(e){return e<1e3?e.toString():e<1e4?`${(e/1e3).toFixed(1)}k`:e<1e6?`${Math.round(e/1e3)}k`:e<1e7?`${(e/1e6).toFixed(1)}M`:`${Math.round(e/1e6)}M`}u(d,"formatTokens");function Q(e,t){if(!t)return e;const o=U(e),f=U(t),n=J(f,o);return n===""||n!==".."&&!n.startsWith(`..${j}`)&&!w(n)?n===""?"~":`~${j}${n}`:e}u(Q,"formatCwdForFooter");class et{static{u(this,"FooterComponent")}autoCompactEnabled=!0;session;footerData;constructor(t,o){this.session=t,this.footerData=o}setSession(t){this.session=t}setAutoCompactEnabled(t){this.autoCompactEnabled=t}invalidate(){}dispose(){}render(t){const o=this.session.state;let f=0,n=0,h=0,W=0,b=0;for(const s of this.session.sessionManager.getEntries())s.type==="message"&&s.message.role==="assistant"&&(f+=s.message.usage.input,n+=s.message.usage.output,h+=s.message.usage.cacheRead,W+=s.message.usage.cacheWrite,b+=s.message.usage.cost.total);const L=this.session.getContextUsage(),k=L?.contextWindow??o.model?.contextWindow??0,R=L?.percent??0,D=L?.percent!==null?R.toFixed(1):"?";let g=Q(this.session.sessionManager.getCwd(),process.env.HOME||process.env.USERPROFILE);const y=this.footerData.getGitBranch();y&&(g=`${g} (${y})`);const A=this.session.sessionManager.getSessionName();A&&(g=`${g} \u2022 ${A}`);const a=[];f&&a.push(`\u2191${d(f)}`),n&&a.push(`\u2193${d(n)}`),h&&a.push(`R${d(h)}`),W&&a.push(`W${d(W)}`);const H=o.model?this.session.modelRegistry.isUsingOAuth(o.model):!1;if(b||H){const s=`$${b.toFixed(3)}${H?" (sub)":""}`;a.push(s)}let $;const I=this.autoCompactEnabled?" (auto)":"",E=D==="?"?`?/${d(k)}${I}`:`${D}%/${d(k)}${I}`;R>90?$=c.fg("error",E):R>70?$=c.fg("warning",E):$=E,a.push($);let i=a.join(" ");const F=o.model?.id||"no-model";let r=p(i);r>t&&(i=C(i,t,"..."),r=p(i));const M=2;let x=F;if(o.model?.reasoning){const s=o.thinkingLevel||"off";x=s==="off"?`${F} \u2022 thinking off`:`${F} \u2022 ${s}`}let l=x;this.footerData.getAvailableProviderCount()>1&&o.model&&(l=`(${o.model.provider}) ${x}`,r+M+p(l)>t&&(l=x));const N=p(l),z=r+M+N;let v;if(z<=t){const s=" ".repeat(t-r-N);v=i+s+l}else{const s=t-r-M;if(s>0){const S=C(l,s,""),m=p(S),P=" ".repeat(Math.max(0,t-r-m));v=i+P+S}else v=i}const B=c.fg("dim",i),G=v.slice(i.length),V=c.fg("dim",G),O=[C(c.fg("dim",g),t,c.fg("dim","...")),B+V],T=this.footerData.getExtensionStatuses();if(T.size>0){const S=Array.from(T.entries()).sort(([m],[P])=>m.localeCompare(P)).map(([,m])=>K(m)).join(" ");O.push(C(S,t,c.fg("dim","...")))}return O}}export{et as FooterComponent,Q as formatCwdForFooter};
@@ -0,0 +1,31 @@
1
+ export { ArminComponent } from "./armin.ts";
2
+ export { AssistantMessageComponent } from "./assistant-message.ts";
3
+ export { BashExecutionComponent } from "./bash-execution.ts";
4
+ export { BorderedLoader } from "./bordered-loader.ts";
5
+ export { BranchSummaryMessageComponent } from "./branch-summary-message.ts";
6
+ export { CompactionSummaryMessageComponent } from "./compaction-summary-message.ts";
7
+ export { CustomEditor } from "./custom-editor.ts";
8
+ export { CustomMessageComponent } from "./custom-message.ts";
9
+ export { DaxnutsComponent } from "./daxnuts.ts";
10
+ export { type RenderDiffOptions, renderDiff } from "./diff.ts";
11
+ export { DynamicBorder } from "./dynamic-border.ts";
12
+ export { ExtensionEditorComponent } from "./extension-editor.ts";
13
+ export { ExtensionInputComponent } from "./extension-input.ts";
14
+ export { ExtensionSelectorComponent } from "./extension-selector.ts";
15
+ export { FooterComponent } from "./footer.ts";
16
+ export { keyHint, keyText, rawKeyHint } from "./keybinding-hints.ts";
17
+ export { LoginDialogComponent } from "./login-dialog.ts";
18
+ export { ModelSelectorComponent } from "./model-selector.ts";
19
+ export { OAuthSelectorComponent } from "./oauth-selector.ts";
20
+ export { type ModelsCallbacks, type ModelsConfig, ScopedModelsSelectorComponent } from "./scoped-models-selector.ts";
21
+ export { SessionSelectorComponent } from "./session-selector.ts";
22
+ export { type SettingsCallbacks, type SettingsConfig, SettingsSelectorComponent } from "./settings-selector.ts";
23
+ export { ShowImagesSelectorComponent } from "./show-images-selector.ts";
24
+ export { SkillInvocationMessageComponent } from "./skill-invocation-message.ts";
25
+ export { ThemeSelectorComponent } from "./theme-selector.ts";
26
+ export { ThinkingSelectorComponent } from "./thinking-selector.ts";
27
+ export { ToolExecutionComponent, type ToolExecutionOptions } from "./tool-execution.ts";
28
+ export { TreeSelectorComponent } from "./tree-selector.ts";
29
+ export { UserMessageComponent } from "./user-message.ts";
30
+ export { UserMessageSelectorComponent } from "./user-message-selector.ts";
31
+ export { truncateToVisualLines, type VisualTruncateResult } from "./visual-truncate.ts";
@@ -0,0 +1 @@
1
+ import{ArminComponent as r}from"./armin.js";import{AssistantMessageComponent as n}from"./assistant-message.js";import{BashExecutionComponent as p}from"./bash-execution.js";import{BorderedLoader as f}from"./bordered-loader.js";import{BranchSummaryMessageComponent as C}from"./branch-summary-message.js";import{CompactionSummaryMessageComponent as a}from"./compaction-summary-message.js";import{CustomEditor as l}from"./custom-editor.js";import{CustomMessageComponent as g}from"./custom-message.js";import{DaxnutsComponent as d}from"./daxnuts.js";import{renderDiff as E}from"./diff.js";import{DynamicBorder as y}from"./dynamic-border.js";import{ExtensionEditorComponent as k}from"./extension-editor.js";import{ExtensionInputComponent as D}from"./extension-input.js";import{ExtensionSelectorComponent as I}from"./extension-selector.js";import{FooterComponent as w}from"./footer.js";import{keyHint as U,keyText as v,rawKeyHint as F}from"./keybinding-hints.js";import{LoginDialogComponent as O}from"./login-dialog.js";import{ModelSelectorComponent as b}from"./model-selector.js";import{OAuthSelectorComponent as q}from"./oauth-selector.js";import{ScopedModelsSelectorComponent as G}from"./scoped-models-selector.js";import{SessionSelectorComponent as N}from"./session-selector.js";import{SettingsSelectorComponent as Q}from"./settings-selector.js";import{ShowImagesSelectorComponent as W}from"./show-images-selector.js";import{SkillInvocationMessageComponent as Y}from"./skill-invocation-message.js";import{ThemeSelectorComponent as _}from"./theme-selector.js";import{ThinkingSelectorComponent as oo}from"./thinking-selector.js";import{ToolExecutionComponent as ro}from"./tool-execution.js";import{TreeSelectorComponent as no}from"./tree-selector.js";import{UserMessageComponent as po}from"./user-message.js";import{UserMessageSelectorComponent as fo}from"./user-message-selector.js";import{truncateToVisualLines as Co}from"./visual-truncate.js";export{r as ArminComponent,n as AssistantMessageComponent,p as BashExecutionComponent,f as BorderedLoader,C as BranchSummaryMessageComponent,a as CompactionSummaryMessageComponent,l as CustomEditor,g as CustomMessageComponent,d as DaxnutsComponent,y as DynamicBorder,k as ExtensionEditorComponent,D as ExtensionInputComponent,I as ExtensionSelectorComponent,w as FooterComponent,O as LoginDialogComponent,b as ModelSelectorComponent,q as OAuthSelectorComponent,G as ScopedModelsSelectorComponent,N as SessionSelectorComponent,Q as SettingsSelectorComponent,W as ShowImagesSelectorComponent,Y as SkillInvocationMessageComponent,_ as ThemeSelectorComponent,oo as ThinkingSelectorComponent,ro as ToolExecutionComponent,no as TreeSelectorComponent,po as UserMessageComponent,fo as UserMessageSelectorComponent,U as keyHint,v as keyText,F as rawKeyHint,E as renderDiff,Co as truncateToVisualLines};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Utilities for formatting keybinding hints in the UI.
3
+ */
4
+ import { type Keybinding } from "@openadapter/koda-tui";
5
+ export interface KeyTextFormatOptions {
6
+ capitalize?: boolean;
7
+ }
8
+ export declare function formatKeyText(key: string, options?: KeyTextFormatOptions): string;
9
+ export declare function keyText(keybinding: Keybinding): string;
10
+ export declare function keyDisplayText(keybinding: Keybinding): string;
11
+ export declare function keyHint(keybinding: Keybinding, description: string): string;
12
+ export declare function rawKeyHint(key: string, description: string): string;
@@ -0,0 +1 @@
1
+ var u=Object.defineProperty;var r=(t,e)=>u(t,"name",{value:e,configurable:!0});import{getKeybindings as o}from"@openadapter/koda-tui";import{theme as i}from"../theme/theme.js";function m(t,e){const n=process.platform==="darwin"&&t.toLowerCase()==="alt"?"option":t;return e.capitalize?n.charAt(0).toUpperCase()+n.slice(1):n}r(m,"formatKeyPart");function a(t,e={}){return t.split("/").map(n=>n.split("+").map(f=>m(f,e)).join("+")).join("/")}r(a,"formatKeyText");function p(t,e={}){return t.length===0?"":a(t.join("/"),e)}r(p,"formatKeys");function c(t){return p(o().getKeys(t))}r(c,"keyText");function g(t){return p(o().getKeys(t),{capitalize:!0})}r(g,"keyDisplayText");function x(t,e){return i.fg("dim",c(t))+i.fg("muted",` ${e}`)}r(x,"keyHint");function d(t,e){return i.fg("dim",a(t))+i.fg("muted",` ${e}`)}r(d,"rawKeyHint");export{a as formatKeyText,g as keyDisplayText,x as keyHint,c as keyText,d as rawKeyHint};
@@ -0,0 +1,51 @@
1
+ import { type OAuthDeviceCodeInfo } from "@openadapter/koda-ai/oauth";
2
+ import { Container, type Focusable, type TUI } from "@openadapter/koda-tui";
3
+ /**
4
+ * Login dialog component - replaces editor during OAuth login flow
5
+ */
6
+ export declare class LoginDialogComponent extends Container implements Focusable {
7
+ private contentContainer;
8
+ private input;
9
+ private tui;
10
+ private abortController;
11
+ private inputResolver?;
12
+ private inputRejecter?;
13
+ private onComplete;
14
+ private _focused;
15
+ get focused(): boolean;
16
+ set focused(value: boolean);
17
+ constructor(tui: TUI, providerId: string, onComplete: (success: boolean, message?: string) => void, providerNameOverride?: string, titleOverride?: string);
18
+ get signal(): AbortSignal;
19
+ private cancel;
20
+ /**
21
+ * Called by onAuth callback - show URL and optional instructions
22
+ */
23
+ showAuth(url: string, instructions?: string): void;
24
+ /**
25
+ * Called by onDeviceCode callback - show URL and user code.
26
+ */
27
+ showDeviceCode(info: OAuthDeviceCodeInfo): void;
28
+ private openUrl;
29
+ /**
30
+ * Show input for manual code/URL entry (for callback server providers)
31
+ */
32
+ showManualInput(prompt: string): Promise<string>;
33
+ /**
34
+ * Called by onPrompt callback - show prompt and wait for input
35
+ * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)
36
+ */
37
+ showPrompt(message: string, placeholder?: string): Promise<string>;
38
+ /**
39
+ * Show informational text without prompting for input.
40
+ */
41
+ showInfo(lines: string[]): void;
42
+ /**
43
+ * Show waiting message (for polling flows like GitHub Copilot)
44
+ */
45
+ showWaiting(message: string): void;
46
+ /**
47
+ * Called by onProgress callback
48
+ */
49
+ showProgress(message: string): void;
50
+ handleInput(data: string): void;
51
+ }
@@ -0,0 +1 @@
1
+ var m=Object.defineProperty;var a=(h,t)=>m(h,"name",{value:t,configurable:!0});import{getOAuthProviders as g}from"@openadapter/koda-ai/oauth";import{Container as l,getKeybindings as x,Input as R,Spacer as r,Text as e}from"@openadapter/koda-tui";import{exec as b}from"child_process";import{theme as i}from"../theme/theme.js";import{DynamicBorder as C}from"./dynamic-border.js";import{keyHint as d}from"./keybinding-hints.js";class I extends l{static{a(this,"LoginDialogComponent")}contentContainer;input;tui;abortController=new AbortController;inputResolver;inputRejecter;onComplete;_focused=!1;get focused(){return this._focused}set focused(t){this._focused=t,this.input.focused=t}constructor(t,n,o,s,c){super(),this.tui=t,this.onComplete=o;const u=g().find(f=>f.id===n),p=s||u?.name||n,w=c??`Login to ${p}`;this.addChild(new C),this.addChild(new e(i.fg("accent",i.bold(w)),1,0)),this.contentContainer=new l,this.addChild(this.contentContainer),this.input=new R,this.input.onSubmit=()=>{this.inputResolver&&(this.inputResolver(this.input.getValue()),this.inputResolver=void 0,this.inputRejecter=void 0)},this.input.onEscape=()=>{this.cancel()},this.addChild(new C)}get signal(){return this.abortController.signal}cancel(){this.abortController.abort(),this.inputRejecter&&(this.inputRejecter(new Error("Login cancelled")),this.inputResolver=void 0,this.inputRejecter=void 0),this.onComplete(!1,"Login cancelled")}showAuth(t,n){this.contentContainer.clear(),this.contentContainer.addChild(new r(1));const o=`\x1B]8;;${t}\x07${t}\x1B]8;;\x07`;this.contentContainer.addChild(new e(i.fg("accent",o),1,0));const s=process.platform==="darwin"?"Cmd+click to open":"Ctrl+click to open",c=`\x1B]8;;${t}\x07${s}\x1B]8;;\x07`;this.contentContainer.addChild(new e(i.fg("dim",c),1,0)),n&&(this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(i.fg("warning",n),1,0))),this.openUrl(t),this.tui.requestRender()}showDeviceCode(t){this.contentContainer.clear(),this.contentContainer.addChild(new r(1));const n=`\x1B]8;;${t.verificationUri}\x07${t.verificationUri}\x1B]8;;\x07`;this.contentContainer.addChild(new e(i.fg("accent",n),1,0));const o=process.platform==="darwin"?"Cmd+click to open":"Ctrl+click to open",s=`\x1B]8;;${t.verificationUri}\x07${o}\x1B]8;;\x07`;this.contentContainer.addChild(new e(i.fg("dim",s),1,0)),this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(i.fg("warning",`Enter code: ${t.userCode}`),1,0)),this.openUrl(t.verificationUri),this.tui.requestRender()}openUrl(t){const n=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{b(`${n} "${t}"`,()=>{})}catch{}}showManualInput(t){return this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(i.fg("dim",t),1,0)),this.contentContainer.addChild(this.input),this.contentContainer.addChild(new e(`(${d("tui.select.cancel","to cancel")})`,1,0)),this.tui.requestRender(),new Promise((n,o)=>{this.inputResolver=n,this.inputRejecter=o})}showPrompt(t,n){return this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(i.fg("text",t),1,0)),n&&this.contentContainer.addChild(new e(i.fg("dim",`e.g., ${n}`),1,0)),this.contentContainer.addChild(this.input),this.contentContainer.addChild(new e(`(${d("tui.select.cancel","to cancel,")} ${d("tui.select.confirm","to submit")})`,1,0)),this.input.setValue(""),this.tui.requestRender(),new Promise((o,s)=>{this.inputResolver=o,this.inputRejecter=s})}showInfo(t){this.contentContainer.clear(),this.contentContainer.addChild(new r(1));for(const n of t)this.contentContainer.addChild(new e(n,1,0));this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(`(${d("tui.select.cancel","to close")})`,1,0)),this.tui.requestRender()}showWaiting(t){this.contentContainer.addChild(new r(1)),this.contentContainer.addChild(new e(i.fg("dim",t),1,0)),this.contentContainer.addChild(new e(`(${d("tui.select.cancel","to cancel")})`,1,0)),this.tui.requestRender()}showProgress(t){this.contentContainer.addChild(new e(i.fg("dim",t),1,0)),this.tui.requestRender()}handleInput(t){if(x().matches(t,"tui.select.cancel")){this.cancel();return}this.input.handleInput(t)}}export{I as LoginDialogComponent};
@@ -0,0 +1,46 @@
1
+ import { type Model } from "@openadapter/koda-ai";
2
+ import { Container, type Focusable, Input, type TUI } from "@openadapter/koda-tui";
3
+ import type { ModelRegistry } from "../../../core/model-registry.ts";
4
+ import type { SettingsManager } from "../../../core/settings-manager.ts";
5
+ interface ScopedModelItem {
6
+ model: Model<any>;
7
+ thinkingLevel?: string;
8
+ }
9
+ /**
10
+ * Component that renders a model selector with search
11
+ */
12
+ export declare class ModelSelectorComponent extends Container implements Focusable {
13
+ private searchInput;
14
+ private _focused;
15
+ get focused(): boolean;
16
+ set focused(value: boolean);
17
+ private listContainer;
18
+ private allModels;
19
+ private scopedModelItems;
20
+ private activeModels;
21
+ private filteredModels;
22
+ private selectedIndex;
23
+ private currentModel?;
24
+ private settingsManager;
25
+ private modelRegistry;
26
+ private onSelectCallback;
27
+ private onCancelCallback;
28
+ private errorMessage?;
29
+ private tui;
30
+ private scopedModels;
31
+ private scope;
32
+ private scopeText?;
33
+ private scopeHintText?;
34
+ constructor(tui: TUI, currentModel: Model<any> | undefined, settingsManager: SettingsManager, modelRegistry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, onSelect: (model: Model<any>) => void, onCancel: () => void, initialSearchInput?: string);
35
+ private loadModels;
36
+ private sortModels;
37
+ private getScopeText;
38
+ private getScopeHintText;
39
+ private setScope;
40
+ private filterModels;
41
+ private updateList;
42
+ handleInput(keyData: string): void;
43
+ private handleSelect;
44
+ getSearchInput(): Input;
45
+ }
46
+ export {};
@@ -0,0 +1,2 @@
1
+ var C=Object.defineProperty;var m=(M,e)=>C(M,"name",{value:e,configurable:!0});import{modelsAreEqual as c}from"@openadapter/koda-ai";import{Container as g,fuzzyFilter as T,getKeybindings as v,Input as $,Spacer as a,Text as n}from"@openadapter/koda-tui";import{theme as l}from"../theme/theme.js";import{DynamicBorder as x}from"./dynamic-border.js";import{keyHint as w}from"./keybinding-hints.js";class L extends g{static{m(this,"ModelSelectorComponent")}searchInput;_focused=!1;get focused(){return this._focused}set focused(e){this._focused=e,this.searchInput.focused=e}listContainer;allModels=[];scopedModelItems=[];activeModels=[];filteredModels=[];selectedIndex=0;currentModel;settingsManager;modelRegistry;onSelectCallback;onCancelCallback;errorMessage;tui;scopedModels;scope="all";scopeText;scopeHintText;constructor(e,s,d,t,i,h,f,o){if(super(),this.tui=e,this.currentModel=s,this.settingsManager=d,this.modelRegistry=t,this.scopedModels=i,this.scope=i.length>0?"scoped":"all",this.onSelectCallback=h,this.onCancelCallback=f,this.addChild(new x),this.addChild(new a(1)),i.length>0)this.scopeText=new n(this.getScopeText(),0,0),this.addChild(this.scopeText),this.scopeHintText=new n(this.getScopeHintText(),0,0),this.addChild(this.scopeHintText);else{const r="Only showing models from configured providers. Use /login to add providers.";this.addChild(new n(l.fg("warning",r),0,0))}this.addChild(new a(1)),this.searchInput=new $,o&&this.searchInput.setValue(o),this.searchInput.onSubmit=()=>{this.filteredModels[this.selectedIndex]&&this.handleSelect(this.filteredModels[this.selectedIndex].model)},this.addChild(this.searchInput),this.addChild(new a(1)),this.listContainer=new g,this.addChild(this.listContainer),this.addChild(new a(1)),this.addChild(new x),this.loadModels().then(()=>{o?this.filterModels(o):this.updateList(),this.tui.requestRender()})}async loadModels(){let e;this.modelRegistry.refresh();const s=this.modelRegistry.getError();s&&(this.errorMessage=s);try{e=(await this.modelRegistry.getAvailable()).map(i=>({provider:i.provider,id:i.id,model:i}))}catch(t){this.allModels=[],this.scopedModelItems=[],this.activeModels=[],this.filteredModels=[],this.errorMessage=t instanceof Error?t.message:String(t);return}this.allModels=this.sortModels(e),this.scopedModels=this.scopedModels.map(t=>{const i=this.modelRegistry.find(t.model.provider,t.model.id);return i?{...t,model:i}:t}),this.scopedModelItems=this.scopedModels.map(t=>({provider:t.model.provider,id:t.model.id,model:t.model})),this.activeModels=this.scope==="scoped"?this.scopedModelItems:this.allModels,this.filteredModels=this.activeModels;const d=this.filteredModels.findIndex(t=>c(this.currentModel,t.model));this.selectedIndex=d>=0?d:Math.min(this.selectedIndex,Math.max(0,this.filteredModels.length-1))}sortModels(e){const s=[...e];return s.sort((d,t)=>{const i=c(this.currentModel,d.model),h=c(this.currentModel,t.model);return i&&!h?-1:!i&&h?1:d.provider.localeCompare(t.provider)}),s}getScopeText(){const e=this.scope==="all"?l.fg("accent","all"):l.fg("muted","all"),s=this.scope==="scoped"?l.fg("accent","scoped"):l.fg("muted","scoped");return`${l.fg("muted","Scope: ")}${e}${l.fg("muted"," | ")}${s}`}getScopeHintText(){return w("tui.input.tab","scope")+l.fg("muted"," (all/scoped)")}setScope(e){if(this.scope===e)return;this.scope=e,this.activeModels=this.scope==="scoped"?this.scopedModelItems:this.allModels;const s=this.activeModels.findIndex(d=>c(this.currentModel,d.model));this.selectedIndex=s>=0?s:0,this.filterModels(this.searchInput.getValue()),this.scopeText&&this.scopeText.setText(this.getScopeText())}filterModels(e){this.filteredModels=e?T(this.activeModels,e,({id:s,provider:d})=>`${s} ${d} ${d}/${s} ${d} ${s}`):this.activeModels,this.selectedIndex=Math.min(this.selectedIndex,Math.max(0,this.filteredModels.length-1)),this.updateList()}updateList(){this.listContainer.clear();const e=10,s=Math.max(0,Math.min(this.selectedIndex-Math.floor(e/2),this.filteredModels.length-e)),d=Math.min(s+e,this.filteredModels.length);for(let t=s;t<d;t++){const i=this.filteredModels[t];if(!i)continue;const h=t===this.selectedIndex,f=c(this.currentModel,i.model);let o="";if(h){const r=l.fg("accent","\u2192 "),p=`${i.id}`,u=l.fg("muted",`[${i.provider}]`),I=f?l.fg("success"," \u2713"):"";o=`${r+l.fg("accent",p)} ${u}${I}`}else{const r=` ${i.id}`,p=l.fg("muted",`[${i.provider}]`),u=f?l.fg("success"," \u2713"):"";o=`${r} ${p}${u}`}this.listContainer.addChild(new n(o,0,0))}if(s>0||d<this.filteredModels.length){const t=l.fg("muted",` (${this.selectedIndex+1}/${this.filteredModels.length})`);this.listContainer.addChild(new n(t,0,0))}if(this.errorMessage){const t=this.errorMessage.split(`
2
+ `);for(const i of t)this.listContainer.addChild(new n(l.fg("error",i),0,0))}else if(this.filteredModels.length===0)this.listContainer.addChild(new n(l.fg("muted"," No matching models"),0,0));else{const t=this.filteredModels[this.selectedIndex];this.listContainer.addChild(new a(1)),this.listContainer.addChild(new n(l.fg("muted",` Model Name: ${t.model.name}`),0,0))}}handleInput(e){const s=v();if(s.matches(e,"tui.input.tab")){if(this.scopedModelItems.length>0){const d=this.scope==="all"?"scoped":"all";this.setScope(d),this.scopeHintText&&this.scopeHintText.setText(this.getScopeHintText())}return}if(s.matches(e,"tui.select.up")){if(this.filteredModels.length===0)return;this.selectedIndex=this.selectedIndex===0?this.filteredModels.length-1:this.selectedIndex-1,this.updateList()}else if(s.matches(e,"tui.select.down")){if(this.filteredModels.length===0)return;this.selectedIndex=this.selectedIndex===this.filteredModels.length-1?0:this.selectedIndex+1,this.updateList()}else if(s.matches(e,"tui.select.confirm")){const d=this.filteredModels[this.selectedIndex];d&&this.handleSelect(d.model)}else s.matches(e,"tui.select.cancel")?this.onCancelCallback():(this.searchInput.handleInput(e),this.filterModels(this.searchInput.getValue()))}handleSelect(e){this.settingsManager.setDefaultModelAndProvider(e.provider,e.id),this.onSelectCallback(e)}getSearchInput(){return this.searchInput}}export{L as ModelSelectorComponent};
@@ -0,0 +1,30 @@
1
+ import { Container, type Focusable } from "@openadapter/koda-tui";
2
+ import type { AuthStatus, AuthStorage } from "../../../core/auth-storage.ts";
3
+ export type AuthSelectorProvider = {
4
+ id: string;
5
+ name: string;
6
+ authType: "oauth" | "api_key";
7
+ };
8
+ /**
9
+ * Component that renders an auth provider selector
10
+ */
11
+ export declare class OAuthSelectorComponent extends Container implements Focusable {
12
+ private searchInput;
13
+ private _focused;
14
+ get focused(): boolean;
15
+ set focused(value: boolean);
16
+ private listContainer;
17
+ private allProviders;
18
+ private filteredProviders;
19
+ private selectedIndex;
20
+ private mode;
21
+ private authStorage;
22
+ private getAuthStatus;
23
+ private onSelectCallback;
24
+ private onCancelCallback;
25
+ constructor(mode: "login" | "logout", authStorage: AuthStorage, providers: AuthSelectorProvider[], onSelect: (providerId: string) => void, onCancel: () => void, getAuthStatus?: (providerId: string) => AuthStatus);
26
+ private filterProviders;
27
+ private updateList;
28
+ private formatStatusIndicator;
29
+ handleInput(keyData: string): void;
30
+ }
@@ -0,0 +1 @@
1
+ var C=Object.defineProperty;var f=(c,e)=>C(c,"name",{value:e,configurable:!0});import{Container as g,fuzzyFilter as p,getKeybindings as P,Input as v,Spacer as h,TruncatedText as o}from"@openadapter/koda-tui";import{theme as s}from"../theme/theme.js";import{DynamicBorder as m}from"./dynamic-border.js";class k extends g{static{f(this,"OAuthSelectorComponent")}searchInput;_focused=!1;get focused(){return this._focused}set focused(e){this._focused=e,this.searchInput.focused=e}listContainer;allProviders;filteredProviders;selectedIndex=0;mode;authStorage;getAuthStatus;onSelectCallback;onCancelCallback;constructor(e,t,n,i,r,a){super(),this.mode=e,this.authStorage=t,this.getAuthStatus=a??(d=>this.authStorage.getAuthStatus(d)),this.allProviders=n,this.filteredProviders=n,this.onSelectCallback=i,this.onCancelCallback=r,this.addChild(new m),this.addChild(new h(1));const l=e==="login"?"Select provider to configure:":"Select provider to logout:";this.addChild(new o(s.fg("accent",s.bold(l)),1,0)),this.addChild(new h(1)),this.searchInput=new v,this.searchInput.onSubmit=()=>{const d=this.filteredProviders[this.selectedIndex];d&&this.onSelectCallback(d.id)},this.addChild(this.searchInput),this.addChild(new h(1)),this.listContainer=new g,this.addChild(this.listContainer),this.addChild(new h(1)),this.addChild(new m),this.filterProviders("")}filterProviders(e){this.filteredProviders=e?p(this.allProviders,e,t=>`${t.name} ${t.id} ${t.authType}`):this.allProviders,this.selectedIndex=Math.max(0,Math.min(this.selectedIndex,Math.max(0,this.filteredProviders.length-1))),this.updateList()}updateList(){this.listContainer.clear();const e=8,t=Math.max(0,Math.min(this.selectedIndex-Math.floor(e/2),this.filteredProviders.length-e)),n=Math.min(t+e,this.filteredProviders.length);for(let i=t;i<n;i++){const r=this.filteredProviders[i];if(!r)continue;const a=i===this.selectedIndex,l=this.formatStatusIndicator(r);let d="";if(a){const u=s.fg("accent","\u2192 "),I=s.fg("accent",r.name);d=u+I+l}else d=` ${s.fg("text",r.name)}`+l;this.listContainer.addChild(new o(d,1,0))}if(t>0||n<this.filteredProviders.length){const i=s.fg("muted",` (${this.selectedIndex+1}/${this.filteredProviders.length})`);this.listContainer.addChild(new o(i,1,0))}if(this.filteredProviders.length===0){const i=this.allProviders.length===0?this.mode==="login"?"No providers available":"No providers logged in. Use /login first.":"No matching providers";this.listContainer.addChild(new o(s.fg("muted",` ${i}`),1,0))}}formatStatusIndicator(e){const t=this.authStorage.get(e.id);if(t?.type===e.authType)return s.fg("success"," \u2713 configured");if(t){const i=t.type==="oauth"?"subscription configured":"API key configured";return s.fg("muted"," \u2022 ")+s.fg("warning",i)}if(e.authType!=="api_key")return s.fg("muted"," \u2022 unconfigured");const n=this.getAuthStatus(e.id);switch(n.source){case"environment":return s.fg("success",` \u2713 env: ${n.label??"API key"}`);case"runtime":return s.fg("success"," \u2713 runtime API key");case"fallback":return s.fg("success"," \u2713 custom API key");case"models_json_key":return s.fg("success"," \u2713 key in models.json");case"models_json_command":return s.fg("success"," \u2713 command in models.json");default:return s.fg("muted"," \u2022 unconfigured")}}handleInput(e){const t=P();if(t.matches(e,"tui.select.up")){if(this.filteredProviders.length===0)return;this.selectedIndex=Math.max(0,this.selectedIndex-1),this.updateList()}else if(t.matches(e,"tui.select.down")){if(this.filteredProviders.length===0)return;this.selectedIndex=Math.min(this.filteredProviders.length-1,this.selectedIndex+1),this.updateList()}else if(t.matches(e,"tui.select.confirm")){const n=this.filteredProviders[this.selectedIndex];n&&this.onSelectCallback(n.id)}else t.matches(e,"tui.select.cancel")?this.onCancelCallback():(this.searchInput.handleInput(e),this.filterProviders(this.searchInput.getValue()))}}export{k as OAuthSelectorComponent};
@@ -0,0 +1,41 @@
1
+ import type { Model } from "@openadapter/koda-ai";
2
+ import { Container, type Focusable, Input } from "@openadapter/koda-tui";
3
+ export interface ModelsConfig {
4
+ allModels: Model<any>[];
5
+ enabledModelIds: string[] | null;
6
+ }
7
+ export interface ModelsCallbacks {
8
+ /** Called whenever the enabled model set or order changes (session-only, no persist) */
9
+ onChange: (enabledModelIds: string[] | null) => void | Promise<void>;
10
+ /** Called when user wants to persist current selection to settings */
11
+ onPersist: (enabledModelIds: string[] | null) => void | Promise<void>;
12
+ onCancel: () => void;
13
+ }
14
+ /**
15
+ * Component for enabling/disabling models for Ctrl+P cycling.
16
+ * Changes are session-only until explicitly persisted with Ctrl+S.
17
+ */
18
+ export declare class ScopedModelsSelectorComponent extends Container implements Focusable {
19
+ private modelsById;
20
+ private allIds;
21
+ private enabledIds;
22
+ private filteredItems;
23
+ private selectedIndex;
24
+ private searchInput;
25
+ private _focused;
26
+ get focused(): boolean;
27
+ set focused(value: boolean);
28
+ private listContainer;
29
+ private footerText;
30
+ private callbacks;
31
+ private maxVisible;
32
+ private isDirty;
33
+ constructor(config: ModelsConfig, callbacks: ModelsCallbacks);
34
+ private buildItems;
35
+ private getFooterText;
36
+ private refresh;
37
+ private notifyChange;
38
+ private updateList;
39
+ handleInput(data: string): void;
40
+ getSearchInput(): Input;
41
+ }
@@ -0,0 +1 @@
1
+ var $=Object.defineProperty;var h=(l,e)=>$(l,"name",{value:e,configurable:!0});import{Container as p,fuzzyFilter as v,getKeybindings as T,Input as M,Key as g,matchesKey as x,Spacer as m,Text as a}from"@openadapter/koda-tui";import{theme as r}from"../theme/theme.js";import{DynamicBorder as b}from"./dynamic-border.js";import{keyText as o}from"./keybinding-hints.js";function I(l,e){return l===null||l.includes(e)}h(I,"isEnabled");function D(l,e){if(l===null)return[e];const t=l.indexOf(e);return t>=0?[...l.slice(0,t),...l.slice(t+1)]:[...l,e]}h(D,"toggle");function C(l,e,t){if(l===null)return null;const n=t??e,s=[...l];for(const i of n)s.includes(i)||s.push(i);return s.length===e.length?null:s}h(C,"enableAll");function y(l,e,t){if(l===null)return t?e.filter(s=>!t.includes(s)):[];const n=new Set(t??l);return l.filter(s=>!n.has(s))}h(y,"clearAll");function S(l,e,t){if(l===null)return null;const n=[...l],s=n.indexOf(e);if(s<0)return n;const i=s+t;if(i<0||i>=n.length)return n;const d=[...n];return[d[s],d[i]]=[d[i],d[s]],d}h(S,"move");function V(l,e){if(l===null)return e;const t=new Set(l);return[...l,...e.filter(n=>!t.has(n))]}h(V,"getSortedIds");class L extends p{static{h(this,"ScopedModelsSelectorComponent")}modelsById=new Map;allIds=[];enabledIds=null;filteredItems=[];selectedIndex=0;searchInput;_focused=!1;get focused(){return this._focused}set focused(e){this._focused=e,this.searchInput.focused=e}listContainer;footerText;callbacks;maxVisible=8;isDirty=!1;constructor(e,t){super(),this.callbacks=t;for(const n of e.allModels){const s=`${n.provider}/${n.id}`;this.modelsById.set(s,n),this.allIds.push(s)}this.enabledIds=e.enabledModelIds===null?null:[...e.enabledModelIds],this.filteredItems=this.buildItems(),this.addChild(new b),this.addChild(new m(1)),this.addChild(new a(r.fg("accent",r.bold("Model Configuration")),0,0)),this.addChild(new a(r.fg("muted",`Session-only. ${o("app.models.save")} to save to settings.`),0,0)),this.addChild(new m(1)),this.searchInput=new M,this.addChild(this.searchInput),this.addChild(new m(1)),this.listContainer=new p,this.addChild(this.listContainer),this.addChild(new m(1)),this.footerText=new a(this.getFooterText(),0,0),this.addChild(this.footerText),this.addChild(new b),this.updateList()}buildItems(){return V(this.enabledIds,this.allIds).filter(e=>this.modelsById.has(e)).map(e=>({fullId:e,model:this.modelsById.get(e),enabled:I(this.enabledIds,e)}))}getFooterText(){const e=this.enabledIds?.length??this.allIds.length,n=this.enabledIds===null?"all enabled":`${e}/${this.allIds.length} enabled`,s=[`${o("tui.select.confirm")} toggle`,`${o("app.models.enableAll")} all`,`${o("app.models.clearAll")} clear`,`${o("app.models.toggleProvider")} provider`,`${o("app.models.reorderUp")}/${o("app.models.reorderDown")} reorder`,`${o("app.models.save")} save`,n];return this.isDirty?r.fg("dim",` ${s.join(" \xB7 ")} `)+r.fg("warning","(unsaved)"):r.fg("dim",` ${s.join(" \xB7 ")}`)}refresh(){const e=this.searchInput.getValue(),t=this.buildItems();this.filteredItems=e?v(t,e,n=>`${n.model.id} ${n.model.provider}`):t,this.selectedIndex=Math.min(this.selectedIndex,Math.max(0,this.filteredItems.length-1)),this.updateList(),this.footerText.setText(this.getFooterText())}notifyChange(){this.callbacks.onChange(this.enabledIds===null?null:[...this.enabledIds])}updateList(){if(this.listContainer.clear(),this.filteredItems.length===0){this.listContainer.addChild(new a(r.fg("muted"," No matching models"),0,0));return}const e=Math.max(0,Math.min(this.selectedIndex-Math.floor(this.maxVisible/2),this.filteredItems.length-this.maxVisible)),t=Math.min(e+this.maxVisible,this.filteredItems.length),n=this.enabledIds===null;for(let s=e;s<t;s++){const i=this.filteredItems[s],d=s===this.selectedIndex,c=d?r.fg("accent","\u2192 "):" ",u=d?r.fg("accent",i.model.id):i.model.id,f=r.fg("muted",` [${i.model.provider}]`),w=n?"":i.enabled?r.fg("success"," \u2713"):r.fg("dim"," \u2717");this.listContainer.addChild(new a(`${c}${u}${f}${w}`,0,0))}if((e>0||t<this.filteredItems.length)&&this.listContainer.addChild(new a(r.fg("muted",` (${this.selectedIndex+1}/${this.filteredItems.length})`),0,0)),this.filteredItems.length>0){const s=this.filteredItems[this.selectedIndex];this.listContainer.addChild(new m(1)),this.listContainer.addChild(new a(r.fg("muted",` Model Name: ${s.model.name}`),0,0))}}handleInput(e){const t=T();if(t.matches(e,"tui.select.up")){if(this.filteredItems.length===0)return;this.selectedIndex=this.selectedIndex===0?this.filteredItems.length-1:this.selectedIndex-1,this.updateList();return}if(t.matches(e,"tui.select.down")){if(this.filteredItems.length===0)return;this.selectedIndex=this.selectedIndex===this.filteredItems.length-1?0:this.selectedIndex+1,this.updateList();return}const n=t.matches(e,"app.models.reorderUp"),s=t.matches(e,"app.models.reorderDown");if(n||s){if(this.enabledIds===null)return;const i=this.filteredItems[this.selectedIndex];if(i&&I(this.enabledIds,i.fullId)){const d=n?-1:1,u=this.enabledIds.indexOf(i.fullId)+d;u>=0&&u<this.enabledIds.length&&(this.enabledIds=S(this.enabledIds,i.fullId,d),this.isDirty=!0,this.selectedIndex+=d,this.refresh(),this.notifyChange())}return}if(t.matches(e,"tui.select.confirm")){const i=this.filteredItems[this.selectedIndex];i&&(this.enabledIds=D(this.enabledIds,i.fullId),this.isDirty=!0,this.refresh(),this.notifyChange());return}if(t.matches(e,"app.models.enableAll")){const i=this.searchInput.getValue()?this.filteredItems.map(d=>d.fullId):void 0;this.enabledIds=C(this.enabledIds,this.allIds,i),this.isDirty=!0,this.refresh(),this.notifyChange();return}if(t.matches(e,"app.models.clearAll")){const i=this.searchInput.getValue()?this.filteredItems.map(d=>d.fullId):void 0;this.enabledIds=y(this.enabledIds,this.allIds,i),this.isDirty=!0,this.refresh(),this.notifyChange();return}if(t.matches(e,"app.models.toggleProvider")){const i=this.filteredItems[this.selectedIndex];if(i){const d=i.model.provider,c=this.allIds.filter(f=>this.modelsById.get(f).provider===d),u=c.every(f=>I(this.enabledIds,f));this.enabledIds=u?y(this.enabledIds,this.allIds,c):C(this.enabledIds,this.allIds,c),this.isDirty=!0,this.refresh(),this.notifyChange()}return}if(t.matches(e,"app.models.save")){this.callbacks.onPersist(this.enabledIds===null?null:[...this.enabledIds]),this.isDirty=!1,this.footerText.setText(this.getFooterText());return}if(x(e,g.ctrl("c"))){this.searchInput.getValue()?(this.searchInput.setValue(""),this.refresh()):this.callbacks.onCancel();return}if(x(e,g.escape)){this.callbacks.onCancel();return}this.searchInput.handleInput(e),this.refresh()}getSearchInput(){return this.searchInput}}export{L as ScopedModelsSelectorComponent};
@@ -0,0 +1,22 @@
1
+ import type { SessionInfo } from "../../../core/session-manager.ts";
2
+ export type SortMode = "threaded" | "recent" | "relevance";
3
+ export type NameFilter = "all" | "named";
4
+ export interface ParsedSearchQuery {
5
+ mode: "tokens" | "regex";
6
+ tokens: {
7
+ kind: "fuzzy" | "phrase";
8
+ value: string;
9
+ }[];
10
+ regex: RegExp | null;
11
+ /** If set, parsing failed and we should treat query as non-matching. */
12
+ error?: string;
13
+ }
14
+ export interface MatchResult {
15
+ matches: boolean;
16
+ /** Lower is better; only meaningful when matches === true */
17
+ score: number;
18
+ }
19
+ export declare function hasSessionName(session: SessionInfo): boolean;
20
+ export declare function parseSearchQuery(query: string): ParsedSearchQuery;
21
+ export declare function matchSession(session: SessionInfo, parsed: ParsedSearchQuery): MatchResult;
22
+ export declare function filterAndSortSessions(sessions: SessionInfo[], query: string, sortMode: SortMode, nameFilter?: NameFilter): SessionInfo[];
@@ -0,0 +1 @@
1
+ var h=Object.defineProperty;var f=(r,n)=>h(r,"name",{value:n,configurable:!0});import{fuzzyMatch as d}from"@openadapter/koda-tui";function a(r){return r.toLowerCase().replace(/\s+/g," ").trim()}f(a,"normalizeWhitespaceLower");function g(r){return`${r.id} ${r.name??""} ${r.allMessagesText} ${r.cwd}`}f(g,"getSessionSearchText");function x(r){return!!r.name?.trim()}f(x,"hasSessionName");function p(r,n){return n==="all"?!0:x(r)}f(p,"matchesNameFilter");function k(r){const n=r.trim();if(!n)return{mode:"tokens",tokens:[],regex:null};if(n.startsWith("re:")){const t=n.slice(3).trim();if(!t)return{mode:"regex",tokens:[],regex:null,error:"Empty regex"};try{return{mode:"regex",tokens:[],regex:new RegExp(t,"i")}}catch(e){const i=e instanceof Error?e.message:String(e);return{mode:"regex",tokens:[],regex:null,error:i}}}const l=[];let c="",s=!1,u=!1;const o=f(t=>{const e=c.trim();c="",e&&l.push({kind:t,value:e})},"flush");for(let t=0;t<n.length;t++){const e=n[t];if(e==='"'){s?(o("phrase"),s=!1):(o("fuzzy"),s=!0);continue}if(!s&&/\s/.test(e)){o("fuzzy");continue}c+=e}return s&&(u=!0),u?{mode:"tokens",tokens:n.split(/\s+/).map(t=>t.trim()).filter(t=>t.length>0).map(t=>({kind:"fuzzy",value:t})),regex:null}:(o(s?"phrase":"fuzzy"),{mode:"tokens",tokens:l,regex:null})}f(k,"parseSearchQuery");function m(r,n){const l=g(r);if(n.mode==="regex"){if(!n.regex)return{matches:!1,score:0};const u=l.search(n.regex);return u<0?{matches:!1,score:0}:{matches:!0,score:u*.1}}if(n.tokens.length===0)return{matches:!0,score:0};let c=0,s=null;for(const u of n.tokens){if(u.kind==="phrase"){s===null&&(s=a(l));const t=a(u.value);if(!t)continue;const e=s.indexOf(t);if(e<0)return{matches:!1,score:0};c+=e*.1;continue}const o=d(u.value,l);if(!o.matches)return{matches:!1,score:0};c+=o.score}return{matches:!0,score:c}}f(m,"matchSession");function v(r,n,l,c="all"){const s=c==="all"?r:r.filter(e=>p(e,c));if(!n.trim())return s;const o=k(n);if(o.error)return[];if(l==="recent"){const e=[];for(const i of s)m(i,o).matches&&e.push(i);return e}const t=[];for(const e of s){const i=m(e,o);i.matches&&t.push({session:e,score:i.score})}return t.sort((e,i)=>e.score!==i.score?e.score-i.score:i.session.modified.getTime()-e.session.modified.getTime()),t.map(e=>e.session)}f(v,"filterAndSortSessions");export{v as filterAndSortSessions,x as hasSessionName,m as matchSession,k as parseSearchQuery};
@@ -0,0 +1,95 @@
1
+ import { type Component, Container, type Focusable } from "@openadapter/koda-tui";
2
+ import { KeybindingsManager } from "../../../core/keybindings.ts";
3
+ import type { SessionInfo, SessionListProgress } from "../../../core/session-manager.ts";
4
+ import { type NameFilter, type SortMode } from "./session-selector-search.ts";
5
+ /**
6
+ * Custom session list component with multi-line items and search
7
+ */
8
+ declare class SessionList implements Component, Focusable {
9
+ getSelectedSessionPath(): string | undefined;
10
+ private allSessions;
11
+ private filteredSessions;
12
+ private selectedIndex;
13
+ private searchInput;
14
+ private showCwd;
15
+ private sortMode;
16
+ private nameFilter;
17
+ private keybindings;
18
+ private showPath;
19
+ private confirmingDeletePath;
20
+ private currentSessionCanonicalPath?;
21
+ onSelect?: (sessionPath: string) => void;
22
+ onCancel?: () => void;
23
+ onExit: () => void;
24
+ onToggleScope?: () => void;
25
+ onToggleSort?: () => void;
26
+ onToggleNameFilter?: () => void;
27
+ onTogglePath?: (showPath: boolean) => void;
28
+ onDeleteConfirmationChange?: (path: string | null) => void;
29
+ onDeleteSession?: (sessionPath: string) => Promise<void>;
30
+ onRenameSession?: (sessionPath: string) => void;
31
+ onError?: (message: string) => void;
32
+ private maxVisible;
33
+ private _focused;
34
+ get focused(): boolean;
35
+ set focused(value: boolean);
36
+ constructor(sessions: SessionInfo[], showCwd: boolean, sortMode: SortMode, nameFilter: NameFilter, keybindings: KeybindingsManager, currentSessionFilePath?: string);
37
+ setSortMode(sortMode: SortMode): void;
38
+ setNameFilter(nameFilter: NameFilter): void;
39
+ setSessions(sessions: SessionInfo[], showCwd: boolean): void;
40
+ private filterSessions;
41
+ private setConfirmingDeletePath;
42
+ private startDeleteConfirmationForSelectedSession;
43
+ private isCurrentSessionPath;
44
+ invalidate(): void;
45
+ render(width: number): string[];
46
+ private buildTreePrefix;
47
+ handleInput(keyData: string): void;
48
+ }
49
+ type SessionsLoader = (onProgress?: SessionListProgress) => Promise<SessionInfo[]>;
50
+ /**
51
+ * Component that renders a session selector
52
+ */
53
+ export declare class SessionSelectorComponent extends Container implements Focusable {
54
+ handleInput(data: string): void;
55
+ private canRename;
56
+ private sessionList;
57
+ private header;
58
+ private keybindings;
59
+ private scope;
60
+ private sortMode;
61
+ private nameFilter;
62
+ private currentSessions;
63
+ private allSessions;
64
+ private currentSessionsLoader;
65
+ private allSessionsLoader;
66
+ private onCancel;
67
+ private requestRender;
68
+ private renameSession?;
69
+ private currentLoading;
70
+ private allLoading;
71
+ private allLoadSeq;
72
+ private mode;
73
+ private renameInput;
74
+ private renameTargetPath;
75
+ private _focused;
76
+ get focused(): boolean;
77
+ set focused(value: boolean);
78
+ private buildBaseLayout;
79
+ constructor(currentSessionsLoader: SessionsLoader, allSessionsLoader: SessionsLoader, onSelect: (sessionPath: string) => void, onCancel: () => void, onExit: () => void, requestRender: () => void, options?: {
80
+ renameSession?: (sessionPath: string, currentName: string | undefined) => Promise<void>;
81
+ showRenameHint?: boolean;
82
+ keybindings?: KeybindingsManager;
83
+ }, currentSessionFilePath?: string);
84
+ private loadCurrentSessions;
85
+ private enterRenameMode;
86
+ private exitRenameMode;
87
+ private confirmRename;
88
+ private loadScope;
89
+ private toggleSortMode;
90
+ private toggleNameFilter;
91
+ private refreshSessionsAfterMutation;
92
+ private toggleScope;
93
+ getSessionList(): SessionList;
94
+ }
95
+ export {};
@@ -0,0 +1,2 @@
1
+ var j=Object.defineProperty;var c=(a,e)=>j(a,"name",{value:e,configurable:!0});import{spawnSync as K}from"node:child_process";import{existsSync as U}from"node:fs";import{unlink as G}from"node:fs/promises";import*as J from"node:os";import{Container as D,getKeybindings as v,Input as H,Spacer as P,Text as V,truncateToWidth as S,visibleWidth as w}from"@openadapter/koda-tui";import{KeybindingsManager as O}from"../../../core/keybindings.js";import{canonicalizePath as Q}from"../../../utils/paths.js";import{theme as h}from"../theme/theme.js";import{DynamicBorder as E}from"./dynamic-border.js";import{keyHint as L,keyText as y}from"./keybinding-hints.js";import{filterAndSortSessions as X,hasSessionName as Y}from"./session-selector-search.js";function A(a){const e=J.homedir();return a&&(a.startsWith(e)?`~${a.slice(e.length)}`:a)}c(A,"shortenPath");function Z(a){const s=new Date().getTime()-a.getTime(),t=Math.floor(s/6e4),i=Math.floor(s/36e5),n=Math.floor(s/864e5);return t<1?"now":t<60?`${t}m`:i<24?`${i}h`:n<7?`${n}d`:n<30?`${Math.floor(n/7)}w`:n<365?`${Math.floor(n/30)}mo`:`${Math.floor(n/365)}y`}c(Z,"formatSessionDate");function T(a){return a&&Q(a)}c(T,"canonicalizePath");class ee{static{c(this,"SessionSelectorHeader")}scope;sortMode;nameFilter;requestRender;loading=!1;loadProgress=null;showPath=!1;confirmingDeletePath=null;statusMessage=null;statusTimeout=null;showRenameHint=!1;constructor(e,s,t,i){this.scope=e,this.sortMode=s,this.nameFilter=t,this.requestRender=i}setScope(e){this.scope=e}setSortMode(e){this.sortMode=e}setNameFilter(e){this.nameFilter=e}setLoading(e){this.loading=e,this.loadProgress=null}setProgress(e,s){this.loadProgress={loaded:e,total:s}}setShowPath(e){this.showPath=e}setShowRenameHint(e){this.showRenameHint=e}setConfirmingDeletePath(e){this.confirmingDeletePath=e}clearStatusTimeout(){this.statusTimeout&&(clearTimeout(this.statusTimeout),this.statusTimeout=null)}setStatusMessage(e,s){this.clearStatusTimeout(),this.statusMessage=e,!(!e||!s)&&(this.statusTimeout=setTimeout(()=>{this.statusMessage=null,this.statusTimeout=null,this.requestRender()},s))}invalidate(){}render(e){const s=this.scope==="current"?"Resume Session (Current Folder)":"Resume Session (All)",t=h.bold(s),i=this.sortMode==="threaded"?"Threaded":this.sortMode==="recent"?"Recent":"Fuzzy",n=h.fg("muted","Sort: ")+h.fg("accent",i),o=this.nameFilter==="all"?"All":"Named",r=h.fg("muted","Name: ")+h.fg("accent",o);let d;if(this.loading){const m=this.loadProgress?`${this.loadProgress.loaded}/${this.loadProgress.total}`:"...";d=`${h.fg("muted","\u25CB Current Folder | ")}${h.fg("accent",`Loading ${m}`)}`}else this.scope==="current"?d=`${h.fg("accent","\u25C9 Current Folder")}${h.fg("muted"," | \u25CB All")}`:d=`${h.fg("muted","\u25CB Current Folder | ")}${h.fg("accent","\u25C9 All")}`;const u=S(`${d} ${r} ${n}`,e,""),x=Math.max(0,e-w(u)-1),l=S(t,x,""),M=Math.max(0,e-w(l)-w(u));let f,g;if(this.confirmingDeletePath!==null){const m=`Delete session? ${L("tui.select.confirm","confirm")} \xB7 ${L("tui.select.cancel","cancel")}`;f=h.fg("error",S(m,e,"\u2026")),g=""}else if(this.statusMessage){const m=this.statusMessage.type==="error"?"error":"accent";f=h.fg(m,S(this.statusMessage.message,e,"\u2026")),g=""}else{const m=this.showPath?"(on)":"(off)",C=h.fg("muted"," \xB7 "),p=L("tui.input.tab","scope")+C+h.fg("muted",'re:<pattern> regex \xB7 "phrase" exact'),R=[L("app.session.toggleSort","sort"),L("app.session.toggleNamedFilter","named"),L("app.session.delete","delete"),L("app.session.togglePath",`path ${m}`)];this.showRenameHint&&R.push(L("app.session.rename","rename"));const b=R.join(C);f=S(p,e,"\u2026"),g=S(b,e,"\u2026")}return[`${l}${" ".repeat(M)}${u}`,f,g]}}function se(a){const e=new Map;for(const i of a){const n=T(i.path)??i.path;e.set(n,{session:i,children:[]})}const s=[];for(const i of a){const n=T(i.path)??i.path,o=e.get(n),r=T(i.parentSessionPath);r&&e.has(r)?e.get(r).children.push(o):s.push(o)}const t=c(i=>{i.sort((n,o)=>o.session.modified.getTime()-n.session.modified.getTime());for(const n of i)t(n.children)},"sortNodes");return t(s),s}c(se,"buildSessionTree");function te(a){const e=[],s=c((t,i,n,o)=>{e.push({session:t.session,depth:i,isLast:o,ancestorContinues:n});for(let r=0;r<t.children.length;r++){const d=r===t.children.length-1,u=i>0?!o:!1;s(t.children[r],i+1,[...n,u],d)}},"walk");for(let t=0;t<a.length;t++)s(a[t],0,[],t===a.length-1);return e}c(te,"flattenSessionTree");class ie{static{c(this,"SessionList")}getSelectedSessionPath(){return this.filteredSessions[this.selectedIndex]?.session.path}allSessions=[];filteredSessions=[];selectedIndex=0;searchInput;showCwd=!1;sortMode="threaded";nameFilter="all";keybindings;showPath=!1;confirmingDeletePath=null;currentSessionCanonicalPath;onSelect;onCancel;onExit=c(()=>{},"onExit");onToggleScope;onToggleSort;onToggleNameFilter;onTogglePath;onDeleteConfirmationChange;onDeleteSession;onRenameSession;onError;maxVisible=10;_focused=!1;get focused(){return this._focused}set focused(e){this._focused=e,this.searchInput.focused=e}constructor(e,s,t,i,n,o){this.allSessions=e,this.filteredSessions=[],this.searchInput=new H,this.showCwd=s,this.sortMode=t,this.nameFilter=i,this.keybindings=n,this.currentSessionCanonicalPath=T(o),this.filterSessions(""),this.searchInput.onSubmit=()=>{if(this.filteredSessions[this.selectedIndex]){const r=this.filteredSessions[this.selectedIndex];this.onSelect&&this.onSelect(r.session.path)}}}setSortMode(e){this.sortMode=e,this.filterSessions(this.searchInput.getValue())}setNameFilter(e){this.nameFilter=e,this.filterSessions(this.searchInput.getValue())}setSessions(e,s){this.allSessions=e,this.showCwd=s,this.filterSessions(this.searchInput.getValue())}filterSessions(e){const s=e.trim(),t=this.nameFilter==="all"?this.allSessions:this.allSessions.filter(i=>Y(i));if(this.sortMode==="threaded"&&!s){const i=se(t);this.filteredSessions=te(i)}else{const i=X(t,e,this.sortMode,"all");this.filteredSessions=i.map(n=>({session:n,depth:0,isLast:!0,ancestorContinues:[]}))}this.selectedIndex=Math.min(this.selectedIndex,Math.max(0,this.filteredSessions.length-1))}setConfirmingDeletePath(e){this.confirmingDeletePath=e,this.onDeleteConfirmationChange?.(e)}startDeleteConfirmationForSelectedSession(){const e=this.filteredSessions[this.selectedIndex];if(e){if(this.isCurrentSessionPath(e.session.path)){this.onError?.("Cannot delete the currently active session");return}this.setConfirmingDeletePath(e.session.path)}}isCurrentSessionPath(e){return this.currentSessionCanonicalPath?(T(e)??e)===this.currentSessionCanonicalPath:!1}invalidate(){}render(e){const s=[];if(s.push(...this.searchInput.render(e)),s.push(""),this.filteredSessions.length===0){let n;if(this.nameFilter==="named"){const o=y("app.session.toggleNamedFilter");this.showCwd?n=` No named sessions found. Press ${o} to show all.`:n=` No named sessions in current folder. Press ${o} to show all, or Tab to view all.`}else this.showCwd?n=" No sessions found":n=" No sessions in current folder. Press Tab to view all.";return s.push(h.fg("muted",S(n,e,"\u2026"))),s}const t=Math.max(0,Math.min(this.selectedIndex-Math.floor(this.maxVisible/2),this.filteredSessions.length-this.maxVisible)),i=Math.min(t+this.maxVisible,this.filteredSessions.length);for(let n=t;n<i;n++){const o=this.filteredSessions[n],r=o.session,d=n===this.selectedIndex,u=r.path===this.confirmingDeletePath,x=this.isCurrentSessionPath(r.path),l=this.buildTreePrefix(o),M=!!r.name,g=(r.name??r.firstMessage).replace(/[\x00-\x1f\x7f]/g," ").trim(),m=Z(r.modified);let p=`${String(r.messageCount)} ${m}`;this.showCwd&&r.cwd&&(p=`${A(r.cwd)} ${p}`),this.showPath&&(p=`${A(r.path)} ${p}`);const R=d?h.fg("accent","\u203A "):" ",b=w(l),W=w(p)+2,_=e-2-b-W,q=S(g,Math.max(10,_),"\u2026");let I=null;u?I="error":x?I="accent":M&&(I="warning");let $=I?h.fg(I,q):q;d&&($=h.bold($));const N=R+h.fg("dim",l)+$,k=w(N),z=Math.max(1,e-k-w(p)),B=h.fg(u?"error":"dim",p);let F=N+" ".repeat(z)+B;d&&(F=h.bg("selectedBg",F)),s.push(S(F,e))}if(t>0||i<this.filteredSessions.length){const n=` (${this.selectedIndex+1}/${this.filteredSessions.length})`,o=h.fg("muted",S(n,e,""));s.push(o)}return s}buildTreePrefix(e){if(e.depth===0)return"";const s=e.ancestorContinues.map(i=>i?"\u2502 ":" "),t=e.isLast?"\u2514\u2500 ":"\u251C\u2500 ";return s.join("")+t}handleInput(e){const s=v();if(this.confirmingDeletePath!==null){if(s.matches(e,"tui.select.confirm")){const t=this.confirmingDeletePath;this.setConfirmingDeletePath(null),this.onDeleteSession?.(t);return}if(s.matches(e,"tui.select.cancel")){this.setConfirmingDeletePath(null);return}return}if(s.matches(e,"tui.input.tab")){this.onToggleScope&&this.onToggleScope();return}if(s.matches(e,"app.session.toggleSort")){this.onToggleSort?.();return}if(this.keybindings.matches(e,"app.session.toggleNamedFilter")){this.onToggleNameFilter?.();return}if(s.matches(e,"app.session.togglePath")){this.showPath=!this.showPath,this.onTogglePath?.(this.showPath);return}if(s.matches(e,"app.session.delete")){this.startDeleteConfirmationForSelectedSession();return}if(s.matches(e,"app.session.rename")){const t=this.filteredSessions[this.selectedIndex];t&&this.onRenameSession?.(t.session.path);return}if(s.matches(e,"app.session.deleteNoninvasive")){if(this.searchInput.getValue().length>0){this.searchInput.handleInput(e),this.filterSessions(this.searchInput.getValue());return}this.startDeleteConfirmationForSelectedSession();return}if(s.matches(e,"tui.select.up"))this.selectedIndex=Math.max(0,this.selectedIndex-1);else if(s.matches(e,"tui.select.down"))this.selectedIndex=Math.min(this.filteredSessions.length-1,this.selectedIndex+1);else if(s.matches(e,"tui.select.pageUp"))this.selectedIndex=Math.max(0,this.selectedIndex-this.maxVisible);else if(s.matches(e,"tui.select.pageDown"))this.selectedIndex=Math.min(this.filteredSessions.length-1,this.selectedIndex+this.maxVisible);else if(s.matches(e,"tui.select.confirm")){const t=this.filteredSessions[this.selectedIndex];t&&this.onSelect&&this.onSelect(t.session.path)}else s.matches(e,"tui.select.cancel")?this.onCancel&&this.onCancel():(this.searchInput.handleInput(e),this.filterSessions(this.searchInput.getValue()))}}async function ne(a){const e=a.startsWith("-")?["--",a]:[a],s=K("trash",e,{encoding:"utf-8"}),t=c(()=>{const i=[];s.error&&i.push(s.error.message);const n=s.stderr?.trim();return n&&i.push(n.split(`
2
+ `)[0]??n),i.length===0?null:`trash: ${i.join(" \xB7 ").slice(0,200)}`},"getTrashErrorHint");if(s.status===0||!U(a))return{ok:!0,method:"trash"};try{return await G(a),{ok:!0,method:"unlink"}}catch(i){const n=i instanceof Error?i.message:String(i),o=t();return{ok:!1,method:"unlink",error:o?`${n} (${o})`:n}}}c(ne,"deleteSessionFile");class Se extends D{static{c(this,"SessionSelectorComponent")}handleInput(e){if(this.mode==="rename"){if(v().matches(e,"tui.select.cancel")){this.exitRenameMode();return}this.renameInput.handleInput(e);return}this.sessionList.handleInput(e)}canRename=!0;sessionList;header;keybindings;scope="current";sortMode="threaded";nameFilter="all";currentSessions=null;allSessions=null;currentSessionsLoader;allSessionsLoader;onCancel;requestRender;renameSession;currentLoading=!1;allLoading=!1;allLoadSeq=0;mode="list";renameInput=new H;renameTargetPath=null;_focused=!1;get focused(){return this._focused}set focused(e){this._focused=e,this.sessionList.focused=e,this.renameInput.focused=e,e&&this.mode==="rename"&&(this.renameInput.focused=!0)}buildBaseLayout(e,s){this.clear(),this.addChild(new P(1)),this.addChild(new E(t=>h.fg("accent",t))),this.addChild(new P(1)),(s?.showHeader??!0)&&(this.addChild(this.header),this.addChild(new P(1))),this.addChild(e),this.addChild(new P(1)),this.addChild(new E(t=>h.fg("accent",t)))}constructor(e,s,t,i,n,o,r,d){super(),this.keybindings=r?.keybindings??O.create(),this.currentSessionsLoader=e,this.allSessionsLoader=s,this.onCancel=i,this.requestRender=o,this.header=new ee(this.scope,this.sortMode,this.nameFilter,this.requestRender);const u=r?.renameSession;this.renameSession=u,this.canRename=!!u,this.header.setShowRenameHint(r?.showRenameHint??this.canRename),this.sessionList=new ie([],!1,this.sortMode,this.nameFilter,this.keybindings,d),this.buildBaseLayout(this.sessionList),this.renameInput.onSubmit=l=>{this.confirmRename(l)};const x=c(()=>this.header.setStatusMessage(null),"clearStatusMessage");this.sessionList.onSelect=l=>{x(),t(l)},this.sessionList.onCancel=()=>{x(),i()},this.sessionList.onExit=()=>{x(),n()},this.sessionList.onToggleScope=()=>this.toggleScope(),this.sessionList.onToggleSort=()=>this.toggleSortMode(),this.sessionList.onToggleNameFilter=()=>this.toggleNameFilter(),this.sessionList.onRenameSession=l=>{if(!u||this.scope==="current"&&this.currentLoading||this.scope==="all"&&this.allLoading)return;const f=(this.scope==="all"?this.allSessions??[]:this.currentSessions??[]).find(g=>g.path===l);this.enterRenameMode(l,f?.name)},this.sessionList.onTogglePath=l=>{this.header.setShowPath(l),this.requestRender()},this.sessionList.onDeleteConfirmationChange=l=>{this.header.setConfirmingDeletePath(l),this.requestRender()},this.sessionList.onError=l=>{this.header.setStatusMessage({type:"error",message:l},3e3),this.requestRender()},this.sessionList.onDeleteSession=async l=>{const M=await ne(l);if(M.ok){this.currentSessions&&(this.currentSessions=this.currentSessions.filter(C=>C.path!==l)),this.allSessions&&(this.allSessions=this.allSessions.filter(C=>C.path!==l));const f=this.scope==="all"?this.allSessions??[]:this.currentSessions??[],g=this.scope==="all";this.sessionList.setSessions(f,g);const m=M.method==="trash"?"Session moved to trash":"Session deleted";this.header.setStatusMessage({type:"info",message:m},2e3),await this.refreshSessionsAfterMutation()}else{const f=M.error??"Unknown error";this.header.setStatusMessage({type:"error",message:`Failed to delete: ${f}`},3e3)}this.requestRender()},this.loadCurrentSessions()}loadCurrentSessions(){this.loadScope("current","initial")}enterRenameMode(e,s){this.mode="rename",this.renameTargetPath=e,this.renameInput.setValue(s??""),this.renameInput.focused=!0;const t=new D;t.addChild(new V(h.bold("Rename Session"),1,0)),t.addChild(new P(1)),t.addChild(this.renameInput),t.addChild(new P(1)),t.addChild(new V(h.fg("muted",`${y("tui.select.confirm")} to save \xB7 ${y("tui.select.cancel")} to cancel`),1,0)),this.buildBaseLayout(t,{showHeader:!1}),this.requestRender()}exitRenameMode(){this.mode="list",this.renameTargetPath=null,this.buildBaseLayout(this.sessionList),this.requestRender()}async confirmRename(e){const s=e.trim();if(!s)return;const t=this.renameTargetPath;if(!t){this.exitRenameMode();return}const i=this.renameSession;if(!i){this.exitRenameMode();return}try{await i(t,s),await this.refreshSessionsAfterMutation()}finally{this.exitRenameMode()}}async loadScope(e,s){const t=e==="all";e==="current"?this.currentLoading=!0:this.allLoading=!0;const i=e==="all"?++this.allLoadSeq:void 0;this.header.setScope(e),this.header.setLoading(!0),this.requestRender();const n=c((o,r)=>{e===this.scope&&(i!==void 0&&i!==this.allLoadSeq||(this.header.setProgress(o,r),this.requestRender()))},"onProgress");try{const o=await(e==="current"?this.currentSessionsLoader(n):this.allSessionsLoader(n));if(e==="current"?(this.currentSessions=o,this.currentLoading=!1):(this.allSessions=o,this.allLoading=!1),e!==this.scope||i!==void 0&&i!==this.allLoadSeq)return;this.header.setLoading(!1),this.sessionList.setSessions(o,t),this.requestRender(),e==="all"&&o.length===0&&(this.currentSessions?.length??0)===0&&this.onCancel()}catch(o){if(e==="current"?this.currentLoading=!1:this.allLoading=!1,e!==this.scope||i!==void 0&&i!==this.allLoadSeq)return;const r=o instanceof Error?o.message:String(o);this.header.setLoading(!1),this.header.setStatusMessage({type:"error",message:`Failed to load sessions: ${r}`},4e3),s==="initial"&&this.sessionList.setSessions([],t),this.requestRender()}}toggleSortMode(){this.sortMode=this.sortMode==="threaded"?"recent":this.sortMode==="recent"?"relevance":"threaded",this.header.setSortMode(this.sortMode),this.sessionList.setSortMode(this.sortMode),this.requestRender()}toggleNameFilter(){this.nameFilter=this.nameFilter==="all"?"named":"all",this.header.setNameFilter(this.nameFilter),this.sessionList.setNameFilter(this.nameFilter),this.requestRender()}async refreshSessionsAfterMutation(){await this.loadScope(this.scope,"refresh")}toggleScope(){if(this.scope==="current"){if(this.scope="all",this.header.setScope(this.scope),this.allSessions!==null){this.header.setLoading(!1),this.sessionList.setSessions(this.allSessions,!0),this.requestRender();return}this.allLoading||this.loadScope("all","toggle");return}this.scope="current",this.header.setScope(this.scope),this.header.setLoading(this.currentLoading),this.sessionList.setSessions(this.currentSessions??[],!1),this.requestRender()}getSessionList(){return this.sessionList}}export{Se as SessionSelectorComponent};