meetsoma 0.3.2 → 0.3.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 (515) hide show
  1. package/dist/thin-cli.js +56 -13
  2. package/package.json +42 -89
  3. package/bin/gum +0 -0
  4. package/dist/bun/cli.d.ts +0 -3
  5. package/dist/bun/cli.d.ts.map +0 -1
  6. package/dist/bun/cli.js +0 -7
  7. package/dist/bun/cli.js.map +0 -1
  8. package/dist/bun/register-bedrock.d.ts +0 -2
  9. package/dist/bun/register-bedrock.d.ts.map +0 -1
  10. package/dist/bun/register-bedrock.js +0 -4
  11. package/dist/bun/register-bedrock.js.map +0 -1
  12. package/dist/cli/args.d.ts +0 -49
  13. package/dist/cli/args.d.ts.map +0 -1
  14. package/dist/cli/args.js +0 -304
  15. package/dist/cli/args.js.map +0 -1
  16. package/dist/cli/config-selector.d.ts +0 -14
  17. package/dist/cli/config-selector.d.ts.map +0 -1
  18. package/dist/cli/config-selector.js +0 -31
  19. package/dist/cli/config-selector.js.map +0 -1
  20. package/dist/cli/file-processor.d.ts +0 -15
  21. package/dist/cli/file-processor.d.ts.map +0 -1
  22. package/dist/cli/file-processor.js +0 -83
  23. package/dist/cli/file-processor.js.map +0 -1
  24. package/dist/cli/initial-message.d.ts +0 -18
  25. package/dist/cli/initial-message.d.ts.map +0 -1
  26. package/dist/cli/initial-message.js +0 -22
  27. package/dist/cli/initial-message.js.map +0 -1
  28. package/dist/cli/list-models.d.ts +0 -9
  29. package/dist/cli/list-models.d.ts.map +0 -1
  30. package/dist/cli/list-models.js +0 -92
  31. package/dist/cli/list-models.js.map +0 -1
  32. package/dist/cli/session-picker.d.ts +0 -9
  33. package/dist/cli/session-picker.d.ts.map +0 -1
  34. package/dist/cli/session-picker.js +0 -35
  35. package/dist/cli/session-picker.js.map +0 -1
  36. package/dist/cli.d.ts +0 -3
  37. package/dist/cli.d.ts.map +0 -1
  38. package/dist/cli.js +0 -601
  39. package/dist/cli.js.map +0 -1
  40. package/dist/config.d.ts +0 -68
  41. package/dist/config.d.ts.map +0 -1
  42. package/dist/config.js +0 -203
  43. package/dist/config.js.map +0 -1
  44. package/dist/core/agent-session-runtime.d.ts +0 -134
  45. package/dist/core/agent-session-runtime.d.ts.map +0 -1
  46. package/dist/core/agent-session-runtime.js +0 -264
  47. package/dist/core/agent-session-runtime.js.map +0 -1
  48. package/dist/core/agent-session.d.ts +0 -585
  49. package/dist/core/agent-session.d.ts.map +0 -1
  50. package/dist/core/agent-session.js +0 -2497
  51. package/dist/core/agent-session.js.map +0 -1
  52. package/dist/core/auth-storage.d.ts +0 -132
  53. package/dist/core/auth-storage.d.ts.map +0 -1
  54. package/dist/core/auth-storage.js +0 -422
  55. package/dist/core/auth-storage.js.map +0 -1
  56. package/dist/core/bash-executor.d.ts +0 -46
  57. package/dist/core/bash-executor.d.ts.map +0 -1
  58. package/dist/core/bash-executor.js +0 -113
  59. package/dist/core/bash-executor.js.map +0 -1
  60. package/dist/core/compaction/branch-summarization.d.ts +0 -88
  61. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  62. package/dist/core/compaction/branch-summarization.js +0 -243
  63. package/dist/core/compaction/branch-summarization.js.map +0 -1
  64. package/dist/core/compaction/compaction.d.ts +0 -121
  65. package/dist/core/compaction/compaction.d.ts.map +0 -1
  66. package/dist/core/compaction/compaction.js +0 -613
  67. package/dist/core/compaction/compaction.js.map +0 -1
  68. package/dist/core/compaction/index.d.ts +0 -7
  69. package/dist/core/compaction/index.d.ts.map +0 -1
  70. package/dist/core/compaction/index.js +0 -7
  71. package/dist/core/compaction/index.js.map +0 -1
  72. package/dist/core/compaction/utils.d.ts +0 -38
  73. package/dist/core/compaction/utils.d.ts.map +0 -1
  74. package/dist/core/compaction/utils.js +0 -153
  75. package/dist/core/compaction/utils.js.map +0 -1
  76. package/dist/core/defaults.d.ts +0 -3
  77. package/dist/core/defaults.d.ts.map +0 -1
  78. package/dist/core/defaults.js +0 -2
  79. package/dist/core/defaults.js.map +0 -1
  80. package/dist/core/diagnostics.d.ts +0 -15
  81. package/dist/core/diagnostics.d.ts.map +0 -1
  82. package/dist/core/diagnostics.js +0 -2
  83. package/dist/core/diagnostics.js.map +0 -1
  84. package/dist/core/event-bus.d.ts +0 -9
  85. package/dist/core/event-bus.d.ts.map +0 -1
  86. package/dist/core/event-bus.js +0 -25
  87. package/dist/core/event-bus.js.map +0 -1
  88. package/dist/core/exec.d.ts +0 -29
  89. package/dist/core/exec.d.ts.map +0 -1
  90. package/dist/core/exec.js +0 -75
  91. package/dist/core/exec.js.map +0 -1
  92. package/dist/core/export-html/ansi-to-html.d.ts +0 -22
  93. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  94. package/dist/core/export-html/ansi-to-html.js +0 -249
  95. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  96. package/dist/core/export-html/index.d.ts +0 -37
  97. package/dist/core/export-html/index.d.ts.map +0 -1
  98. package/dist/core/export-html/index.js +0 -224
  99. package/dist/core/export-html/index.js.map +0 -1
  100. package/dist/core/export-html/template.css +0 -1001
  101. package/dist/core/export-html/template.html +0 -55
  102. package/dist/core/export-html/template.js +0 -1690
  103. package/dist/core/export-html/tool-renderer.d.ts +0 -40
  104. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  105. package/dist/core/export-html/tool-renderer.js +0 -95
  106. package/dist/core/export-html/tool-renderer.js.map +0 -1
  107. package/dist/core/export-html/vendor/highlight.min.js +0 -1213
  108. package/dist/core/export-html/vendor/marked.min.js +0 -6
  109. package/dist/core/extensions/index.d.ts +0 -12
  110. package/dist/core/extensions/index.d.ts.map +0 -1
  111. package/dist/core/extensions/index.js +0 -9
  112. package/dist/core/extensions/index.js.map +0 -1
  113. package/dist/core/extensions/loader.d.ts +0 -25
  114. package/dist/core/extensions/loader.d.ts.map +0 -1
  115. package/dist/core/extensions/loader.js +0 -436
  116. package/dist/core/extensions/loader.js.map +0 -1
  117. package/dist/core/extensions/runner.d.ts +0 -148
  118. package/dist/core/extensions/runner.d.ts.map +0 -1
  119. package/dist/core/extensions/runner.js +0 -700
  120. package/dist/core/extensions/runner.js.map +0 -1
  121. package/dist/core/extensions/types.d.ts +0 -1076
  122. package/dist/core/extensions/types.d.ts.map +0 -1
  123. package/dist/core/extensions/types.js +0 -35
  124. package/dist/core/extensions/types.js.map +0 -1
  125. package/dist/core/extensions/wrapper.d.ts +0 -20
  126. package/dist/core/extensions/wrapper.d.ts.map +0 -1
  127. package/dist/core/extensions/wrapper.js +0 -22
  128. package/dist/core/extensions/wrapper.js.map +0 -1
  129. package/dist/core/footer-data-provider.d.ts +0 -48
  130. package/dist/core/footer-data-provider.d.ts.map +0 -1
  131. package/dist/core/footer-data-provider.js +0 -314
  132. package/dist/core/footer-data-provider.js.map +0 -1
  133. package/dist/core/index.d.ts +0 -11
  134. package/dist/core/index.d.ts.map +0 -1
  135. package/dist/core/index.js +0 -11
  136. package/dist/core/index.js.map +0 -1
  137. package/dist/core/keybindings.d.ts +0 -285
  138. package/dist/core/keybindings.d.ts.map +0 -1
  139. package/dist/core/keybindings.js +0 -251
  140. package/dist/core/keybindings.js.map +0 -1
  141. package/dist/core/messages.d.ts +0 -77
  142. package/dist/core/messages.d.ts.map +0 -1
  143. package/dist/core/messages.js +0 -123
  144. package/dist/core/messages.js.map +0 -1
  145. package/dist/core/model-registry.d.ts +0 -132
  146. package/dist/core/model-registry.d.ts.map +0 -1
  147. package/dist/core/model-registry.js +0 -583
  148. package/dist/core/model-registry.js.map +0 -1
  149. package/dist/core/model-resolver.d.ts +0 -110
  150. package/dist/core/model-resolver.d.ts.map +0 -1
  151. package/dist/core/model-resolver.js +0 -486
  152. package/dist/core/model-resolver.js.map +0 -1
  153. package/dist/core/output-guard.d.ts +0 -6
  154. package/dist/core/output-guard.d.ts.map +0 -1
  155. package/dist/core/output-guard.js +0 -59
  156. package/dist/core/output-guard.js.map +0 -1
  157. package/dist/core/package-manager.d.ts +0 -172
  158. package/dist/core/package-manager.d.ts.map +0 -1
  159. package/dist/core/package-manager.js +0 -1783
  160. package/dist/core/package-manager.js.map +0 -1
  161. package/dist/core/prompt-templates.d.ts +0 -51
  162. package/dist/core/prompt-templates.d.ts.map +0 -1
  163. package/dist/core/prompt-templates.js +0 -249
  164. package/dist/core/prompt-templates.js.map +0 -1
  165. package/dist/core/resolve-config-value.d.ts +0 -23
  166. package/dist/core/resolve-config-value.d.ts.map +0 -1
  167. package/dist/core/resolve-config-value.js +0 -126
  168. package/dist/core/resolve-config-value.js.map +0 -1
  169. package/dist/core/resource-loader.d.ts +0 -185
  170. package/dist/core/resource-loader.d.ts.map +0 -1
  171. package/dist/core/resource-loader.js +0 -698
  172. package/dist/core/resource-loader.js.map +0 -1
  173. package/dist/core/sdk.d.ts +0 -93
  174. package/dist/core/sdk.d.ts.map +0 -1
  175. package/dist/core/sdk.js +0 -236
  176. package/dist/core/sdk.js.map +0 -1
  177. package/dist/core/session-manager.d.ts +0 -332
  178. package/dist/core/session-manager.d.ts.map +0 -1
  179. package/dist/core/session-manager.js +0 -1104
  180. package/dist/core/session-manager.js.map +0 -1
  181. package/dist/core/settings-manager.d.ts +0 -237
  182. package/dist/core/settings-manager.d.ts.map +0 -1
  183. package/dist/core/settings-manager.js +0 -702
  184. package/dist/core/settings-manager.js.map +0 -1
  185. package/dist/core/skills.d.ts +0 -60
  186. package/dist/core/skills.d.ts.map +0 -1
  187. package/dist/core/skills.js +0 -409
  188. package/dist/core/skills.js.map +0 -1
  189. package/dist/core/slash-commands.d.ts +0 -14
  190. package/dist/core/slash-commands.d.ts.map +0 -1
  191. package/dist/core/slash-commands.js +0 -23
  192. package/dist/core/slash-commands.js.map +0 -1
  193. package/dist/core/source-info.d.ts +0 -18
  194. package/dist/core/source-info.d.ts.map +0 -1
  195. package/dist/core/source-info.js +0 -19
  196. package/dist/core/source-info.js.map +0 -1
  197. package/dist/core/system-prompt.d.ts +0 -28
  198. package/dist/core/system-prompt.d.ts.map +0 -1
  199. package/dist/core/system-prompt.js +0 -116
  200. package/dist/core/system-prompt.js.map +0 -1
  201. package/dist/core/timings.d.ts +0 -8
  202. package/dist/core/timings.d.ts.map +0 -1
  203. package/dist/core/timings.js +0 -31
  204. package/dist/core/timings.js.map +0 -1
  205. package/dist/core/tools/bash.d.ts +0 -73
  206. package/dist/core/tools/bash.d.ts.map +0 -1
  207. package/dist/core/tools/bash.js +0 -342
  208. package/dist/core/tools/bash.js.map +0 -1
  209. package/dist/core/tools/edit-diff.d.ts +0 -85
  210. package/dist/core/tools/edit-diff.d.ts.map +0 -1
  211. package/dist/core/tools/edit-diff.js +0 -337
  212. package/dist/core/tools/edit-diff.js.map +0 -1
  213. package/dist/core/tools/edit.d.ts +0 -53
  214. package/dist/core/tools/edit.d.ts.map +0 -1
  215. package/dist/core/tools/edit.js +0 -196
  216. package/dist/core/tools/edit.js.map +0 -1
  217. package/dist/core/tools/file-mutation-queue.d.ts +0 -6
  218. package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
  219. package/dist/core/tools/file-mutation-queue.js +0 -37
  220. package/dist/core/tools/file-mutation-queue.js.map +0 -1
  221. package/dist/core/tools/find.d.ts +0 -46
  222. package/dist/core/tools/find.d.ts.map +0 -1
  223. package/dist/core/tools/find.js +0 -258
  224. package/dist/core/tools/find.js.map +0 -1
  225. package/dist/core/tools/grep.d.ts +0 -56
  226. package/dist/core/tools/grep.d.ts.map +0 -1
  227. package/dist/core/tools/grep.js +0 -293
  228. package/dist/core/tools/grep.js.map +0 -1
  229. package/dist/core/tools/index.d.ts +0 -115
  230. package/dist/core/tools/index.d.ts.map +0 -1
  231. package/dist/core/tools/index.js +0 -86
  232. package/dist/core/tools/index.js.map +0 -1
  233. package/dist/core/tools/ls.d.ts +0 -46
  234. package/dist/core/tools/ls.d.ts.map +0 -1
  235. package/dist/core/tools/ls.js +0 -172
  236. package/dist/core/tools/ls.js.map +0 -1
  237. package/dist/core/tools/path-utils.d.ts +0 -8
  238. package/dist/core/tools/path-utils.d.ts.map +0 -1
  239. package/dist/core/tools/path-utils.js +0 -81
  240. package/dist/core/tools/path-utils.js.map +0 -1
  241. package/dist/core/tools/read.d.ts +0 -46
  242. package/dist/core/tools/read.d.ts.map +0 -1
  243. package/dist/core/tools/read.js +0 -225
  244. package/dist/core/tools/read.js.map +0 -1
  245. package/dist/core/tools/render-utils.d.ts +0 -21
  246. package/dist/core/tools/render-utils.d.ts.map +0 -1
  247. package/dist/core/tools/render-utils.js +0 -49
  248. package/dist/core/tools/render-utils.js.map +0 -1
  249. package/dist/core/tools/tool-definition-wrapper.d.ts +0 -14
  250. package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
  251. package/dist/core/tools/tool-definition-wrapper.js +0 -32
  252. package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
  253. package/dist/core/tools/truncate.d.ts +0 -70
  254. package/dist/core/tools/truncate.d.ts.map +0 -1
  255. package/dist/core/tools/truncate.js +0 -205
  256. package/dist/core/tools/truncate.js.map +0 -1
  257. package/dist/core/tools/write.d.ts +0 -35
  258. package/dist/core/tools/write.d.ts.map +0 -1
  259. package/dist/core/tools/write.js +0 -216
  260. package/dist/core/tools/write.js.map +0 -1
  261. package/dist/index.d.ts +0 -28
  262. package/dist/index.d.ts.map +0 -1
  263. package/dist/index.js +0 -43
  264. package/dist/index.js.map +0 -1
  265. package/dist/lib/config.js +0 -22
  266. package/dist/lib/detect.js +0 -94
  267. package/dist/lib/display.js +0 -182
  268. package/dist/main.d.ts +0 -8
  269. package/dist/main.d.ts.map +0 -1
  270. package/dist/main.js +0 -806
  271. package/dist/main.js.map +0 -1
  272. package/dist/migrations.d.ts +0 -33
  273. package/dist/migrations.d.ts.map +0 -1
  274. package/dist/migrations.js +0 -261
  275. package/dist/migrations.js.map +0 -1
  276. package/dist/modes/index.d.ts +0 -9
  277. package/dist/modes/index.d.ts.map +0 -1
  278. package/dist/modes/index.js +0 -8
  279. package/dist/modes/index.js.map +0 -1
  280. package/dist/modes/interactive/components/armin.d.ts +0 -34
  281. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  282. package/dist/modes/interactive/components/armin.js +0 -333
  283. package/dist/modes/interactive/components/armin.js.map +0 -1
  284. package/dist/modes/interactive/components/assistant-message.d.ts +0 -18
  285. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  286. package/dist/modes/interactive/components/assistant-message.js +0 -107
  287. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  288. package/dist/modes/interactive/components/bash-execution.d.ts +0 -34
  289. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  290. package/dist/modes/interactive/components/bash-execution.js +0 -175
  291. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  292. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
  293. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  294. package/dist/modes/interactive/components/bordered-loader.js +0 -51
  295. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  296. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
  297. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  298. package/dist/modes/interactive/components/branch-summary-message.js +0 -44
  299. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  300. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
  301. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  302. package/dist/modes/interactive/components/compaction-summary-message.js +0 -45
  303. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  304. package/dist/modes/interactive/components/config-selector.d.ts +0 -71
  305. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  306. package/dist/modes/interactive/components/config-selector.js +0 -479
  307. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  308. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
  309. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  310. package/dist/modes/interactive/components/countdown-timer.js +0 -33
  311. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  312. package/dist/modes/interactive/components/custom-editor.d.ts +0 -21
  313. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  314. package/dist/modes/interactive/components/custom-editor.js +0 -70
  315. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  316. package/dist/modes/interactive/components/custom-message.d.ts +0 -20
  317. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  318. package/dist/modes/interactive/components/custom-message.js +0 -79
  319. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  320. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  321. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  322. package/dist/modes/interactive/components/daxnuts.js +0 -140
  323. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  324. package/dist/modes/interactive/components/diff.d.ts +0 -12
  325. package/dist/modes/interactive/components/diff.d.ts.map +0 -1
  326. package/dist/modes/interactive/components/diff.js +0 -133
  327. package/dist/modes/interactive/components/diff.js.map +0 -1
  328. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
  329. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  330. package/dist/modes/interactive/components/dynamic-border.js +0 -21
  331. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  332. package/dist/modes/interactive/components/extension-editor.d.ts +0 -20
  333. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  334. package/dist/modes/interactive/components/extension-editor.js +0 -111
  335. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  336. package/dist/modes/interactive/components/extension-input.d.ts +0 -23
  337. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  338. package/dist/modes/interactive/components/extension-input.js +0 -61
  339. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  340. package/dist/modes/interactive/components/extension-selector.d.ts +0 -24
  341. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  342. package/dist/modes/interactive/components/extension-selector.js +0 -78
  343. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  344. package/dist/modes/interactive/components/footer.d.ts +0 -27
  345. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  346. package/dist/modes/interactive/components/footer.js +0 -201
  347. package/dist/modes/interactive/components/footer.js.map +0 -1
  348. package/dist/modes/interactive/components/index.d.ts +0 -32
  349. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  350. package/dist/modes/interactive/components/index.js +0 -33
  351. package/dist/modes/interactive/components/index.js.map +0 -1
  352. package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -8
  353. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
  354. package/dist/modes/interactive/components/keybinding-hints.js +0 -22
  355. package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
  356. package/dist/modes/interactive/components/login-dialog.d.ts +0 -42
  357. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  358. package/dist/modes/interactive/components/login-dialog.js +0 -145
  359. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  360. package/dist/modes/interactive/components/model-selector.d.ts +0 -47
  361. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  362. package/dist/modes/interactive/components/model-selector.js +0 -275
  363. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  364. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -19
  365. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  366. package/dist/modes/interactive/components/oauth-selector.js +0 -97
  367. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  368. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -49
  369. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  370. package/dist/modes/interactive/components/scoped-models-selector.js +0 -275
  371. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  372. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
  373. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  374. package/dist/modes/interactive/components/session-selector-search.js +0 -155
  375. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  376. package/dist/modes/interactive/components/session-selector.d.ts +0 -95
  377. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  378. package/dist/modes/interactive/components/session-selector.js +0 -848
  379. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  380. package/dist/modes/interactive/components/settings-selector.d.ts +0 -58
  381. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  382. package/dist/modes/interactive/components/settings-selector.js +0 -301
  383. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  384. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
  385. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  386. package/dist/modes/interactive/components/show-images-selector.js +0 -39
  387. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  388. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
  389. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  390. package/dist/modes/interactive/components/skill-invocation-message.js +0 -47
  391. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  392. package/dist/modes/interactive/components/theme-selector.d.ts +0 -11
  393. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  394. package/dist/modes/interactive/components/theme-selector.js +0 -50
  395. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  396. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
  397. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  398. package/dist/modes/interactive/components/thinking-selector.js +0 -51
  399. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  400. package/dist/modes/interactive/components/tool-execution.d.ts +0 -58
  401. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  402. package/dist/modes/interactive/components/tool-execution.js +0 -274
  403. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  404. package/dist/modes/interactive/components/tree-selector.d.ts +0 -89
  405. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  406. package/dist/modes/interactive/components/tree-selector.js +0 -1084
  407. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  408. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
  409. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  410. package/dist/modes/interactive/components/user-message-selector.js +0 -113
  411. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  412. package/dist/modes/interactive/components/user-message.d.ts +0 -9
  413. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  414. package/dist/modes/interactive/components/user-message.js +0 -28
  415. package/dist/modes/interactive/components/user-message.js.map +0 -1
  416. package/dist/modes/interactive/components/visual-truncate.d.ts +0 -24
  417. package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
  418. package/dist/modes/interactive/components/visual-truncate.js +0 -33
  419. package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
  420. package/dist/modes/interactive/interactive-mode.d.ts +0 -318
  421. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  422. package/dist/modes/interactive/interactive-mode.js +0 -3907
  423. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  424. package/dist/modes/interactive/theme/dark.json +0 -85
  425. package/dist/modes/interactive/theme/light.json +0 -84
  426. package/dist/modes/interactive/theme/theme-schema.json +0 -335
  427. package/dist/modes/interactive/theme/theme.d.ts +0 -81
  428. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  429. package/dist/modes/interactive/theme/theme.js +0 -970
  430. package/dist/modes/interactive/theme/theme.js.map +0 -1
  431. package/dist/modes/print-mode.d.ts +0 -28
  432. package/dist/modes/print-mode.d.ts.map +0 -1
  433. package/dist/modes/print-mode.js +0 -108
  434. package/dist/modes/print-mode.js.map +0 -1
  435. package/dist/modes/rpc/jsonl.d.ts +0 -17
  436. package/dist/modes/rpc/jsonl.d.ts.map +0 -1
  437. package/dist/modes/rpc/jsonl.js +0 -49
  438. package/dist/modes/rpc/jsonl.js.map +0 -1
  439. package/dist/modes/rpc/rpc-client.d.ts +0 -217
  440. package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
  441. package/dist/modes/rpc/rpc-client.js +0 -401
  442. package/dist/modes/rpc/rpc-client.js.map +0 -1
  443. package/dist/modes/rpc/rpc-mode.d.ts +0 -20
  444. package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
  445. package/dist/modes/rpc/rpc-mode.js +0 -542
  446. package/dist/modes/rpc/rpc-mode.js.map +0 -1
  447. package/dist/modes/rpc/rpc-types.d.ts +0 -408
  448. package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
  449. package/dist/modes/rpc/rpc-types.js +0 -8
  450. package/dist/modes/rpc/rpc-types.js.map +0 -1
  451. package/dist/utils/changelog.d.ts +0 -21
  452. package/dist/utils/changelog.d.ts.map +0 -1
  453. package/dist/utils/changelog.js +0 -87
  454. package/dist/utils/changelog.js.map +0 -1
  455. package/dist/utils/child-process.d.ts +0 -11
  456. package/dist/utils/child-process.d.ts.map +0 -1
  457. package/dist/utils/child-process.js +0 -78
  458. package/dist/utils/child-process.js.map +0 -1
  459. package/dist/utils/clipboard-image.d.ts +0 -11
  460. package/dist/utils/clipboard-image.d.ts.map +0 -1
  461. package/dist/utils/clipboard-image.js +0 -245
  462. package/dist/utils/clipboard-image.js.map +0 -1
  463. package/dist/utils/clipboard-native.d.ts +0 -8
  464. package/dist/utils/clipboard-native.d.ts.map +0 -1
  465. package/dist/utils/clipboard-native.js +0 -14
  466. package/dist/utils/clipboard-native.js.map +0 -1
  467. package/dist/utils/clipboard.d.ts +0 -2
  468. package/dist/utils/clipboard.d.ts.map +0 -1
  469. package/dist/utils/clipboard.js +0 -78
  470. package/dist/utils/clipboard.js.map +0 -1
  471. package/dist/utils/exif-orientation.d.ts +0 -5
  472. package/dist/utils/exif-orientation.d.ts.map +0 -1
  473. package/dist/utils/exif-orientation.js +0 -158
  474. package/dist/utils/exif-orientation.js.map +0 -1
  475. package/dist/utils/frontmatter.d.ts +0 -8
  476. package/dist/utils/frontmatter.d.ts.map +0 -1
  477. package/dist/utils/frontmatter.js +0 -26
  478. package/dist/utils/frontmatter.js.map +0 -1
  479. package/dist/utils/git.d.ts +0 -26
  480. package/dist/utils/git.d.ts.map +0 -1
  481. package/dist/utils/git.js +0 -163
  482. package/dist/utils/git.js.map +0 -1
  483. package/dist/utils/image-convert.d.ts +0 -9
  484. package/dist/utils/image-convert.d.ts.map +0 -1
  485. package/dist/utils/image-convert.js +0 -39
  486. package/dist/utils/image-convert.js.map +0 -1
  487. package/dist/utils/image-resize.d.ts +0 -36
  488. package/dist/utils/image-resize.d.ts.map +0 -1
  489. package/dist/utils/image-resize.js +0 -137
  490. package/dist/utils/image-resize.js.map +0 -1
  491. package/dist/utils/mime.d.ts +0 -2
  492. package/dist/utils/mime.d.ts.map +0 -1
  493. package/dist/utils/mime.js +0 -26
  494. package/dist/utils/mime.js.map +0 -1
  495. package/dist/utils/photon.d.ts +0 -21
  496. package/dist/utils/photon.d.ts.map +0 -1
  497. package/dist/utils/photon.js +0 -121
  498. package/dist/utils/photon.js.map +0 -1
  499. package/dist/utils/shell.d.ts +0 -26
  500. package/dist/utils/shell.d.ts.map +0 -1
  501. package/dist/utils/shell.js +0 -186
  502. package/dist/utils/shell.js.map +0 -1
  503. package/dist/utils/sleep.d.ts +0 -5
  504. package/dist/utils/sleep.d.ts.map +0 -1
  505. package/dist/utils/sleep.js +0 -17
  506. package/dist/utils/sleep.js.map +0 -1
  507. package/dist/utils/tools-manager.d.ts +0 -3
  508. package/dist/utils/tools-manager.d.ts.map +0 -1
  509. package/dist/utils/tools-manager.js +0 -252
  510. package/dist/utils/tools-manager.js.map +0 -1
  511. package/dist/welcome/about.js +0 -50
  512. package/dist/welcome/auth.js +0 -126
  513. package/dist/welcome/intro.js +0 -90
  514. package/dist/welcome/qa.js +0 -131
  515. package/scripts/install-gum.sh +0 -141
