@asterxsk/kiln 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/README.md +2 -2
  2. package/agent/version.txt +1 -1
  3. package/bin/kiln.js +10 -8
  4. package/package.json +1 -1
  5. package/agent.bak.20260905-190020/AGENTS.md +0 -67
  6. package/agent.bak.20260905-190020/README.md +0 -5
  7. package/agent.bak.20260905-190020/extensions/ask-user/index.ts +0 -418
  8. package/agent.bak.20260905-190020/extensions/ask-user/install.ps1 +0 -23
  9. package/agent.bak.20260905-190020/extensions/ask-user/install.sh +0 -21
  10. package/agent.bak.20260905-190020/extensions/ask-user/package-lock.json +0 -769
  11. package/agent.bak.20260905-190020/extensions/ask-user/package.json +0 -19
  12. package/agent.bak.20260905-190020/extensions/ask-user/prompt.ts +0 -45
  13. package/agent.bak.20260905-190020/extensions/ask-user/tsconfig.json +0 -7
  14. package/agent.bak.20260905-190020/extensions/background-terminals/docs/implementation-guide.md +0 -942
  15. package/agent.bak.20260905-190020/extensions/background-terminals/index.ts +0 -629
  16. package/agent.bak.20260905-190020/extensions/background-terminals/install.ps1 +0 -23
  17. package/agent.bak.20260905-190020/extensions/background-terminals/install.sh +0 -21
  18. package/agent.bak.20260905-190020/extensions/background-terminals/package-lock.json +0 -769
  19. package/agent.bak.20260905-190020/extensions/background-terminals/package.json +0 -17
  20. package/agent.bak.20260905-190020/extensions/background-terminals/src/domain.ts +0 -87
  21. package/agent.bak.20260905-190020/extensions/background-terminals/src/manager.ts +0 -907
  22. package/agent.bak.20260905-190020/extensions/background-terminals/src/output.ts +0 -84
  23. package/agent.bak.20260905-190020/extensions/background-terminals/src/prompt.ts +0 -142
  24. package/agent.bak.20260905-190020/extensions/background-terminals/src/result-delivery.ts +0 -27
  25. package/agent.bak.20260905-190020/extensions/background-terminals/src/runtime.ts +0 -36
  26. package/agent.bak.20260905-190020/extensions/background-terminals/src/ui/output-view.ts +0 -79
  27. package/agent.bak.20260905-190020/extensions/background-terminals/src/ui/ps.ts +0 -621
  28. package/agent.bak.20260905-190020/extensions/background-terminals/src/widget-order.ts +0 -121
  29. package/agent.bak.20260905-190020/extensions/background-terminals/test/manager.test.ts +0 -735
  30. package/agent.bak.20260905-190020/extensions/background-terminals/test/output.test.ts +0 -109
  31. package/agent.bak.20260905-190020/extensions/background-terminals/test/prompt.test.ts +0 -125
  32. package/agent.bak.20260905-190020/extensions/background-terminals/test/ps.test.ts +0 -82
  33. package/agent.bak.20260905-190020/extensions/background-terminals/test/result-delivery.test.ts +0 -44
  34. package/agent.bak.20260905-190020/extensions/background-terminals/tsconfig.json +0 -7
  35. package/agent.bak.20260905-190020/extensions/destructive/README.md +0 -34
  36. package/agent.bak.20260905-190020/extensions/destructive/index.ts +0 -124
  37. package/agent.bak.20260905-190020/extensions/destructive/install.ps1 +0 -23
  38. package/agent.bak.20260905-190020/extensions/destructive/install.sh +0 -21
  39. package/agent.bak.20260905-190020/extensions/file-search/index.ts +0 -459
  40. package/agent.bak.20260905-190020/extensions/file-search/install.ps1 +0 -23
  41. package/agent.bak.20260905-190020/extensions/file-search/install.sh +0 -21
  42. package/agent.bak.20260905-190020/extensions/file-search/package-lock.json +0 -2253
  43. package/agent.bak.20260905-190020/extensions/file-search/package.json +0 -23
  44. package/agent.bak.20260905-190020/extensions/file-search/src/args.ts +0 -122
  45. package/agent.bak.20260905-190020/extensions/file-search/src/binaries.ts +0 -422
  46. package/agent.bak.20260905-190020/extensions/file-search/src/output.ts +0 -126
  47. package/agent.bak.20260905-190020/extensions/file-search/src/process.ts +0 -146
  48. package/agent.bak.20260905-190020/extensions/file-search/src/prompt.ts +0 -52
  49. package/agent.bak.20260905-190020/extensions/file-search/test/index.spec.ts +0 -443
  50. package/agent.bak.20260905-190020/extensions/file-search/tsconfig.json +0 -7
  51. package/agent.bak.20260905-190020/extensions/goal/README.md +0 -50
  52. package/agent.bak.20260905-190020/extensions/goal/index.ts +0 -155
  53. package/agent.bak.20260905-190020/extensions/goal/install.ps1 +0 -23
  54. package/agent.bak.20260905-190020/extensions/goal/install.sh +0 -21
  55. package/agent.bak.20260905-190020/extensions/kiln-update/README.md +0 -25
  56. package/agent.bak.20260905-190020/extensions/kiln-update/index.ts +0 -99
  57. package/agent.bak.20260905-190020/extensions/kiln-update/install.ps1 +0 -23
  58. package/agent.bak.20260905-190020/extensions/kiln-update/install.sh +0 -21
  59. package/agent.bak.20260905-190020/extensions/modelconf/PLAN.md +0 -915
  60. package/agent.bak.20260905-190020/extensions/modelconf/README.md +0 -66
  61. package/agent.bak.20260905-190020/extensions/modelconf/index.ts +0 -296
  62. package/agent.bak.20260905-190020/extensions/modelconf/install.ps1 +0 -23
  63. package/agent.bak.20260905-190020/extensions/modelconf/install.sh +0 -21
  64. package/agent.bak.20260905-190020/extensions/modelconf/package-lock.json +0 -1809
  65. package/agent.bak.20260905-190020/extensions/modelconf/package.json +0 -13
  66. package/agent.bak.20260905-190020/extensions/modelconf/src/fuzzy.ts +0 -26
  67. package/agent.bak.20260905-190020/extensions/modelconf/src/glob.ts +0 -13
  68. package/agent.bak.20260905-190020/extensions/modelconf/src/persistence.test.ts +0 -46
  69. package/agent.bak.20260905-190020/extensions/modelconf/src/persistence.ts +0 -164
  70. package/agent.bak.20260905-190020/extensions/modelconf/src/ui/ModelConfView.test.ts +0 -75
  71. package/agent.bak.20260905-190020/extensions/modelconf/src/ui/ModelConfView.ts +0 -1101
  72. package/agent.bak.20260905-190020/extensions/modelconf/tsconfig.json +0 -15
  73. package/agent.bak.20260905-190020/extensions/pi-web-access/CHANGELOG.md +0 -690
  74. package/agent.bak.20260905-190020/extensions/pi-web-access/LICENSE +0 -21
  75. package/agent.bak.20260905-190020/extensions/pi-web-access/README.md +0 -470
  76. package/agent.bak.20260905-190020/extensions/pi-web-access/SECURITY.md +0 -5
  77. package/agent.bak.20260905-190020/extensions/pi-web-access/activity.ts +0 -101
  78. package/agent.bak.20260905-190020/extensions/pi-web-access/auth-fetch.ts +0 -148
  79. package/agent.bak.20260905-190020/extensions/pi-web-access/banner.png +0 -0
  80. package/agent.bak.20260905-190020/extensions/pi-web-access/brightdata-unlocker.ts +0 -272
  81. package/agent.bak.20260905-190020/extensions/pi-web-access/chrome-cookies.ts +0 -669
  82. package/agent.bak.20260905-190020/extensions/pi-web-access/content-find.ts +0 -139
  83. package/agent.bak.20260905-190020/extensions/pi-web-access/credential-source.ts +0 -191
  84. package/agent.bak.20260905-190020/extensions/pi-web-access/data-uri-sanitize.ts +0 -406
  85. package/agent.bak.20260905-190020/extensions/pi-web-access/datalab-pdf-extract.ts +0 -568
  86. package/agent.bak.20260905-190020/extensions/pi-web-access/declared-web-links.ts +0 -173
  87. package/agent.bak.20260905-190020/extensions/pi-web-access/evidence/CONTRACT-EVIDENCE.md +0 -496
  88. package/agent.bak.20260905-190020/extensions/pi-web-access/evidence/contract-probe.mjs +0 -140
  89. package/agent.bak.20260905-190020/extensions/pi-web-access/exa.ts +0 -526
  90. package/agent.bak.20260905-190020/extensions/pi-web-access/extract.ts +0 -1196
  91. package/agent.bak.20260905-190020/extensions/pi-web-access/feature-config.ts +0 -29
  92. package/agent.bak.20260905-190020/extensions/pi-web-access/fetch-params.ts +0 -111
  93. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-adc.ts +0 -298
  94. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-api.ts +0 -353
  95. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-pdf-extract.ts +0 -108
  96. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-search.ts +0 -21
  97. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-url-context.ts +0 -128
  98. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-web-config.ts +0 -101
  99. package/agent.bak.20260905-190020/extensions/pi-web-access/gemini-web.ts +0 -487
  100. package/agent.bak.20260905-190020/extensions/pi-web-access/github-api.ts +0 -197
  101. package/agent.bak.20260905-190020/extensions/pi-web-access/github-extract.ts +0 -746
  102. package/agent.bak.20260905-190020/extensions/pi-web-access/github-issue-pr.ts +0 -700
  103. package/agent.bak.20260905-190020/extensions/pi-web-access/index.ts +0 -1737
  104. package/agent.bak.20260905-190020/extensions/pi-web-access/package-lock.json +0 -5808
  105. package/agent.bak.20260905-190020/extensions/pi-web-access/package.json +0 -64
  106. package/agent.bak.20260905-190020/extensions/pi-web-access/page-query.ts +0 -96
  107. package/agent.bak.20260905-190020/extensions/pi-web-access/pdf-extract.ts +0 -409
  108. package/agent.bak.20260905-190020/extensions/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
  109. package/agent.bak.20260905-190020/extensions/pi-web-access/promise-try.d.ts +0 -7
  110. package/agent.bak.20260905-190020/extensions/pi-web-access/query-rewrite.ts +0 -51
  111. package/agent.bak.20260905-190020/extensions/pi-web-access/render-search-error.ts +0 -170
  112. package/agent.bak.20260905-190020/extensions/pi-web-access/rsc-extract.ts +0 -338
  113. package/agent.bak.20260905-190020/extensions/pi-web-access/search-types.ts +0 -20
  114. package/agent.bak.20260905-190020/extensions/pi-web-access/source-check.ts +0 -282
  115. package/agent.bak.20260905-190020/extensions/pi-web-access/ssrf-protection.ts +0 -526
  116. package/agent.bak.20260905-190020/extensions/pi-web-access/storage.ts +0 -521
  117. package/agent.bak.20260905-190020/extensions/pi-web-access/summary-model-scope.ts +0 -125
  118. package/agent.bak.20260905-190020/extensions/pi-web-access/test/auth-fetch.test.mjs +0 -208
  119. package/agent.bak.20260905-190020/extensions/pi-web-access/test/brightdata-unlocker.test.mjs +0 -840
  120. package/agent.bak.20260905-190020/extensions/pi-web-access/test/chrome-cookie-extraction.test.mjs +0 -441
  121. package/agent.bak.20260905-190020/extensions/pi-web-access/test/config-path.test.mjs +0 -283
  122. package/agent.bak.20260905-190020/extensions/pi-web-access/test/content-find.test.mjs +0 -25
  123. package/agent.bak.20260905-190020/extensions/pi-web-access/test/credential-source.test.mjs +0 -118
  124. package/agent.bak.20260905-190020/extensions/pi-web-access/test/data-uri-sanitize.test.mjs +0 -210
  125. package/agent.bak.20260905-190020/extensions/pi-web-access/test/datalab-pdf-extract.test.mjs +0 -552
  126. package/agent.bak.20260905-190020/extensions/pi-web-access/test/declared-web-links.test.mjs +0 -212
  127. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-answer-storage.test.mjs +0 -40
  128. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-cache-storage.test.mjs +0 -334
  129. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-content-domain-policy.test.mjs +0 -95
  130. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-modes.test.mjs +0 -53
  131. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-not-found-guidance.test.mjs +0 -92
  132. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-params.test.mjs +0 -86
  133. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-render-call.test.mjs +0 -34
  134. package/agent.bak.20260905-190020/extensions/pi-web-access/test/fetch-routing.test.mjs +0 -173
  135. package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-adc-auth.test.mjs +0 -257
  136. package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-api-transport.test.mjs +0 -170
  137. package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-pdf-extract.test.mjs +0 -133
  138. package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +0 -178
  139. package/agent.bak.20260905-190020/extensions/pi-web-access/test/gemini-web-header-overflow.test.mjs +0 -148
  140. package/agent.bak.20260905-190020/extensions/pi-web-access/test/get-search-content.test.mjs +0 -223
  141. package/agent.bak.20260905-190020/extensions/pi-web-access/test/github-extract.test.mjs +0 -378
  142. package/agent.bak.20260905-190020/extensions/pi-web-access/test/github-issue-pr.test.mjs +0 -565
  143. package/agent.bak.20260905-190020/extensions/pi-web-access/test/inline-content-config.test.mjs +0 -99
  144. package/agent.bak.20260905-190020/extensions/pi-web-access/test/lazy-extract-load.test.mjs +0 -118
  145. package/agent.bak.20260905-190020/extensions/pi-web-access/test/local-video-oversize.test.mjs +0 -52
  146. package/agent.bak.20260905-190020/extensions/pi-web-access/test/package-typebox-dependency.test.mjs +0 -50
  147. package/agent.bak.20260905-190020/extensions/pi-web-access/test/page-query.test.mjs +0 -51
  148. package/agent.bak.20260905-190020/extensions/pi-web-access/test/pdf-config.test.mjs +0 -140
  149. package/agent.bak.20260905-190020/extensions/pi-web-access/test/pdf-extract.test.mjs +0 -500
  150. package/agent.bak.20260905-190020/extensions/pi-web-access/test/proxy-transport.test.mjs +0 -286
  151. package/agent.bak.20260905-190020/extensions/pi-web-access/test/query-rewrite.test.mjs +0 -52
  152. package/agent.bak.20260905-190020/extensions/pi-web-access/test/rsc-fallback.test.mjs +0 -102
  153. package/agent.bak.20260905-190020/extensions/pi-web-access/test/search-error-render.test.mjs +0 -152
  154. package/agent.bak.20260905-190020/extensions/pi-web-access/test/search-providers.test.mjs +0 -274
  155. package/agent.bak.20260905-190020/extensions/pi-web-access/test/source-check.test.mjs +0 -179
  156. package/agent.bak.20260905-190020/extensions/pi-web-access/test/ssrf-allow-ranges-config.test.mjs +0 -205
  157. package/agent.bak.20260905-190020/extensions/pi-web-access/test/ssrf-protection.test.mjs +0 -456
  158. package/agent.bak.20260905-190020/extensions/pi-web-access/test/summary-model-scope.test.mjs +0 -106
  159. package/agent.bak.20260905-190020/extensions/pi-web-access/test/tool-registration-config.test.mjs +0 -182
  160. package/agent.bak.20260905-190020/extensions/pi-web-access/test/web-search-answer-render.test.mjs +0 -66
  161. package/agent.bak.20260905-190020/extensions/pi-web-access/test/youtube-extract-errors.test.mjs +0 -64
  162. package/agent.bak.20260905-190020/extensions/pi-web-access/tsconfig.json +0 -11
  163. package/agent.bak.20260905-190020/extensions/pi-web-access/utils.ts +0 -451
  164. package/agent.bak.20260905-190020/extensions/pi-web-access/video-extract.ts +0 -392
  165. package/agent.bak.20260905-190020/extensions/pi-web-access/youtube-extract.ts +0 -328
  166. package/agent.bak.20260905-190020/extensions/shared/activity-status.ts +0 -31
  167. package/agent.bak.20260905-190020/extensions/shared/child-session.ts +0 -148
  168. package/agent.bak.20260905-190020/extensions/shared/context-utilization.ts +0 -47
  169. package/agent.bak.20260905-190020/extensions/shared/dashboard-state.ts +0 -99
  170. package/agent.bak.20260905-190020/extensions/shared/install.ps1 +0 -23
  171. package/agent.bak.20260905-190020/extensions/shared/install.sh +0 -21
  172. package/agent.bak.20260905-190020/extensions/shared/test/child-session.test.ts +0 -270
  173. package/agent.bak.20260905-190020/extensions/shared/test/context-utilization.test.ts +0 -48
  174. package/agent.bak.20260905-190020/extensions/shared/test/tool-call-timeout.test.ts +0 -117
  175. package/agent.bak.20260905-190020/extensions/shared/test/widget-order.test.ts +0 -167
  176. package/agent.bak.20260905-190020/extensions/shared/tool-call-timeout.ts +0 -104
  177. package/agent.bak.20260905-190020/extensions/skillsconf/README.md +0 -74
  178. package/agent.bak.20260905-190020/extensions/skillsconf/index.ts +0 -92
  179. package/agent.bak.20260905-190020/extensions/skillsconf/install.ps1 +0 -23
  180. package/agent.bak.20260905-190020/extensions/skillsconf/install.sh +0 -21
  181. package/agent.bak.20260905-190020/extensions/skillsconf/package-lock.json +0 -1809
  182. package/agent.bak.20260905-190020/extensions/skillsconf/package.json +0 -18
  183. package/agent.bak.20260905-190020/extensions/skillsconf/src/delete-skill.test.ts +0 -64
  184. package/agent.bak.20260905-190020/extensions/skillsconf/src/delete-skill.ts +0 -45
  185. package/agent.bak.20260905-190020/extensions/skillsconf/src/filter.test.ts +0 -80
  186. package/agent.bak.20260905-190020/extensions/skillsconf/src/filter.ts +0 -74
  187. package/agent.bak.20260905-190020/extensions/skillsconf/src/fuzzy.ts +0 -26
  188. package/agent.bak.20260905-190020/extensions/skillsconf/src/persistence.test.ts +0 -72
  189. package/agent.bak.20260905-190020/extensions/skillsconf/src/persistence.ts +0 -169
  190. package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/SkillConfView.test.ts +0 -337
  191. package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/SkillConfView.ts +0 -758
  192. package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/text-input.ts +0 -91
  193. package/agent.bak.20260905-190020/extensions/skillsconf/src/ui/tui-helpers.ts +0 -144
  194. package/agent.bak.20260905-190020/extensions/skillsconf/tsconfig.json +0 -15
  195. package/agent.bak.20260905-190020/extensions/statusline/index.ts +0 -282
  196. package/agent.bak.20260905-190020/extensions/statusline/install.ps1 +0 -23
  197. package/agent.bak.20260905-190020/extensions/statusline/install.sh +0 -21
  198. package/agent.bak.20260905-190020/extensions/subagents/docs/design-plan.md +0 -568
  199. package/agent.bak.20260905-190020/extensions/subagents/docs/effect-v4-extension-guide.md +0 -354
  200. package/agent.bak.20260905-190020/extensions/subagents/docs/effect-v4-notes.md +0 -571
  201. package/agent.bak.20260905-190020/extensions/subagents/index.ts +0 -826
  202. package/agent.bak.20260905-190020/extensions/subagents/install.ps1 +0 -23
  203. package/agent.bak.20260905-190020/extensions/subagents/install.sh +0 -21
  204. package/agent.bak.20260905-190020/extensions/subagents/package-lock.json +0 -2244
  205. package/agent.bak.20260905-190020/extensions/subagents/package.json +0 -19
  206. package/agent.bak.20260905-190020/extensions/subagents/src/backend.ts +0 -73
  207. package/agent.bak.20260905-190020/extensions/subagents/src/backends/claude.ts +0 -701
  208. package/agent.bak.20260905-190020/extensions/subagents/src/backends/codex.ts +0 -1060
  209. package/agent.bak.20260905-190020/extensions/subagents/src/backends/pi.ts +0 -575
  210. package/agent.bak.20260905-190020/extensions/subagents/src/backends/stub.ts +0 -300
  211. package/agent.bak.20260905-190020/extensions/subagents/src/by-the-way.ts +0 -21
  212. package/agent.bak.20260905-190020/extensions/subagents/src/domain.ts +0 -253
  213. package/agent.bak.20260905-190020/extensions/subagents/src/format.ts +0 -74
  214. package/agent.bak.20260905-190020/extensions/subagents/src/manager.ts +0 -736
  215. package/agent.bak.20260905-190020/extensions/subagents/src/prompt.ts +0 -92
  216. package/agent.bak.20260905-190020/extensions/subagents/src/result-delivery.ts +0 -20
  217. package/agent.bak.20260905-190020/extensions/subagents/src/runtime.ts +0 -53
  218. package/agent.bak.20260905-190020/extensions/subagents/src/ui/takeover.ts +0 -583
  219. package/agent.bak.20260905-190020/extensions/subagents/src/ui/transcript.ts +0 -201
  220. package/agent.bak.20260905-190020/extensions/subagents/src/widget-order.ts +0 -121
  221. package/agent.bak.20260905-190020/extensions/subagents/test/by-the-way.test.ts +0 -29
  222. package/agent.bak.20260905-190020/extensions/subagents/test/claude.test.ts +0 -119
  223. package/agent.bak.20260905-190020/extensions/subagents/test/codex.test.ts +0 -102
  224. package/agent.bak.20260905-190020/extensions/subagents/test/context-usage.test.ts +0 -107
  225. package/agent.bak.20260905-190020/extensions/subagents/test/manager.test.ts +0 -276
  226. package/agent.bak.20260905-190020/extensions/subagents/test/result-delivery.test.ts +0 -27
  227. package/agent.bak.20260905-190020/extensions/subagents/test/takeover.test.ts +0 -29
  228. package/agent.bak.20260905-190020/extensions/subagents/tsconfig.json +0 -7
  229. package/agent.bak.20260905-190020/extensions/taste/index.ts +0 -443
  230. package/agent.bak.20260905-190020/extensions/taste/install.ps1 +0 -23
  231. package/agent.bak.20260905-190020/extensions/taste/install.sh +0 -21
  232. package/agent.bak.20260905-190020/extensions/todo/AGENTS.md +0 -38
  233. package/agent.bak.20260905-190020/extensions/todo/LICENSE +0 -21
  234. package/agent.bak.20260905-190020/extensions/todo/config.ts +0 -55
  235. package/agent.bak.20260905-190020/extensions/todo/index.ts +0 -151
  236. package/agent.bak.20260905-190020/extensions/todo/install.ps1 +0 -23
  237. package/agent.bak.20260905-190020/extensions/todo/install.sh +0 -21
  238. package/agent.bak.20260905-190020/extensions/todo/locales/de.json +0 -17
  239. package/agent.bak.20260905-190020/extensions/todo/locales/en.json +0 -15
  240. package/agent.bak.20260905-190020/extensions/todo/locales/es.json +0 -17
  241. package/agent.bak.20260905-190020/extensions/todo/locales/fr.json +0 -17
  242. package/agent.bak.20260905-190020/extensions/todo/locales/pt-BR.json +0 -17
  243. package/agent.bak.20260905-190020/extensions/todo/locales/pt.json +0 -17
  244. package/agent.bak.20260905-190020/extensions/todo/locales/ru.json +0 -17
  245. package/agent.bak.20260905-190020/extensions/todo/locales/uk.json +0 -17
  246. package/agent.bak.20260905-190020/extensions/todo/locales/zh.json +0 -17
  247. package/agent.bak.20260905-190020/extensions/todo/package-lock.json +0 -3358
  248. package/agent.bak.20260905-190020/extensions/todo/package.json +0 -67
  249. package/agent.bak.20260905-190020/extensions/todo/state/i18n-bridge.ts +0 -64
  250. package/agent.bak.20260905-190020/extensions/todo/state/invariants.ts +0 -20
  251. package/agent.bak.20260905-190020/extensions/todo/state/replay.ts +0 -38
  252. package/agent.bak.20260905-190020/extensions/todo/state/selectors.ts +0 -107
  253. package/agent.bak.20260905-190020/extensions/todo/state/state-reducer.ts +0 -326
  254. package/agent.bak.20260905-190020/extensions/todo/state/state.ts +0 -18
  255. package/agent.bak.20260905-190020/extensions/todo/state/store.ts +0 -82
  256. package/agent.bak.20260905-190020/extensions/todo/state/task-graph.ts +0 -57
  257. package/agent.bak.20260905-190020/extensions/todo/todo-overlay.ts +0 -204
  258. package/agent.bak.20260905-190020/extensions/todo/todo.ts +0 -155
  259. package/agent.bak.20260905-190020/extensions/todo/tool/response-envelope.ts +0 -109
  260. package/agent.bak.20260905-190020/extensions/todo/tool/types.ts +0 -206
  261. package/agent.bak.20260905-190020/extensions/todo/view/format.ts +0 -177
  262. package/agent.bak.20260905-190020/extensions/todo/widget-order.ts +0 -121
  263. package/agent.bak.20260905-190020/extensions/trim-context/README.md +0 -54
  264. package/agent.bak.20260905-190020/extensions/trim-context/index.ts +0 -487
  265. package/agent.bak.20260905-190020/extensions/trim-context/install.ps1 +0 -23
  266. package/agent.bak.20260905-190020/extensions/trim-context/install.sh +0 -21
  267. package/agent.bak.20260905-190020/keybindings.json +0 -7
