@gajae-code/coding-agent 0.13.2 → 0.14.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 (610) hide show
  1. package/CHANGELOG.md +215 -8
  2. package/README.md +2 -0
  3. package/bin/gajaessi.js +4 -0
  4. package/dist/types/async/job-manager.d.ts +55 -2
  5. package/dist/types/async/support.d.ts +14 -0
  6. package/dist/types/capability/mcp.d.ts +6 -0
  7. package/dist/types/capability/types.d.ts +6 -0
  8. package/dist/types/cli/accounts-cli.d.ts +19 -0
  9. package/dist/types/cli/args.d.ts +3 -0
  10. package/dist/types/cli/config-cli.d.ts +6 -0
  11. package/dist/types/cli/crash-cli.d.ts +10 -0
  12. package/dist/types/cli/customize-doctor.d.ts +145 -0
  13. package/dist/types/cli/daemon-cli.d.ts +3 -1
  14. package/dist/types/cli/mcp-cli.d.ts +11 -0
  15. package/dist/types/cli/notify-cli.d.ts +1 -1
  16. package/dist/types/cli/root-flags.d.ts +12 -0
  17. package/dist/types/cli/setup-cli.d.ts +3 -1
  18. package/dist/types/cli/skills-cli.d.ts +2 -1
  19. package/dist/types/cli/update-cli.d.ts +19 -1
  20. package/dist/types/cli.d.ts +6 -0
  21. package/dist/types/commands/accounts.d.ts +40 -0
  22. package/dist/types/commands/crash.d.ts +24 -0
  23. package/dist/types/commands/customize.d.ts +22 -0
  24. package/dist/types/commands/daemon.d.ts +1 -1
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/commands/setup.d.ts +6 -0
  27. package/dist/types/commands/skills.d.ts +6 -1
  28. package/dist/types/commands/update.d.ts +7 -0
  29. package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
  30. package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
  31. package/dist/types/config/config-schema-version.d.ts +10 -0
  32. package/dist/types/config/file-lock.d.ts +18 -0
  33. package/dist/types/config/model-profile-activation.d.ts +3 -1
  34. package/dist/types/config/model-registry.d.ts +10 -1
  35. package/dist/types/config/models-config-schema.d.ts +2 -0
  36. package/dist/types/config/settings-schema.d.ts +73 -9
  37. package/dist/types/config/settings.d.ts +63 -0
  38. package/dist/types/config/skill-settings-defaults.d.ts +26 -0
  39. package/dist/types/config/task-delegation.d.ts +39 -0
  40. package/dist/types/config/update-channel.d.ts +10 -0
  41. package/dist/types/coordinator-mcp/server.d.ts +5 -1
  42. package/dist/types/crash/index-store.d.ts +87 -0
  43. package/dist/types/crash/nudge.d.ts +50 -0
  44. package/dist/types/crash/record-loader.d.ts +17 -0
  45. package/dist/types/crash/report.d.ts +134 -0
  46. package/dist/types/crash/sanitize.d.ts +25 -0
  47. package/dist/types/cursor.d.ts +13 -2
  48. package/dist/types/customization/import.d.ts +37 -0
  49. package/dist/types/customization/index.d.ts +4 -0
  50. package/dist/types/customization/inventory.d.ts +25 -0
  51. package/dist/types/customization/mutations.d.ts +32 -0
  52. package/dist/types/customization/types.d.ts +115 -0
  53. package/dist/types/daemon/control-types.d.ts +8 -1
  54. package/dist/types/daemon/operator-contract.d.ts +4 -4
  55. package/dist/types/discovery/claude.d.ts +39 -1
  56. package/dist/types/discovery/codex.d.ts +39 -1
  57. package/dist/types/discovery/index.d.ts +2 -0
  58. package/dist/types/discovery/mcp-compat.d.ts +30 -0
  59. package/dist/types/edit/renderer.d.ts +23 -0
  60. package/dist/types/extensibility/extensions/runner.d.ts +3 -0
  61. package/dist/types/extensibility/extensions/types.d.ts +21 -4
  62. package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
  63. package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
  64. package/dist/types/extensibility/hooks/loader.d.ts +19 -5
  65. package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
  66. package/dist/types/extensibility/skill-management.d.ts +107 -0
  67. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
  68. package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
  69. package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
  70. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
  71. package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
  72. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
  73. package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
  74. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
  75. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
  76. package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
  77. package/dist/types/hooks/events.d.ts +60 -0
  78. package/dist/types/hooks/normalize.d.ts +83 -0
  79. package/dist/types/hooks/skill-state.d.ts +9 -2
  80. package/dist/types/main.d.ts +2 -1
  81. package/dist/types/modes/acp/abort-scope.d.ts +13 -0
  82. package/dist/types/modes/acp/acp-agent.d.ts +7 -4
  83. package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
  84. package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
  85. package/dist/types/modes/components/customization/index.d.ts +1 -0
  86. package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
  87. package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
  88. package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
  89. package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
  90. package/dist/types/modes/components/oauth-selector.d.ts +10 -4
  91. package/dist/types/modes/components/pet-capability.d.ts +7 -21
  92. package/dist/types/modes/components/settings-selector.d.ts +5 -0
  93. package/dist/types/modes/components/status-line/gh.d.ts +6 -2
  94. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  95. package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
  96. package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
  97. package/dist/types/modes/interactive-mode.d.ts +1 -0
  98. package/dist/types/modes/theme/defaults/index.d.ts +118 -0
  99. package/dist/types/modes/types.d.ts +1 -0
  100. package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
  101. package/dist/types/runtime-mcp/config.d.ts +9 -0
  102. package/dist/types/runtime-mcp/manager.d.ts +26 -1
  103. package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
  104. package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
  105. package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
  106. package/dist/types/runtime-mcp/protocol.d.ts +278 -0
  107. package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
  108. package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
  109. package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
  110. package/dist/types/runtime-mcp/types.d.ts +102 -10
  111. package/dist/types/sdk/acp/adapter.d.ts +26 -5
  112. package/dist/types/sdk/broker/broker.d.ts +3 -55
  113. package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
  114. package/dist/types/sdk/broker/session-index.d.ts +14 -5
  115. package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
  116. package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
  117. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
  118. package/dist/types/sdk/bus/config.d.ts +11 -0
  119. package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
  120. package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
  121. package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
  122. package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
  123. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
  124. package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
  125. package/dist/types/sdk/bus/index.d.ts +85 -99
  126. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
  127. package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
  128. package/dist/types/sdk/bus/notification-service.d.ts +52 -0
  129. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
  130. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
  131. package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
  132. package/dist/types/sdk/bus/session-control.d.ts +25 -1
  133. package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
  134. package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
  135. package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
  136. package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
  137. package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
  138. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
  139. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
  140. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
  141. package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
  142. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
  143. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
  144. package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
  145. package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
  146. package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
  147. package/dist/types/sdk/cli/rows.d.ts +2 -11
  148. package/dist/types/sdk/cli/session-cli.d.ts +15 -25
  149. package/dist/types/sdk/client/client.d.ts +97 -1
  150. package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
  151. package/dist/types/sdk/host/control/index.d.ts +1 -1
  152. package/dist/types/sdk/host/control/operations.d.ts +18 -5
  153. package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
  154. package/dist/types/sdk/host/host.d.ts +15 -1
  155. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  156. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  157. package/dist/types/sdk/host/session-runtime.d.ts +127 -7
  158. package/dist/types/sdk/host/types.d.ts +1 -1
  159. package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
  160. package/dist/types/sdk/index.d.ts +2 -1
  161. package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
  162. package/dist/types/sdk/lifecycle/client.d.ts +59 -0
  163. package/dist/types/sdk/lifecycle/index.d.ts +3 -0
  164. package/dist/types/sdk/lifecycle/service.d.ts +232 -0
  165. package/dist/types/sdk/mcp/server.d.ts +9 -6
  166. package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
  167. package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
  168. package/dist/types/sdk/prompt-status.d.ts +10 -3
  169. package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
  170. package/dist/types/sdk/receipt-state.d.ts +17 -0
  171. package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
  172. package/dist/types/sdk/router/index.d.ts +1 -0
  173. package/dist/types/sdk/router/session-router.d.ts +152 -0
  174. package/dist/types/sdk/session-list.d.ts +22 -0
  175. package/dist/types/sdk/session-reconnect.d.ts +43 -1
  176. package/dist/types/sdk/session.d.ts +34 -1
  177. package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
  178. package/dist/types/session/account-inventory.d.ts +86 -0
  179. package/dist/types/session/agent-session.d.ts +145 -6
  180. package/dist/types/session/agent-storage.d.ts +10 -0
  181. package/dist/types/session/coordinator-tool-label.d.ts +28 -0
  182. package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
  183. package/dist/types/session/messages.d.ts +1 -1
  184. package/dist/types/session/secure-token-file.d.ts +3 -0
  185. package/dist/types/session/session-manager.d.ts +47 -1
  186. package/dist/types/session/startup-auth-config.d.ts +44 -0
  187. package/dist/types/session/terminal-abort.d.ts +378 -0
  188. package/dist/types/session/yield-queue.d.ts +7 -0
  189. package/dist/types/session-import/claude.d.ts +26 -0
  190. package/dist/types/session-import/codex.d.ts +88 -0
  191. package/dist/types/session-import/command.d.ts +35 -0
  192. package/dist/types/session-import/detect.d.ts +22 -0
  193. package/dist/types/session-import/index.d.ts +7 -0
  194. package/dist/types/session-import/provider-codex.d.ts +22 -0
  195. package/dist/types/session-import/provider-service.d.ts +38 -0
  196. package/dist/types/session-import/redact.d.ts +23 -0
  197. package/dist/types/session-import/service.d.ts +47 -0
  198. package/dist/types/session-import/types.d.ts +120 -0
  199. package/dist/types/setup/paseo/check.d.ts +16 -0
  200. package/dist/types/setup/paseo/install-saga.d.ts +115 -0
  201. package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
  202. package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
  203. package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
  204. package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
  205. package/dist/types/setup/paseo/provider-config.d.ts +35 -0
  206. package/dist/types/setup/paseo/remove.d.ts +14 -0
  207. package/dist/types/setup/paseo/result-types.d.ts +59 -0
  208. package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
  209. package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
  210. package/dist/types/skill-state/active-state.d.ts +5 -1
  211. package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
  212. package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
  213. package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
  214. package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
  215. package/dist/types/slash-commands/types.d.ts +7 -1
  216. package/dist/types/task/executor.d.ts +10 -0
  217. package/dist/types/task/index.d.ts +3 -1
  218. package/dist/types/tools/ask-answer-registry.d.ts +6 -3
  219. package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
  220. package/dist/types/tools/bash.d.ts +2 -6
  221. package/dist/types/tools/browser/attach.d.ts +11 -0
  222. package/dist/types/tools/browser/launch.d.ts +20 -0
  223. package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
  224. package/dist/types/tools/browser/render.d.ts +1 -0
  225. package/dist/types/tools/browser.d.ts +3 -1
  226. package/dist/types/tools/image-gen.d.ts +10 -2
  227. package/dist/types/tools/index.d.ts +8 -0
  228. package/dist/types/tools/monitor.d.ts +1 -1
  229. package/dist/types/tools/skill-discovery.d.ts +8 -1
  230. package/dist/types/tools/subagent.d.ts +2 -0
  231. package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
  232. package/dist/types/utils/herdr-pane.d.ts +76 -0
  233. package/package.json +19 -9
  234. package/scripts/build-binary.ts +2 -1
  235. package/scripts/build-sdk-package-smoke.ts +2 -13
  236. package/scripts/capture-sticky-viewport-showcase.ts +0 -1
  237. package/scripts/compile-args.ts +2 -0
  238. package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
  239. package/scripts/generate-sdk-operation-inventory.ts +28 -0
  240. package/scripts/generate-telegram-baseline-manifest.ts +1 -0
  241. package/scripts/generate-tool-catalog.ts +6 -4
  242. package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
  243. package/src/async/job-manager.ts +352 -17
  244. package/src/async/support.ts +25 -0
  245. package/src/autoresearch/dashboard.ts +28 -13
  246. package/src/capability/index.ts +3 -1
  247. package/src/capability/mcp.ts +6 -0
  248. package/src/capability/types.ts +6 -0
  249. package/src/cli/accounts-cli.ts +395 -0
  250. package/src/cli/args.ts +23 -0
  251. package/src/cli/auth-broker-cli.ts +136 -66
  252. package/src/cli/auth-gateway-cli.ts +94 -70
  253. package/src/cli/config-cli.ts +27 -2
  254. package/src/cli/crash-cli.ts +78 -0
  255. package/src/cli/customize-doctor.ts +1605 -0
  256. package/src/cli/daemon-cli.ts +12 -3
  257. package/src/cli/fast-help.ts +1 -0
  258. package/src/cli/mcp-cli.ts +128 -60
  259. package/src/cli/notify-cli.ts +8 -14
  260. package/src/cli/root-flags.ts +8 -0
  261. package/src/cli/setup-cli.ts +145 -0
  262. package/src/cli/skills-cli.ts +38 -2
  263. package/src/cli/update-cli.ts +167 -12
  264. package/src/cli.ts +4 -0
  265. package/src/commands/accounts.ts +71 -0
  266. package/src/commands/crash.ts +35 -0
  267. package/src/commands/customize.ts +84 -0
  268. package/src/commands/daemon.ts +2 -2
  269. package/src/commands/deep-interview.ts +2 -0
  270. package/src/commands/launch.ts +1 -0
  271. package/src/commands/mcp.ts +12 -7
  272. package/src/commands/ralplan.ts +2 -0
  273. package/src/commands/sdk.ts +65 -32
  274. package/src/commands/setup.ts +5 -0
  275. package/src/commands/skills.ts +14 -4
  276. package/src/commands/ultragoal.ts +10 -1
  277. package/src/commands/update.ts +26 -15
  278. package/src/config/atomic-yaml-patch-worker.ts +57 -0
  279. package/src/config/atomic-yaml-patch.ts +769 -29
  280. package/src/config/config-schema-version.ts +10 -0
  281. package/src/config/file-lock.ts +70 -1
  282. package/src/config/mcp-schema.json +52 -14
  283. package/src/config/model-profile-activation.ts +23 -2
  284. package/src/config/model-profiles.ts +88 -21
  285. package/src/config/model-registry.ts +147 -21
  286. package/src/config/models-config-schema.ts +1 -1
  287. package/src/config/settings-schema.ts +77 -7
  288. package/src/config/settings.ts +4038 -199
  289. package/src/config/skill-settings-defaults.ts +41 -3
  290. package/src/config/task-delegation.ts +87 -0
  291. package/src/config/update-channel.ts +23 -0
  292. package/src/coordinator-mcp/server.ts +377 -308
  293. package/src/crash/index-store.ts +723 -0
  294. package/src/crash/nudge.ts +89 -0
  295. package/src/crash/record-loader.ts +149 -0
  296. package/src/crash/report.ts +551 -0
  297. package/src/crash/sanitize.ts +129 -0
  298. package/src/cursor.ts +36 -10
  299. package/src/customization/import.ts +946 -0
  300. package/src/customization/index.ts +4 -0
  301. package/src/customization/inventory.ts +335 -0
  302. package/src/customization/mutations.ts +141 -0
  303. package/src/customization/types.ts +223 -0
  304. package/src/daemon/control-types.ts +8 -1
  305. package/src/daemon/operator-contract.ts +6 -6
  306. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
  307. package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
  308. package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
  309. package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
  310. package/src/discovery/claude-hooks.ts +38 -0
  311. package/src/discovery/claude.ts +142 -209
  312. package/src/discovery/codex-hooks.ts +38 -0
  313. package/src/discovery/codex.ts +132 -198
  314. package/src/discovery/helpers.ts +8 -1
  315. package/src/discovery/index.ts +2 -0
  316. package/src/discovery/mcp-compat.ts +234 -0
  317. package/src/discovery/mcp-json.ts +6 -0
  318. package/src/edit/renderer.ts +40 -0
  319. package/src/edit/streaming.ts +4 -2
  320. package/src/exec/bash-executor.ts +24 -20
  321. package/src/export/html/index.ts +51 -2
  322. package/src/extensibility/extensions/loader.ts +9 -1
  323. package/src/extensibility/extensions/runner.ts +17 -4
  324. package/src/extensibility/extensions/types.ts +31 -6
  325. package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
  326. package/src/extensibility/gjc-plugins/installer.ts +9 -5
  327. package/src/extensibility/gjc-plugins/observability.ts +8 -2
  328. package/src/extensibility/gjc-plugins/registry.ts +13 -2
  329. package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
  330. package/src/extensibility/gjc-plugins/schema.ts +222 -39
  331. package/src/extensibility/hooks/loader.ts +154 -10
  332. package/src/extensibility/runtime-skill-discovery.ts +257 -60
  333. package/src/extensibility/skill-management.ts +368 -0
  334. package/src/extensibility/skills.ts +52 -16
  335. package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
  336. package/src/gjc-runtime/launch-worktree.ts +56 -2
  337. package/src/gjc-runtime/linux-proc.ts +7 -1
  338. package/src/gjc-runtime/ralplan-runtime.ts +100 -164
  339. package/src/gjc-runtime/session-state-lock.ts +992 -0
  340. package/src/gjc-runtime/session-state-sidecar.ts +644 -142
  341. package/src/gjc-runtime/state-writer.ts +39 -14
  342. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
  343. package/src/gjc-runtime/ultragoal-guard.ts +11 -4
  344. package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
  345. package/src/gjc-runtime/workflow-settings.ts +596 -0
  346. package/src/goals/tools/goal-tool.ts +6 -1
  347. package/src/hooks/events.ts +291 -0
  348. package/src/hooks/native-skill-hook.ts +4 -0
  349. package/src/hooks/normalize.ts +369 -0
  350. package/src/hooks/skill-state.ts +165 -46
  351. package/src/internal-urls/docs-index.generated.ts +41 -32
  352. package/src/main.ts +36 -5
  353. package/src/migrate/mcp-mapper.ts +25 -2
  354. package/src/modes/acp/abort-scope.ts +29 -0
  355. package/src/modes/acp/acp-agent.ts +423 -98
  356. package/src/modes/components/assistant-message.ts +6 -1
  357. package/src/modes/components/chrome.ts +4 -3
  358. package/src/modes/components/customization/customization-dashboard.ts +443 -0
  359. package/src/modes/components/customization/import-wizard.ts +372 -0
  360. package/src/modes/components/customization/index.ts +1 -0
  361. package/src/modes/components/dynamic-theme-text.ts +22 -0
  362. package/src/modes/components/gajae-pet-widget.ts +607 -193
  363. package/src/modes/components/irc-sidebar.ts +11 -0
  364. package/src/modes/components/iterm-pet-transport.ts +585 -0
  365. package/src/modes/components/model-selector.ts +1 -6
  366. package/src/modes/components/oauth-selector.ts +277 -86
  367. package/src/modes/components/pet-capability.ts +35 -31
  368. package/src/modes/components/settings-selector.ts +29 -5
  369. package/src/modes/components/status-line/gh.ts +45 -1
  370. package/src/modes/components/status-line/segments.ts +19 -4
  371. package/src/modes/components/tool-status-header.ts +13 -3
  372. package/src/modes/controllers/command-controller.ts +20 -8
  373. package/src/modes/controllers/extension-ui-controller.ts +56 -257
  374. package/src/modes/controllers/input-controller.ts +10 -0
  375. package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
  376. package/src/modes/controllers/selector-controller.ts +238 -77
  377. package/src/modes/controllers/stt-controller.ts +3 -3
  378. package/src/modes/interactive-mode.ts +88 -16
  379. package/src/modes/print-mode.ts +35 -6
  380. package/src/modes/runtime-init.ts +21 -68
  381. package/src/modes/theme/defaults/index.ts +2 -0
  382. package/src/modes/theme/defaults/ouroboros.json +118 -0
  383. package/src/modes/types.ts +1 -0
  384. package/src/modes/utils/injected-user-submission.ts +25 -0
  385. package/src/modes/utils/terminal-bell.ts +15 -1
  386. package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
  387. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  388. package/src/prompts/agents/critic.md +1 -1
  389. package/src/prompts/system/rlm-research.md +1 -1
  390. package/src/prompts/system/system-prompt.md +0 -2
  391. package/src/prompts/tools/bash.md +7 -1
  392. package/src/prompts/tools/browser.md +1 -1
  393. package/src/prompts/tools/cron.md +6 -6
  394. package/src/prompts/tools/read.md +0 -2
  395. package/src/prompts/tools/skill-discovery.md +4 -2
  396. package/src/runtime-mcp/client.ts +427 -23
  397. package/src/runtime-mcp/config.ts +37 -5
  398. package/src/runtime-mcp/manager-pool.test.ts +56 -0
  399. package/src/runtime-mcp/manager.ts +52 -2
  400. package/src/runtime-mcp/oauth-discovery.ts +13 -0
  401. package/src/runtime-mcp/oauth-flow.ts +46 -1
  402. package/src/runtime-mcp/pool-key.ts +5 -1
  403. package/src/runtime-mcp/pool.test.ts +9 -0
  404. package/src/runtime-mcp/protocol.test.ts +353 -0
  405. package/src/runtime-mcp/protocol.ts +624 -0
  406. package/src/runtime-mcp/scope-config.ts +78 -0
  407. package/src/runtime-mcp/tool-bridge.ts +44 -10
  408. package/src/runtime-mcp/transports/http.ts +84 -13
  409. package/src/runtime-mcp/types.ts +123 -12
  410. package/src/sdk/acp/adapter.ts +328 -97
  411. package/src/sdk/broker/broker.ts +160 -741
  412. package/src/sdk/broker/ensure.ts +9 -1
  413. package/src/sdk/broker/lifecycle.ts +510 -116
  414. package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
  415. package/src/sdk/broker/process-incarnation.ts +19 -0
  416. package/src/sdk/broker/session-index.ts +516 -117
  417. package/src/sdk/broker/startup-failure.ts +28 -5
  418. package/src/sdk/broker/transport.ts +1 -13
  419. package/src/sdk/bus/chat-daemon-cli.ts +4 -2
  420. package/src/sdk/bus/chat-daemon-control.ts +67 -6
  421. package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
  422. package/src/sdk/bus/config.ts +13 -0
  423. package/src/sdk/bus/conversation-store.ts +59 -171
  424. package/src/sdk/bus/daemon-paths.ts +20 -0
  425. package/src/sdk/bus/discord-conversation.ts +2 -0
  426. package/src/sdk/bus/discord-daemon.ts +524 -126
  427. package/src/sdk/bus/discord-live-provider.ts +206 -79
  428. package/src/sdk/bus/existing-thread-readiness.ts +4 -97
  429. package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
  430. package/src/sdk/bus/index.ts +2480 -456
  431. package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
  432. package/src/sdk/bus/lifecycle-commands.ts +2 -2
  433. package/src/sdk/bus/managed-daemon.ts +2 -145
  434. package/src/sdk/bus/notification-service.ts +196 -0
  435. package/src/sdk/bus/operator-runtime.ts +1 -1
  436. package/src/sdk/bus/prompt-reconciliation.ts +24 -15
  437. package/src/sdk/bus/reconciliation-store.ts +553 -24
  438. package/src/sdk/bus/session-control.ts +49 -3
  439. package/src/sdk/bus/slack-conversation.ts +4 -0
  440. package/src/sdk/bus/slack-daemon.ts +733 -134
  441. package/src/sdk/bus/slack-live-provider.ts +65 -15
  442. package/src/sdk/bus/slack-provider.ts +4 -0
  443. package/src/sdk/bus/slack-thread-binding.ts +9 -104
  444. package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
  445. package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
  446. package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
  447. package/src/sdk/bus/telegram-daemon-control.ts +3 -13
  448. package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
  449. package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
  450. package/src/sdk/bus/telegram-daemon.ts +2552 -2280
  451. package/src/sdk/bus/telegram-reference.ts +1 -226
  452. package/src/sdk/bus/telegram-setup.ts +2 -2
  453. package/src/sdk/bus/threaded-render.ts +1 -0
  454. package/src/sdk/bus/topic-registry.ts +279 -146
  455. package/src/sdk/cli/rows.ts +2 -35
  456. package/src/sdk/cli/session-cli.ts +776 -700
  457. package/src/sdk/client/client.ts +892 -1
  458. package/src/sdk/host/control/dispatch.ts +93 -58
  459. package/src/sdk/host/control/index.ts +1 -1
  460. package/src/sdk/host/control/operations.ts +18 -10
  461. package/src/sdk/host/control/runtime-gate.ts +40 -0
  462. package/src/sdk/host/host.ts +63 -12
  463. package/src/sdk/host/query/handlers.ts +66 -7
  464. package/src/sdk/host/reverse-leases.ts +2 -2
  465. package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
  466. package/src/sdk/host/session-runtime.test.ts +2787 -34
  467. package/src/sdk/host/session-runtime.ts +1489 -101
  468. package/src/sdk/host/surface-policy.ts +12 -8
  469. package/src/sdk/host/types.ts +1 -1
  470. package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
  471. package/src/sdk/host/websocket-transport.ts +85 -50
  472. package/src/sdk/index.ts +2 -1
  473. package/src/sdk/lifecycle/broker-client.ts +53 -0
  474. package/src/sdk/lifecycle/client.ts +234 -0
  475. package/src/sdk/lifecycle/index.ts +3 -0
  476. package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
  477. package/src/sdk/lifecycle/service.ts +720 -0
  478. package/src/sdk/mcp/server.ts +226 -188
  479. package/src/sdk/prompt-deadline-lease.ts +55 -0
  480. package/src/sdk/prompt-deadline-manager.ts +148 -0
  481. package/src/sdk/prompt-status.ts +11 -3
  482. package/src/sdk/protocol/operation-inventory.generated.json +272 -129
  483. package/src/sdk/protocol/operation-registry.ts +71 -8
  484. package/src/sdk/receipt-state.ts +43 -0
  485. package/src/sdk/reconciliation-extensions.ts +14 -0
  486. package/src/sdk/router/index.ts +1 -0
  487. package/src/sdk/router/session-router.ts +1658 -0
  488. package/src/sdk/session-list.ts +93 -0
  489. package/src/sdk/session-reconnect.ts +45 -1
  490. package/src/sdk/session.ts +716 -120
  491. package/src/sdk/transport/serve-cli.ts +18 -34
  492. package/src/session/account-inventory.ts +603 -0
  493. package/src/session/agent-session.ts +2873 -559
  494. package/src/session/agent-storage.ts +35 -0
  495. package/src/session/blob-store.ts +32 -1
  496. package/src/session/coordinator-tool-label.ts +40 -0
  497. package/src/session/internal/managed-session-scope.ts +4 -0
  498. package/src/session/internal/managed-session-storage.ts +199 -31
  499. package/src/session/messages.ts +1 -1
  500. package/src/session/secure-token-file.ts +80 -0
  501. package/src/session/session-manager.ts +757 -57
  502. package/src/session/session-storage.ts +25 -16
  503. package/src/session/startup-auth-config.ts +297 -0
  504. package/src/session/terminal-abort.ts +1253 -0
  505. package/src/session/yield-queue.ts +57 -15
  506. package/src/session-import/claude.ts +334 -0
  507. package/src/session-import/codex.ts +1033 -0
  508. package/src/session-import/command.ts +77 -0
  509. package/src/session-import/detect.ts +133 -0
  510. package/src/session-import/index.ts +7 -0
  511. package/src/session-import/provider-codex.ts +327 -0
  512. package/src/session-import/provider-service.ts +457 -0
  513. package/src/session-import/redact.ts +128 -0
  514. package/src/session-import/service.ts +1264 -0
  515. package/src/session-import/types.ts +148 -0
  516. package/src/setup/paseo/check.ts +213 -0
  517. package/src/setup/paseo/install-saga.ts +293 -0
  518. package/src/setup/paseo/json-publisher.ts +263 -0
  519. package/src/setup/paseo/orchestration-preferences.ts +86 -0
  520. package/src/setup/paseo/paseo-ownership.ts +224 -0
  521. package/src/setup/paseo/paseo-setup.ts +253 -0
  522. package/src/setup/paseo/provider-config.ts +139 -0
  523. package/src/setup/paseo/remove.ts +183 -0
  524. package/src/setup/paseo/result-types.ts +79 -0
  525. package/src/setup/paseo/setup-deps.ts +175 -0
  526. package/src/setup/paseo/skills-bridge.ts +260 -0
  527. package/src/skill-state/active-state.ts +21 -11
  528. package/src/slash-commands/acp-builtins.ts +9 -1
  529. package/src/slash-commands/builtin-registry.ts +117 -19
  530. package/src/slash-commands/helpers/credential-switch.ts +143 -0
  531. package/src/slash-commands/helpers/mcp.ts +9 -3
  532. package/src/slash-commands/helpers/usage-report.ts +61 -56
  533. package/src/slash-commands/types.ts +7 -2
  534. package/src/task/executor.ts +30 -11
  535. package/src/task/index.ts +66 -7
  536. package/src/task/render.ts +23 -9
  537. package/src/tools/ask-answer-registry.ts +23 -7
  538. package/src/tools/ask.ts +8 -4
  539. package/src/tools/bash-sleep-advisory.ts +115 -0
  540. package/src/tools/bash.ts +98 -18
  541. package/src/tools/browser/attach.ts +71 -3
  542. package/src/tools/browser/launch.ts +86 -13
  543. package/src/tools/browser/profile-discovery.ts +57 -7
  544. package/src/tools/browser/render.ts +8 -1
  545. package/src/tools/browser.ts +130 -21
  546. package/src/tools/computer.enforcement.test.ts +1 -1
  547. package/src/tools/computer.ts +3 -2
  548. package/src/tools/cron.ts +12 -1
  549. package/src/tools/image-gen.ts +349 -142
  550. package/src/tools/index.ts +8 -0
  551. package/src/tools/job.ts +33 -6
  552. package/src/tools/monitor.ts +41 -2
  553. package/src/tools/skill-discovery.ts +21 -29
  554. package/src/tools/subagent.ts +142 -24
  555. package/src/tools/todo-contract.ts +55 -3
  556. package/src/tools/todo-write.ts +4 -3
  557. package/src/tools/tool-catalog.generated.ts +6 -6
  558. package/src/tools/ultragoal-ask-guard.ts +10 -3
  559. package/src/utils/herdr-pane.ts +345 -0
  560. package/src/utils/title-generator.ts +2 -0
  561. package/src/web/scrapers/index.ts +6 -4
  562. package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
  563. package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
  564. package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
  565. package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
  566. package/dist/types/runtime/lazy-service.test.d.ts +0 -1
  567. package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
  568. package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
  569. package/dist/types/runtime-mcp/config.test.d.ts +0 -1
  570. package/dist/types/runtime-mcp/http.test.d.ts +0 -1
  571. package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
  572. package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
  573. package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
  574. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
  575. package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
  576. package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
  577. package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
  578. package/dist/types/sdk/elevation/audit.d.ts +0 -93
  579. package/dist/types/sdk/elevation/capability.d.ts +0 -3
  580. package/dist/types/sdk/elevation/digest.d.ts +0 -72
  581. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
  582. package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
  583. package/dist/types/sdk/elevation/owner.d.ts +0 -48
  584. package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
  585. package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
  586. package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
  587. package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
  588. package/dist/types/session/auth-broker-config.d.ts +0 -13
  589. package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
  590. package/dist/types/skills/skills.test.d.ts +0 -1
  591. package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
  592. package/dist/types/task/token-log.test.d.ts +0 -1
  593. package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
  594. package/dist/types/tools/descriptors.test.d.ts +0 -1
  595. package/scripts/g005-daemon-smoke.ts +0 -180
  596. package/scripts/g011-daemon-path-smoke.ts +0 -153
  597. package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
  598. package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
  599. package/src/sdk/bus/telegram-cli.ts +0 -212
  600. package/src/sdk/elevation/allowlist.ts +0 -54
  601. package/src/sdk/elevation/audit.ts +0 -208
  602. package/src/sdk/elevation/capability.ts +0 -41
  603. package/src/sdk/elevation/digest.ts +0 -129
  604. package/src/sdk/elevation/dispatch-receipt.ts +0 -184
  605. package/src/sdk/elevation/grant-ledger.ts +0 -1142
  606. package/src/sdk/elevation/owner.ts +0 -109
  607. package/src/session/auth-broker-config.ts +0 -109
  608. /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
  609. /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
  610. /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