@@ -1 +0,0 @@
1
- {"version":3,"file":"scoped-models-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/scoped-models-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAGd,KAAK,EAKL,MAAM,sBAAsB,CAAC;AA2D9B,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACxB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,qEAAqE;IACrE,sBAAsB,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC/B,gEAAgE;IAChE,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,sEAAsE;IACtE,SAAS,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC/C,0EAA0E;IAC1E,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yCAAyC;IACzC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,sFAAsF;IACtF,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnF,QAAQ,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,SAAU,YAAW,SAAS;IAChF,OAAO,CAAC,UAAU,CAAsC;IACxD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAQ;IAG3B,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IACD,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,OAAO,CAAS;IAExB,YAAY,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAoC3D;IAED,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,UAAU;IAuClB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAmH9B;IAED,cAAc,IAAI,KAAK,CAEtB;CACD","sourcesContent":["import type { Model } from \"@mariozechner/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\n\n// EnabledIds: null = all enabled (no filter), string[] = explicit ordered list\ntype EnabledIds = string[] | null;\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id]; // First toggle: start with only this one\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null; // Already all enabled\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, allIds: string[], id: string, delta: number): EnabledIds {\n\tconst list = enabledIds ?? [...allIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\ninterface ModelItem {\n\tfullId: string;\n\tmodel: Model<any>;\n\tenabled: boolean;\n}\n\nexport interface ModelsConfig {\n\tallModels: Model<any>[];\n\tenabledModelIds: Set<string>;\n\t/** true if enabledModels setting is defined (empty = all enabled) */\n\thasEnabledModelsFilter: boolean;\n}\n\nexport interface ModelsCallbacks {\n\t/** Called when a model is toggled (session-only, no persist) */\n\tonModelToggle: (modelId: string, enabled: boolean) => void;\n\t/** Called when user wants to persist current selection to settings */\n\tonPersist: (enabledModelIds: string[]) => void;\n\t/** Called when user enables all models. Returns list of all model IDs. */\n\tonEnableAll: (allModelIds: string[]) => void;\n\t/** Called when user clears all models */\n\tonClearAll: () => void;\n\t/** Called when user toggles all models for a provider. Returns affected model IDs. */\n\tonToggleProvider: (provider: string, modelIds: string[], enabled: boolean) => void;\n\tonCancel: () => void;\n}\n\n/**\n * Component for enabling/disabling models for Ctrl+P cycling.\n * Changes are session-only until explicitly persisted with Ctrl+S.\n */\nexport class ScopedModelsSelectorComponent extends Container implements Focusable {\n\tprivate modelsById: Map<string, Model<any>> = new Map();\n\tprivate allIds: string[] = [];\n\tprivate enabledIds: EnabledIds = null;\n\tprivate filteredItems: ModelItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\n\t// Focusable implementation - propagate to searchInput for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\tprivate listContainer: Container;\n\tprivate footerText: Text;\n\tprivate callbacks: ModelsCallbacks;\n\tprivate maxVisible = 15;\n\tprivate isDirty = false;\n\n\tconstructor(config: ModelsConfig, callbacks: ModelsCallbacks) {\n\t\tsuper();\n\t\tthis.callbacks = callbacks;\n\n\t\tfor (const model of config.allModels) {\n\t\t\tconst fullId = `${model.provider}/${model.id}`;\n\t\t\tthis.modelsById.set(fullId, model);\n\t\t\tthis.allIds.push(fullId);\n\t\t}\n\n\t\tthis.enabledIds = config.hasEnabledModelsFilter ? [...config.enabledModelIds] : null;\n\t\tthis.filteredItems = this.buildItems();\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Model Configuration\")), 0, 0));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"Session-only. Ctrl+S to save to settings.\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.updateList();\n\t}\n\n\tprivate buildItems(): ModelItem[] {\n\t\t// Filter out IDs that no longer have a corresponding model (e.g., after logout)\n\t\treturn getSortedIds(this.enabledIds, this.allIds)\n\t\t\t.filter((id) => this.modelsById.has(id))\n\t\t\t.map((id) => ({\n\t\t\t\tfullId: id,\n\t\t\t\tmodel: this.modelsById.get(id)!,\n\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t}));\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst enabledCount = this.enabledIds?.length ?? this.allIds.length;\n\t\tconst allEnabled = this.enabledIds === null;\n\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.allIds.length} enabled`;\n\t\tconst parts = [\"Enter toggle\", \"^A all\", \"^X clear\", \"^P provider\", \"Alt+↑↓ reorder\", \"^S save\", countText];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.filteredItems.length > 0) {\n\t\t\tconst selected = this.filteredItems[this.selectedIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` Model Name: ${selected.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Alt+Up/Down - Reorder enabled models\n\t\tif (matchesKey(data, Key.alt(\"up\")) || matchesKey(data, Key.alt(\"down\"))) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = matchesKey(data, Key.alt(\"up\")) ? -1 : 1;\n\t\t\t\tconst enabledList = this.enabledIds ?? this.allIds;\n\t\t\t\tconst currentIndex = enabledList.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\t// Only move if within bounds\n\t\t\t\tif (newIndex >= 0 && newIndex < enabledList.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, this.allIds, item.fullId, delta);\n\t\t\t\t\tthis.isDirty = true;\n\t\t\t\t\tthis.selectedIndex += delta;\n\t\t\t\t\tthis.refresh();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on Enter\n\t\tif (matchesKey(data, Key.enter)) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst wasAllEnabled = this.enabledIds === null;\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tif (wasAllEnabled) this.callbacks.onClearAll();\n\t\t\t\tthis.callbacks.onModelToggle(item.fullId, isEnabled(this.enabledIds, item.fullId));\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+A - Enable all (filtered if search active, otherwise all)\n\t\tif (matchesKey(data, Key.ctrl(\"a\"))) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.allIds, targetIds);\n\t\t\tthis.isDirty = true;\n\t\t\tthis.callbacks.onEnableAll(targetIds ?? this.allIds);\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+X - Clear all (filtered if search active, otherwise all)\n\t\tif (matchesKey(data, Key.ctrl(\"x\"))) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.allIds, targetIds);\n\t\t\tthis.isDirty = true;\n\t\t\tthis.callbacks.onClearAll();\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+P - Toggle provider of current item\n\t\tif (matchesKey(data, Key.ctrl(\"p\"))) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.allIds.filter((id) => this.modelsById.get(id)!.provider === provider);\n\t\t\t\tconst allEnabled = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allEnabled\n\t\t\t\t\t? clearAll(this.enabledIds, this.allIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.allIds, providerIds);\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.callbacks.onToggleProvider(provider, providerIds, !allEnabled);\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+S - Save/persist to settings\n\t\tif (matchesKey(data, Key.ctrl(\"s\"))) {\n\t\t\tthis.callbacks.onPersist(this.enabledIds ?? [...this.allIds]);\n\t\t\tthis.isDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape - cancel\n\t\tif (matchesKey(data, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
@@ -1,275 +0,0 @@
1
- import { Container, fuzzyFilter, getKeybindings, Input, Key, matchesKey, Spacer, Text, } from "@mariozechner/pi-tui";
2
- import { theme } from "../theme/theme.js";
3
- import { DynamicBorder } from "./dynamic-border.js";
4
- function isEnabled(enabledIds, id) {
5
- return enabledIds === null || enabledIds.includes(id);
6
- }
7
- function toggle(enabledIds, id) {
8
- if (enabledIds === null)
9
- return [id]; // First toggle: start with only this one
10
- const index = enabledIds.indexOf(id);
11
- if (index >= 0)
12
- return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];
13
- return [...enabledIds, id];
14
- }
15
- function enableAll(enabledIds, allIds, targetIds) {
16
- if (enabledIds === null)
17
- return null; // Already all enabled
18
- const targets = targetIds ?? allIds;
19
- const result = [...enabledIds];
20
- for (const id of targets) {
21
- if (!result.includes(id))
22
- result.push(id);
23
- }
24
- return result.length === allIds.length ? null : result;
25
- }
26
- function clearAll(enabledIds, allIds, targetIds) {
27
- if (enabledIds === null) {
28
- return targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];
29
- }
30
- const targets = new Set(targetIds ?? enabledIds);
31
- return enabledIds.filter((id) => !targets.has(id));
32
- }
33
- function move(enabledIds, allIds, id, delta) {
34
- const list = enabledIds ?? [...allIds];
35
- const index = list.indexOf(id);
36
- if (index < 0)
37
- return list;
38
- const newIndex = index + delta;
39
- if (newIndex < 0 || newIndex >= list.length)
40
- return list;
41
- const result = [...list];
42
- [result[index], result[newIndex]] = [result[newIndex], result[index]];
43
- return result;
44
- }
45
- function getSortedIds(enabledIds, allIds) {
46
- if (enabledIds === null)
47
- return allIds;
48
- const enabledSet = new Set(enabledIds);
49
- return [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];
50
- }
51
- /**
52
- * Component for enabling/disabling models for Ctrl+P cycling.
53
- * Changes are session-only until explicitly persisted with Ctrl+S.
54
- */
55
- export class ScopedModelsSelectorComponent extends Container {
56
- modelsById = new Map();
57
- allIds = [];
58
- enabledIds = null;
59
- filteredItems = [];
60
- selectedIndex = 0;
61
- searchInput;
62
- // Focusable implementation - propagate to searchInput for IME cursor positioning
63
- _focused = false;
64
- get focused() {
65
- return this._focused;
66
- }
67
- set focused(value) {
68
- this._focused = value;
69
- this.searchInput.focused = value;
70
- }
71
- listContainer;
72
- footerText;
73
- callbacks;
74
- maxVisible = 15;
75
- isDirty = false;
76
- constructor(config, callbacks) {
77
- super();
78
- this.callbacks = callbacks;
79
- for (const model of config.allModels) {
80
- const fullId = `${model.provider}/${model.id}`;
81
- this.modelsById.set(fullId, model);
82
- this.allIds.push(fullId);
83
- }
84
- this.enabledIds = config.hasEnabledModelsFilter ? [...config.enabledModelIds] : null;
85
- this.filteredItems = this.buildItems();
86
- // Header
87
- this.addChild(new DynamicBorder());
88
- this.addChild(new Spacer(1));
89
- this.addChild(new Text(theme.fg("accent", theme.bold("Model Configuration")), 0, 0));
90
- this.addChild(new Text(theme.fg("muted", "Session-only. Ctrl+S to save to settings."), 0, 0));
91
- this.addChild(new Spacer(1));
92
- // Search input
93
- this.searchInput = new Input();
94
- this.addChild(this.searchInput);
95
- this.addChild(new Spacer(1));
96
- // List container
97
- this.listContainer = new Container();
98
- this.addChild(this.listContainer);
99
- // Footer hint
100
- this.addChild(new Spacer(1));
101
- this.footerText = new Text(this.getFooterText(), 0, 0);
102
- this.addChild(this.footerText);
103
- this.addChild(new DynamicBorder());
104
- this.updateList();
105
- }
106
- buildItems() {
107
- // Filter out IDs that no longer have a corresponding model (e.g., after logout)
108
- return getSortedIds(this.enabledIds, this.allIds)
109
- .filter((id) => this.modelsById.has(id))
110
- .map((id) => ({
111
- fullId: id,
112
- model: this.modelsById.get(id),
113
- enabled: isEnabled(this.enabledIds, id),
114
- }));
115
- }
116
- getFooterText() {
117
- const enabledCount = this.enabledIds?.length ?? this.allIds.length;
118
- const allEnabled = this.enabledIds === null;
119
- const countText = allEnabled ? "all enabled" : `${enabledCount}/${this.allIds.length} enabled`;
120
- const parts = ["Enter toggle", "^A all", "^X clear", "^P provider", "Alt+↑↓ reorder", "^S save", countText];
121
- return this.isDirty
122
- ? theme.fg("dim", ` ${parts.join(" · ")} `) + theme.fg("warning", "(unsaved)")
123
- : theme.fg("dim", ` ${parts.join(" · ")}`);
124
- }
125
- refresh() {
126
- const query = this.searchInput.getValue();
127
- const items = this.buildItems();
128
- this.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;
129
- this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));
130
- this.updateList();
131
- this.footerText.setText(this.getFooterText());
132
- }
133
- updateList() {
134
- this.listContainer.clear();
135
- if (this.filteredItems.length === 0) {
136
- this.listContainer.addChild(new Text(theme.fg("muted", " No matching models"), 0, 0));
137
- return;
138
- }
139
- const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));
140
- const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
141
- const allEnabled = this.enabledIds === null;
142
- for (let i = startIndex; i < endIndex; i++) {
143
- const item = this.filteredItems[i];
144
- const isSelected = i === this.selectedIndex;
145
- const prefix = isSelected ? theme.fg("accent", "→ ") : " ";
146
- const modelText = isSelected ? theme.fg("accent", item.model.id) : item.model.id;
147
- const providerBadge = theme.fg("muted", ` [${item.model.provider}]`);
148
- const status = allEnabled ? "" : item.enabled ? theme.fg("success", " ✓") : theme.fg("dim", " ✗");
149
- this.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));
150
- }
151
- // Add scroll indicator if needed
152
- if (startIndex > 0 || endIndex < this.filteredItems.length) {
153
- this.listContainer.addChild(new Text(theme.fg("muted", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0));
154
- }
155
- if (this.filteredItems.length > 0) {
156
- const selected = this.filteredItems[this.selectedIndex];
157
- this.listContainer.addChild(new Spacer(1));
158
- this.listContainer.addChild(new Text(theme.fg("muted", ` Model Name: ${selected.model.name}`), 0, 0));
159
- }
160
- }
161
- handleInput(data) {
162
- const kb = getKeybindings();
163
- // Navigation
164
- if (kb.matches(data, "tui.select.up")) {
165
- if (this.filteredItems.length === 0)
166
- return;
167
- this.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;
168
- this.updateList();
169
- return;
170
- }
171
- if (kb.matches(data, "tui.select.down")) {
172
- if (this.filteredItems.length === 0)
173
- return;
174
- this.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;
175
- this.updateList();
176
- return;
177
- }
178
- // Alt+Up/Down - Reorder enabled models
179
- if (matchesKey(data, Key.alt("up")) || matchesKey(data, Key.alt("down"))) {
180
- const item = this.filteredItems[this.selectedIndex];
181
- if (item && isEnabled(this.enabledIds, item.fullId)) {
182
- const delta = matchesKey(data, Key.alt("up")) ? -1 : 1;
183
- const enabledList = this.enabledIds ?? this.allIds;
184
- const currentIndex = enabledList.indexOf(item.fullId);
185
- const newIndex = currentIndex + delta;
186
- // Only move if within bounds
187
- if (newIndex >= 0 && newIndex < enabledList.length) {
188
- this.enabledIds = move(this.enabledIds, this.allIds, item.fullId, delta);
189
- this.isDirty = true;
190
- this.selectedIndex += delta;
191
- this.refresh();
192
- }
193
- }
194
- return;
195
- }
196
- // Toggle on Enter
197
- if (matchesKey(data, Key.enter)) {
198
- const item = this.filteredItems[this.selectedIndex];
199
- if (item) {
200
- const wasAllEnabled = this.enabledIds === null;
201
- this.enabledIds = toggle(this.enabledIds, item.fullId);
202
- this.isDirty = true;
203
- if (wasAllEnabled)
204
- this.callbacks.onClearAll();
205
- this.callbacks.onModelToggle(item.fullId, isEnabled(this.enabledIds, item.fullId));
206
- this.refresh();
207
- }
208
- return;
209
- }
210
- // Ctrl+A - Enable all (filtered if search active, otherwise all)
211
- if (matchesKey(data, Key.ctrl("a"))) {
212
- const targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;
213
- this.enabledIds = enableAll(this.enabledIds, this.allIds, targetIds);
214
- this.isDirty = true;
215
- this.callbacks.onEnableAll(targetIds ?? this.allIds);
216
- this.refresh();
217
- return;
218
- }
219
- // Ctrl+X - Clear all (filtered if search active, otherwise all)
220
- if (matchesKey(data, Key.ctrl("x"))) {
221
- const targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;
222
- this.enabledIds = clearAll(this.enabledIds, this.allIds, targetIds);
223
- this.isDirty = true;
224
- this.callbacks.onClearAll();
225
- this.refresh();
226
- return;
227
- }
228
- // Ctrl+P - Toggle provider of current item
229
- if (matchesKey(data, Key.ctrl("p"))) {
230
- const item = this.filteredItems[this.selectedIndex];
231
- if (item) {
232
- const provider = item.model.provider;
233
- const providerIds = this.allIds.filter((id) => this.modelsById.get(id).provider === provider);
234
- const allEnabled = providerIds.every((id) => isEnabled(this.enabledIds, id));
235
- this.enabledIds = allEnabled
236
- ? clearAll(this.enabledIds, this.allIds, providerIds)
237
- : enableAll(this.enabledIds, this.allIds, providerIds);
238
- this.isDirty = true;
239
- this.callbacks.onToggleProvider(provider, providerIds, !allEnabled);
240
- this.refresh();
241
- }
242
- return;
243
- }
244
- // Ctrl+S - Save/persist to settings
245
- if (matchesKey(data, Key.ctrl("s"))) {
246
- this.callbacks.onPersist(this.enabledIds ?? [...this.allIds]);
247
- this.isDirty = false;
248
- this.footerText.setText(this.getFooterText());
249
- return;
250
- }
251
- // Ctrl+C - clear search or cancel if empty
252
- if (matchesKey(data, Key.ctrl("c"))) {
253
- if (this.searchInput.getValue()) {
254
- this.searchInput.setValue("");
255
- this.refresh();
256
- }
257
- else {
258
- this.callbacks.onCancel();
259
- }
260
- return;
261
- }
262
- // Escape - cancel
263
- if (matchesKey(data, Key.escape)) {
264
- this.callbacks.onCancel();
265
- return;
266
- }
267
- // Pass everything else to search input
268
- this.searchInput.handleInput(data);
269
- this.refresh();
270
- }
271
- getSearchInput() {
272
- return this.searchInput;
273
- }
274
- }
275
- //# sourceMappingURL=scoped-models-selector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scoped-models-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/scoped-models-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Model } from \"@mariozechner/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\n\n// EnabledIds: null = all enabled (no filter), string[] = explicit ordered list\ntype EnabledIds = string[] | null;\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id]; // First toggle: start with only this one\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null; // Already all enabled\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, allIds: string[], id: string, delta: number): EnabledIds {\n\tconst list = enabledIds ?? [...allIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\ninterface ModelItem {\n\tfullId: string;\n\tmodel: Model<any>;\n\tenabled: boolean;\n}\n\nexport interface ModelsConfig {\n\tallModels: Model<any>[];\n\tenabledModelIds: Set<string>;\n\t/** true if enabledModels setting is defined (empty = all enabled) */\n\thasEnabledModelsFilter: boolean;\n}\n\nexport interface ModelsCallbacks {\n\t/** Called when a model is toggled (session-only, no persist) */\n\tonModelToggle: (modelId: string, enabled: boolean) => void;\n\t/** Called when user wants to persist current selection to settings */\n\tonPersist: (enabledModelIds: string[]) => void;\n\t/** Called when user enables all models. Returns list of all model IDs. */\n\tonEnableAll: (allModelIds: string[]) => void;\n\t/** Called when user clears all models */\n\tonClearAll: () => void;\n\t/** Called when user toggles all models for a provider. Returns affected model IDs. */\n\tonToggleProvider: (provider: string, modelIds: string[], enabled: boolean) => void;\n\tonCancel: () => void;\n}\n\n/**\n * Component for enabling/disabling models for Ctrl+P cycling.\n * Changes are session-only until explicitly persisted with Ctrl+S.\n */\nexport class ScopedModelsSelectorComponent extends Container implements Focusable {\n\tprivate modelsById: Map<string, Model<any>> = new Map();\n\tprivate allIds: string[] = [];\n\tprivate enabledIds: EnabledIds = null;\n\tprivate filteredItems: ModelItem[] = [];\n\tprivate selectedIndex = 0;\n\tprivate searchInput: Input;\n\n\t// Focusable implementation - propagate to searchInput for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\tprivate listContainer: Container;\n\tprivate footerText: Text;\n\tprivate callbacks: ModelsCallbacks;\n\tprivate maxVisible = 15;\n\tprivate isDirty = false;\n\n\tconstructor(config: ModelsConfig, callbacks: ModelsCallbacks) {\n\t\tsuper();\n\t\tthis.callbacks = callbacks;\n\n\t\tfor (const model of config.allModels) {\n\t\t\tconst fullId = `${model.provider}/${model.id}`;\n\t\t\tthis.modelsById.set(fullId, model);\n\t\t\tthis.allIds.push(fullId);\n\t\t}\n\n\t\tthis.enabledIds = config.hasEnabledModelsFilter ? [...config.enabledModelIds] : null;\n\t\tthis.filteredItems = this.buildItems();\n\n\t\t// Header\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Model Configuration\")), 0, 0));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"Session-only. Ctrl+S to save to settings.\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Search input\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// List container\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\n\t\t// Footer hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.updateList();\n\t}\n\n\tprivate buildItems(): ModelItem[] {\n\t\t// Filter out IDs that no longer have a corresponding model (e.g., after logout)\n\t\treturn getSortedIds(this.enabledIds, this.allIds)\n\t\t\t.filter((id) => this.modelsById.has(id))\n\t\t\t.map((id) => ({\n\t\t\t\tfullId: id,\n\t\t\t\tmodel: this.modelsById.get(id)!,\n\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t}));\n\t}\n\n\tprivate getFooterText(): string {\n\t\tconst enabledCount = this.enabledIds?.length ?? this.allIds.length;\n\t\tconst allEnabled = this.enabledIds === null;\n\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.allIds.length} enabled`;\n\t\tconst parts = [\"Enter toggle\", \"^A all\", \"^X clear\", \"^P provider\", \"Alt+↑↓ reorder\", \"^S save\", countText];\n\t\treturn this.isDirty\n\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t}\n\n\tprivate refresh(): void {\n\t\tconst query = this.searchInput.getValue();\n\t\tconst items = this.buildItems();\n\t\tthis.filteredItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i]!;\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.filteredItems.length > 0) {\n\t\t\tconst selected = this.filteredItems[this.selectedIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` Model Name: ${selected.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\t// Navigation\n\t\tif (kb.matches(data, \"tui.select.up\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(data, \"tui.select.down\")) {\n\t\t\tif (this.filteredItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\t// Alt+Up/Down - Reorder enabled models\n\t\tif (matchesKey(data, Key.alt(\"up\")) || matchesKey(data, Key.alt(\"down\"))) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = matchesKey(data, Key.alt(\"up\")) ? -1 : 1;\n\t\t\t\tconst enabledList = this.enabledIds ?? this.allIds;\n\t\t\t\tconst currentIndex = enabledList.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\t// Only move if within bounds\n\t\t\t\tif (newIndex >= 0 && newIndex < enabledList.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, this.allIds, item.fullId, delta);\n\t\t\t\t\tthis.isDirty = true;\n\t\t\t\t\tthis.selectedIndex += delta;\n\t\t\t\t\tthis.refresh();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Toggle on Enter\n\t\tif (matchesKey(data, Key.enter)) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst wasAllEnabled = this.enabledIds === null;\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tif (wasAllEnabled) this.callbacks.onClearAll();\n\t\t\t\tthis.callbacks.onModelToggle(item.fullId, isEnabled(this.enabledIds, item.fullId));\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+A - Enable all (filtered if search active, otherwise all)\n\t\tif (matchesKey(data, Key.ctrl(\"a\"))) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.allIds, targetIds);\n\t\t\tthis.isDirty = true;\n\t\t\tthis.callbacks.onEnableAll(targetIds ?? this.allIds);\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+X - Clear all (filtered if search active, otherwise all)\n\t\tif (matchesKey(data, Key.ctrl(\"x\"))) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.filteredItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.allIds, targetIds);\n\t\t\tthis.isDirty = true;\n\t\t\tthis.callbacks.onClearAll();\n\t\t\tthis.refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+P - Toggle provider of current item\n\t\tif (matchesKey(data, Key.ctrl(\"p\"))) {\n\t\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.allIds.filter((id) => this.modelsById.get(id)!.provider === provider);\n\t\t\t\tconst allEnabled = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allEnabled\n\t\t\t\t\t? clearAll(this.enabledIds, this.allIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.allIds, providerIds);\n\t\t\t\tthis.isDirty = true;\n\t\t\t\tthis.callbacks.onToggleProvider(provider, providerIds, !allEnabled);\n\t\t\t\tthis.refresh();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+S - Save/persist to settings\n\t\tif (matchesKey(data, Key.ctrl(\"s\"))) {\n\t\t\tthis.callbacks.onPersist(this.enabledIds ?? [...this.allIds]);\n\t\t\tthis.isDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\t// Ctrl+C - clear search or cancel if empty\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.refresh();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Escape - cancel\n\t\tif (matchesKey(data, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass everything else to search input\n\t\tthis.searchInput.handleInput(data);\n\t\tthis.refresh();\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n}\n"]}
@@ -1,23 +0,0 @@
1
- import type { SessionInfo } from "../../../core/session-manager.js";
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[];
23
- //# sourceMappingURL=session-selector-search.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-selector-search.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/session-selector-search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAEpE,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,CAAC;AAEzC,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,MAAM,EAAE;QAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;CACd;AAUD,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAE5D;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CA2EjE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAsCzF;AAED,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,UAAU,GAAE,UAAkB,GAC5B,WAAW,EAAE,CAiCf","sourcesContent":["import { fuzzyMatch } from \"@mariozechner/pi-tui\";\nimport type { SessionInfo } from \"../../../core/session-manager.js\";\n\nexport type SortMode = \"threaded\" | \"recent\" | \"relevance\";\n\nexport type NameFilter = \"all\" | \"named\";\n\nexport interface ParsedSearchQuery {\n\tmode: \"tokens\" | \"regex\";\n\ttokens: { kind: \"fuzzy\" | \"phrase\"; value: string }[];\n\tregex: RegExp | null;\n\t/** If set, parsing failed and we should treat query as non-matching. */\n\terror?: string;\n}\n\nexport interface MatchResult {\n\tmatches: boolean;\n\t/** Lower is better; only meaningful when matches === true */\n\tscore: number;\n}\n\nfunction normalizeWhitespaceLower(text: string): string {\n\treturn text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nfunction getSessionSearchText(session: SessionInfo): string {\n\treturn `${session.id} ${session.name ?? \"\"} ${session.allMessagesText} ${session.cwd}`;\n}\n\nexport function hasSessionName(session: SessionInfo): boolean {\n\treturn Boolean(session.name?.trim());\n}\n\nfunction matchesNameFilter(session: SessionInfo, filter: NameFilter): boolean {\n\tif (filter === \"all\") return true;\n\treturn hasSessionName(session);\n}\n\nexport function parseSearchQuery(query: string): ParsedSearchQuery {\n\tconst trimmed = query.trim();\n\tif (!trimmed) {\n\t\treturn { mode: \"tokens\", tokens: [], regex: null };\n\t}\n\n\t// Regex mode: re:<pattern>\n\tif (trimmed.startsWith(\"re:\")) {\n\t\tconst pattern = trimmed.slice(3).trim();\n\t\tif (!pattern) {\n\t\t\treturn { mode: \"regex\", tokens: [], regex: null, error: \"Empty regex\" };\n\t\t}\n\t\ttry {\n\t\t\treturn { mode: \"regex\", tokens: [], regex: new RegExp(pattern, \"i\") };\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\treturn { mode: \"regex\", tokens: [], regex: null, error: msg };\n\t\t}\n\t}\n\n\t// Token mode with quote support.\n\t// Example: foo \"node cve\" bar\n\tconst tokens: { kind: \"fuzzy\" | \"phrase\"; value: string }[] = [];\n\tlet buf = \"\";\n\tlet inQuote = false;\n\tlet hadUnclosedQuote = false;\n\n\tconst flush = (kind: \"fuzzy\" | \"phrase\"): void => {\n\t\tconst v = buf.trim();\n\t\tbuf = \"\";\n\t\tif (!v) return;\n\t\ttokens.push({ kind, value: v });\n\t};\n\n\tfor (let i = 0; i < trimmed.length; i++) {\n\t\tconst ch = trimmed[i]!;\n\t\tif (ch === '\"') {\n\t\t\tif (inQuote) {\n\t\t\t\tflush(\"phrase\");\n\t\t\t\tinQuote = false;\n\t\t\t} else {\n\t\t\t\tflush(\"fuzzy\");\n\t\t\t\tinQuote = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inQuote && /\\s/.test(ch)) {\n\t\t\tflush(\"fuzzy\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tbuf += ch;\n\t}\n\n\tif (inQuote) {\n\t\thadUnclosedQuote = true;\n\t}\n\n\t// If quotes were unbalanced, fall back to plain whitespace tokenization.\n\tif (hadUnclosedQuote) {\n\t\treturn {\n\t\t\tmode: \"tokens\",\n\t\t\ttokens: trimmed\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.map((t) => t.trim())\n\t\t\t\t.filter((t) => t.length > 0)\n\t\t\t\t.map((t) => ({ kind: \"fuzzy\" as const, value: t })),\n\t\t\tregex: null,\n\t\t};\n\t}\n\n\tflush(inQuote ? \"phrase\" : \"fuzzy\");\n\n\treturn { mode: \"tokens\", tokens, regex: null };\n}\n\nexport function matchSession(session: SessionInfo, parsed: ParsedSearchQuery): MatchResult {\n\tconst text = getSessionSearchText(session);\n\n\tif (parsed.mode === \"regex\") {\n\t\tif (!parsed.regex) {\n\t\t\treturn { matches: false, score: 0 };\n\t\t}\n\t\tconst idx = text.search(parsed.regex);\n\t\tif (idx < 0) return { matches: false, score: 0 };\n\t\treturn { matches: true, score: idx * 0.1 };\n\t}\n\n\tif (parsed.tokens.length === 0) {\n\t\treturn { matches: true, score: 0 };\n\t}\n\n\tlet totalScore = 0;\n\tlet normalizedText: string | null = null;\n\n\tfor (const token of parsed.tokens) {\n\t\tif (token.kind === \"phrase\") {\n\t\t\tif (normalizedText === null) {\n\t\t\t\tnormalizedText = normalizeWhitespaceLower(text);\n\t\t\t}\n\t\t\tconst phrase = normalizeWhitespaceLower(token.value);\n\t\t\tif (!phrase) continue;\n\t\t\tconst idx = normalizedText.indexOf(phrase);\n\t\t\tif (idx < 0) return { matches: false, score: 0 };\n\t\t\ttotalScore += idx * 0.1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst m = fuzzyMatch(token.value, text);\n\t\tif (!m.matches) return { matches: false, score: 0 };\n\t\ttotalScore += m.score;\n\t}\n\n\treturn { matches: true, score: totalScore };\n}\n\nexport function filterAndSortSessions(\n\tsessions: SessionInfo[],\n\tquery: string,\n\tsortMode: SortMode,\n\tnameFilter: NameFilter = \"all\",\n): SessionInfo[] {\n\tconst nameFiltered =\n\t\tnameFilter === \"all\" ? sessions : sessions.filter((session) => matchesNameFilter(session, nameFilter));\n\tconst trimmed = query.trim();\n\tif (!trimmed) return nameFiltered;\n\n\tconst parsed = parseSearchQuery(query);\n\tif (parsed.error) return [];\n\n\t// Recent mode: filter only, keep incoming order.\n\tif (sortMode === \"recent\") {\n\t\tconst filtered: SessionInfo[] = [];\n\t\tfor (const s of nameFiltered) {\n\t\t\tconst res = matchSession(s, parsed);\n\t\t\tif (res.matches) filtered.push(s);\n\t\t}\n\t\treturn filtered;\n\t}\n\n\t// Relevance mode: sort by score, tie-break by modified desc.\n\tconst scored: { session: SessionInfo; score: number }[] = [];\n\tfor (const s of nameFiltered) {\n\t\tconst res = matchSession(s, parsed);\n\t\tif (!res.matches) continue;\n\t\tscored.push({ session: s, score: res.score });\n\t}\n\n\tscored.sort((a, b) => {\n\t\tif (a.score !== b.score) return a.score - b.score;\n\t\treturn b.session.modified.getTime() - a.session.modified.getTime();\n\t});\n\n\treturn scored.map((r) => r.session);\n}\n"]}
@@ -1,155 +0,0 @@
1
- import { fuzzyMatch } from "@mariozechner/pi-tui";
2
- function normalizeWhitespaceLower(text) {
3
- return text.toLowerCase().replace(/\s+/g, " ").trim();
4
- }
5
- function getSessionSearchText(session) {
6
- return `${session.id} ${session.name ?? ""} ${session.allMessagesText} ${session.cwd}`;
7
- }
8
- export function hasSessionName(session) {
9
- return Boolean(session.name?.trim());
10
- }
11
- function matchesNameFilter(session, filter) {
12
- if (filter === "all")
13
- return true;
14
- return hasSessionName(session);
15
- }
16
- export function parseSearchQuery(query) {
17
- const trimmed = query.trim();
18
- if (!trimmed) {
19
- return { mode: "tokens", tokens: [], regex: null };
20
- }
21
- // Regex mode: re:<pattern>
22
- if (trimmed.startsWith("re:")) {
23
- const pattern = trimmed.slice(3).trim();
24
- if (!pattern) {
25
- return { mode: "regex", tokens: [], regex: null, error: "Empty regex" };
26
- }
27
- try {
28
- return { mode: "regex", tokens: [], regex: new RegExp(pattern, "i") };
29
- }
30
- catch (err) {
31
- const msg = err instanceof Error ? err.message : String(err);
32
- return { mode: "regex", tokens: [], regex: null, error: msg };
33
- }
34
- }
35
- // Token mode with quote support.
36
- // Example: foo "node cve" bar
37
- const tokens = [];
38
- let buf = "";
39
- let inQuote = false;
40
- let hadUnclosedQuote = false;
41
- const flush = (kind) => {
42
- const v = buf.trim();
43
- buf = "";
44
- if (!v)
45
- return;
46
- tokens.push({ kind, value: v });
47
- };
48
- for (let i = 0; i < trimmed.length; i++) {
49
- const ch = trimmed[i];
50
- if (ch === '"') {
51
- if (inQuote) {
52
- flush("phrase");
53
- inQuote = false;
54
- }
55
- else {
56
- flush("fuzzy");
57
- inQuote = true;
58
- }
59
- continue;
60
- }
61
- if (!inQuote && /\s/.test(ch)) {
62
- flush("fuzzy");
63
- continue;
64
- }
65
- buf += ch;
66
- }
67
- if (inQuote) {
68
- hadUnclosedQuote = true;
69
- }
70
- // If quotes were unbalanced, fall back to plain whitespace tokenization.
71
- if (hadUnclosedQuote) {
72
- return {
73
- mode: "tokens",
74
- tokens: trimmed
75
- .split(/\s+/)
76
- .map((t) => t.trim())
77
- .filter((t) => t.length > 0)
78
- .map((t) => ({ kind: "fuzzy", value: t })),
79
- regex: null,
80
- };
81
- }
82
- flush(inQuote ? "phrase" : "fuzzy");
83
- return { mode: "tokens", tokens, regex: null };
84
- }
85
- export function matchSession(session, parsed) {
86
- const text = getSessionSearchText(session);
87
- if (parsed.mode === "regex") {
88
- if (!parsed.regex) {
89
- return { matches: false, score: 0 };
90
- }
91
- const idx = text.search(parsed.regex);
92
- if (idx < 0)
93
- return { matches: false, score: 0 };
94
- return { matches: true, score: idx * 0.1 };
95
- }
96
- if (parsed.tokens.length === 0) {
97
- return { matches: true, score: 0 };
98
- }
99
- let totalScore = 0;
100
- let normalizedText = null;
101
- for (const token of parsed.tokens) {
102
- if (token.kind === "phrase") {
103
- if (normalizedText === null) {
104
- normalizedText = normalizeWhitespaceLower(text);
105
- }
106
- const phrase = normalizeWhitespaceLower(token.value);
107
- if (!phrase)
108
- continue;
109
- const idx = normalizedText.indexOf(phrase);
110
- if (idx < 0)
111
- return { matches: false, score: 0 };
112
- totalScore += idx * 0.1;
113
- continue;
114
- }
115
- const m = fuzzyMatch(token.value, text);
116
- if (!m.matches)
117
- return { matches: false, score: 0 };
118
- totalScore += m.score;
119
- }
120
- return { matches: true, score: totalScore };
121
- }
122
- export function filterAndSortSessions(sessions, query, sortMode, nameFilter = "all") {
123
- const nameFiltered = nameFilter === "all" ? sessions : sessions.filter((session) => matchesNameFilter(session, nameFilter));
124
- const trimmed = query.trim();
125
- if (!trimmed)
126
- return nameFiltered;
127
- const parsed = parseSearchQuery(query);
128
- if (parsed.error)
129
- return [];
130
- // Recent mode: filter only, keep incoming order.
131
- if (sortMode === "recent") {
132
- const filtered = [];
133
- for (const s of nameFiltered) {
134
- const res = matchSession(s, parsed);
135
- if (res.matches)
136
- filtered.push(s);
137
- }
138
- return filtered;
139
- }
140
- // Relevance mode: sort by score, tie-break by modified desc.
141
- const scored = [];
142
- for (const s of nameFiltered) {
143
- const res = matchSession(s, parsed);
144
- if (!res.matches)
145
- continue;
146
- scored.push({ session: s, score: res.score });
147
- }
148
- scored.sort((a, b) => {
149
- if (a.score !== b.score)
150
- return a.score - b.score;
151
- return b.session.modified.getTime() - a.session.modified.getTime();
152
- });
153
- return scored.map((r) => r.session);
154
- }
155
- //# sourceMappingURL=session-selector-search.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-selector-search.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/session-selector-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { fuzzyMatch } from \"@mariozechner/pi-tui\";\nimport type { SessionInfo } from \"../../../core/session-manager.js\";\n\nexport type SortMode = \"threaded\" | \"recent\" | \"relevance\";\n\nexport type NameFilter = \"all\" | \"named\";\n\nexport interface ParsedSearchQuery {\n\tmode: \"tokens\" | \"regex\";\n\ttokens: { kind: \"fuzzy\" | \"phrase\"; value: string }[];\n\tregex: RegExp | null;\n\t/** If set, parsing failed and we should treat query as non-matching. */\n\terror?: string;\n}\n\nexport interface MatchResult {\n\tmatches: boolean;\n\t/** Lower is better; only meaningful when matches === true */\n\tscore: number;\n}\n\nfunction normalizeWhitespaceLower(text: string): string {\n\treturn text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nfunction getSessionSearchText(session: SessionInfo): string {\n\treturn `${session.id} ${session.name ?? \"\"} ${session.allMessagesText} ${session.cwd}`;\n}\n\nexport function hasSessionName(session: SessionInfo): boolean {\n\treturn Boolean(session.name?.trim());\n}\n\nfunction matchesNameFilter(session: SessionInfo, filter: NameFilter): boolean {\n\tif (filter === \"all\") return true;\n\treturn hasSessionName(session);\n}\n\nexport function parseSearchQuery(query: string): ParsedSearchQuery {\n\tconst trimmed = query.trim();\n\tif (!trimmed) {\n\t\treturn { mode: \"tokens\", tokens: [], regex: null };\n\t}\n\n\t// Regex mode: re:<pattern>\n\tif (trimmed.startsWith(\"re:\")) {\n\t\tconst pattern = trimmed.slice(3).trim();\n\t\tif (!pattern) {\n\t\t\treturn { mode: \"regex\", tokens: [], regex: null, error: \"Empty regex\" };\n\t\t}\n\t\ttry {\n\t\t\treturn { mode: \"regex\", tokens: [], regex: new RegExp(pattern, \"i\") };\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\treturn { mode: \"regex\", tokens: [], regex: null, error: msg };\n\t\t}\n\t}\n\n\t// Token mode with quote support.\n\t// Example: foo \"node cve\" bar\n\tconst tokens: { kind: \"fuzzy\" | \"phrase\"; value: string }[] = [];\n\tlet buf = \"\";\n\tlet inQuote = false;\n\tlet hadUnclosedQuote = false;\n\n\tconst flush = (kind: \"fuzzy\" | \"phrase\"): void => {\n\t\tconst v = buf.trim();\n\t\tbuf = \"\";\n\t\tif (!v) return;\n\t\ttokens.push({ kind, value: v });\n\t};\n\n\tfor (let i = 0; i < trimmed.length; i++) {\n\t\tconst ch = trimmed[i]!;\n\t\tif (ch === '\"') {\n\t\t\tif (inQuote) {\n\t\t\t\tflush(\"phrase\");\n\t\t\t\tinQuote = false;\n\t\t\t} else {\n\t\t\t\tflush(\"fuzzy\");\n\t\t\t\tinQuote = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inQuote && /\\s/.test(ch)) {\n\t\t\tflush(\"fuzzy\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tbuf += ch;\n\t}\n\n\tif (inQuote) {\n\t\thadUnclosedQuote = true;\n\t}\n\n\t// If quotes were unbalanced, fall back to plain whitespace tokenization.\n\tif (hadUnclosedQuote) {\n\t\treturn {\n\t\t\tmode: \"tokens\",\n\t\t\ttokens: trimmed\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.map((t) => t.trim())\n\t\t\t\t.filter((t) => t.length > 0)\n\t\t\t\t.map((t) => ({ kind: \"fuzzy\" as const, value: t })),\n\t\t\tregex: null,\n\t\t};\n\t}\n\n\tflush(inQuote ? \"phrase\" : \"fuzzy\");\n\n\treturn { mode: \"tokens\", tokens, regex: null };\n}\n\nexport function matchSession(session: SessionInfo, parsed: ParsedSearchQuery): MatchResult {\n\tconst text = getSessionSearchText(session);\n\n\tif (parsed.mode === \"regex\") {\n\t\tif (!parsed.regex) {\n\t\t\treturn { matches: false, score: 0 };\n\t\t}\n\t\tconst idx = text.search(parsed.regex);\n\t\tif (idx < 0) return { matches: false, score: 0 };\n\t\treturn { matches: true, score: idx * 0.1 };\n\t}\n\n\tif (parsed.tokens.length === 0) {\n\t\treturn { matches: true, score: 0 };\n\t}\n\n\tlet totalScore = 0;\n\tlet normalizedText: string | null = null;\n\n\tfor (const token of parsed.tokens) {\n\t\tif (token.kind === \"phrase\") {\n\t\t\tif (normalizedText === null) {\n\t\t\t\tnormalizedText = normalizeWhitespaceLower(text);\n\t\t\t}\n\t\t\tconst phrase = normalizeWhitespaceLower(token.value);\n\t\t\tif (!phrase) continue;\n\t\t\tconst idx = normalizedText.indexOf(phrase);\n\t\t\tif (idx < 0) return { matches: false, score: 0 };\n\t\t\ttotalScore += idx * 0.1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst m = fuzzyMatch(token.value, text);\n\t\tif (!m.matches) return { matches: false, score: 0 };\n\t\ttotalScore += m.score;\n\t}\n\n\treturn { matches: true, score: totalScore };\n}\n\nexport function filterAndSortSessions(\n\tsessions: SessionInfo[],\n\tquery: string,\n\tsortMode: SortMode,\n\tnameFilter: NameFilter = \"all\",\n): SessionInfo[] {\n\tconst nameFiltered =\n\t\tnameFilter === \"all\" ? sessions : sessions.filter((session) => matchesNameFilter(session, nameFilter));\n\tconst trimmed = query.trim();\n\tif (!trimmed) return nameFiltered;\n\n\tconst parsed = parseSearchQuery(query);\n\tif (parsed.error) return [];\n\n\t// Recent mode: filter only, keep incoming order.\n\tif (sortMode === \"recent\") {\n\t\tconst filtered: SessionInfo[] = [];\n\t\tfor (const s of nameFiltered) {\n\t\t\tconst res = matchSession(s, parsed);\n\t\t\tif (res.matches) filtered.push(s);\n\t\t}\n\t\treturn filtered;\n\t}\n\n\t// Relevance mode: sort by score, tie-break by modified desc.\n\tconst scored: { session: SessionInfo; score: number }[] = [];\n\tfor (const s of nameFiltered) {\n\t\tconst res = matchSession(s, parsed);\n\t\tif (!res.matches) continue;\n\t\tscored.push({ session: s, score: res.score });\n\t}\n\n\tscored.sort((a, b) => {\n\t\tif (a.score !== b.score) return a.score - b.score;\n\t\treturn b.session.modified.getTime() - a.session.modified.getTime();\n\t});\n\n\treturn scored.map((r) => r.session);\n}\n"]}