@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,10 +1,9 @@
1
1
  import { getAgentDir } from "@gajae-code/utils";
2
2
  import { CliParseError } from "@gajae-code/utils/cli";
3
3
  import { readSdkBrokerDiscovery, SdkClient, SdkClientError } from "../client";
4
+ import { SessionListTraversalError, sessionListPageFromResponse, traverseSessionList } from "../session-list";
4
5
  import { DEFAULT_PENDING_CEILING_BYTES, MIN_PENDING_CEILING_BYTES, startSocketServe, startStdioServe } from "./index";
5
6
 
6
- const MAX_SESSION_LIST_PAGES = 10_000;
7
-
8
7
  type ServeMode = { kind: "stdio" } | { kind: "socket"; socketPath: string };
9
8
 
10
9
  interface ServeArguments {
@@ -85,32 +84,29 @@ function brokerResult(value: unknown): Record<string, unknown> {
85
84
  return isRecord(value) && isRecord(value.result) ? value.result : {};
86
85
  }
87
86
 
88
- function brokerSessionRows(value: Record<string, unknown>): BrokerSessionRow[] {
89
- if (!Array.isArray(value.sessions)) return [];
90
- return value.sessions.flatMap(item => {
87
+ function brokerSessionRows(sessions: readonly unknown[]): BrokerSessionRow[] {
88
+ return sessions.flatMap(item => {
91
89
  if (!isRecord(item) || typeof item.sessionId !== "string" || !item.sessionId) return [];
92
90
  return [{ sessionId: item.sessionId, live: item.live === true, ambiguous: item.ambiguous === true }];
93
91
  });
94
92
  }
95
93
 
96
- /**
97
- * Exhausts broker `session.list` cursor pagination (default page limit 100) to
98
- * one full snapshot; exported for tests.
99
- */
94
+ /** Exhausts strict broker `session.list` pages into one full session snapshot. */
100
95
  export async function listBrokerSessions(broker: SdkClient): Promise<BrokerSessionRow[]> {
101
- const rows: BrokerSessionRow[] = [];
102
- let cursor: string | undefined;
103
- for (let pageCount = 0; pageCount < MAX_SESSION_LIST_PAGES; pageCount++) {
104
- const listed = brokerResult(await broker.global("session.list", cursor === undefined ? {} : { cursor }));
105
- rows.push(...brokerSessionRows(listed));
106
- const nextCursor =
107
- typeof listed.continuationCursor === "string" && listed.continuationCursor.length > 0
108
- ? listed.continuationCursor
109
- : undefined;
110
- if (!nextCursor) return rows;
111
- cursor = nextCursor;
96
+ try {
97
+ const pages = await traverseSessionList(
98
+ {},
99
+ async input => await broker.global("session.list", input),
100
+ response => {
101
+ brokerResult(response);
102
+ return sessionListPageFromResponse(response);
103
+ },
104
+ );
105
+ return pages.flatMap(page => brokerSessionRows(page.sessions));
106
+ } catch (error) {
107
+ if (error instanceof SessionListTraversalError) throw new SdkClientError("protocol_error", error.message);
108
+ throw error;
112
109
  }
113
- throw new SdkClientError("protocol_error", "session.list exceeded the page budget.");
114
110
  }
115
111
 
116
112
  /** Selects the session to serve through broker `session.list` truth (C10); exported for tests. */
@@ -156,19 +152,7 @@ export async function runSdkServe(argv: string[]): Promise<void> {
156
152
  const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
157
153
  const token = typeof endpoint.token === "string" ? endpoint.token : "";
158
154
  if (!url) throw new Error("unavailable: broker returned an invalid endpoint record");
159
- const options = {
160
- url,
161
- token,
162
- pendingCeilingBytes,
163
- validateDownstreamFrame: (source: string): boolean => {
164
- try {
165
- const frame = JSON.parse(source) as { type?: unknown; elevationRequestId?: unknown };
166
- return frame.type !== "control_request" || frame.elevationRequestId === undefined;
167
- } catch {
168
- return true;
169
- }
170
- },
171
- };
155
+ const options = { url, token, pendingCeilingBytes };
172
156
  const handle =
173
157
  parsed.mode.kind === "stdio"
174
158
  ? await startStdioServe(options)
@@ -0,0 +1,603 @@
1
+ import {
2
+ type AuthStorage,
3
+ type CachedCredentialHealth,
4
+ type CachedUsageReport,
5
+ type CredentialHealthResult,
6
+ type CredentialInventoryRecord,
7
+ getEnvApiKey,
8
+ listProvidersWithEnvKey,
9
+ type Provider,
10
+ type UsageLimit,
11
+ type UsageStatus,
12
+ type UsageUnit,
13
+ type UsageWindow,
14
+ } from "@gajae-code/ai/core";
15
+ import type { RawSettings, Settings, SettingsAtomicPatch } from "../config/settings";
16
+ import { parsePersistedCredentialSelector } from "./startup-auth-config";
17
+
18
+ /** A redacted usage observation attached to an account row. */
19
+ export interface AccountUsageCache extends CachedUsageReport {}
20
+
21
+ /** Safe account health state used by presentation surfaces. */
22
+ export interface AccountHealthCache extends CachedCredentialHealth {}
23
+
24
+ export type AccountInventorySource = "stored" | "env" | "config" | "runtime";
25
+
26
+ /** Fixed presentation classification for a persisted disabled credential. */
27
+ export type AccountInventoryDisabledCause = "auth_failure" | "user_removed" | "duplicate" | "replaced" | "unknown";
28
+
29
+ export interface AccountInventoryCapabilities {
30
+ canCheck: boolean;
31
+ canPin: boolean;
32
+ canRemove: boolean;
33
+ hasCachedUsage: boolean;
34
+ }
35
+
36
+ export interface AccountInventoryRouting {
37
+ /** True when this row is the session's last recorded stored credential. */
38
+ active: boolean;
39
+ /** True when this source is the effective source for the provider/session. */
40
+ selected: boolean;
41
+ marker: "active" | "selected" | "available";
42
+ }
43
+
44
+ /**
45
+ * Payload-free account row for renderers. This type deliberately has no
46
+ * AuthCredential, API-key bytes, access token, refresh token, or raw usage.
47
+ */
48
+ export interface AccountInventoryRow {
49
+ /** Stable, non-secret presentation id. */
50
+ id: string;
51
+ /** Numeric storage id when this is a persisted row. */
52
+ credentialId?: number;
53
+ provider: string;
54
+ credentialKind: "oauth" | "api_key";
55
+ source: AccountInventorySource;
56
+ sourceLabel: string;
57
+ identityLabel: string | null;
58
+ /** OAuth identity is intentionally limited to safe labels from inventory. */
59
+ oauthIdentity?: { label: string };
60
+ disabled: boolean;
61
+ disabledCause: AccountInventoryDisabledCause | null;
62
+ health: AccountHealthCache;
63
+ usage?: AccountUsageCache;
64
+ capabilities: AccountInventoryCapabilities;
65
+ routing: AccountInventoryRouting;
66
+ }
67
+
68
+ export interface AccountInventorySnapshot {
69
+ generatedAt: number;
70
+ generation: number;
71
+ rows: AccountInventoryRow[];
72
+ }
73
+
74
+ export interface AccountInventoryInput {
75
+ authStorage: AuthStorage;
76
+ modelRegistry?: {
77
+ getAvailable?: () => Array<{ provider: string }>;
78
+ getProviderBaseUrl?: (provider: string) => string | undefined;
79
+ };
80
+ sessionId?: string;
81
+ provider?: string;
82
+ nowMs?: number;
83
+ }
84
+
85
+ type SyntheticAccountSource = Exclude<AccountInventorySource, "stored">;
86
+
87
+ /** Source-scoped cache hooks supplied by AuthStorage. */
88
+ interface SourceHealthStorage {
89
+ peekCachedCredentialHealthForSource: (provider: string, source: SyntheticAccountSource) => CachedCredentialHealth;
90
+ recordCredentialHealthForSource: (
91
+ provider: string,
92
+ source: SyntheticAccountSource,
93
+ health: CachedCredentialHealth,
94
+ ) => void;
95
+ }
96
+
97
+ export interface AccountInventoryCheckResult {
98
+ rowId: string;
99
+ provider: string;
100
+ credentialId?: number;
101
+ ok: boolean | null;
102
+ reason?: string;
103
+ }
104
+
105
+ function asSafeLabel(value: unknown): string | null {
106
+ if (typeof value !== "string") return null;
107
+ const normalized = value
108
+ .replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, " ")
109
+ .replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, " ")
110
+ .replace(/bearer\s+[^\s,;]+/gi, "Bearer [redacted]")
111
+ .replace(/(api[_-]?key|token|secret|authorization)[=:]\s*[^\s,;]+/gi, "$1=[redacted]")
112
+ .replace(/https?:\/\/[^\s?#]+(?:\?[^\s#]*)?/gi, value => value.split("?")[0] ?? "[redacted URL]")
113
+ .replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
114
+ .replace(/[\u061c\u200e\u200f\u200b-\u200d\u2060\u202a-\u202e\u2066-\u2069\ufeff]/g, "")
115
+ .replace(/\s+/g, " ")
116
+ .trim();
117
+ return normalized.length > 0 ? normalized.slice(0, 160) : null;
118
+ }
119
+
120
+ function safeProvider(value: unknown): string {
121
+ return asSafeLabel(value) ?? "unknown-provider";
122
+ }
123
+
124
+ function optionalSafeLabel(value: unknown): string | undefined {
125
+ return asSafeLabel(value) ?? undefined;
126
+ }
127
+
128
+ function asRecord(value: unknown): Record<string, unknown> | undefined {
129
+ return value !== null && typeof value === "object" && !Array.isArray(value)
130
+ ? (value as Record<string, unknown>)
131
+ : undefined;
132
+ }
133
+
134
+ function finiteNumber(value: unknown): number | undefined {
135
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
136
+ }
137
+
138
+ function classifyDisabledCause(value: unknown, disabled: boolean): AccountInventoryDisabledCause | null {
139
+ if (!disabled) return null;
140
+ if (typeof value !== "string") return "unknown";
141
+ const cause = value.trim();
142
+ if (/^(?:deleted|logged out) by user(?:$|\b)/i.test(cause) || /^disabled via auth-broker$/i.test(cause)) {
143
+ return "user_removed";
144
+ }
145
+ if (/^deduplicated duplicate credential$/i.test(cause)) return "duplicate";
146
+ if (/^replaced by newer credential$/i.test(cause)) return "replaced";
147
+ if (
148
+ /^(?:oauth|auth-broker) refresh failed:/i.test(cause) ||
149
+ /invalid_grant|grant is invalid|invalid_token|revoked|unauthorized|expired.*refresh|refresh.*expired/i.test(
150
+ cause,
151
+ ) ||
152
+ (/\b(401|403)\b/.test(cause) && !/timeout|network|fetch failed|ECONNREFUSED/i.test(cause))
153
+ ) {
154
+ return "auth_failure";
155
+ }
156
+ return "unknown";
157
+ }
158
+ function sourceId(provider: string, source: AccountInventorySource, credentialId?: number): string {
159
+ const safe = safeProvider(provider);
160
+ return credentialId === undefined ? `${safe}:${source}` : `${safe}:stored:${credentialId}`;
161
+ }
162
+
163
+ function sourceLabel(source: AccountInventorySource): string {
164
+ switch (source) {
165
+ case "stored":
166
+ return "stored credential";
167
+ case "env":
168
+ return "environment API key";
169
+ case "config":
170
+ return "config API key";
171
+ case "runtime":
172
+ return "runtime API key";
173
+ }
174
+ }
175
+
176
+ function providerSet(input: AccountInventoryInput, inventory: CredentialInventoryRecord[]): Set<string> {
177
+ const providers = new Set(inventory.flatMap(row => (typeof row.provider === "string" ? [row.provider] : [])));
178
+ for (const provider of input.modelRegistry?.getAvailable?.() ?? []) {
179
+ if (typeof provider?.provider === "string") providers.add(provider.provider);
180
+ }
181
+ // This only asks whether a known env-backed provider is present. The key value
182
+ // never enters the snapshot or any renderer.
183
+ for (const provider of listProvidersWithEnvKey()) {
184
+ if (getEnvApiKey(provider)) providers.add(provider);
185
+ }
186
+ return providers;
187
+ }
188
+
189
+ function storedHealth(authStorage: AuthStorage, row: CredentialInventoryRecord): AccountHealthCache {
190
+ const cached = asRecord(authStorage.getCachedCredentialHealth(row.id));
191
+ if (row.disabled) return { status: "failed", reason: null };
192
+ const status: AccountHealthCache["status"] =
193
+ cached?.status === "ok" ||
194
+ cached?.status === "failed" ||
195
+ cached?.status === "unverifiable" ||
196
+ cached?.status === "unknown"
197
+ ? cached.status
198
+ : "unknown";
199
+ return {
200
+ status,
201
+ reason: asSafeLabel(cached?.reason),
202
+ ...(finiteNumber(cached?.checkedAt) !== undefined ? { checkedAt: finiteNumber(cached?.checkedAt) } : {}),
203
+ ...(finiteNumber(cached?.retainUntil) !== undefined ? { retainUntil: finiteNumber(cached?.retainUntil) } : {}),
204
+ };
205
+ }
206
+
207
+ function storedUsage(authStorage: AuthStorage, row: CredentialInventoryRecord): AccountUsageCache | undefined {
208
+ return authStorage.getCachedUsageReport(row.provider as Provider, row.id);
209
+ }
210
+
211
+ function safeUsageUnit(value: unknown): UsageUnit {
212
+ return value === "percent" ||
213
+ value === "tokens" ||
214
+ value === "requests" ||
215
+ value === "usd" ||
216
+ value === "minutes" ||
217
+ value === "bytes" ||
218
+ value === "unknown"
219
+ ? value
220
+ : "unknown";
221
+ }
222
+
223
+ function safeUsageStatus(value: unknown): UsageStatus | undefined {
224
+ return value === "ok" || value === "warning" || value === "exhausted" || value === "unknown" ? value : undefined;
225
+ }
226
+
227
+ function redactUsageWindow(value: unknown): UsageWindow | undefined {
228
+ const window = asRecord(value);
229
+ if (!window) return undefined;
230
+ return {
231
+ id: asSafeLabel(window.id) ?? "usage-window",
232
+ label: asSafeLabel(window.label) ?? "usage window",
233
+ ...(finiteNumber(window.durationMs) !== undefined ? { durationMs: finiteNumber(window.durationMs) } : {}),
234
+ ...(finiteNumber(window.resetsAt) !== undefined ? { resetsAt: finiteNumber(window.resetsAt) } : {}),
235
+ };
236
+ }
237
+
238
+ function redactUsageLimit(value: unknown, reportProvider: string): UsageLimit {
239
+ const limit = asRecord(value);
240
+ const scope = asRecord(limit?.scope);
241
+ const amount = asRecord(limit?.amount);
242
+ const used = finiteNumber(amount?.used);
243
+ const amountLimit = finiteNumber(amount?.limit);
244
+ const remaining = finiteNumber(amount?.remaining);
245
+ const usedFraction = finiteNumber(amount?.usedFraction);
246
+ const remainingFraction = finiteNumber(amount?.remainingFraction);
247
+ const notes = Array.isArray(limit?.notes)
248
+ ? limit.notes.map(note => asSafeLabel(note)).filter((note): note is string => note !== null)
249
+ : undefined;
250
+ const status = safeUsageStatus(limit?.status);
251
+ const window = redactUsageWindow(limit?.window);
252
+ return {
253
+ id: asSafeLabel(limit?.id) ?? "usage-limit",
254
+ label: asSafeLabel(limit?.label) ?? "usage limit",
255
+ scope: {
256
+ provider: safeProvider(scope?.provider ?? reportProvider),
257
+ ...(optionalSafeLabel(scope?.accountId) ? { accountId: optionalSafeLabel(scope?.accountId) } : {}),
258
+ ...(optionalSafeLabel(scope?.projectId) ? { projectId: optionalSafeLabel(scope?.projectId) } : {}),
259
+ ...(optionalSafeLabel(scope?.orgId) ? { orgId: optionalSafeLabel(scope?.orgId) } : {}),
260
+ ...(optionalSafeLabel(scope?.modelId) ? { modelId: optionalSafeLabel(scope?.modelId) } : {}),
261
+ ...(optionalSafeLabel(scope?.tier) ? { tier: optionalSafeLabel(scope?.tier) } : {}),
262
+ ...(optionalSafeLabel(scope?.windowId) ? { windowId: optionalSafeLabel(scope?.windowId) } : {}),
263
+ ...(typeof scope?.shared === "boolean" ? { shared: scope.shared } : {}),
264
+ },
265
+ ...(window ? { window } : {}),
266
+ amount: {
267
+ ...(used !== undefined ? { used } : {}),
268
+ ...(amountLimit !== undefined ? { limit: amountLimit } : {}),
269
+ ...(remaining !== undefined ? { remaining } : {}),
270
+ ...(usedFraction !== undefined ? { usedFraction } : {}),
271
+ ...(remainingFraction !== undefined ? { remainingFraction } : {}),
272
+ unit: safeUsageUnit(amount?.unit),
273
+ },
274
+ ...(status !== undefined ? { status } : {}),
275
+ ...(notes !== undefined ? { notes } : {}),
276
+ };
277
+ }
278
+
279
+ function redactUsageReport(report: CachedUsageReport["report"]): CachedUsageReport["report"] {
280
+ const value = asRecord(report);
281
+ const provider = safeProvider(value?.provider);
282
+ const metadata = asRecord(value?.metadata);
283
+ const safeMetadata = metadata
284
+ ? Object.fromEntries(
285
+ ["email", "accountId", "account", "user", "projectId", "orgId"].flatMap(key => {
286
+ const safe = asSafeLabel(metadata[key]);
287
+ return safe ? [[key, safe]] : [];
288
+ }),
289
+ )
290
+ : undefined;
291
+ const limits = Array.isArray(value?.limits) ? value.limits.map(limit => redactUsageLimit(limit, provider)) : [];
292
+ return {
293
+ provider,
294
+ fetchedAt: finiteNumber(value?.fetchedAt) ?? 0,
295
+ limits,
296
+ ...(safeMetadata && Object.keys(safeMetadata).length > 0 ? { metadata: safeMetadata } : {}),
297
+ };
298
+ }
299
+
300
+ function redactUsageCache(usage: CachedUsageReport | undefined): AccountUsageCache | undefined {
301
+ if (!usage || !asRecord(usage.report)) return undefined;
302
+ return {
303
+ report: redactUsageReport(usage.report),
304
+ fetchedAt: finiteNumber(usage.fetchedAt) ?? 0,
305
+ freshUntil: finiteNumber(usage.freshUntil) ?? 0,
306
+ retainUntil: finiteNumber(usage.retainUntil) ?? 0,
307
+ freshness: usage.freshness === "fresh" ? "fresh" : "stale-last-good",
308
+ };
309
+ }
310
+
311
+ function canPinStoredOAuth(authStorage: AuthStorage, provider: string): boolean {
312
+ if (authStorage.hasRuntimeApiKey(provider) || authStorage.hasConfigApiKey(provider)) return false;
313
+ return !getEnvApiKey(provider);
314
+ }
315
+
316
+ function sourceHealth(authStorage: AuthStorage, provider: string, source: SyntheticAccountSource): AccountHealthCache {
317
+ const getter = (authStorage as AuthStorage & SourceHealthStorage).peekCachedCredentialHealthForSource;
318
+ const cached = getter.call(authStorage, provider, source);
319
+ return {
320
+ status:
321
+ cached.status === "ok" ||
322
+ cached.status === "failed" ||
323
+ cached.status === "unverifiable" ||
324
+ cached.status === "unknown"
325
+ ? cached.status
326
+ : "unknown",
327
+ reason: asSafeLabel(cached.reason),
328
+ ...(finiteNumber(cached.checkedAt) !== undefined ? { checkedAt: finiteNumber(cached.checkedAt) } : {}),
329
+ ...(finiteNumber(cached.retainUntil) !== undefined ? { retainUntil: finiteNumber(cached.retainUntil) } : {}),
330
+ };
331
+ }
332
+
333
+ function recordSourceHealth(
334
+ authStorage: AuthStorage,
335
+ provider: string,
336
+ source: SyntheticAccountSource,
337
+ ok: boolean | null,
338
+ reason: unknown,
339
+ ): void {
340
+ const recorder = (authStorage as AuthStorage & SourceHealthStorage).recordCredentialHealthForSource;
341
+ const now = Date.now();
342
+ recorder.call(authStorage, provider, source, {
343
+ status: ok === true ? "ok" : ok === false ? "failed" : "unverifiable",
344
+ reason: asSafeLabel(reason),
345
+ checkedAt: now,
346
+ retainUntil: now + 24 * 60 * 60_000,
347
+ });
348
+ }
349
+
350
+ function addStoredRows(
351
+ rows: AccountInventoryRow[],
352
+ authStorage: AuthStorage,
353
+ inventory: CredentialInventoryRecord[],
354
+ sessionId: string | undefined,
355
+ ): void {
356
+ const removalTargetIds = new Set(
357
+ (typeof authStorage.listCredentialRemovalTargets === "function"
358
+ ? authStorage.listCredentialRemovalTargets()
359
+ : []
360
+ ).map(target => target.id),
361
+ );
362
+ for (const record of inventory) {
363
+ const identityLabel = asSafeLabel(record.identityLabel);
364
+ const safeUsage = redactUsageCache(storedUsage(authStorage, record));
365
+ const active =
366
+ typeof record.provider === "string" &&
367
+ authStorage.getSessionCredentialRowId(record.provider, sessionId) === record.id;
368
+ const canPin =
369
+ record.credentialKind === "oauth" && !record.disabled && canPinStoredOAuth(authStorage, record.provider);
370
+ const canRemove = record.credentialKind === "oauth" && removalTargetIds.has(record.id);
371
+ rows.push({
372
+ id: sourceId(record.provider, "stored", record.id),
373
+ credentialId: record.id,
374
+ provider: safeProvider(record.provider),
375
+ credentialKind: record.credentialKind,
376
+ source: "stored",
377
+ sourceLabel: sourceLabel("stored"),
378
+ identityLabel,
379
+ ...(record.credentialKind === "oauth" && identityLabel ? { oauthIdentity: { label: identityLabel } } : {}),
380
+ disabled: record.disabled,
381
+ disabledCause: classifyDisabledCause(record.disabledCause, record.disabled),
382
+ health: storedHealth(authStorage, record),
383
+ ...(safeUsage ? { usage: safeUsage } : {}),
384
+ capabilities: {
385
+ canCheck: true,
386
+ canPin,
387
+ canRemove,
388
+ hasCachedUsage: safeUsage !== undefined,
389
+ },
390
+ routing: {
391
+ active,
392
+ selected: active,
393
+ marker: active ? "active" : "available",
394
+ },
395
+ });
396
+ }
397
+ }
398
+
399
+ function addSyntheticRows(
400
+ rows: AccountInventoryRow[],
401
+ authStorage: AuthStorage,
402
+ providers: Set<string>,
403
+ sessionId: string | undefined,
404
+ ): void {
405
+ for (const provider of [...providers].sort((a, b) => a.localeCompare(b))) {
406
+ const runtime = authStorage.hasRuntimeApiKey(provider);
407
+ const config = authStorage.hasConfigApiKey(provider);
408
+ const env = Boolean(getEnvApiKey(provider));
409
+ const effectiveType = authStorage.getEffectiveCredentialType(provider, sessionId);
410
+
411
+ const add = (source: AccountInventorySource): void => {
412
+ const selected =
413
+ source === "runtime"
414
+ ? runtime && effectiveType === "api_key"
415
+ : source === "config"
416
+ ? config && effectiveType === "api_key" && !runtime
417
+ : env && effectiveType === "api_key" && !runtime && !config;
418
+ const id = sourceId(provider, source);
419
+ rows.push({
420
+ id,
421
+ provider: safeProvider(provider),
422
+ credentialKind: "api_key",
423
+ source,
424
+ sourceLabel: sourceLabel(source),
425
+ identityLabel: null,
426
+ disabled: false,
427
+ disabledCause: null,
428
+ health: sourceHealth(authStorage, provider, source as SyntheticAccountSource),
429
+ capabilities: {
430
+ canCheck: true,
431
+ canPin: false,
432
+ canRemove: false,
433
+ hasCachedUsage: false,
434
+ },
435
+ routing: {
436
+ active: false,
437
+ selected,
438
+ marker: selected ? "selected" : "available",
439
+ },
440
+ });
441
+ };
442
+
443
+ // Keep synthetic rows even when a stored row exists: they represent
444
+ // explicit sources that can shadow stored credentials.
445
+ if (runtime) add("runtime");
446
+ if (config) add("config");
447
+ if (env) add("env");
448
+ }
449
+ }
450
+
451
+ /** Build a redacted, cache-only account snapshot. This function never probes. */
452
+ export function buildAccountInventorySnapshot(input: AccountInventoryInput): AccountInventorySnapshot {
453
+ const nowMs = input.nowMs ?? Date.now();
454
+ const inventory = input.authStorage.listCredentialInventory();
455
+ const rows: AccountInventoryRow[] = [];
456
+ addStoredRows(rows, input.authStorage, inventory, input.sessionId);
457
+ addSyntheticRows(rows, input.authStorage, providerSet(input, inventory), input.sessionId);
458
+ rows.sort((left, right) => left.id.localeCompare(right.id));
459
+ return { generatedAt: nowMs, generation: input.authStorage.getGeneration(), rows };
460
+ }
461
+
462
+ /** Short alias used by command/report callers. */
463
+ export const buildAccountInventory = buildAccountInventorySnapshot;
464
+
465
+ function applyStoredCheck(
466
+ rows: AccountInventoryRow[],
467
+ authStorage: AuthStorage,
468
+ results: CredentialHealthResult[],
469
+ ): AccountInventoryCheckResult[] {
470
+ const byId = new Map(rows.filter(row => row.credentialId !== undefined).map(row => [row.credentialId!, row]));
471
+ const checked: AccountInventoryCheckResult[] = [];
472
+ for (const result of results) {
473
+ const row = byId.get(result.id);
474
+ if (!row) continue;
475
+ row.health = {
476
+ status: result.ok === true ? "ok" : result.ok === false ? "failed" : "unverifiable",
477
+ reason: asSafeLabel(result.reason),
478
+ };
479
+ if (result.report) {
480
+ const cached =
481
+ row.credentialId === undefined
482
+ ? undefined
483
+ : authStorage.getCachedUsageReport(row.provider as Provider, row.credentialId);
484
+ if (cached) {
485
+ row.usage = redactUsageCache(cached);
486
+ row.capabilities.hasCachedUsage = true;
487
+ }
488
+ }
489
+ checked.push({
490
+ rowId: row.id,
491
+ provider: row.provider,
492
+ credentialId: row.credentialId,
493
+ ok: result.ok,
494
+ reason: asSafeLabel(result.reason) ?? undefined,
495
+ });
496
+ }
497
+ return checked;
498
+ }
499
+
500
+ /**
501
+ * Run the explicit sequential checker and return a fresh redacted snapshot.
502
+ * AuthStorage.checkCredentials performs stored-row probes sequentially; the
503
+ * synthetic API-key probes below are also intentionally sequential.
504
+ */
505
+ export async function checkAccountInventory(input: AccountInventoryInput): Promise<AccountInventorySnapshot> {
506
+ const fullSnapshot = buildAccountInventorySnapshot(input);
507
+ const rows = input.provider ? fullSnapshot.rows.filter(row => row.provider === input.provider) : fullSnapshot.rows;
508
+ const snapshot: AccountInventorySnapshot = { ...fullSnapshot, rows };
509
+ const authStorage = input.authStorage;
510
+ applyStoredCheck(
511
+ rows,
512
+ authStorage,
513
+ await authStorage.checkCredentials({
514
+ provider: input.provider,
515
+ baseUrlResolver: provider => input.modelRegistry?.getProviderBaseUrl?.(provider),
516
+ }),
517
+ );
518
+ const syntheticRows = rows.filter(row => row.source !== "stored");
519
+ for (const row of syntheticRows) {
520
+ let key: string | undefined;
521
+ if (row.source === "env") key = getEnvApiKey(row.provider);
522
+ else if (row.source === "runtime" && authStorage.hasRuntimeApiKey(row.provider))
523
+ key = await authStorage.peekApiKey(row.provider);
524
+ else if (
525
+ row.source === "config" &&
526
+ authStorage.hasConfigApiKey(row.provider) &&
527
+ !authStorage.hasRuntimeApiKey(row.provider)
528
+ ) {
529
+ key = await authStorage.peekApiKey(row.provider);
530
+ }
531
+ const result = key
532
+ ? await authStorage.checkApiKeyCredential(row.provider as Provider, key, {
533
+ baseUrl: input.modelRegistry?.getProviderBaseUrl?.(row.provider),
534
+ })
535
+ : { provider: row.provider, type: "api_key" as const, ok: null, reason: "API-key source is unavailable" };
536
+ row.health = {
537
+ status: result.ok === true ? "ok" : result.ok === false ? "failed" : "unverifiable",
538
+ reason: asSafeLabel(result.reason),
539
+ };
540
+ recordSourceHealth(authStorage, row.provider, row.source as SyntheticAccountSource, result.ok, result.reason);
541
+ if (result.report) {
542
+ row.usage = {
543
+ report: redactUsageReport(result.report),
544
+ fetchedAt: finiteNumber(result.report.fetchedAt) ?? 0,
545
+ freshUntil: Date.now() + 15 * 60_000,
546
+ retainUntil: Date.now() + 24 * 60 * 60_000,
547
+ freshness: "fresh",
548
+ };
549
+ row.capabilities.hasCachedUsage = true;
550
+ }
551
+ }
552
+ return snapshot;
553
+ }
554
+
555
+ export const checkAccountInventorySnapshot = checkAccountInventory;
556
+
557
+ function selectorMatchesRemovedRow(
558
+ selector: string,
559
+ provider: string,
560
+ inventory: readonly CredentialInventoryRecord[],
561
+ removedIds: ReadonlySet<number>,
562
+ ): boolean {
563
+ const parsed = parsePersistedCredentialSelector(selector);
564
+ if (!parsed) return false;
565
+ if (parsed.kind === "id") return removedIds.has(Number(parsed.value));
566
+ return inventory.some(
567
+ row =>
568
+ row.provider === provider &&
569
+ removedIds.has(row.id) &&
570
+ (parsed.kind === "email"
571
+ ? row.email?.trim().toLowerCase() === parsed.value.trim().toLowerCase()
572
+ : parsed.kind === "account"
573
+ ? row.accountId === parsed.value
574
+ : row.projectId === parsed.value),
575
+ );
576
+ }
577
+
578
+ /** Clear a global persistent pin only after its selected credential was removed. */
579
+ export async function clearPersistentPinForRemovedRows(
580
+ settings: Pick<Settings, "commitAtomicBatchWithCurrent">,
581
+ provider: string,
582
+ inventory: readonly CredentialInventoryRecord[],
583
+ removedIds: readonly number[],
584
+ ): Promise<boolean> {
585
+ const removed = new Set(removedIds);
586
+ if (removed.size === 0) return false;
587
+ let cleared = false;
588
+ await settings.commitAtomicBatchWithCurrent(current => {
589
+ const auth = asRecord((current as RawSettings).auth);
590
+ const pins = asRecord(auth?.credentialPins);
591
+ const selector = pins?.[provider];
592
+ if (typeof selector !== "string" || !selectorMatchesRemovedRow(selector, provider, inventory, removed)) return [];
593
+ const nextPins = { ...pins };
594
+ delete nextPins[provider];
595
+ cleared = true;
596
+ const patches: SettingsAtomicPatch[] = [{ path: "auth.credentialPins", op: "set", value: nextPins }];
597
+ if (!Object.values(nextPins).some(value => typeof value === "string" && value.startsWith("id:"))) {
598
+ patches.push({ path: "auth.credentialPinStoreIdentity", op: "unset" });
599
+ }
600
+ return patches;
601
+ });
602
+ return cleared;
603
+ }