@gajae-code/coding-agent 0.11.11 → 0.12.1

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 (344) hide show
  1. package/CHANGELOG.md +131 -4
  2. package/dist/types/async/job-manager.d.ts +17 -3
  3. package/dist/types/cli/read-cli.d.ts +1 -0
  4. package/dist/types/commands/deep-interview.d.ts +9 -0
  5. package/dist/types/commands/harness.d.ts +22 -0
  6. package/dist/types/commands/read.d.ts +6 -0
  7. package/dist/types/config/model-registry.d.ts +4 -0
  8. package/dist/types/config/provider-auth-health.d.ts +14 -0
  9. package/dist/types/config/provider-ranking.d.ts +59 -0
  10. package/dist/types/config/settings-schema.d.ts +83 -1
  11. package/dist/types/config/settings.d.ts +2 -0
  12. package/dist/types/exa/mcp-client.d.ts +10 -1
  13. package/dist/types/exec/bash-executor.d.ts +45 -12
  14. package/dist/types/extensibility/extensions/types.d.ts +38 -4
  15. package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
  16. package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
  17. package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
  18. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
  19. package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
  20. package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
  21. package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
  22. package/dist/types/extensibility/shared-events.d.ts +6 -0
  23. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
  24. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
  25. package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
  26. package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
  27. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  28. package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
  29. package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
  30. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -1
  31. package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
  32. package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
  33. package/dist/types/gjc-runtime/team-runtime.d.ts +27 -1
  34. package/dist/types/gjc-runtime/team-store.d.ts +12 -0
  35. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
  36. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
  37. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
  38. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
  39. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
  40. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
  41. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  42. package/dist/types/main.d.ts +1 -1
  43. package/dist/types/memories/index.d.ts +2 -0
  44. package/dist/types/modes/acp/acp-agent.d.ts +10 -19
  45. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  46. package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
  47. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  48. package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
  49. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  50. package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
  51. package/dist/types/modes/components/settings-selector.d.ts +11 -0
  52. package/dist/types/modes/components/status-line/gh.d.ts +5 -0
  53. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  54. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
  55. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  56. package/dist/types/modes/interactive-mode.d.ts +2 -0
  57. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  58. package/dist/types/modes/types.d.ts +2 -0
  59. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  60. package/dist/types/reminders/star-reminder.d.ts +3 -13
  61. package/dist/types/runtime-mcp/manager.d.ts +1 -0
  62. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  63. package/dist/types/sdk/acp/adapter.d.ts +3 -1
  64. package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
  65. package/dist/types/sdk/broker/transport.d.ts +2 -0
  66. package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
  67. package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
  68. package/dist/types/sdk/bus/config.d.ts +6 -2
  69. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  70. package/dist/types/sdk/bus/index.d.ts +44 -1
  71. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
  72. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  73. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
  74. package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
  75. package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
  76. package/dist/types/sdk/bus/rich-render.d.ts +2 -0
  77. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
  78. package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
  79. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
  80. package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
  81. package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
  82. package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
  83. package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
  84. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  85. package/dist/types/sdk/host/host.d.ts +2 -0
  86. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  87. package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
  88. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  89. package/dist/types/sdk/prompt-status.d.ts +23 -3
  90. package/dist/types/sdk/session.d.ts +6 -0
  91. package/dist/types/session/agent-session.d.ts +82 -12
  92. package/dist/types/session/artifacts.d.ts +8 -0
  93. package/dist/types/session/blob-store.d.ts +57 -4
  94. package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
  95. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  96. package/dist/types/session/session-manager.d.ts +48 -19
  97. package/dist/types/session/session-storage.d.ts +4 -0
  98. package/dist/types/session/streaming-output.d.ts +96 -12
  99. package/dist/types/setup/credential-import.d.ts +12 -0
  100. package/dist/types/skill-state/active-state.d.ts +12 -4
  101. package/dist/types/skill-state/workflow-hud.d.ts +9 -0
  102. package/dist/types/task/executor.d.ts +3 -2
  103. package/dist/types/task/index.d.ts +3 -1
  104. package/dist/types/task/provider-retry-status.d.ts +8 -0
  105. package/dist/types/task/receipt.d.ts +7 -1
  106. package/dist/types/task/types.d.ts +23 -0
  107. package/dist/types/tools/ask-answer-registry.d.ts +2 -2
  108. package/dist/types/tools/bash-interactive.d.ts +4 -1
  109. package/dist/types/tools/bash.d.ts +3 -1
  110. package/dist/types/tools/browser/launch.d.ts +7 -0
  111. package/dist/types/tools/fetch.d.ts +17 -1
  112. package/dist/types/tools/image-gen.d.ts +4 -0
  113. package/dist/types/tools/index.d.ts +4 -0
  114. package/dist/types/tools/output-meta.d.ts +44 -3
  115. package/dist/types/tools/path-utils.d.ts +1 -0
  116. package/dist/types/tools/read-internals.d.ts +12 -0
  117. package/dist/types/tools/read.d.ts +45 -7
  118. package/dist/types/tools/resource-gc.d.ts +4 -0
  119. package/dist/types/tools/review.d.ts +5 -7
  120. package/dist/types/tools/subagent.d.ts +2 -0
  121. package/dist/types/tools/tool-result.d.ts +7 -1
  122. package/dist/types/utils/gh.d.ts +13 -0
  123. package/dist/types/utils/image-resize.d.ts +1 -0
  124. package/dist/types/web/search/providers/kimi.d.ts +2 -0
  125. package/dist/types/web/search/providers/searxng.d.ts +7 -0
  126. package/dist/types/web/search/providers/xai.d.ts +2 -0
  127. package/package.json +11 -13
  128. package/scripts/acp-conformance-agent.ts +218 -0
  129. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  130. package/scripts/capture-gjc-bundle-settings.ts +306 -0
  131. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  132. package/scripts/generate-sdk-operation-inventory.ts +5 -0
  133. package/scripts/resident-memory-bench.ts +1341 -0
  134. package/scripts/run-acp-conformance.ts +285 -0
  135. package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
  136. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  137. package/src/async/job-manager.ts +78 -20
  138. package/src/capability/index.ts +8 -0
  139. package/src/cli/fast-help.ts +1 -1
  140. package/src/cli/plugin-cli.ts +176 -18
  141. package/src/cli/read-cli.ts +2 -1
  142. package/src/cli.ts +1 -0
  143. package/src/commands/deep-interview.ts +29 -9
  144. package/src/commands/harness.ts +35 -12
  145. package/src/commands/read.ts +11 -2
  146. package/src/commands/team.ts +20 -2
  147. package/src/config/file-lock.ts +11 -2
  148. package/src/config/model-registry.ts +21 -2
  149. package/src/config/provider-auth-health.ts +42 -0
  150. package/src/config/provider-ranking.ts +119 -0
  151. package/src/config/settings-schema.ts +74 -1
  152. package/src/config/settings.ts +246 -108
  153. package/src/coordinator-mcp/question-gate-codec.ts +1 -1
  154. package/src/coordinator-mcp/server.ts +5 -12
  155. package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
  156. package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
  157. package/src/defaults/gjc/skills/team/SKILL.md +3 -1
  158. package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
  159. package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
  160. package/src/defaults/gjc-defaults.ts +4 -4
  161. package/src/eval/py/executor.ts +7 -2
  162. package/src/exa/mcp-client.ts +12 -3
  163. package/src/exec/bash-executor.ts +144 -27
  164. package/src/extensibility/extensions/runner.ts +15 -0
  165. package/src/extensibility/extensions/types.ts +46 -5
  166. package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
  167. package/src/extensibility/gjc-plugins/index.ts +19 -2
  168. package/src/extensibility/gjc-plugins/installer.ts +189 -50
  169. package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
  170. package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
  171. package/src/extensibility/gjc-plugins/observability.ts +3 -3
  172. package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
  173. package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
  174. package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
  175. package/src/extensibility/gjc-plugins/schema.ts +84 -12
  176. package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
  177. package/src/extensibility/gjc-plugins/types.ts +141 -0
  178. package/src/extensibility/gjc-plugins/validation.ts +9 -0
  179. package/src/extensibility/shared-events.ts +5 -0
  180. package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
  181. package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
  182. package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
  183. package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
  184. package/src/gjc-runtime/deep-interview-state.ts +12 -943
  185. package/src/gjc-runtime/gc-render.ts +1 -0
  186. package/src/gjc-runtime/gc-runtime.ts +11 -1
  187. package/src/gjc-runtime/launch-tmux.ts +25 -6
  188. package/src/gjc-runtime/managed-owner-admission.ts +1 -1
  189. package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
  190. package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
  191. package/src/gjc-runtime/state-runtime.ts +2 -1
  192. package/src/gjc-runtime/state-writer.ts +70 -222
  193. package/src/gjc-runtime/team-launch.ts +42 -5
  194. package/src/gjc-runtime/team-runtime.ts +1085 -40
  195. package/src/gjc-runtime/team-store.ts +32 -0
  196. package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
  197. package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
  198. package/src/gjc-runtime/team-workers.ts +1 -0
  199. package/src/gjc-runtime/tmux-owner-isolation.ts +28 -0
  200. package/src/gjc-runtime/tmux-sessions.ts +58 -13
  201. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
  202. package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
  203. package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
  204. package/src/gjc-runtime/workflow-manifest.ts +38 -247
  205. package/src/hooks/native-skill-hook.ts +17 -4
  206. package/src/hooks/skill-state.ts +1 -23
  207. package/src/internal-urls/docs-index.generated.ts +21 -22
  208. package/src/internal-urls/local-root-gc.ts +127 -0
  209. package/src/main.ts +9 -5
  210. package/src/memories/index.ts +10 -0
  211. package/src/modes/DESIGN.md +98 -0
  212. package/src/modes/acp/acp-agent.ts +339 -191
  213. package/src/modes/acp/acp-event-mapper.ts +14 -7
  214. package/src/modes/acp/acp-mode.ts +39 -3
  215. package/src/modes/components/assistant-message.ts +123 -22
  216. package/src/modes/components/gjc-bundle-settings.ts +508 -0
  217. package/src/modes/components/irc-sidebar.ts +176 -62
  218. package/src/modes/components/model-selector.ts +61 -4
  219. package/src/modes/components/notifications-settings-editor.ts +12 -1
  220. package/src/modes/components/oauth-selector.ts +96 -28
  221. package/src/modes/components/read-tool-group.ts +82 -14
  222. package/src/modes/components/session-observer-overlay.ts +457 -83
  223. package/src/modes/components/settings-selector.ts +116 -23
  224. package/src/modes/components/status-line/gh.ts +16 -0
  225. package/src/modes/components/tool-execution.ts +138 -27
  226. package/src/modes/components/tool-status-header.ts +3 -14
  227. package/src/modes/components/transcript-viewer-overlay.ts +99 -24
  228. package/src/modes/controllers/command-controller.ts +4 -0
  229. package/src/modes/controllers/event-controller.ts +109 -27
  230. package/src/modes/controllers/extension-ui-controller.ts +26 -2
  231. package/src/modes/controllers/input-controller.ts +18 -3
  232. package/src/modes/controllers/selector-controller.ts +127 -36
  233. package/src/modes/interactive-mode.ts +62 -3
  234. package/src/modes/irc-observation-ledger.ts +71 -15
  235. package/src/modes/runtime-init.ts +22 -2
  236. package/src/modes/types.ts +2 -0
  237. package/src/modes/utils/ui-helpers.ts +94 -1
  238. package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
  239. package/src/prompts/agents/architect.md +9 -1
  240. package/src/prompts/agents/critic.md +9 -0
  241. package/src/prompts/system/eager-todo.md +8 -4
  242. package/src/prompts/system/system-prompt.md +11 -5
  243. package/src/prompts/tools/bash.md +5 -5
  244. package/src/prompts/tools/read.md +4 -2
  245. package/src/prompts/tools/search-tool-bm25.md +5 -0
  246. package/src/prompts/tools/task.md +1 -1
  247. package/src/reminders/star-reminder.ts +4 -42
  248. package/src/runtime-mcp/manager.ts +19 -4
  249. package/src/runtime-mcp/smithery-auth.ts +17 -2
  250. package/src/runtime-mcp/smithery-connect.ts +11 -1
  251. package/src/sdk/acp/adapter.ts +22 -6
  252. package/src/sdk/broker/lifecycle.ts +25 -6
  253. package/src/sdk/broker/transport.ts +35 -3
  254. package/src/sdk/bus/attachment-registry.ts +5 -1
  255. package/src/sdk/bus/chat-daemon-cli.ts +4 -39
  256. package/src/sdk/bus/chat-daemon-control.ts +6 -3
  257. package/src/sdk/bus/config.ts +18 -2
  258. package/src/sdk/bus/control-drain-lease.ts +104 -0
  259. package/src/sdk/bus/index.ts +984 -146
  260. package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
  261. package/src/sdk/bus/lifecycle-commands.ts +4 -1
  262. package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
  263. package/src/sdk/bus/prompt-reconciliation.ts +2 -1
  264. package/src/sdk/bus/reconciliation-store.ts +303 -0
  265. package/src/sdk/bus/rich-draft.ts +1 -1
  266. package/src/sdk/bus/rich-render.ts +2 -2
  267. package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
  268. package/src/sdk/bus/telegram-cli.ts +33 -8
  269. package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
  270. package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
  271. package/src/sdk/bus/telegram-daemon.ts +916 -23
  272. package/src/sdk/bus/telegram-reference.ts +40 -3
  273. package/src/sdk/bus/threaded-render.ts +48 -3
  274. package/src/sdk/bus/topic-registry.ts +20 -0
  275. package/src/sdk/host/control/dispatch.ts +5 -1
  276. package/src/sdk/host/control/operations.ts +1 -1
  277. package/src/sdk/host/host.ts +23 -1
  278. package/src/sdk/host/query/handlers.ts +55 -0
  279. package/src/sdk/host/query/revision-store.ts +36 -2
  280. package/src/sdk/host/reverse-leases.ts +44 -7
  281. package/src/sdk/mcp/server.ts +46 -18
  282. package/src/sdk/prompt-status.ts +16 -3
  283. package/src/sdk/protocol/operation-inventory.generated.json +51 -0
  284. package/src/sdk/protocol/operation-registry.ts +7 -2
  285. package/src/sdk/session.ts +101 -10
  286. package/src/session/agent-session.ts +1286 -220
  287. package/src/session/artifacts.ts +22 -0
  288. package/src/session/auth-broker-config.ts +10 -3
  289. package/src/session/blob-store.ts +915 -24
  290. package/src/session/internal/managed-session-scope.ts +44 -6
  291. package/src/session/internal/managed-session-storage.ts +48 -6
  292. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  293. package/src/session/session-manager.ts +2364 -438
  294. package/src/session/session-storage.ts +9 -1
  295. package/src/session/streaming-output.ts +500 -111
  296. package/src/setup/credential-import.ts +75 -13
  297. package/src/setup/provider-onboarding.ts +19 -4
  298. package/src/skill-state/active-state.ts +32 -10
  299. package/src/skill-state/workflow-hud.ts +42 -2
  300. package/src/skill-state/workflow-mutation-guard.ts +560 -8
  301. package/src/task/executor.ts +122 -39
  302. package/src/task/index.ts +23 -14
  303. package/src/task/provider-retry-status.ts +16 -0
  304. package/src/task/receipt.ts +23 -7
  305. package/src/task/render.ts +6 -2
  306. package/src/task/types.ts +108 -0
  307. package/src/tools/ask-answer-registry.ts +12 -6
  308. package/src/tools/ask.ts +169 -118
  309. package/src/tools/ast-edit.ts +1 -0
  310. package/src/tools/ast-grep.ts +1 -0
  311. package/src/tools/bash-interactive.ts +8 -3
  312. package/src/tools/bash.ts +503 -60
  313. package/src/tools/browser/launch.ts +41 -6
  314. package/src/tools/fetch.ts +114 -23
  315. package/src/tools/find.ts +1 -0
  316. package/src/tools/image-gen.ts +29 -5
  317. package/src/tools/index.ts +4 -0
  318. package/src/tools/output-meta.ts +281 -20
  319. package/src/tools/path-utils.ts +8 -3
  320. package/src/tools/read-internals.ts +44 -0
  321. package/src/tools/read.ts +1560 -310
  322. package/src/tools/resource-gc.ts +182 -18
  323. package/src/tools/review.ts +5 -7
  324. package/src/tools/search.ts +1 -0
  325. package/src/tools/subagent-render.ts +6 -2
  326. package/src/tools/subagent.ts +6 -0
  327. package/src/tools/telegram-send.ts +6 -3
  328. package/src/tools/tool-result.ts +14 -1
  329. package/src/utils/gh.ts +39 -0
  330. package/src/utils/image-resize.ts +3 -0
  331. package/src/web/search/providers/anthropic.ts +4 -4
  332. package/src/web/search/providers/codex.ts +1 -1
  333. package/src/web/search/providers/kimi.ts +15 -5
  334. package/src/web/search/providers/searxng.ts +47 -4
  335. package/src/web/search/providers/xai.ts +7 -2
  336. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
  337. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
  338. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
  339. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
  340. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
  341. package/src/gjc-runtime/deep-interview-draft.ts +0 -843
  342. package/src/gjc-runtime/deep-interview-payload.ts +0 -262
  343. package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
  344. package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