@@ -1,1101 +0,0 @@
1
- import { applyBulk, toggleInEnabled } from "../persistence.js";
2
- import type { ModelId } from "../persistence.js";
3
- import { globToRegExp } from "../glob.js";
4
- import { fuzzyFilter } from "../fuzzy.js";
5
- // Minimal Component type to avoid requiring @earendil-works/pi-tui at build time.
6
- // We mirror the pi-tui Component contract used by ctx.ui.custom.
7
- export interface Component {
8
- render(width: number): string[];
9
- handleInput?(data: string): void;
10
- invalidate(): void;
11
- }
12
-
13
- // Focusable contract per docs/tui.md — propagate focused to child Input
14
- export interface Focusable {
15
- focused: boolean;
16
- }
17
-
18
- // ---- local helpers for width/truncation (fallback when pi-tui not available) ----
19
-
20
- function stripAnsi(s: string): string {
21
- // strip CSI ...m, OSC 8 hyperlink, and APC cursor marker
22
- return s.replace(/\x1b\[[0-9;]*m/g, "").replace(/\x1b\]8;;.*?\x1b\\/g, "").replace(/\x1b_pi:c\x07/g, "");
23
- }
24
-
25
- function visibleWidthFallback(s: string): number {
26
- const stripped = stripAnsi(s);
27
- let w = 0;
28
- for (const ch of stripped) {
29
- const cp = ch.codePointAt(0) ?? 0;
30
- // crude wide char detection: CJK + emoji ranges
31
- if (cp >= 0x1100 && (
32
- cp <= 0x115F || cp === 0x2329 || cp === 0x232A ||
33
- (cp >= 0x2E80 && cp <= 0xA4CF && cp !== 0x303F) ||
34
- (cp >= 0xAC00 && cp <= 0xD7A3) ||
35
- (cp >= 0xF900 && cp <= 0xFAFF) ||
36
- (cp >= 0xFE10 && cp <= 0xFE19) ||
37
- (cp >= 0xFE30 && cp <= 0xFE6F) ||
38
- (cp >= 0xFF00 && cp <= 0xFF60) ||
39
- (cp >= 0xFFE0 && cp <= 0xFFE6)
40
- )) {
41
- w += 2;
42
- } else {
43
- w += 1;
44
- }
45
- }
46
- return w;
47
- }
48
-
49
- function extractAnsiCode(str: string, pos: number): { code: string; length: number } | null {
50
- if (str[pos] !== "\x1b") return null;
51
- const next = str[pos + 1];
52
- if (next === "[") {
53
- let i = pos + 2;
54
- while (i < str.length) {
55
- const c = str[i];
56
- if ((c >= "0" && c <= "9") || c === ";" || c === ":" || c === "?" ) { i++; continue; }
57
- // final char
58
- i++;
59
- return { code: str.slice(pos, i), length: i - pos };
60
- }
61
- return null;
62
- }
63
- if (next === "]") {
64
- const end = str.indexOf("\x1b\\", pos);
65
- if (end !== -1) return { code: str.slice(pos, end + 2), length: end + 2 - pos };
66
- const bel = str.indexOf("\x07", pos);
67
- if (bel !== -1) return { code: str.slice(pos, bel + 1), length: bel + 1 - pos };
68
- return null;
69
- }
70
- if (str.startsWith("\x1b_pi:c\x07", pos)) return { code: "\x1b_pi:c\x07", length: 7 };
71
- return null;
72
- }
73
-
74
- function truncateFallback(text: string, maxWidth: number, ellipsis = "..."): string {
75
- if (maxWidth <= 0) return "";
76
- const vw = visibleWidthFallback(text);
77
- if (vw <= maxWidth) return text;
78
- const ellW = visibleWidthFallback(ellipsis);
79
- const target = maxWidth - ellW;
80
- if (target <= 0) {
81
- // truncate ellipsis itself if needed
82
- let out = "";
83
- let w = 0;
84
- let i = 0;
85
- while (i < text.length) {
86
- const ansi = extractAnsiCode(text, i);
87
- if (ansi) { out += ansi.code; i += ansi.length; continue; }
88
- // grapheme: take one codepoint
89
- const ch = text[i];
90
- // handle surrogate pair
91
- let grapheme = ch;
92
- if (ch.charCodeAt(0) >= 0xD800 && ch.charCodeAt(0) <= 0xDBFF && i + 1 < text.length) {
93
- grapheme = text.slice(i, i + 2);
94
- }
95
- const gw = visibleWidthFallback(grapheme);
96
- if (w + gw > maxWidth) break;
97
- out += grapheme;
98
- w += gw;
99
- i += grapheme.length;
100
- }
101
- return out;
102
- }
103
- let out = "";
104
- let w = 0;
105
- let i = 0;
106
- let pendingAnsi = "";
107
- while (i < text.length) {
108
- const ansi = extractAnsiCode(text, i);
109
- if (ansi) { pendingAnsi += ansi.code; out += ansi.code; i += ansi.length; continue; }
110
- let grapheme = text[i];
111
- if (grapheme.charCodeAt(0) >= 0xD800 && grapheme.charCodeAt(0) <= 0xDBFF && i + 1 < text.length) {
112
- grapheme = text.slice(i, i + 2);
113
- }
114
- const gw = visibleWidthFallback(grapheme);
115
- if (w + gw > target) break;
116
- out += grapheme;
117
- w += gw;
118
- i += grapheme.length;
119
- }
120
- out += ellipsis;
121
- // Append pending ansi resets? naive: ensure reset at end not needed
122
- return out;
123
- }
124
-
125
- // Try to use pi-tui's truncate if available at runtime (optional). For compile-time we use fallback.
126
- let truncateToWidthFn: (text: string, maxWidth: number, ellipsis?: string, pad?: boolean) => string = truncateFallback;
127
- try {
128
- // @ts-ignore - optional dynamic import may fail at build if module not installed; fallback is fine
129
- // We keep fallback as default; runtime override attempted via dynamic import is not critical
130
- } catch {}
131
-
132
- // ---------------------------------------------------------------------------
133
- // Simple Input fallback — mimics @earendil-works/pi-tui Input for search mode
134
- // Handles printable chars, backspace (\x7f, \x08), delete, left/right arrows.
135
- // Propagates focused flag per Focusable contract. Fallback when pi-tui Input not resolvable.
136
-
137
- class SimpleSearchInput implements Component, Focusable {
138
- value = "";
139
- focused = false;
140
- private cursor = 0;
141
- // Keep for compatibility with pi-tui Input shape
142
- getValue(): string { return this.value; }
143
- setValue(v: string): void { this.value = v; this.cursor = v.length; }
144
-
145
- handleInput(data: string): void {
146
- if (!data) return;
147
- // Handle bracketed paste markers — strip and insert content
148
- if (data.includes("\x1b[200~")) {
149
- const start = data.indexOf("\x1b[200~");
150
- const end = data.indexOf("\x1b[201~");
151
- if (end !== -1) {
152
- const paste = data.substring(start + 6, end);
153
- this.insertAtCursor(paste);
154
- const remaining = data.slice(end + 6);
155
- if (remaining) this.handleInput(remaining);
156
- return;
157
- } else {
158
- // incomplete paste marker — strip marker and insert rest
159
- data = data.replace("\x1b[200~", "");
160
- }
161
- }
162
- if (data.includes("\x1b[201~")) {
163
- data = data.replace("\x1b[201~", "");
164
- }
165
-
166
- // Special keys — handle one at a time if data contains escapes
167
- // Backspace: \x7f or \x08 or \b
168
- if (data === "\x7f" || data === "\x08" || data === "\b") {
169
- this.handleBackspace();
170
- return;
171
- }
172
- // Delete (forward): \x1b[3~
173
- if (data === "\x1b[3~") {
174
- this.handleDelete();
175
- return;
176
- }
177
- // Arrows for cursor movement within input
178
- if (data === "\x1b[D" || data === "\x1bOD") { // left
179
- if (this.cursor > 0) this.cursor--;
180
- return;
181
- }
182
- if (data === "\x1b[C" || data === "\x1bOC") { // right
183
- if (this.cursor < this.value.length) this.cursor++;
184
- return;
185
- }
186
- if (data === "\x1b[H" || data === "\x1bOH" || data === "\x1b[1~") { // home
187
- this.cursor = 0;
188
- return;
189
- }
190
- if (data === "\x1b[F" || data === "\x1bOF" || data === "\x1b[4~") { // end
191
- this.cursor = this.value.length;
192
- return;
193
- }
194
- // Ctrl-U (kill line)
195
- if (data === "\x15") {
196
- this.value = "";
197
- this.cursor = 0;
198
- return;
199
- }
200
- // Ctrl-W (delete word backwards)
201
- if (data === "\x17") {
202
- this.deleteWordBackwards();
203
- return;
204
- }
205
- // If data looks like an escape sequence (arrow, etc.) not handled above and length >1, ignore
206
- if (data.startsWith("\x1b") && data.length > 1) {
207
- // Unknown escape — ignore (avoid inserting ESC into query)
208
- return;
209
- }
210
- // Ctrl-C / Ctrl-D etc — ignore
211
- if (data.length === 1 && data.charCodeAt(0) < 0x20) {
212
- return;
213
- }
214
- // Printable insertion — insert at cursor (support multi-char paste without bracket markers)
215
- // Filter out non-printable control chars
216
- let insert = "";
217
- for (const ch of data) {
218
- const code = ch.charCodeAt(0);
219
- if (code >= 0x20 && code !== 0x7f) insert += ch;
220
- }
221
- if (insert) this.insertAtCursor(insert);
222
- }
223
-
224
- private insertAtCursor(text: string): void {
225
- this.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);
226
- this.cursor += text.length;
227
- }
228
- private handleBackspace(): void {
229
- if (this.cursor > 0) {
230
- this.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);
231
- this.cursor--;
232
- }
233
- }
234
- private handleDelete(): void {
235
- if (this.cursor < this.value.length) {
236
- this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);
237
- }
238
- }
239
- private deleteWordBackwards(): void {
240
- if (this.cursor === 0) return;
241
- let pos = this.cursor;
242
- while (pos > 0 && this.value[pos - 1] === " ") pos--;
243
- while (pos > 0 && this.value[pos - 1] !== " ") pos--;
244
- this.value = this.value.slice(0, pos) + this.value.slice(this.cursor);
245
- this.cursor = pos;
246
- }
247
-
248
- render(width: number): string[] {
249
- // Render with cursor marker when focused. Use \x1b_pi:c\x07 marker for IME if needed? Simple underscore.
250
- // Show placeholder when empty and not focused? When focused, show cursor.
251
- const cursorMark = "\x1b_pi:c\x07";
252
- let display: string;
253
- if (this.focused) {
254
- const before = this.value.slice(0, this.cursor);
255
- const after = this.value.slice(this.cursor);
256
- // Insert cursor marker + visual block; terminal will show cursor at marker
257
- display = before + cursorMark + (after.length > 0 ? after : " ");
258
- // Also truncate to width with visibleWidth handling? Keep simple truncation
259
- // Use truncateFallback to keep ANSI safe (cursorMark is ANSI-like)
260
- if (visibleWidthFallback(display) > width) {
261
- // simple scroll: show window around cursor
262
- const half = Math.floor(width / 2);
263
- let start = Math.max(0, this.cursor - half);
264
- // crude slice
265
- let slice = this.value.slice(start, start + width);
266
- const curInSlice = this.cursor - start;
267
- display = slice.slice(0, curInSlice) + cursorMark + slice.slice(curInSlice);
268
- }
269
- } else {
270
- display = this.value;
271
- }
272
- // Apply truncate for width
273
- const line = truncateFallback(display, width);
274
- return [line];
275
- }
276
-
277
- invalidate(): void {}
278
- }
279
-
280
- // ---------------------------------------------------------------------------
281
-
282
- export interface ModelRow {
283
- id: string; // "provider/modelId"
284
- provider: string;
285
- modelId: string;
286
- visible: boolean;
287
- name?: string;
288
- }
289
-
290
- export interface ModelConfViewOpts {
291
- tui: any;
292
- theme: any;
293
- keybindings: any;
294
- allModels: Array<{ provider: string; id: string; name?: string }>;
295
- visibleSet: Set<string>;
296
- enabledRaw: string[] | undefined;
297
- onDone: (saved: boolean) => void;
298
- onPersist: (nextEnabled: string[] | undefined) => Promise<void>;
299
- allIds?: string[];
300
- }
301
-
302
- type ContentEntry =
303
- | { kind: "header"; provider: string }
304
- | { kind: "row"; row: ModelRow; flatIndex: number };
305
-
306
- export class ModelConfView implements Component, Focusable {
307
- private tui: any;
308
- private theme: any;
309
- private keybindings: any;
310
- private onDone: (saved: boolean) => void;
311
- private _onPersist: (next: string[] | undefined) => Promise<void>;
312
-
313
- private rows: ModelRow[] = [];
314
- private sortedProviders: string[] = [];
315
- private rowsByProvider: Map<string, ModelRow[]> = new Map();
316
- private cursorIndex: number = 0;
317
- private collapsed: Set<string> = new Set();
318
- private originalEnabled: string[] | undefined;
319
- private draftEnabled: string[] | undefined;
320
- private allIds: string[] = [];
321
- private pendingDiscard = false;
322
-
323
- private activeProviderIndex: number = 0;
324
- private perProviderCursor: Map<string, number> = new Map();
325
-
326
- private searchActive = false;
327
- private searchQuery = "";
328
- private filteredRows: ModelRow[] | null = null;
329
- private searchInput: SimpleSearchInput;
330
- private _focused = false;
331
- get focused(): boolean { return this._focused; }
332
- set focused(v: boolean) {
333
- this._focused = v;
334
- if (this.searchInput) this.searchInput.focused = v && this.searchActive;
335
- }
336
-
337
- private lastBulkMessage: string | null = null;
338
- private lastBulkTimer: ReturnType<typeof setTimeout> | null = null;
339
-
340
- constructor(opts: ModelConfViewOpts) {
341
- this.tui = opts.tui;
342
- this.theme = opts.theme;
343
- this.keybindings = opts.keybindings;
344
- this.onDone = opts.onDone;
345
- this._onPersist = opts.onPersist;
346
-
347
- this.searchInput = new SimpleSearchInput();
348
- try {
349
- const req: any = (globalThis as any).require ?? (typeof require !== "undefined" ? require : undefined);
350
- if (req) {
351
- let mod: any;
352
- try { mod = req("@earendil-works/pi-tui"); } catch { try { mod = req("@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui"); } catch {} }
353
- if (mod?.Input) {
354
- const real = new mod.Input();
355
- if (typeof real.value === "string" || typeof real.getValue === "function") {
356
- const wrapped: any = real;
357
- if (!("value" in wrapped) || typeof wrapped.value !== "string") {
358
- Object.defineProperty(wrapped, "value", {
359
- get() { return typeof wrapped.getValue === "function" ? wrapped.getValue() : wrapped._value ?? ""; },
360
- set(v: string) { if (typeof wrapped.setValue === "function") wrapped.setValue(v); else wrapped._value = v; },
361
- configurable: true,
362
- });
363
- }
364
- this.searchInput = wrapped;
365
- }
366
- }
367
- }
368
- } catch {}
369
-
370
- const all = opts.allModels ?? [];
371
- this.rows = all.map((m) => {
372
- const id = `${m.provider}/${m.id}`;
373
- return {
374
- id,
375
- provider: m.provider,
376
- modelId: m.id,
377
- visible: opts.visibleSet.has(id),
378
- name: m.name ?? m.id,
379
- } as ModelRow;
380
- });
381
-
382
- this.rows.sort((a, b) => {
383
- if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
384
- return a.modelId.localeCompare(b.modelId);
385
- });
386
-
387
- this.rowsByProvider = new Map();
388
- for (const r of this.rows) {
389
- const arr = this.rowsByProvider.get(r.provider);
390
- if (arr) arr.push(r);
391
- else this.rowsByProvider.set(r.provider, [r]);
392
- }
393
- this.sortedProviders = [...this.rowsByProvider.keys()].sort((a, b) => a.localeCompare(b));
394
-
395
- const ordered: ModelRow[] = [];
396
- for (const p of this.sortedProviders) {
397
- const grp = this.rowsByProvider.get(p)!;
398
- grp.sort((a, b) => a.modelId.localeCompare(b.modelId));
399
- ordered.push(...grp);
400
- }
401
- this.rows = ordered;
402
-
403
- this.activeProviderIndex = 0;
404
- this.perProviderCursor = new Map();
405
- for (const p of this.sortedProviders) this.perProviderCursor.set(p, 0);
406
- const initActive = this.activeProvider;
407
- if (initActive) {
408
- const base = this.rowsByProvider.get(initActive) ?? [];
409
- this.cursorIndex = base.length > 0 ? 0 : -1;
410
- } else {
411
- this.cursorIndex = this.rows.length > 0 ? 0 : -1;
412
- }
413
-
414
- this.allIds = opts.allIds ?? all.map((m) => `${m.provider}/${m.id}`);
415
- this.originalEnabled = opts.enabledRaw === undefined ? undefined : [...opts.enabledRaw];
416
- this.draftEnabled = opts.enabledRaw === undefined ? undefined : [...opts.enabledRaw];
417
- this.pendingDiscard = false;
418
- }
419
-
420
- getVisibleCount(): number {
421
- return this.rows.filter((r) => r.visible).length;
422
- }
423
-
424
- private isDirty(): boolean {
425
- const a = this.originalEnabled;
426
- const b = this.draftEnabled;
427
- if (a === undefined && b === undefined) return false;
428
- if (a === undefined || b === undefined) return true;
429
- if (a.length !== b.length) return true;
430
- const sa = [...a].sort();
431
- const sb = [...b].sort();
432
- return JSON.stringify(sa) !== JSON.stringify(sb);
433
- }
434
-
435
- private rebuildVisibility(): void {
436
- const draft = this.draftEnabled;
437
- if (draft === undefined || draft.length === 0) {
438
- for (const r of this.rows) r.visible = true;
439
- return;
440
- }
441
- const hidden = draft as string[];
442
- const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
443
- const stripThinking = (p: string) => {
444
- const idx = p.lastIndexOf(":");
445
- if (idx !== -1 && VALID_THINKING.has(p.slice(idx + 1))) return p.slice(0, idx);
446
- return p;
447
- };
448
- const matchesPattern = (ref: string, pattern: string): boolean => {
449
- const pat = stripThinking(pattern);
450
- const lowerRef = ref.toLowerCase();
451
- const lowerPat = pat.toLowerCase();
452
- const bareId = ref.split("/").slice(1).join("/").toLowerCase();
453
- const hasGlob = /[*?[\]]/.test(pat);
454
- if (hasGlob) {
455
- const rx = globToRegExp(pat);
456
- if (rx.test(ref)) return true;
457
- if (rx.test(bareId)) return true;
458
- return false;
459
- }
460
- return lowerRef === lowerPat || bareId === lowerPat;
461
- };
462
- for (const r of this.rows) {
463
- let isHidden = false;
464
- for (const pat of hidden) {
465
- if (matchesPattern(r.id, pat)) { isHidden = true; break; }
466
- }
467
- r.visible = !isHidden;
468
- }
469
- }
470
-
471
- private safeFg(color: string, text: string): string {
472
- try {
473
- if (this.theme && typeof this.theme.fg === "function") {
474
- return this.theme.fg(color, text);
475
- }
476
- } catch {}
477
- return text;
478
- }
479
-
480
- private safeBold(text: string): string {
481
- try {
482
- if (this.theme && typeof this.theme.bold === "function") {
483
- return this.theme.bold(text);
484
- }
485
- } catch {}
486
- return text;
487
- }
488
-
489
- private safeBg(color: string, text: string): string {
490
- try {
491
- if (this.theme && typeof this.theme.bg === "function") {
492
- return this.theme.bg(color, text);
493
- }
494
- } catch {}
495
- return text;
496
- }
497
-
498
- private highlight(text: string): string {
499
- try {
500
- if (this.theme && typeof this.theme.bg === "function") {
501
- try {
502
- const v = this.theme.bg("selectedBg", text);
503
- if (v !== text) return v;
504
- } catch {}
505
- try {
506
- const v2 = (this.theme as any).bg("selection", text);
507
- if (v2 !== text) return v2;
508
- } catch {}
509
- }
510
- } catch {}
511
- try {
512
- if (this.theme && typeof this.theme.fg === "function") {
513
- return this.theme.fg("accent", text);
514
- }
515
- } catch {}
516
- return `› ${text}`;
517
- }
518
-
519
- private isProviderCollapsed(provider: string): boolean {
520
- return this.collapsed.has(provider);
521
- }
522
-
523
- private get activeProvider(): string | undefined {
524
- if (this.sortedProviders.length === 0) return undefined;
525
- const idx = Math.max(0, Math.min(this.activeProviderIndex, this.sortedProviders.length - 1));
526
- return this.sortedProviders[idx];
527
- }
528
-
529
- private get activeRows(): ModelRow[] {
530
- const p = this.activeProvider;
531
- if (!p) return [];
532
- return this.rowsByProvider.get(p) ?? [];
533
- }
534
-
535
- private get rowsToShow(): ModelRow[] {
536
- const base = this.activeRows;
537
- if (this.filteredRows !== null) {
538
- const filteredForActive = this.filteredRows.filter((r) => r.provider === this.activeProvider);
539
- if (filteredForActive.length !== this.filteredRows.length) return filteredForActive;
540
- return this.filteredRows;
541
- }
542
- return base;
543
- }
544
-
545
- private cursorRow(): ModelRow | undefined {
546
- const list = this.rowsToShow;
547
- if (this.cursorIndex < 0 || this.cursorIndex >= list.length) return undefined;
548
- return list[this.cursorIndex];
549
- }
550
-
551
- private getCurrentProvider(): string | undefined {
552
- return this.activeProvider;
553
- }
554
-
555
- private switchProvider(delta: number): void {
556
- if (this.sortedProviders.length <= 1) return;
557
- const curProvider = this.activeProvider;
558
- if (curProvider) this.perProviderCursor.set(curProvider, this.cursorIndex);
559
- let next = this.activeProviderIndex + delta;
560
- next = (next + this.sortedProviders.length) % this.sortedProviders.length;
561
- this.activeProviderIndex = next;
562
- const nextProvider = this.activeProvider!;
563
- let saved = this.perProviderCursor.get(nextProvider);
564
- if (saved === undefined) saved = 0;
565
- const targetRows = this.rowsToShowForProvider(nextProvider);
566
- if (targetRows.length === 0) this.cursorIndex = -1;
567
- else this.cursorIndex = Math.max(0, Math.min(saved, targetRows.length - 1));
568
- if (this.filteredRows !== null && this.searchQuery.trim()) {
569
- this.recomputeFilteredForActive();
570
- const after = this.rowsToShow;
571
- if (after.length === 0) this.cursorIndex = -1;
572
- else this.cursorIndex = Math.max(0, Math.min(this.cursorIndex, after.length - 1));
573
- }
574
- }
575
-
576
- private applyVisibleBulk(action: "include" | "exclude"): void {
577
- const list = this.rowsToShow;
578
- if (list.length === 0) return;
579
- const ids = list.map((r) => `${r.provider}/${r.modelId}` as ModelId);
580
- this.draftEnabled = applyBulk(this.draftEnabled as any, this.allIds as unknown as ModelId[], ids, action) as any;
581
- this.rebuildVisibility();
582
- const verb = action === "include" ? "Included" : "Excluded";
583
- const prov = this.activeProvider ?? "";
584
- this.lastBulkMessage = `${verb} ${ids.length} in ${prov}`;
585
- if (this.lastBulkTimer) { try { clearTimeout(this.lastBulkTimer); } catch {} }
586
- this.lastBulkTimer = setTimeout(() => { this.lastBulkMessage = null; try { this.tui?.requestRender?.(); } catch {} }, 4000) as any;
587
- if (this.cursorIndex >= this.rowsToShow.length) this.cursorIndex = Math.max(0, this.rowsToShow.length - 1);
588
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
589
- try { this.tui?.requestRender?.(); } catch {}
590
- }
591
-
592
- private rowsToShowForProvider(provider: string): ModelRow[] {
593
- const base = this.rowsByProvider.get(provider) ?? [];
594
- if (this.filteredRows !== null) {
595
- const anyForProvider = this.filteredRows.some((r) => r.provider === provider);
596
- if (anyForProvider) return this.filteredRows.filter((r) => r.provider === provider);
597
- if (this.searchQuery.trim()) {
598
- try {
599
- return fuzzyFilter(this.searchQuery, base, (r) => `${r.provider}/${r.modelId} ${r.name ?? ""}`);
600
- } catch { return []; }
601
- }
602
- return [];
603
- }
604
- return base;
605
- }
606
-
607
- private recomputeFilteredForActive(): void {
608
- const q = this.searchQuery;
609
- if (!q.trim()) {
610
- this.filteredRows = null;
611
- return;
612
- }
613
- const base = this.activeRows;
614
- try {
615
- this.filteredRows = fuzzyFilter(q, base, (r) => `${r.provider}/${r.modelId} ${r.name ?? ""}`);
616
- } catch {
617
- this.filteredRows = null;
618
- }
619
- }
620
-
621
- private renderTabBar(width: number): string {
622
- if (this.sortedProviders.length === 0) return this.safeFg("dim", " (no providers)");
623
- const tabs: { styled: string; width: number }[] = [];
624
- for (let i = 0; i < this.sortedProviders.length; i++) {
625
- const p = this.sortedProviders[i];
626
- const group = this.rowsByProvider.get(p) ?? [];
627
- const vis = group.filter((r) => r.visible).length;
628
- const total = group.length;
629
- const count = `${vis}/${total}`;
630
- const rawLabel = `${p} ${count}`;
631
- let styled: string;
632
- if (i === this.activeProviderIndex) {
633
- const inner = ` [${rawLabel}] `;
634
- let hl = inner;
635
- try {
636
- const bgged = this.safeBg("selection", inner);
637
- if (bgged !== inner) hl = bgged;
638
- else hl = this.safeFg("accent", this.safeBold(inner));
639
- } catch {
640
- hl = this.safeFg("accent", this.safeBold(inner));
641
- }
642
- styled = hl;
643
- } else {
644
- styled = this.safeFg("dim", ` [${rawLabel}] `);
645
- }
646
- const w = visibleWidthFallback(stripAnsi(styled));
647
- tabs.push({ styled, width: w });
648
- }
649
- let totalW = tabs.reduce((s, t) => s + t.width, 0) + Math.max(0, tabs.length - 1);
650
- if (totalW <= width) {
651
- return tabs.map((t) => t.styled).join("");
652
- }
653
- let start = this.activeProviderIndex;
654
- let end = this.activeProviderIndex + 1;
655
- let curW = tabs[this.activeProviderIndex].width;
656
- let left = this.activeProviderIndex - 1;
657
- let right = this.activeProviderIndex + 1;
658
- while (left >= 0 || right < tabs.length) {
659
- let expanded = false;
660
- if (left >= 0) {
661
- const need = curW + 1 + tabs[left].width;
662
- if (need <= width - 4) {
663
- curW = need;
664
- start = left;
665
- left--;
666
- expanded = true;
667
- }
668
- }
669
- if (right < tabs.length) {
670
- const need = curW + 1 + tabs[right].width;
671
- if (need <= width - 4) {
672
- curW = need;
673
- end = right + 1;
674
- right++;
675
- expanded = true;
676
- }
677
- }
678
- if (!expanded) break;
679
- }
680
- const visible = tabs.slice(start, end);
681
- let out = visible.map((t) => t.styled).join("");
682
- if (start > 0) out = this.safeFg("dim", "‹ ") + out;
683
- if (end < tabs.length) out = out + this.safeFg("dim", " ›");
684
- return this.truncate(out, width);
685
- }
686
-
687
- private getAvailableHeight(): number {
688
- let h: number | undefined;
689
- try {
690
- const term = (this.tui as any)?.terminal;
691
- if (term) {
692
- if (typeof term.rows === "number") h = term.rows;
693
- else if (typeof term.height === "number") h = term.height;
694
- else if (typeof term.getSize === "function") {
695
- const sz = term.getSize();
696
- if (sz && typeof sz.rows === "number") h = sz.rows;
697
- }
698
- }
699
- } catch {}
700
- if (h === undefined || h === null) {
701
- try {
702
- const c: any = (globalThis as any).process?.stdout;
703
- if (c && typeof c.rows === "number") h = c.rows;
704
- } catch {}
705
- }
706
- if (h === undefined || h === null || h <= 0) h = 24;
707
- const searchExtra = this.searchActive ? 1 : (this.filteredRows !== null && this.searchQuery ? 1 : 0);
708
- // Half-screen: reserve half the terminal height for the list
709
- const half = Math.floor(h / 2);
710
- // Account for chrome: title + 2 dividers + tab bar + blank spacer + status + 2-line footer
711
- const chrome = 8 + searchExtra;
712
- const avail = Math.max(5, half - chrome);
713
- return Math.min(avail, 20);
714
- }
715
-
716
- private truncate(text: string, width: number): string {
717
- try {
718
- return truncateToWidthFn(text, width);
719
- } catch {
720
- return truncateFallback(text, width);
721
- }
722
- }
723
-
724
- render(width: number): string[] {
725
- const lines: string[] = [];
726
- const total = this.rows.length;
727
- const visible = this.getVisibleCount();
728
- const dirtyMark = this.isDirty() ? this.safeFg("warning", " ● unsaved") : "";
729
- const titleText = this.safeFg("accent", this.safeBold("modelconf")) + this.safeFg("dim", ` ${total} models ${visible} visible`) + dirtyMark;
730
- lines.push(this.truncate(titleText, width));
731
- lines.push(this.truncate(this.safeFg("dim", "─".repeat(Math.max(0, width))), width));
732
- lines.push(this.truncate(this.renderTabBar(width), width));
733
- lines.push(this.truncate(this.safeFg("dim", "─".repeat(Math.max(0, width))), width));
734
- if (this.searchActive) {
735
- const inputWidth = Math.max(10, width - 4);
736
- const rendered = this.searchInput.render(inputWidth);
737
- const inputLine = rendered[0] ?? (this.searchInput as any).value ?? "";
738
- const prefix = this.safeFg("accent", "/ ");
739
- const line = prefix + inputLine;
740
- lines.push(this.truncate(line, width));
741
- } else if (this.filteredRows !== null && this.searchQuery) {
742
- const hint = this.safeFg("dim", `filtered in ${this.activeProvider ?? ""}: "${this.searchQuery}" (${this.rowsToShow.length}/${this.activeRows.length}) • Esc to clear • / to search`);
743
- lines.push(this.truncate(hint, width));
744
- }
745
- const rowsToShow = this.rowsToShow;
746
- if (rowsToShow.length === 0) {
747
- if (this.filteredRows !== null) {
748
- const q = this.searchQuery;
749
- const prov = this.activeProvider ?? "provider";
750
- lines.push(this.truncate(this.safeFg("warning", ` No models match '${q}' in ${prov}`), width));
751
- lines.push(this.truncate(this.safeFg("dim", " Press Esc to clear filter"), width));
752
- } else if (this.sortedProviders.length === 0) {
753
- lines.push(this.truncate(this.safeFg("dim", " No providers configured"), width));
754
- } else {
755
- lines.push(this.truncate(this.safeFg("dim", ` No models in ${this.activeProvider ?? "provider"}`), width));
756
- }
757
- } else {
758
- const maxVisible = this.getAvailableHeight();
759
- let start = 0;
760
- let end = rowsToShow.length;
761
- if (rowsToShow.length > maxVisible) {
762
- const cursor = this.cursorIndex;
763
- const half = Math.floor(maxVisible / 2);
764
- start = Math.max(0, Math.min(cursor - half, rowsToShow.length - maxVisible));
765
- end = Math.min(start + maxVisible, rowsToShow.length);
766
- }
767
- for (let idx = start; idx < end; idx++) {
768
- const row = rowsToShow[idx];
769
- const isCursor = this.cursorIndex === idx;
770
- const mark = row.visible ? this.safeFg("success", "◉") : this.safeFg("dim", "○");
771
- const labelPart = `${mark} ${row.modelId}`;
772
- const dimName = row.name && row.name !== row.modelId ? this.safeFg("dim", ` ${row.name}`) : "";
773
- let rawLine = `${labelPart}${dimName}`;
774
- rawLine = ` ${rawLine}`;
775
- let rendered: string;
776
- if (isCursor) {
777
- const highlighted = this.highlight(rawLine);
778
- rendered = this.truncate(highlighted, width);
779
- } else {
780
- rendered = this.truncate(rawLine, width);
781
- }
782
- lines.push(rendered);
783
- }
784
- if (rowsToShow.length > maxVisible) {
785
- const pos = this.cursorIndex >= 0 ? this.cursorIndex + 1 : 0;
786
- const indicator = this.safeFg("dim", ` (${pos}/${rowsToShow.length}) in ${this.activeProvider ?? ""}`);
787
- lines.push(this.truncate(indicator, width));
788
- }
789
- }
790
- lines.push("");
791
- if (this.pendingDiscard) {
792
- const msg = this.safeFg("warning", "Discard changes? (y/N)") + this.safeFg("dim", " y: discard n: keep editing Esc: discard");
793
- lines.push(this.truncate(msg, width));
794
- } else if (this.lastBulkMessage) {
795
- const isInc = this.lastBulkMessage.startsWith("Included") || this.lastBulkMessage.startsWith("Enabled");
796
- const bulk = this.safeFg(isInc ? "success" : "warning", this.lastBulkMessage) + this.safeFg("dim", this.isDirty() ? " • ● unsaved — Enter save" : "");
797
- lines.push(this.truncate(bulk, width));
798
- } else if (this.isDirty()) {
799
- lines.push(this.truncate(this.safeFg("warning", "● unsaved — press Enter to save"), width));
800
- } else if (this.searchActive) {
801
- lines.push(this.truncate(this.safeFg("dim", "filtering — Esc clear • Enter keep filter"), width));
802
- } else {
803
- const countLine = this.safeFg("dim", `${visible} visible / ${total} total`);
804
- lines.push(this.truncate(countLine, width));
805
- }
806
- // --- Persistent keybinds footer — always visible at bottom (all binds) ---
807
- const kb1 = "Tab/⇧Tab ←→ switch provider │ ↑↓/j k Home/End navigate │ Space toggle │ / filter";
808
- const kb2 = "a add visible │ x hide visible │ d toggle provider │ Enter save │ Esc/q close";
809
- const sep = this.safeFg("dim", " │ ");
810
- // If terminal is wide enough, show in one line; otherwise split into two
811
- const oneLine = `${kb1} │ ${kb2}`;
812
- let footerLines: string[];
813
- try {
814
- const w = visibleWidthFallback(stripAnsi(oneLine));
815
- if (w + 2 <= width) {
816
- footerLines = [this.safeFg("dim", oneLine)];
817
- } else {
818
- footerLines = [this.safeFg("dim", kb1), this.safeFg("dim", kb2)];
819
- }
820
- } catch {
821
- footerLines = [this.safeFg("dim", kb1), this.safeFg("dim", kb2)];
822
- }
823
- for (const fl of footerLines) lines.push(this.truncate(fl, width));
824
- return lines.map((l) => this.truncate(l, width));
825
- }
826
-
827
- handleInput(data: string): void {
828
- if (!data) return;
829
- const tryKb = (keyId: string): boolean => {
830
- try {
831
- if (this.keybindings) {
832
- if (typeof this.keybindings.matches === "function" && this.keybindings.matches(data, keyId)) return true;
833
- if (typeof this.keybindings.match === "function" && this.keybindings.match(data, keyId)) return true;
834
- }
835
- } catch {}
836
- return false;
837
- };
838
- if (this.pendingDiscard) {
839
- if (data === "y" || data === "Y") {
840
- this.pendingDiscard = false;
841
- this.onDone(false);
842
- return;
843
- }
844
- if (data === "n" || data === "N") {
845
- this.pendingDiscard = false;
846
- try { this.tui?.requestRender?.(); } catch {}
847
- return;
848
- }
849
- const isEscPend = data === "\x1b" || tryKb("escape") || data.includes("\x1b[27");
850
- if (isEscPend) {
851
- this.pendingDiscard = false;
852
- this.onDone(false);
853
- return;
854
- }
855
- return;
856
- }
857
- if (!this.searchActive && data === "/") {
858
- this.searchActive = true;
859
- this.searchInput.focused = true;
860
- this._focused = true;
861
- if (typeof (this.searchInput as any).setValue === "function") (this.searchInput as any).setValue("");
862
- else (this.searchInput as any).value = "";
863
- this.searchQuery = "";
864
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
865
- this.cursorIndex = this.rowsToShow.length > 0 ? 0 : -1;
866
- try { this.tui?.requestRender?.(); } catch {}
867
- return;
868
- }
869
- if (this.searchActive) {
870
- // Arrow/Home/End navigate the filtered list while typing (left/right still edit the query).
871
- const navUp = data === "\x1b[A" || data === "\x1bOA" || tryKb("up");
872
- const navDown = data === "\x1b[B" || data === "\x1bOB" || tryKb("down");
873
- const navHome = data === "\x1b[H" || data === "\x1b[1~" || data === "\x1bOH" || tryKb("home");
874
- const navEnd = data === "\x1b[F" || data === "\x1b[4~" || data === "\x1bOF" || tryKb("end");
875
- if (navUp || navDown || navHome || navEnd) {
876
- const navList = this.rowsToShow;
877
- if (navList.length > 0) {
878
- if (navUp) this.cursorIndex = (this.cursorIndex - 1 + navList.length) % navList.length;
879
- else if (navDown) this.cursorIndex = (this.cursorIndex + 1) % navList.length;
880
- else if (navHome) this.cursorIndex = 0;
881
- else this.cursorIndex = navList.length - 1;
882
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
883
- }
884
- try { this.tui?.requestRender?.(); } catch {}
885
- return;
886
- }
887
- const isEscKitty = data.includes("\x1b[27");
888
- const isEsc = data === "\x1b" || tryKb("escape") || isEscKitty;
889
- const isEnter = data === "\r" || data === "\n" || data === "\r\n" || data.includes("\r") || data.includes("\n") || tryKb("enter") || tryKb("return");
890
- if (data === "\t" || data === "\x1b[Z") {
891
- try { this.tui?.requestRender?.(); } catch {}
892
- return;
893
- }
894
- if (isEsc) {
895
- this.searchActive = false;
896
- this.searchInput.focused = false;
897
- this.filteredRows = null;
898
- this.searchQuery = "";
899
- if (typeof (this.searchInput as any).setValue === "function") (this.searchInput as any).setValue("");
900
- else (this.searchInput as any).value = "";
901
- const prov = this.activeProvider;
902
- if (prov) {
903
- const saved = this.perProviderCursor.get(prov);
904
- const list = this.rowsToShow;
905
- if (list.length === 0) this.cursorIndex = -1;
906
- else this.cursorIndex = saved !== undefined ? Math.max(0, Math.min(saved, list.length - 1)) : 0;
907
- } else {
908
- this.cursorIndex = this.rowsToShow.length > 0 ? 0 : -1;
909
- }
910
- try { this.tui?.requestRender?.(); } catch {}
911
- return;
912
- } else if (isEnter) {
913
- this.searchActive = false;
914
- this.searchInput.focused = false;
915
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
916
- try { this.tui?.requestRender?.(); } catch {}
917
- return;
918
- } else {
919
- try { (this.searchInput as any).handleInput?.(data); } catch {}
920
- let q: string = "";
921
- try {
922
- const si: any = this.searchInput;
923
- if (typeof si.getValue === "function") q = si.getValue();
924
- else if (typeof si.value === "string") q = si.value;
925
- else q = String(si.value ?? "");
926
- } catch { q = (this.searchInput as any).value ?? ""; }
927
- this.searchQuery = q;
928
- if (!q.trim()) {
929
- this.filteredRows = null;
930
- const prov = this.activeProvider;
931
- if (prov) {
932
- const saved = this.perProviderCursor.get(prov);
933
- this.cursorIndex = saved !== undefined ? Math.max(0, Math.min(saved, this.activeRows.length - 1)) : 0;
934
- if (this.activeRows.length === 0) this.cursorIndex = -1;
935
- } else {
936
- this.cursorIndex = 0;
937
- }
938
- } else {
939
- try {
940
- const base = this.activeRows;
941
- this.filteredRows = fuzzyFilter(q, base, (r) => `${r.provider}/${r.modelId} ${r.name ?? ""}`);
942
- } catch {
943
- this.filteredRows = null;
944
- }
945
- this.cursorIndex = this.rowsToShow.length > 0 ? 0 : -1;
946
- }
947
- try { this.tui?.requestRender?.(); } catch {}
948
- return;
949
- }
950
- }
951
- if (data === "\t" || data === "\x09") {
952
- this.switchProvider(1);
953
- try { this.tui?.requestRender?.(); } catch {}
954
- return;
955
- }
956
- if (data === "\x1b[Z") {
957
- this.switchProvider(-1);
958
- try { this.tui?.requestRender?.(); } catch {}
959
- return;
960
- }
961
- if (!this.searchActive && (data === "d" || data === "D")) {
962
- const active = this.activeRows;
963
- if (active.length === 0) return;
964
- const vis = active.filter((r) => r.visible).length;
965
- const allVisible = vis === active.length;
966
- const ids = active.map((r) => `${r.provider}/${r.modelId}` as ModelId);
967
- if (allVisible) {
968
- this.draftEnabled = applyBulk(this.draftEnabled as any, this.allIds as unknown as ModelId[], ids, "exclude") as any;
969
- this.lastBulkMessage = `Disabled all ${ids.length} in ${this.activeProvider ?? "provider"}`;
970
- } else {
971
- this.draftEnabled = applyBulk(this.draftEnabled as any, this.allIds as unknown as ModelId[], ids, "include") as any;
972
- this.lastBulkMessage = `Enabled all ${ids.length} in ${this.activeProvider ?? "provider"}`;
973
- }
974
- this.rebuildVisibility();
975
- if (this.lastBulkTimer) { try { clearTimeout(this.lastBulkTimer); } catch {} }
976
- this.lastBulkTimer = setTimeout(() => { this.lastBulkMessage = null; try { this.tui?.requestRender?.(); } catch {} }, 4000) as any;
977
- if (this.cursorIndex >= this.rowsToShow.length) this.cursorIndex = Math.max(0, this.rowsToShow.length - 1);
978
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
979
- try { this.tui?.requestRender?.(); } catch {}
980
- return;
981
- }
982
- if (!this.searchActive && (data === "a" || data === "A")) {
983
- this.applyVisibleBulk("include");
984
- return;
985
- }
986
- if (!this.searchActive && (data === "x" || data === "X")) {
987
- this.applyVisibleBulk("exclude");
988
- return;
989
- }
990
- const isEscKitty = data.includes("\x1b[27");
991
- const isEsc = data === "\x1b" || tryKb("escape") || isEscKitty;
992
- const isQ = data === "q" || data === "Q";
993
- if ((isEsc || isQ) && this.filteredRows !== null) {
994
- this.filteredRows = null;
995
- this.searchQuery = "";
996
- if (typeof (this.searchInput as any).setValue === "function") (this.searchInput as any).setValue("");
997
- else (this.searchInput as any).value = "";
998
- this.searchInput.focused = false;
999
- this.searchActive = false;
1000
- const prov = this.activeProvider;
1001
- if (prov) {
1002
- const saved = this.perProviderCursor.get(prov);
1003
- const list = this.activeRows;
1004
- if (list.length === 0) this.cursorIndex = -1;
1005
- else this.cursorIndex = saved !== undefined ? Math.max(0, Math.min(saved, list.length - 1)) : 0;
1006
- } else {
1007
- this.cursorIndex = this.rowsToShow.length > 0 ? 0 : -1;
1008
- }
1009
- try { this.tui?.requestRender?.(); } catch {}
1010
- return;
1011
- }
1012
- if (isEsc || isQ) {
1013
- if (this.isDirty()) {
1014
- this.pendingDiscard = true;
1015
- try { this.tui?.requestRender?.(); } catch {}
1016
- return;
1017
- }
1018
- this.onDone(false);
1019
- return;
1020
- }
1021
- if (data === " ") {
1022
- const row = this.cursorRow();
1023
- if (!row) return;
1024
- const modelId = `${row.provider}/${row.modelId}` as ModelId;
1025
- // Hide/show operates on the full model list (this.allIds is the full registry),
1026
- // even though the view is scoped to configured providers. This ensures toggling
1027
- // a model affects the main full enabledModels list, not just the scoped subset.
1028
- this.draftEnabled = toggleInEnabled(modelId, this.draftEnabled, this.allIds as ModelId[]);
1029
- this.rebuildVisibility();
1030
- this.pendingDiscard = false;
1031
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
1032
- try { this.tui?.requestRender?.(); } catch {}
1033
- return;
1034
- }
1035
- const isEnter = data === "\r" || data === "\n" || data === "\r\n" || tryKb("enter") || tryKb("return");
1036
- const isEnterRaw = isEnter || data.includes("\r") || data.includes("\n");
1037
- if (isEnterRaw) {
1038
- const toSave = this.draftEnabled;
1039
- Promise.resolve(this._onPersist(toSave as any)).then(() => {
1040
- this.onDone(true);
1041
- }).catch(() => {
1042
- try { this.tui?.requestRender?.(); } catch {}
1043
- });
1044
- return;
1045
- }
1046
- // Left/Right also switch provider (alternative to Tab/Shift-Tab) when not in search
1047
- const isLeft = data === "\x1b[D" || data === "\x1bOD" || tryKb("left");
1048
- const isRight = data === "\x1b[C" || data === "\x1bOC" || tryKb("right");
1049
- if (isLeft) {
1050
- this.switchProvider(-1);
1051
- try { this.tui?.requestRender?.(); } catch {}
1052
- return;
1053
- }
1054
- if (isRight) {
1055
- this.switchProvider(1);
1056
- try { this.tui?.requestRender?.(); } catch {}
1057
- return;
1058
- }
1059
- let handled = false;
1060
- const isUp = data === "k" || data === "\x1b[A" || data === "\x1bOA" || tryKb("up") || tryKb("k");
1061
- const isDown = data === "j" || data === "\x1b[B" || data === "\x1bOB" || tryKb("down") || tryKb("j");
1062
- const isHome = data === "g" || data === "\x1b[H" || data === "\x1b[1~" || data === "\x1bOH" || tryKb("home") || tryKb("g");
1063
- const isEnd = data === "G" || data === "\x1b[F" || data === "\x1b[4~" || data === "\x1bOF" || tryKb("end") || tryKb("G");
1064
- const navList = this.rowsToShow;
1065
- if (isUp) {
1066
- if (navList.length > 0) {
1067
- const next = (this.cursorIndex - 1 + navList.length) % navList.length;
1068
- this.cursorIndex = next;
1069
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
1070
- handled = true;
1071
- }
1072
- } else if (isDown) {
1073
- if (navList.length > 0) {
1074
- const next = (this.cursorIndex + 1) % navList.length;
1075
- this.cursorIndex = next;
1076
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
1077
- handled = true;
1078
- }
1079
- } else if (isHome) {
1080
- if (navList.length > 0) {
1081
- this.cursorIndex = 0;
1082
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
1083
- handled = true;
1084
- }
1085
- } else if (isEnd) {
1086
- if (navList.length > 0) {
1087
- this.cursorIndex = navList.length - 1;
1088
- if (this.activeProvider) this.perProviderCursor.set(this.activeProvider, this.cursorIndex);
1089
- handled = true;
1090
- }
1091
- }
1092
- if (handled) {
1093
- try { this.tui?.requestRender?.(); } catch {}
1094
- }
1095
- }
1096
-
1097
- invalidate(): void {
1098
- try { this.tui?.requestRender?.(); } catch {}
1099
- }
1100
- }
1101
-