@@ -1,3 +1,5 @@
1
+ import type { AuthCredentialSelector, CredentialInventoryRecord, CredentialRemovalTarget } from "@gajae-code/ai/core";
2
+ import { getEnvApiKey } from "@gajae-code/ai/core";
1
3
  import { getOAuthProviders } from "@gajae-code/ai/utils/oauth";
2
4
  import type { OAuthProviderInfo } from "@gajae-code/ai/utils/oauth/types";
3
5
  import { Container, fuzzyFilter, Input, matchesKey, Spacer, TruncatedText } from "@gajae-code/tui";
@@ -10,16 +12,44 @@ import type { ImportableCredential } from "../../setup/credential-import";
10
12
  import { DynamicBorder } from "./dynamic-border";
11
13
 
12
14
  const OAUTH_SELECTOR_MAX_VISIBLE = 10;
13
- /**
14
- * Component that renders an OAuth provider selector.
15
- */
15
+ const SAFE_LABEL_MAX_LENGTH = 160;
16
+
17
+ export interface OAuthSelectorAccountOptions {
18
+ accountProviderId?: string;
19
+ onAccountSelect?: (selector: AuthCredentialSelector) => void | Promise<void>;
20
+ onAutoSelect?: () => void | Promise<void>;
21
+ onAddAccount?: () => void | Promise<void>;
22
+ onAccountRemove?: (targets: readonly CredentialRemovalTarget[]) => void | Promise<void>;
23
+ }
24
+
25
+ type AccountEntry =
26
+ | { kind: "account"; row: CredentialInventoryRecord; target?: CredentialRemovalTarget; selectable: boolean }
27
+ | { kind: "auto"; selectable: true }
28
+ | { kind: "add"; selectable: boolean }
29
+ | { kind: "all"; selectable: boolean };
30
+
31
+ function safeLabel(value: unknown, fallback: string): string {
32
+ if (typeof value !== "string") return fallback;
33
+ const normalized = value
34
+ .replace(/bearer\s+[^\s,;]+/gi, "Bearer [redacted]")
35
+ .replace(/(api[_-]?key|token|secret|authorization)[=:]\s*[^\s,;]+/gi, "$1=[redacted]")
36
+ .replace(/[\u0000-\u001f\u007f]/g, " ")
37
+ .replace(/\s+/g, " ")
38
+ .trim()
39
+ .slice(0, SAFE_LABEL_MAX_LENGTH);
40
+ return normalized || fallback;
41
+ }
42
+
43
+ /** Component that renders an OAuth provider selector or a provider-scoped account selector. */
16
44
  export class OAuthSelectorComponent extends Container {
17
45
  #listContainer: Container;
18
46
  #allProviders: OAuthProviderInfo[] = [];
19
47
  #sortedProviders: OAuthProviderInfo[] = [];
20
48
  #filteredProviders: OAuthProviderInfo[] = [];
49
+ #accountEntries: AccountEntry[] = [];
50
+ #filteredAccountEntries: AccountEntry[] = [];
21
51
  #searchInput: Input;
22
- #selectedIndex: number = 0;
52
+ #selectedIndex = 0;
23
53
  #mode: "login" | "logout";
24
54
  #authStorage: AuthStorage;
25
55
  #onSelectCallback: (providerId: string) => void;
@@ -29,9 +59,16 @@ export class OAuthSelectorComponent extends Container {
29
59
  #requestRenderCallback?: () => void;
30
60
  #authState: Map<string, "checking" | "valid" | "invalid"> = new Map();
31
61
  #externalCredentialCandidates: ImportableCredential[] = [];
32
- #spinnerFrame: number = 0;
62
+ #spinnerFrame = 0;
33
63
  #spinnerInterval?: NodeJS.Timeout;
34
- #validationGeneration: number = 0;
64
+ #validationGeneration = 0;
65
+ #accountProviderId?: string;
66
+ #onAccountSelect?: (selector: AuthCredentialSelector) => void | Promise<void>;
67
+ #onAutoSelect?: () => void | Promise<void>;
68
+ #onAddAccount?: () => void | Promise<void>;
69
+ #onAccountRemove?: (targets: readonly CredentialRemovalTarget[]) => void | Promise<void>;
70
+ #pendingAccountRemovalTargets?: readonly CredentialRemovalTarget[];
71
+
35
72
  constructor(
36
73
  mode: "login" | "logout",
37
74
  authStorage: AuthStorage,
@@ -41,7 +78,7 @@ export class OAuthSelectorComponent extends Container {
41
78
  validateAuth?: (providerId: string) => Promise<boolean>;
42
79
  requestRender?: () => void;
43
80
  externalCredentialCandidates?: ImportableCredential[];
44
- },
81
+ } & Partial<OAuthSelectorAccountOptions>,
45
82
  ) {
46
83
  super();
47
84
  this.#mode = mode;
@@ -51,29 +88,32 @@ export class OAuthSelectorComponent extends Container {
51
88
  this.#validateAuthCallback = options?.validateAuth;
52
89
  this.#requestRenderCallback = options?.requestRender;
53
90
  this.#externalCredentialCandidates = options?.externalCredentialCandidates ?? [];
54
- // Load all OAuth providers
55
- this.#loadProviders();
91
+ this.#accountProviderId = options?.accountProviderId;
92
+ this.#onAccountSelect = options?.onAccountSelect;
93
+ this.#onAutoSelect = options?.onAutoSelect;
94
+ this.#onAddAccount = options?.onAddAccount;
95
+ this.#onAccountRemove = options?.onAccountRemove;
96
+
97
+ if (this.#accountProviderId) this.#loadAccountEntries();
98
+ else this.#loadProviders();
99
+
56
100
  this.addChild(new DynamicBorder());
57
101
  this.addChild(new Spacer(1));
58
- // Add title
59
- const title = mode === "login" ? "Select provider to login:" : "Select provider to logout:";
102
+ const title = this.#accountProviderId
103
+ ? `${mode === "login" ? "Select account to login for" : "Select account to logout from"} ${safeLabel(this.#accountProviderId, "provider")}:`
104
+ : mode === "login"
105
+ ? "Select provider to login:"
106
+ : "Select provider to logout:";
60
107
  this.addChild(new TruncatedText(theme.bold(title)));
61
108
  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
109
  this.#searchInput = new Input();
65
- this.#searchInput.onSubmit = () => {
66
- this.#selectCurrentProvider();
67
- };
110
+ this.#searchInput.onSubmit = () => this.#selectCurrent();
68
111
  this.addChild(this.#searchInput);
69
112
  this.addChild(new Spacer(1));
70
- // Create list container
71
113
  this.#listContainer = new Container();
72
114
  this.addChild(this.#listContainer);
73
115
  this.addChild(new Spacer(1));
74
- // Add bottom border
75
116
  this.addChild(new DynamicBorder());
76
- // Initial render
77
117
  this.#updateList();
78
118
  this.#startValidation();
79
119
  }
@@ -87,12 +127,47 @@ export class OAuthSelectorComponent extends Container {
87
127
  this.stopValidation();
88
128
  super.dispose();
89
129
  }
130
+
90
131
  #loadProviders(): void {
91
132
  this.#allProviders = getOAuthProviders();
92
133
  }
93
134
 
135
+ #loadAccountEntries(): void {
136
+ const provider = this.#accountProviderId;
137
+ if (!provider) return;
138
+ const inventory = this.#authStorage
139
+ .listCredentialInventory(provider)
140
+ .filter(row => row.provider === provider)
141
+ .sort((left, right) => left.id - right.id);
142
+ const targets = new Map(
143
+ this.#authStorage.listCredentialRemovalTargets(provider).map(target => [target.id, target]),
144
+ );
145
+ const apiKeyOverrideActive =
146
+ this.#authStorage.hasRuntimeApiKey(provider) ||
147
+ this.#authStorage.hasConfigApiKey(provider) ||
148
+ Boolean(getEnvApiKey(provider));
149
+ const rows = inventory.filter(row => this.#mode === "login" || row.credentialKind === "oauth");
150
+ this.#accountEntries = rows.map(row => ({
151
+ kind: "account" as const,
152
+ row,
153
+ target: targets.get(row.id),
154
+ selectable:
155
+ row.credentialKind === "oauth" &&
156
+ !apiKeyOverrideActive &&
157
+ (this.#mode === "login" ? !row.disabled : targets.has(row.id)),
158
+ }));
159
+ if (this.#mode === "login") {
160
+ this.#accountEntries.push(
161
+ { kind: "auto", selectable: true },
162
+ { kind: "add", selectable: this.#onAddAccount !== undefined },
163
+ );
164
+ } else if (this.#accountEntries.some(entry => entry.kind === "account" && entry.selectable)) {
165
+ this.#accountEntries.push({ kind: "all", selectable: this.#onAccountRemove !== undefined });
166
+ }
167
+ }
168
+
94
169
  #startValidation(): void {
95
- if (!this.#validateAuthCallback) return;
170
+ if (this.#accountProviderId || !this.#validateAuthCallback) return;
96
171
  const generation = this.#validationGeneration + 1;
97
172
  this.#validationGeneration = generation;
98
173
 
@@ -122,17 +197,12 @@ export class OAuthSelectorComponent extends Container {
122
197
  } catch {
123
198
  isValid = false;
124
199
  }
125
-
126
200
  if (generation !== this.#validationGeneration) return;
127
201
  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
202
  if (authGeneration === this.#authStorage.getGeneration()) {
131
203
  recordProviderAuthHealth(this.#authStorage, providerId, isValid ? "valid" : "invalid");
132
204
  }
133
- if (![...this.#authState.values()].includes("checking")) {
134
- this.#stopSpinner();
135
- }
205
+ if (![...this.#authState.values()].includes("checking")) this.#stopSpinner();
136
206
  this.#updateList();
137
207
  this.#requestRenderCallback?.();
138
208
  }
@@ -141,9 +211,7 @@ export class OAuthSelectorComponent extends Container {
141
211
  if (this.#spinnerInterval) return;
142
212
  this.#spinnerInterval = setInterval(() => {
143
213
  const frameCount = theme.spinnerFrames.length;
144
- if (frameCount > 0) {
145
- this.#spinnerFrame = (this.#spinnerFrame + 1) % frameCount;
146
- }
214
+ if (frameCount > 0) this.#spinnerFrame = (this.#spinnerFrame + 1) % frameCount;
147
215
  this.#updateList();
148
216
  this.#requestRenderCallback?.();
149
217
  }, 80);
@@ -167,15 +235,70 @@ export class OAuthSelectorComponent extends Container {
167
235
  const spinner = frameCount > 0 ? theme.spinnerFrames[this.#spinnerFrame % frameCount] : theme.status.pending;
168
236
  return theme.fg("warning", ` ${spinner} checking`);
169
237
  }
170
- if (state === "invalid") {
171
- return theme.fg("error", ` ${theme.status.error} invalid`);
238
+ if (state === "invalid") return theme.fg("error", ` ${theme.status.error} invalid`);
239
+ if (state === "valid") return theme.fg("success", ` ${theme.status.success} logged in`);
240
+ return this.#authStorage.hasAuth(providerId) ? theme.fg("success", ` ${theme.status.success} logged in`) : "";
241
+ }
242
+
243
+ #accountLabel(entry: AccountEntry): string {
244
+ switch (entry.kind) {
245
+ case "auto":
246
+ return "AUTO (ranked)";
247
+ case "add":
248
+ return "Add new account";
249
+ case "all":
250
+ return "Remove all accounts";
251
+ case "account": {
252
+ const identity =
253
+ entry.row.credentialKind === "oauth"
254
+ ? safeLabel(entry.row.identityLabel, `OAuth account · row ${entry.row.id}`)
255
+ : `API key · row ${entry.row.id}`;
256
+ const status = entry.row.disabled
257
+ ? `disabled${entry.row.disabledCause ? `: ${safeLabel(entry.row.disabledCause, "disabled")}` : ""}`
258
+ : "active";
259
+ return `${identity} (${status})`;
260
+ }
172
261
  }
173
- if (state === "valid") {
174
- return theme.fg("success", ` ${theme.status.success} logged in`);
262
+ }
263
+
264
+ #clearPendingAccountRemoval(): boolean {
265
+ if (this.#pendingAccountRemovalTargets === undefined) return false;
266
+ this.#pendingAccountRemovalTargets = undefined;
267
+ this.#statusMessage = undefined;
268
+ return true;
269
+ }
270
+
271
+ #getAccountRemovalTargets(): CredentialRemovalTarget[] {
272
+ return this.#accountEntries
273
+ .filter(
274
+ (entry): entry is Extract<AccountEntry, { kind: "account" }> =>
275
+ entry.kind === "account" && entry.selectable && entry.target !== undefined,
276
+ )
277
+ .map(entry => entry.target as CredentialRemovalTarget);
278
+ }
279
+
280
+ #confirmOrArmAccountRemoval(targets: readonly CredentialRemovalTarget[], prompt: string): void {
281
+ if (this.#pendingAccountRemovalTargets !== undefined) {
282
+ const pending = this.#pendingAccountRemovalTargets;
283
+ this.#pendingAccountRemovalTargets = undefined;
284
+ this.#statusMessage = undefined;
285
+ void this.#onAccountRemove?.(pending);
286
+ return;
175
287
  }
176
- return this.#authStorage.hasAuth(providerId) ? theme.fg("success", ` ${theme.status.success} logged in`) : "";
288
+ if (targets.length === 0) {
289
+ this.#statusMessage = "No accounts available to remove.";
290
+ } else {
291
+ this.#pendingAccountRemovalTargets = targets;
292
+ this.#statusMessage = `${prompt} Enter to confirm, Esc to cancel`;
293
+ }
294
+ this.#updateList();
177
295
  }
178
296
  #updateList(): void {
297
+ if (this.#accountProviderId) {
298
+ this.#updateAccountList();
299
+ return;
300
+ }
301
+
179
302
  const selectedProviderId = this.#filteredProviders[this.#selectedIndex]?.id;
180
303
  const rankedProviders = this.#allProviders.map(provider => ({
181
304
  provider,
@@ -185,8 +308,6 @@ export class OAuthSelectorComponent extends Container {
185
308
  }));
186
309
  rankedProviders.sort(compareRankedProviders);
187
310
  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
311
  this.#filteredProviders = fuzzyFilter(
191
312
  this.#sortedProviders,
192
313
  this.#searchInput.getValue(),
@@ -208,33 +329,25 @@ export class OAuthSelectorComponent extends Container {
208
329
  ? 0
209
330
  : Math.max(0, Math.min(this.#selectedIndex - Math.floor(maxVisible / 2), total - maxVisible));
210
331
  const endIndex = Math.min(startIndex + maxVisible, total);
211
-
212
332
  for (let i = startIndex; i < endIndex; i++) {
213
333
  const provider = this.#filteredProviders[i];
214
334
  if (!provider) continue;
215
335
  const isSelected = i === this.#selectedIndex;
216
336
  const isAvailable = provider.available;
217
337
  const statusIndicator = this.#getStatusIndicator(provider.id);
218
-
219
- let line = "";
220
- if (isSelected) {
221
- const prefix = theme.fg("accent", `${theme.nav.cursor} `);
222
- const text = isAvailable ? theme.fg("accent", provider.name) : theme.fg("dim", provider.name);
223
- line = prefix + text + statusIndicator;
224
- } else {
225
- const text = isAvailable ? ` ${provider.name}` : theme.fg("dim", ` ${provider.name}`);
226
- line = text + statusIndicator;
227
- }
228
- this.#listContainer.addChild(new TruncatedText(line, 0, 0));
338
+ const prefix = isSelected ? theme.fg("accent", `${theme.nav.cursor} `) : " ";
339
+ const text = isAvailable
340
+ ? isSelected
341
+ ? theme.fg("accent", provider.name)
342
+ : provider.name
343
+ : theme.fg("dim", provider.name);
344
+ this.#listContainer.addChild(new TruncatedText(prefix + text + statusIndicator, 0, 0));
229
345
  }
230
-
231
- // Scroll indicator when list is windowed
232
346
  if (startIndex > 0 || endIndex < total) {
233
- const scrollInfo = theme.fg("muted", ` (${this.#selectedIndex + 1}/${total})`);
234
- this.#listContainer.addChild(new TruncatedText(scrollInfo, 0, 0));
347
+ this.#listContainer.addChild(
348
+ new TruncatedText(theme.fg("muted", ` (${this.#selectedIndex + 1}/${total})`), 0, 0),
349
+ );
235
350
  }
236
-
237
- // Show "no providers" if empty
238
351
  if (total === 0) {
239
352
  const message = this.#searchInput.getValue().trim()
240
353
  ? "No providers match the filter"
@@ -245,7 +358,13 @@ export class OAuthSelectorComponent extends Container {
245
358
  }
246
359
  if (this.#statusMessage) {
247
360
  this.#listContainer.addChild(new Spacer(1));
248
- this.#listContainer.addChild(new TruncatedText(theme.fg("warning", ` ${this.#statusMessage}`), 0, 0));
361
+ this.#listContainer.addChild(
362
+ new TruncatedText(
363
+ theme.fg("warning", ` ${safeLabel(this.#statusMessage, "Unable to select provider")}`),
364
+ 0,
365
+ 0,
366
+ ),
367
+ );
249
368
  }
250
369
  if (this.#mode === "login" && this.#externalCredentialCandidates.length > 0) {
251
370
  this.#listContainer.addChild(new Spacer(1));
@@ -254,7 +373,7 @@ export class OAuthSelectorComponent extends Container {
254
373
  new TruncatedText(
255
374
  theme.fg(
256
375
  "success",
257
- ` ${theme.status.success} Imported ${credential.provider} from ${credential.source}`,
376
+ ` ${theme.status.success} Imported ${safeLabel(credential.provider, "provider")} from ${safeLabel(credential.source, "external source")}`,
258
377
  ),
259
378
  0,
260
379
  0,
@@ -263,7 +382,88 @@ export class OAuthSelectorComponent extends Container {
263
382
  }
264
383
  }
265
384
  }
266
- #selectCurrentProvider(): void {
385
+
386
+ #updateAccountList(): void {
387
+ const query = this.#searchInput.getValue().trim().toLowerCase();
388
+ this.#filteredAccountEntries = this.#accountEntries.filter(entry =>
389
+ this.#accountLabel(entry).toLowerCase().includes(query),
390
+ );
391
+ if (this.#selectedIndex >= this.#filteredAccountEntries.length) {
392
+ this.#selectedIndex = Math.max(0, this.#filteredAccountEntries.length - 1);
393
+ }
394
+ this.#listContainer.clear();
395
+ const total = this.#filteredAccountEntries.length;
396
+ const maxVisible = OAUTH_SELECTOR_MAX_VISIBLE;
397
+ const startIndex =
398
+ total <= maxVisible
399
+ ? 0
400
+ : Math.max(0, Math.min(this.#selectedIndex - Math.floor(maxVisible / 2), total - maxVisible));
401
+ const endIndex = Math.min(startIndex + maxVisible, total);
402
+ for (let i = startIndex; i < endIndex; i++) {
403
+ const entry = this.#filteredAccountEntries[i];
404
+ if (!entry) continue;
405
+ const selected = i === this.#selectedIndex;
406
+ const prefix = selected ? theme.fg("accent", `${theme.nav.cursor} `) : " ";
407
+ const label = this.#accountLabel(entry);
408
+ const disabled = !entry.selectable;
409
+ const text = disabled ? theme.fg("dim", label) : selected ? theme.fg("accent", label) : label;
410
+ this.#listContainer.addChild(new TruncatedText(prefix + text, 0, 0));
411
+ }
412
+ if (startIndex > 0 || endIndex < total) {
413
+ this.#listContainer.addChild(
414
+ new TruncatedText(theme.fg("muted", ` (${this.#selectedIndex + 1}/${total})`), 0, 0),
415
+ );
416
+ }
417
+ if (total === 0) {
418
+ this.#listContainer.addChild(new TruncatedText(theme.fg("muted", " No accounts available"), 0, 0));
419
+ }
420
+ if (this.#statusMessage) {
421
+ this.#listContainer.addChild(new Spacer(1));
422
+ this.#listContainer.addChild(
423
+ new TruncatedText(
424
+ theme.fg("warning", ` ${safeLabel(this.#statusMessage, "Unable to select account")}`),
425
+ 0,
426
+ 0,
427
+ ),
428
+ );
429
+ }
430
+ }
431
+
432
+ #selectCurrent(): void {
433
+ if (this.#accountProviderId) {
434
+ const selected = this.#filteredAccountEntries[this.#selectedIndex];
435
+ if (!selected) return;
436
+ if (!selected.selectable) {
437
+ this.#statusMessage = "This account is not selectable.";
438
+ this.#updateList();
439
+ return;
440
+ }
441
+ this.#statusMessage = undefined;
442
+ this.stopValidation();
443
+ if (selected.kind === "account") {
444
+ if (selected.row.credentialKind !== "oauth") return;
445
+ if (this.#mode === "login") {
446
+ void this.#onAccountSelect?.({ kind: "id", value: String(selected.row.id) });
447
+ } else if (selected.target) {
448
+ this.#confirmOrArmAccountRemoval([selected.target], "Remove this account?");
449
+ }
450
+ } else if (selected.kind === "auto") {
451
+ void this.#onAutoSelect?.();
452
+ } else if (selected.kind === "add") {
453
+ void this.#onAddAccount?.();
454
+ } else if (selected.kind === "all") {
455
+ if (this.#pendingAccountRemovalTargets !== undefined) {
456
+ const targets = this.#pendingAccountRemovalTargets;
457
+ this.#pendingAccountRemovalTargets = undefined;
458
+ void this.#onAccountRemove?.(targets);
459
+ } else {
460
+ const targets = this.#getAccountRemovalTargets();
461
+ this.#confirmOrArmAccountRemoval(targets, `Remove all ${targets.length} accounts?`);
462
+ }
463
+ }
464
+ return;
465
+ }
466
+
267
467
  const selectedProvider = this.#filteredProviders[this.#selectedIndex];
268
468
  if (selectedProvider?.available) {
269
469
  this.#statusMessage = undefined;
@@ -274,64 +474,55 @@ export class OAuthSelectorComponent extends Container {
274
474
  this.#updateList();
275
475
  }
276
476
  }
477
+
277
478
  handleInput(keyData: string): void {
278
- // Up arrow
479
+ const isConfirm = matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n";
480
+ const isCancel = matchesSelectCancel(keyData);
481
+ const pendingConfirmationCleared = !isConfirm && !isCancel ? this.#clearPendingAccountRemoval() : false;
482
+ const itemCount = this.#accountProviderId ? this.#filteredAccountEntries.length : this.#filteredProviders.length;
279
483
  if (matchesKey(keyData, "up")) {
280
- if (this.#filteredProviders.length > 0) {
281
- this.#selectedIndex =
282
- this.#selectedIndex === 0 ? this.#filteredProviders.length - 1 : this.#selectedIndex - 1;
283
- }
484
+ this.#clearPendingAccountRemoval();
485
+ if (itemCount > 0) this.#selectedIndex = this.#selectedIndex === 0 ? itemCount - 1 : this.#selectedIndex - 1;
284
486
  this.#statusMessage = undefined;
285
487
  this.#updateList();
286
488
  return;
287
489
  }
288
- // Down arrow
289
490
  if (matchesKey(keyData, "down")) {
290
- if (this.#filteredProviders.length > 0) {
291
- this.#selectedIndex =
292
- this.#selectedIndex === this.#filteredProviders.length - 1 ? 0 : this.#selectedIndex + 1;
293
- }
491
+ this.#clearPendingAccountRemoval();
492
+ if (itemCount > 0) this.#selectedIndex = this.#selectedIndex === itemCount - 1 ? 0 : this.#selectedIndex + 1;
294
493
  this.#statusMessage = undefined;
295
494
  this.#updateList();
296
495
  return;
297
496
  }
298
- // Page up - jump up by one visible page
299
497
  if (matchesKey(keyData, "pageUp")) {
300
- if (this.#filteredProviders.length > 0) {
301
- this.#selectedIndex = Math.max(0, this.#selectedIndex - OAUTH_SELECTOR_MAX_VISIBLE);
302
- }
498
+ this.#clearPendingAccountRemoval();
499
+ if (itemCount > 0) this.#selectedIndex = Math.max(0, this.#selectedIndex - OAUTH_SELECTOR_MAX_VISIBLE);
303
500
  this.#statusMessage = undefined;
304
501
  this.#updateList();
305
502
  return;
306
503
  }
307
- // Page down - jump down by one visible page
308
504
  if (matchesKey(keyData, "pageDown")) {
309
- if (this.#filteredProviders.length > 0) {
310
- this.#selectedIndex = Math.min(
311
- this.#filteredProviders.length - 1,
312
- this.#selectedIndex + OAUTH_SELECTOR_MAX_VISIBLE,
313
- );
314
- }
505
+ this.#clearPendingAccountRemoval();
506
+ if (itemCount > 0)
507
+ this.#selectedIndex = Math.min(itemCount - 1, this.#selectedIndex + OAUTH_SELECTOR_MAX_VISIBLE);
315
508
  this.#statusMessage = undefined;
316
509
  this.#updateList();
317
510
  return;
318
511
  }
319
- // Enter
320
- if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
321
- this.#selectCurrentProvider();
512
+ if (isConfirm) {
513
+ this.#selectCurrent();
322
514
  return;
323
515
  }
324
- // Escape or Ctrl+C
325
- if (matchesSelectCancel(keyData)) {
516
+ if (isCancel) {
517
+ const pending = this.#clearPendingAccountRemoval();
326
518
  this.stopValidation();
519
+ if (pending) this.#updateList();
327
520
  this.#onCancelCallback();
328
521
  return;
329
522
  }
330
- // Everything else edits the filter. A changed query invalidates the current
331
- // position, so selection restarts at the best match.
332
523
  const previousQuery = this.#searchInput.getValue();
333
524
  this.#searchInput.handleInput(keyData);
334
- if (this.#searchInput.getValue() !== previousQuery) {
525
+ if (pendingConfirmationCleared || this.#searchInput.getValue() !== previousQuery) {
335
526
  this.#selectedIndex = 0;
336
527
  this.#statusMessage = undefined;
337
528
  this.#updateList();
@@ -6,8 +6,9 @@ import {
6
6
  shouldProbeSixelCapability,
7
7
  TERMINAL,
8
8
  } from "@gajae-code/tui";
9
+ import type { PetTransportAvailability } from "./iterm-pet-transport";
9
10
 
10
- export type PetPixelProtocol = "sixel" | "kitty";
11
+ export type PetPixelProtocol = "sixel" | "kitty" | "iterm";
11
12
 
12
13
  export const PET_UNAVAILABLE_DESCRIPTION = "Unavailable: requires compatible Kitty or Sixel overlay rendering";
13
14
  export const PET_SAVED_UNAVAILABLE_DESCRIPTION =
@@ -21,9 +22,34 @@ export function getPetUnavailableWarning(env: NodeJS.ProcessEnv = Bun.env): stri
21
22
  return isUnderTerminalMultiplexer(env) ? PET_MULTIPLEXER_UNAVAILABLE_WARNING : PET_UNAVAILABLE_WARNING;
22
23
  }
23
24
 
25
+ let latestItermAvailability: PetTransportAvailability | undefined;
26
+ let verifiedItermAvailability: PetTransportAvailability | undefined;
27
+ const verifiedItermListeners = new Set<(availability: PetTransportAvailability | undefined) => void>();
28
+ export function subscribeVerifiedItermPetAvailability(
29
+ callback: (availability: PetTransportAvailability | undefined) => void,
30
+ ): () => void {
31
+ verifiedItermListeners.add(callback);
32
+ return () => verifiedItermListeners.delete(callback);
33
+ }
34
+ export function setVerifiedItermPetAvailability(availability: PetTransportAvailability | undefined): void {
35
+ latestItermAvailability = availability;
36
+ verifiedItermAvailability = availability?.available ? availability : undefined;
37
+ for (const listener of verifiedItermListeners) listener(verifiedItermAvailability);
38
+ }
39
+ export function getItermPetAvailability(): PetTransportAvailability | undefined {
40
+ return latestItermAvailability;
41
+ }
42
+ export function getVerifiedItermPetAvailability(): PetTransportAvailability | undefined {
43
+ return verifiedItermAvailability;
44
+ }
45
+ export function getItermPetUnavailableReason(): string | undefined {
46
+ return latestItermAvailability?.available ? undefined : latestItermAvailability?.reason;
47
+ }
48
+
24
49
  export function getPetPixelProtocol(): PetPixelProtocol | null {
25
- if (TERMINAL.imageProtocol === ImageProtocol.Kitty) return "kitty";
50
+ if (TERMINAL.imageProtocol === ImageProtocol.Kitty && !isUnderTerminalMultiplexer()) return "kitty";
26
51
  if (TERMINAL.imageProtocol === ImageProtocol.Sixel) return "sixel";
52
+ if (verifiedItermAvailability?.available) return "iterm";
27
53
  return null;
28
54
  }
29
55
 
@@ -41,31 +67,13 @@ export function createPetSelectItems(
41
67
  const current = option.value === currentValue;
42
68
  const savedUnavailable = disabled && current;
43
69
  let description = `${option.description ?? ""}${current ? " (current)" : ""}`;
44
- if (disabled) {
45
- description = savedUnavailable ? PET_SAVED_UNAVAILABLE_DESCRIPTION : PET_UNAVAILABLE_DESCRIPTION;
46
- }
47
- return {
48
- ...option,
49
- label: savedUnavailable ? `${option.label} (saved)` : option.label,
50
- description,
51
- disabled,
52
- };
70
+ if (disabled) description = savedUnavailable ? PET_SAVED_UNAVAILABLE_DESCRIPTION : PET_UNAVAILABLE_DESCRIPTION;
71
+ return { ...option, label: savedUnavailable ? `${option.label} (saved)` : option.label, description, disabled };
53
72
  });
54
73
  }
55
74
 
56
- /**
57
- * Grace period before declaring the terminal pet-incapable at startup. The
58
- * asynchronous Sixel capability probe starts inside `TUI.start()` and answers
59
- * within its own 250 ms deadline; this margin covers probe scheduling so a
60
- * supported terminal is never told it is incompatible while the probe is
61
- * still in flight.
62
- */
63
75
  export const PET_CAPABILITY_SETTLE_MS = 1_000;
64
76
 
65
- /**
66
- * Whether the asynchronous startup Sixel capability probe may still enable
67
- * graphics for this session, meaning current unavailability is not final.
68
- */
69
77
  export function isPetCapabilityProbePending(
70
78
  env: NodeJS.ProcessEnv = Bun.env,
71
79
  platform: NodeJS.Platform = process.platform,
@@ -75,15 +83,6 @@ export function isPetCapabilityProbePending(
75
83
  return shouldProbeSixelCapability(env, platform);
76
84
  }
77
85
 
78
- /**
79
- * Deliver the pet-unavailable startup warning only once the capability
80
- * question is settled. With no probe pending, unavailability is final and
81
- * `onUnavailable` fires immediately. While a probe may still enable
82
- * graphics, the warning is deferred: a protocol-change event cancels it (the
83
- * saved pet re-applies through the existing subscription), and only the
84
- * settle deadline passing with the terminal still unavailable emits it.
85
- * Returns a disposer that cancels the pending decision.
86
- */
87
86
  export function warnWhenPetCapabilitySettled(options: {
88
87
  probePending: boolean;
89
88
  isAvailable?: () => boolean;
@@ -96,16 +95,21 @@ export function warnWhenPetCapabilitySettled(options: {
96
95
  }
97
96
  const isAvailable = options.isAvailable ?? isPetAvailable;
98
97
  let settled = false;
98
+ let unsubscribeIterm = () => {};
99
99
  const finish = () => {
100
100
  if (settled) return;
101
101
  settled = true;
102
102
  clearTimeout(timer);
103
103
  unsubscribe();
104
+ unsubscribeIterm();
104
105
  };
105
106
  const unsubscribe = onImageProtocolChanged(protocol => {
106
107
  if (!protocol) return;
107
108
  finish();
108
109
  });
110
+ unsubscribeIterm = subscribeVerifiedItermPetAvailability(availability => {
111
+ if (availability?.available) finish();
112
+ });
109
113
  const timer = setTimeout(() => {
110
114
  finish();
111
115
  if (!isAvailable()) options.onUnavailable();