@@ -1,6 +1,8 @@
1
1
  import { getOAuthProviders } from "@gajae-code/ai/utils/oauth";
2
2
  import type { OAuthProviderInfo } from "@gajae-code/ai/utils/oauth/types";
3
- import { Container, matchesKey, Spacer, TruncatedText } from "@gajae-code/tui";
3
+ import { Container, fuzzyFilter, Input, matchesKey, Spacer, TruncatedText } from "@gajae-code/tui";
4
+ import { recordProviderAuthHealth } from "../../config/provider-auth-health";
5
+ import { compareRankedProviders, type ProviderAuthState } from "../../config/provider-ranking";
4
6
  import { theme } from "../../modes/theme/theme";
5
7
  import { matchesSelectCancel } from "../../modes/utils/keybinding-matchers";
6
8
  import type { AuthStorage } from "../../session/auth-storage";
@@ -14,6 +16,9 @@ const OAUTH_SELECTOR_MAX_VISIBLE = 10;
14
16
  export class OAuthSelectorComponent extends Container {
15
17
  #listContainer: Container;
16
18
  #allProviders: OAuthProviderInfo[] = [];
19
+ #sortedProviders: OAuthProviderInfo[] = [];
20
+ #filteredProviders: OAuthProviderInfo[] = [];
21
+ #searchInput: Input;
17
22
  #selectedIndex: number = 0;
18
23
  #mode: "login" | "logout";
19
24
  #authStorage: AuthStorage;
@@ -54,6 +59,14 @@ export class OAuthSelectorComponent extends Container {
54
59
  const title = mode === "login" ? "Select provider to login:" : "Select provider to logout:";
55
60
  this.addChild(new TruncatedText(theme.bold(title)));
56
61
  this.addChild(new Spacer(1));
62
+ // Filter box: the provider list is long enough that arrow-key-only
63
+ // navigation buries entries below the visible window.
64
+ this.#searchInput = new Input();
65
+ this.#searchInput.onSubmit = () => {
66
+ this.#selectCurrentProvider();
67
+ };
68
+ this.addChild(this.#searchInput);
69
+ this.addChild(new Spacer(1));
57
70
  // Create list container
58
71
  this.#listContainer = new Container();
59
72
  this.addChild(this.#listContainer);
@@ -91,7 +104,7 @@ export class OAuthSelectorComponent extends Container {
91
104
  }
92
105
  this.#authState.set(provider.id, "checking");
93
106
  pending += 1;
94
- void this.#validateProvider(provider.id, generation);
107
+ void this.#validateProvider(provider.id, generation, this.#authStorage.getGeneration());
95
108
  }
96
109
 
97
110
  if (pending > 0) {
@@ -101,7 +114,7 @@ export class OAuthSelectorComponent extends Container {
101
114
  }
102
115
  }
103
116
 
104
- async #validateProvider(providerId: string, generation: number): Promise<void> {
117
+ async #validateProvider(providerId: string, generation: number, authGeneration: number): Promise<void> {
105
118
  if (!this.#validateAuthCallback) return;
106
119
  let isValid = false;
107
120
  try {
@@ -112,6 +125,11 @@ export class OAuthSelectorComponent extends Container {
112
125
 
113
126
  if (generation !== this.#validationGeneration) return;
114
127
  this.#authState.set(providerId, isValid ? "valid" : "invalid");
128
+ // Only record the ordering hint when the credentials validated are still the
129
+ // current ones; a result from a superseded generation must not describe them.
130
+ if (authGeneration === this.#authStorage.getGeneration()) {
131
+ recordProviderAuthHealth(this.#authStorage, providerId, isValid ? "valid" : "invalid");
132
+ }
115
133
  if (![...this.#authState.values()].includes("checking")) {
116
134
  this.#stopSpinner();
117
135
  }
@@ -138,6 +156,10 @@ export class OAuthSelectorComponent extends Container {
138
156
  }
139
157
  }
140
158
 
159
+ #getProviderAuthState(providerId: string): ProviderAuthState {
160
+ return this.#authState.get(providerId) ?? "none";
161
+ }
162
+
141
163
  #getStatusIndicator(providerId: string): string {
142
164
  const state = this.#authState.get(providerId);
143
165
  if (state === "checking") {
@@ -154,9 +176,32 @@ export class OAuthSelectorComponent extends Container {
154
176
  return this.#authStorage.hasAuth(providerId) ? theme.fg("success", ` ${theme.status.success} logged in`) : "";
155
177
  }
156
178
  #updateList(): void {
179
+ const selectedProviderId = this.#filteredProviders[this.#selectedIndex]?.id;
180
+ const rankedProviders = this.#allProviders.map(provider => ({
181
+ provider,
182
+ id: provider.id,
183
+ label: provider.name,
184
+ authState: this.#getProviderAuthState(provider.id),
185
+ }));
186
+ rankedProviders.sort(compareRankedProviders);
187
+ this.#sortedProviders = rankedProviders.map(({ provider }) => provider);
188
+ // Filter after ranking so an empty query preserves the curated order and a
189
+ // query still surfaces matches in that same order of preference.
190
+ this.#filteredProviders = fuzzyFilter(
191
+ this.#sortedProviders,
192
+ this.#searchInput.getValue(),
193
+ provider => `${provider.name} ${provider.id}`,
194
+ );
195
+ if (selectedProviderId !== undefined) {
196
+ const selectedIndex = this.#filteredProviders.findIndex(provider => provider.id === selectedProviderId);
197
+ if (selectedIndex >= 0) this.#selectedIndex = selectedIndex;
198
+ }
199
+ if (this.#selectedIndex >= this.#filteredProviders.length) {
200
+ this.#selectedIndex = Math.max(0, this.#filteredProviders.length - 1);
201
+ }
157
202
  this.#listContainer.clear();
158
203
 
159
- const total = this.#allProviders.length;
204
+ const total = this.#filteredProviders.length;
160
205
  const maxVisible = OAUTH_SELECTOR_MAX_VISIBLE;
161
206
  const startIndex =
162
207
  total <= maxVisible
@@ -165,7 +210,7 @@ export class OAuthSelectorComponent extends Container {
165
210
  const endIndex = Math.min(startIndex + maxVisible, total);
166
211
 
167
212
  for (let i = startIndex; i < endIndex; i++) {
168
- const provider = this.#allProviders[i];
213
+ const provider = this.#filteredProviders[i];
169
214
  if (!provider) continue;
170
215
  const isSelected = i === this.#selectedIndex;
171
216
  const isAvailable = provider.available;
@@ -191,8 +236,11 @@ export class OAuthSelectorComponent extends Container {
191
236
 
192
237
  // Show "no providers" if empty
193
238
  if (total === 0) {
194
- const message =
195
- this.#mode === "login" ? "No OAuth providers available" : "No OAuth providers logged in. Use /login first.";
239
+ const message = this.#searchInput.getValue().trim()
240
+ ? "No providers match the filter"
241
+ : this.#mode === "login"
242
+ ? "No OAuth providers available"
243
+ : "No OAuth providers logged in. Use /login first.";
196
244
  this.#listContainer.addChild(new TruncatedText(theme.fg("muted", ` ${message}`), 0, 0));
197
245
  }
198
246
  if (this.#statusMessage) {
@@ -215,58 +263,78 @@ export class OAuthSelectorComponent extends Container {
215
263
  }
216
264
  }
217
265
  }
266
+ #selectCurrentProvider(): void {
267
+ const selectedProvider = this.#filteredProviders[this.#selectedIndex];
268
+ if (selectedProvider?.available) {
269
+ this.#statusMessage = undefined;
270
+ this.stopValidation();
271
+ this.#onSelectCallback(selectedProvider.id);
272
+ } else if (selectedProvider) {
273
+ this.#statusMessage = "Provider unavailable in this environment.";
274
+ this.#updateList();
275
+ }
276
+ }
218
277
  handleInput(keyData: string): void {
219
278
  // Up arrow
220
279
  if (matchesKey(keyData, "up")) {
221
- if (this.#allProviders.length > 0) {
222
- this.#selectedIndex = this.#selectedIndex === 0 ? this.#allProviders.length - 1 : this.#selectedIndex - 1;
280
+ if (this.#filteredProviders.length > 0) {
281
+ this.#selectedIndex =
282
+ this.#selectedIndex === 0 ? this.#filteredProviders.length - 1 : this.#selectedIndex - 1;
223
283
  }
224
284
  this.#statusMessage = undefined;
225
285
  this.#updateList();
286
+ return;
226
287
  }
227
288
  // Down arrow
228
- else if (matchesKey(keyData, "down")) {
229
- if (this.#allProviders.length > 0) {
230
- this.#selectedIndex = this.#selectedIndex === this.#allProviders.length - 1 ? 0 : this.#selectedIndex + 1;
289
+ if (matchesKey(keyData, "down")) {
290
+ if (this.#filteredProviders.length > 0) {
291
+ this.#selectedIndex =
292
+ this.#selectedIndex === this.#filteredProviders.length - 1 ? 0 : this.#selectedIndex + 1;
231
293
  }
232
294
  this.#statusMessage = undefined;
233
295
  this.#updateList();
296
+ return;
234
297
  }
235
298
  // Page up - jump up by one visible page
236
- else if (matchesKey(keyData, "pageUp")) {
237
- if (this.#allProviders.length > 0) {
299
+ if (matchesKey(keyData, "pageUp")) {
300
+ if (this.#filteredProviders.length > 0) {
238
301
  this.#selectedIndex = Math.max(0, this.#selectedIndex - OAUTH_SELECTOR_MAX_VISIBLE);
239
302
  }
240
303
  this.#statusMessage = undefined;
241
304
  this.#updateList();
305
+ return;
242
306
  }
243
307
  // Page down - jump down by one visible page
244
- else if (matchesKey(keyData, "pageDown")) {
245
- if (this.#allProviders.length > 0) {
308
+ if (matchesKey(keyData, "pageDown")) {
309
+ if (this.#filteredProviders.length > 0) {
246
310
  this.#selectedIndex = Math.min(
247
- this.#allProviders.length - 1,
311
+ this.#filteredProviders.length - 1,
248
312
  this.#selectedIndex + OAUTH_SELECTOR_MAX_VISIBLE,
249
313
  );
250
314
  }
251
315
  this.#statusMessage = undefined;
252
316
  this.#updateList();
317
+ return;
253
318
  }
254
319
  // Enter
255
- else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
256
- const selectedProvider = this.#allProviders[this.#selectedIndex];
257
- if (selectedProvider?.available) {
258
- this.#statusMessage = undefined;
259
- this.stopValidation();
260
- this.#onSelectCallback(selectedProvider.id);
261
- } else if (selectedProvider) {
262
- this.#statusMessage = "Provider unavailable in this environment.";
263
- this.#updateList();
264
- }
320
+ if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
321
+ this.#selectCurrentProvider();
322
+ return;
265
323
  }
266
324
  // Escape or Ctrl+C
267
- else if (matchesSelectCancel(keyData)) {
325
+ if (matchesSelectCancel(keyData)) {
268
326
  this.stopValidation();
269
327
  this.#onCancelCallback();
328
+ return;
329
+ }
330
+ // Everything else edits the filter. A changed query invalidates the current
331
+ // position, so selection restarts at the best match.
332
+ const previousQuery = this.#searchInput.getValue();
333
+ this.#searchInput.handleInput(keyData);
334
+ if (this.#searchInput.getValue() !== previousQuery) {
335
+ this.#selectedIndex = 0;
336
+ this.#statusMessage = undefined;
337
+ this.#updateList();
270
338
  }
271
339
  }
272
340
  }
@@ -3,7 +3,7 @@ import { Container, Text } from "@gajae-code/tui";
3
3
  import { InternalUrlRouter } from "../../internal-urls";
4
4
  import { getLanguageFromPath, theme } from "../../modes/theme/theme";
5
5
  import { splitPathAndSel } from "../../tools/path-utils";
6
- import { PREVIEW_LIMITS, shortenPath } from "../../tools/render-utils";
6
+ import { PREVIEW_LIMITS, replaceTabs, shortenPath } from "../../tools/render-utils";
7
7
  import { renderCodeCell } from "../../tui";
8
8
  import type { ToolExecutionHandle } from "./tool-execution";
9
9
 
@@ -53,9 +53,16 @@ type ReadToolResultDetails = {
53
53
  conflictCount?: number;
54
54
  };
55
55
 
56
- type ReadToolGroupOptions = {
57
- showContentPreview?: boolean;
58
- };
56
+ type ReadToolVisibleProjection = ReadonlyArray<{
57
+ path: string;
58
+ status: ReadEntry["status"];
59
+ correctedFrom?: string;
60
+ conflictCount?: number;
61
+ preview?: {
62
+ lines: readonly string[];
63
+ hiddenLineCount: number;
64
+ };
65
+ }>;
59
66
 
60
67
  function getSuffixResolution(details: ReadToolResultDetails | undefined): ReadToolSuffixResolution | undefined {
61
68
  if (typeof details?.suffixResolution?.from !== "string" || typeof details.suffixResolution.to !== "string") {
@@ -82,13 +89,16 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
82
89
  #expanded = false;
83
90
  #manuallyExpanded: boolean | undefined;
84
91
  #showContentPreview: boolean;
92
+ #visibleTranscriptChanged = false;
93
+ #lastVisibleProjection: ReadToolVisibleProjection = [];
85
94
 
86
- constructor(options: ReadToolGroupOptions = {}) {
95
+ constructor(options: { showContentPreview?: boolean } = {}) {
87
96
  super();
88
97
  this.#showContentPreview = options.showContentPreview ?? false;
89
98
  this.#text = new Text("", 0, 0);
90
99
  this.addChild(this.#text);
91
100
  this.#updateDisplay();
101
+ this.#lastVisibleProjection = this.#visibleProjection();
92
102
  }
93
103
 
94
104
  updateArgs(args: ReadRenderArgs, toolCallId?: string): void {
@@ -102,7 +112,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
102
112
  };
103
113
  entry.path = rawPath;
104
114
  this.#entries.set(toolCallId, entry);
105
- this.#updateDisplay();
115
+ this.#updateDisplayAndNotify();
106
116
  }
107
117
 
108
118
  updateResult(
@@ -126,23 +136,20 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
126
136
  typeof details?.conflictCount === "number" && details.conflictCount > 0 ? details.conflictCount : undefined;
127
137
  entry.conflictCount = conflictCount;
128
138
  entry.status = result.isError ? "error" : suffixResolution ? "warning" : "success";
129
- // Store the text content for preview/expanded display
130
139
  const textContent = result.content?.find(c => c.type === "text")?.text;
131
- if (textContent !== undefined) {
132
- entry.contentText = textContent;
133
- }
134
- this.#updateDisplay();
140
+ entry.contentText = textContent;
141
+ this.#updateDisplayAndNotify();
135
142
  }
136
143
 
137
144
  setArgsComplete(_toolCallId?: string): void {
138
- this.#updateDisplay();
145
+ this.#updateDisplayAndNotify();
139
146
  }
140
147
 
141
148
  /** Applies automatic expansion unless this renderer instance has an explicit fold choice. */
142
149
  setExpanded(expanded: boolean): void {
143
150
  if (this.#manuallyExpanded !== undefined) return;
144
151
  this.#expanded = expanded;
145
- this.#updateDisplay();
152
+ this.#updateDisplayAndNotify();
146
153
  }
147
154
 
148
155
  /**
@@ -152,13 +159,74 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
152
159
  setManuallyExpanded(expanded: boolean): void {
153
160
  this.#manuallyExpanded = expanded;
154
161
  this.#expanded = expanded;
155
- this.#updateDisplay();
162
+ this.#updateDisplayAndNotify();
156
163
  }
157
164
 
158
165
  getComponent(): Component {
159
166
  return this;
160
167
  }
161
168
 
169
+ consumeVisibleTranscriptChange(): boolean {
170
+ const changed = this.#visibleTranscriptChanged;
171
+ this.#visibleTranscriptChanged = false;
172
+ return changed;
173
+ }
174
+
175
+ #visibleProjection(): ReadToolVisibleProjection {
176
+ return [...this.#entries.values()].map(entry => {
177
+ if (!this.#shouldRenderPreview(entry)) {
178
+ return {
179
+ path: entry.path,
180
+ status: entry.status,
181
+ correctedFrom: entry.correctedFrom,
182
+ conflictCount: entry.conflictCount,
183
+ };
184
+ }
185
+ const lines = replaceTabs(entry.contentText ?? "")
186
+ .split(/\r?\n/)
187
+ .map(line => line.slice(line.lastIndexOf("\r") + 1));
188
+ const visibleLineCount = this.#expanded ? lines.length : Math.min(lines.length, COLLAPSED_PREVIEW_LINES);
189
+ return {
190
+ path: entry.path,
191
+ status: entry.status,
192
+ correctedFrom: entry.correctedFrom,
193
+ preview: {
194
+ lines: lines.slice(0, visibleLineCount),
195
+ hiddenLineCount: lines.length - visibleLineCount,
196
+ },
197
+ };
198
+ });
199
+ }
200
+
201
+ #sameVisibleProjection(left: ReadToolVisibleProjection, right: ReadToolVisibleProjection): boolean {
202
+ if (left.length !== right.length) return false;
203
+ return left.every((entry, index) => {
204
+ const other = right[index];
205
+ if (
206
+ !other ||
207
+ entry.path !== other.path ||
208
+ entry.status !== other.status ||
209
+ entry.correctedFrom !== other.correctedFrom ||
210
+ (!entry.preview && entry.conflictCount !== other.conflictCount)
211
+ )
212
+ return false;
213
+ if (!entry.preview || !other.preview) return entry.preview === other.preview;
214
+ return (
215
+ entry.preview.hiddenLineCount === other.preview.hiddenLineCount &&
216
+ entry.preview.lines.length === other.preview.lines.length &&
217
+ entry.preview.lines.every((line, lineIndex) => line === other.preview!.lines[lineIndex])
218
+ );
219
+ });
220
+ }
221
+
222
+ #updateDisplayAndNotify(): void {
223
+ this.#updateDisplay();
224
+ const after = this.#visibleProjection();
225
+ if (this.#sameVisibleProjection(after, this.#lastVisibleProjection)) return;
226
+ this.#lastVisibleProjection = after;
227
+ this.#visibleTranscriptChanged = true;
228
+ }
229
+
162
230
  #updateDisplay(): void {
163
231
  const entries = [...this.#entries.values()];
164
232