@songsid/agend 2.2.0-beta.2 → 2.2.0-beta.20

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 (389) hide show
  1. package/README.md +40 -24
  2. package/README.zh-TW.md +40 -24
  3. package/dist/agent-cli-instructions.md +6 -2
  4. package/dist/agent-cli.js +15 -7
  5. package/dist/agent-cli.js.map +1 -1
  6. package/dist/agent-endpoint.js +3 -0
  7. package/dist/agent-endpoint.js.map +1 -1
  8. package/dist/agent-whats-new.js +16 -4
  9. package/dist/agent-whats-new.js.map +1 -1
  10. package/dist/auth-api.d.ts +3 -1
  11. package/dist/auth-api.js +17 -1
  12. package/dist/auth-api.js.map +1 -1
  13. package/dist/backend/antigravity.d.ts +33 -0
  14. package/dist/backend/antigravity.js +126 -18
  15. package/dist/backend/antigravity.js.map +1 -1
  16. package/dist/backend/claude-carry.d.ts +22 -0
  17. package/dist/backend/claude-carry.js +170 -0
  18. package/dist/backend/claude-carry.js.map +1 -0
  19. package/dist/backend/claude-code.d.ts +65 -2
  20. package/dist/backend/claude-code.js +226 -33
  21. package/dist/backend/claude-code.js.map +1 -1
  22. package/dist/backend/codex-metadata.d.ts +33 -0
  23. package/dist/backend/codex-metadata.js +122 -18
  24. package/dist/backend/codex-metadata.js.map +1 -1
  25. package/dist/backend/codex.d.ts +3 -0
  26. package/dist/backend/codex.js +17 -1
  27. package/dist/backend/codex.js.map +1 -1
  28. package/dist/backend/credential-profile.d.ts +40 -3
  29. package/dist/backend/credential-profile.js +113 -5
  30. package/dist/backend/credential-profile.js.map +1 -1
  31. package/dist/backend/effort-metadata.d.ts +37 -1
  32. package/dist/backend/effort-metadata.js +86 -15
  33. package/dist/backend/effort-metadata.js.map +1 -1
  34. package/dist/backend/grok.d.ts +4 -0
  35. package/dist/backend/grok.js +14 -0
  36. package/dist/backend/grok.js.map +1 -1
  37. package/dist/backend/kiro.d.ts +27 -1
  38. package/dist/backend/kiro.js +63 -10
  39. package/dist/backend/kiro.js.map +1 -1
  40. package/dist/backend/launch-effort.d.ts +61 -0
  41. package/dist/backend/launch-effort.js +170 -0
  42. package/dist/backend/launch-effort.js.map +1 -0
  43. package/dist/backend/muse.d.ts +84 -0
  44. package/dist/backend/muse.js +449 -53
  45. package/dist/backend/muse.js.map +1 -1
  46. package/dist/backend/types.d.ts +48 -2
  47. package/dist/backend/types.js +12 -1
  48. package/dist/backend/types.js.map +1 -1
  49. package/dist/backend-command.d.ts +91 -0
  50. package/dist/backend-command.js +122 -0
  51. package/dist/backend-command.js.map +1 -0
  52. package/dist/background-work-ended.d.ts +18 -0
  53. package/dist/background-work-ended.js +30 -0
  54. package/dist/background-work-ended.js.map +1 -0
  55. package/dist/cache-service.d.ts +2 -0
  56. package/dist/cache-service.js +2 -1
  57. package/dist/cache-service.js.map +1 -1
  58. package/dist/channel/adapters/discord.d.ts +26 -1
  59. package/dist/channel/adapters/discord.js +103 -3
  60. package/dist/channel/adapters/discord.js.map +1 -1
  61. package/dist/channel/adapters/telegram.d.ts +35 -3
  62. package/dist/channel/adapters/telegram.js +122 -23
  63. package/dist/channel/adapters/telegram.js.map +1 -1
  64. package/dist/channel/mcp-tools.js +5 -3
  65. package/dist/channel/mcp-tools.js.map +1 -1
  66. package/dist/channel/message-edit-errors.d.ts +5 -0
  67. package/dist/channel/message-edit-errors.js +24 -0
  68. package/dist/channel/message-edit-errors.js.map +1 -0
  69. package/dist/channel/telegram-markdown.d.ts +6 -0
  70. package/dist/channel/telegram-markdown.js +104 -0
  71. package/dist/channel/telegram-markdown.js.map +1 -0
  72. package/dist/channel/tool-router.d.ts +2 -0
  73. package/dist/channel/tool-router.js +6 -5
  74. package/dist/channel/tool-router.js.map +1 -1
  75. package/dist/channel/types.d.ts +46 -4
  76. package/dist/cli.js +184 -34
  77. package/dist/cli.js.map +1 -1
  78. package/dist/command-table.d.ts +2 -2
  79. package/dist/command-table.js +5 -2
  80. package/dist/command-table.js.map +1 -1
  81. package/dist/compact-watch.d.ts +86 -0
  82. package/dist/compact-watch.js +288 -0
  83. package/dist/compact-watch.js.map +1 -0
  84. package/dist/config-validator.js +55 -5
  85. package/dist/config-validator.js.map +1 -1
  86. package/dist/config.d.ts +1 -0
  87. package/dist/config.js +2 -1
  88. package/dist/config.js.map +1 -1
  89. package/dist/cross-instance-envelope.js +2 -0
  90. package/dist/cross-instance-envelope.js.map +1 -1
  91. package/dist/daemon.d.ts +129 -1
  92. package/dist/daemon.js +754 -94
  93. package/dist/daemon.js.map +1 -1
  94. package/dist/delivery-outbox.d.ts +64 -8
  95. package/dist/delivery-outbox.js +315 -24
  96. package/dist/delivery-outbox.js.map +1 -1
  97. package/dist/delivery-reconciliation.d.ts +18 -1
  98. package/dist/delivery-reconciliation.js +67 -2
  99. package/dist/delivery-reconciliation.js.map +1 -1
  100. package/dist/doctor.js +7 -0
  101. package/dist/doctor.js.map +1 -1
  102. package/dist/fleet-context.d.ts +12 -1
  103. package/dist/fleet-manager.d.ts +392 -19
  104. package/dist/fleet-manager.js +2030 -275
  105. package/dist/fleet-manager.js.map +1 -1
  106. package/dist/forged-envelope-scan.d.ts +4 -3
  107. package/dist/forged-envelope-scan.js +4 -3
  108. package/dist/forged-envelope-scan.js.map +1 -1
  109. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +84 -16
  110. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +16 -1
  111. package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
  112. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -0
  113. package/dist/host-memory.d.ts +10 -0
  114. package/dist/host-memory.js +33 -1
  115. package/dist/host-memory.js.map +1 -1
  116. package/dist/human-delivery-receipts.d.ts +83 -0
  117. package/dist/human-delivery-receipts.js +194 -0
  118. package/dist/human-delivery-receipts.js.map +1 -0
  119. package/dist/install-lock.d.ts +18 -1
  120. package/dist/install-lock.js +30 -3
  121. package/dist/install-lock.js.map +1 -1
  122. package/dist/instance-avatar.d.ts +5 -4
  123. package/dist/instance-avatar.js +12 -8
  124. package/dist/instance-avatar.js.map +1 -1
  125. package/dist/instance-config-impact.js +1 -0
  126. package/dist/instance-config-impact.js.map +1 -1
  127. package/dist/instance-lifecycle.d.ts +25 -6
  128. package/dist/instance-lifecycle.js +76 -27
  129. package/dist/instance-lifecycle.js.map +1 -1
  130. package/dist/instructions.d.ts +1 -1
  131. package/dist/instructions.js +3 -3
  132. package/dist/instructions.js.map +1 -1
  133. package/dist/kiro-compact-pane.d.ts +38 -0
  134. package/dist/kiro-compact-pane.js +57 -0
  135. package/dist/kiro-compact-pane.js.map +1 -0
  136. package/dist/kiro-log-gate.d.ts +42 -0
  137. package/dist/kiro-log-gate.js +39 -0
  138. package/dist/kiro-log-gate.js.map +1 -0
  139. package/dist/launchd-handoff.d.ts +43 -0
  140. package/dist/launchd-handoff.js +56 -0
  141. package/dist/launchd-handoff.js.map +1 -0
  142. package/dist/locale.js +268 -42
  143. package/dist/locale.js.map +1 -1
  144. package/dist/log-service.d.ts +99 -0
  145. package/dist/log-service.js +243 -0
  146. package/dist/log-service.js.map +1 -0
  147. package/dist/log-steps.d.ts +169 -0
  148. package/dist/log-steps.js +858 -0
  149. package/dist/log-steps.js.map +1 -0
  150. package/dist/login-controller.d.ts +20 -3
  151. package/dist/login-controller.js +71 -19
  152. package/dist/login-controller.js.map +1 -1
  153. package/dist/login-flows.d.ts +5 -2
  154. package/dist/login-flows.js +5 -4
  155. package/dist/login-flows.js.map +1 -1
  156. package/dist/login-shell.d.ts +21 -0
  157. package/dist/login-shell.js +98 -0
  158. package/dist/login-shell.js.map +1 -0
  159. package/dist/memory-pressure.d.ts +13 -1
  160. package/dist/memory-pressure.js +50 -10
  161. package/dist/memory-pressure.js.map +1 -1
  162. package/dist/needs-you-hub.js +2 -0
  163. package/dist/needs-you-hub.js.map +1 -1
  164. package/dist/needs-you-live.d.ts +6 -0
  165. package/dist/needs-you-live.js +23 -3
  166. package/dist/needs-you-live.js.map +1 -1
  167. package/dist/outbound-handlers.d.ts +100 -0
  168. package/dist/outbound-handlers.js +277 -93
  169. package/dist/outbound-handlers.js.map +1 -1
  170. package/dist/outbound-schemas.d.ts +30 -15
  171. package/dist/outbound-schemas.js +23 -5
  172. package/dist/outbound-schemas.js.map +1 -1
  173. package/dist/provider-probe.d.ts +29 -0
  174. package/dist/provider-probe.js +198 -2
  175. package/dist/provider-probe.js.map +1 -1
  176. package/dist/public-link-progress.d.ts +1 -1
  177. package/dist/public-link-progress.js +8 -2
  178. package/dist/public-link-progress.js.map +1 -1
  179. package/dist/public-preview.d.ts +101 -0
  180. package/dist/public-preview.js +236 -0
  181. package/dist/public-preview.js.map +1 -0
  182. package/dist/public-web-gateway.d.ts +2 -0
  183. package/dist/public-web-gateway.js +20 -6
  184. package/dist/public-web-gateway.js.map +1 -1
  185. package/dist/public-web-link.d.ts +24 -1
  186. package/dist/public-web-link.js +63 -9
  187. package/dist/public-web-link.js.map +1 -1
  188. package/dist/quickstart-api.d.ts +1 -1
  189. package/dist/quickstart-api.js +8 -6
  190. package/dist/quickstart-api.js.map +1 -1
  191. package/dist/quickstart.d.ts +12 -0
  192. package/dist/quickstart.js +36 -6
  193. package/dist/quickstart.js.map +1 -1
  194. package/dist/reply-buttons-controller.d.ts +89 -5
  195. package/dist/reply-buttons-controller.js +273 -8
  196. package/dist/reply-buttons-controller.js.map +1 -1
  197. package/dist/reply-buttons.d.ts +48 -3
  198. package/dist/reply-buttons.js +105 -10
  199. package/dist/reply-buttons.js.map +1 -1
  200. package/dist/reply-polls.d.ts +85 -0
  201. package/dist/reply-polls.js +154 -0
  202. package/dist/reply-polls.js.map +1 -0
  203. package/dist/restart-guard.d.ts +6 -3
  204. package/dist/restart-guard.js +6 -3
  205. package/dist/restart-guard.js.map +1 -1
  206. package/dist/restart-progress.d.ts +33 -2
  207. package/dist/restart-progress.js +30 -2
  208. package/dist/restart-progress.js.map +1 -1
  209. package/dist/sd-notify.d.ts +22 -1
  210. package/dist/sd-notify.js +63 -10
  211. package/dist/sd-notify.js.map +1 -1
  212. package/dist/service-activation.d.ts +15 -7
  213. package/dist/service-activation.js +42 -26
  214. package/dist/service-activation.js.map +1 -1
  215. package/dist/service-installer.d.ts +55 -0
  216. package/dist/service-installer.js +90 -3
  217. package/dist/service-installer.js.map +1 -1
  218. package/dist/service-plan.d.ts +11 -0
  219. package/dist/service-plan.js +23 -0
  220. package/dist/service-plan.js.map +1 -1
  221. package/dist/settings-api.js +14 -4
  222. package/dist/settings-api.js.map +1 -1
  223. package/dist/settings-change.js +4 -2
  224. package/dist/settings-change.js.map +1 -1
  225. package/dist/settings-effect.js +2 -0
  226. package/dist/settings-effect.js.map +1 -1
  227. package/dist/spawn-gate.js +5 -1
  228. package/dist/spawn-gate.js.map +1 -1
  229. package/dist/spawn-hold-reply.d.ts +12 -0
  230. package/dist/spawn-hold-reply.js +39 -0
  231. package/dist/spawn-hold-reply.js.map +1 -0
  232. package/dist/systemd-peer-bus.d.ts +95 -0
  233. package/dist/systemd-peer-bus.js +430 -0
  234. package/dist/systemd-peer-bus.js.map +1 -0
  235. package/dist/systemd-runtime.d.ts +27 -1
  236. package/dist/systemd-runtime.js +69 -7
  237. package/dist/systemd-runtime.js.map +1 -1
  238. package/dist/tips.js +1 -1
  239. package/dist/tips.js.map +1 -1
  240. package/dist/tool-permissions.js +3 -3
  241. package/dist/tool-permissions.js.map +1 -1
  242. package/dist/tool-progress.js +3 -2
  243. package/dist/tool-progress.js.map +1 -1
  244. package/dist/topic-commands.d.ts +71 -4
  245. package/dist/topic-commands.js +167 -34
  246. package/dist/topic-commands.js.map +1 -1
  247. package/dist/transcript-delta-reader.d.ts +3 -3
  248. package/dist/transcript-delta-reader.js +8 -8
  249. package/dist/transcript-delta-reader.js.map +1 -1
  250. package/dist/transcript-jsonl.d.ts +85 -3
  251. package/dist/transcript-jsonl.js +156 -13
  252. package/dist/transcript-jsonl.js.map +1 -1
  253. package/dist/transcript-monitor.d.ts +11 -0
  254. package/dist/transcript-monitor.js +61 -13
  255. package/dist/transcript-monitor.js.map +1 -1
  256. package/dist/transcript-sources.d.ts +24 -0
  257. package/dist/transcript-sources.js +211 -56
  258. package/dist/transcript-sources.js.map +1 -1
  259. package/dist/tunnel/cloudflared.d.ts +7 -15
  260. package/dist/tunnel/cloudflared.js +36 -1
  261. package/dist/tunnel/cloudflared.js.map +1 -1
  262. package/dist/tunnel/purpose-lane.d.ts +5 -1
  263. package/dist/tunnel/purpose-lane.js +14 -7
  264. package/dist/tunnel/purpose-lane.js.map +1 -1
  265. package/dist/tunnel/types.d.ts +5 -1
  266. package/dist/tunnel/types.js.map +1 -1
  267. package/dist/turn-resume.d.ts +2 -0
  268. package/dist/turn-resume.js +1 -1
  269. package/dist/turn-resume.js.map +1 -1
  270. package/dist/types.d.ts +22 -0
  271. package/dist/ui/chat-commands.js +1 -0
  272. package/dist/ui/chat-mentions.js +63 -0
  273. package/dist/ui/chat-render.js +80 -10
  274. package/dist/ui/chat-store.js +70 -6
  275. package/dist/ui/chat-strings.js +62 -32
  276. package/dist/ui/chat-thread.js +199 -24
  277. package/dist/ui/chat-time.js +80 -0
  278. package/dist/ui/chat-tour.js +17 -14
  279. package/dist/ui/panel-chat.js +45 -21
  280. package/dist/ui/panel-details.js +2 -0
  281. package/dist/ui/panel-fleet.js +213 -58
  282. package/dist/ui/panel-log.js +428 -0
  283. package/dist/ui/panel-needs.js +14 -10
  284. package/dist/ui/panel-settings.js +82 -17
  285. package/dist/ui/preview-panel.js +55 -15
  286. package/dist/ui/preview-status.js +28 -0
  287. package/dist/ui/preview.js +44 -3
  288. package/dist/ui/settings-dialogs.js +11 -6
  289. package/dist/ui/settings-model.js +3 -1
  290. package/dist/ui/settings-strings.js +32 -12
  291. package/dist/ui/settings-token.js +8 -1
  292. package/dist/ui/settings-wizard.js +5 -3
  293. package/dist/ui/shared/app-i18n.js +41 -15
  294. package/dist/ui/shared/app-prefs.js +250 -0
  295. package/dist/ui/shared/app-route.js +6 -1
  296. package/dist/ui/shared/app-shell.js +165 -8
  297. package/dist/ui/shared/app-store.js +5 -1
  298. package/dist/ui/shared/app-stream.js +26 -5
  299. package/dist/ui/shared/app.css +170 -30
  300. package/dist/ui/shared/app.js +11 -1
  301. package/dist/ui/shared/fonts/README.md +1 -1
  302. package/dist/ui/shared/header-tools.js +83 -13
  303. package/dist/ui/shared/instance-nav.js +178 -51
  304. package/dist/ui/shared/instance-switch.js +8 -5
  305. package/dist/ui/shared/panel-view.js +21 -4
  306. package/dist/ui/shared/signin.js +15 -9
  307. package/dist/ui/shared/theme.js +39 -7
  308. package/dist/ui/shared/tokens.css +1 -1
  309. package/dist/ui/shared/ui-icons.js +2 -0
  310. package/dist/ui/shared/usage-dialog.js +23 -5
  311. package/dist/ui/shared/view-strings.js +40 -4
  312. package/dist/ui/signin.html +8 -3
  313. package/dist/unrecognised-prompt.d.ts +23 -0
  314. package/dist/unrecognised-prompt.js +74 -0
  315. package/dist/unrecognised-prompt.js.map +1 -0
  316. package/dist/update-check.d.ts +31 -0
  317. package/dist/update-check.js +47 -0
  318. package/dist/update-check.js.map +1 -1
  319. package/dist/update-install.d.ts +13 -1
  320. package/dist/update-install.js +16 -4
  321. package/dist/update-install.js.map +1 -1
  322. package/dist/update-launch.d.ts +48 -1
  323. package/dist/update-launch.js +159 -5
  324. package/dist/update-launch.js.map +1 -1
  325. package/dist/update-marker.d.ts +51 -0
  326. package/dist/update-marker.js +61 -0
  327. package/dist/update-marker.js.map +1 -1
  328. package/dist/usage/i18n-keys.d.ts +1 -1
  329. package/dist/usage/i18n-keys.js +1 -1
  330. package/dist/usage/i18n-keys.js.map +1 -1
  331. package/dist/usage/providers.d.ts +62 -13
  332. package/dist/usage/providers.js +256 -68
  333. package/dist/usage/providers.js.map +1 -1
  334. package/dist/usage/statusline-usage.d.ts +6 -2
  335. package/dist/usage/statusline-usage.js +10 -4
  336. package/dist/usage/statusline-usage.js.map +1 -1
  337. package/dist/view-api.js +31 -9
  338. package/dist/view-api.js.map +1 -1
  339. package/dist/web-api.d.ts +82 -4
  340. package/dist/web-api.js +632 -88
  341. package/dist/web-api.js.map +1 -1
  342. package/dist/web-auth.js +5 -2
  343. package/dist/web-auth.js.map +1 -1
  344. package/dist/web-chat-history.d.ts +26 -1
  345. package/dist/web-chat-history.js +47 -8
  346. package/dist/web-chat-history.js.map +1 -1
  347. package/dist/web-commands.d.ts +41 -5
  348. package/dist/web-commands.js +25 -7
  349. package/dist/web-commands.js.map +1 -1
  350. package/dist/web-login.d.ts +14 -0
  351. package/dist/web-login.js +4 -2
  352. package/dist/web-login.js.map +1 -1
  353. package/dist/web-mentions.d.ts +44 -0
  354. package/dist/web-mentions.js +75 -0
  355. package/dist/web-mentions.js.map +1 -0
  356. package/dist/web-prefs.d.ts +81 -0
  357. package/dist/web-prefs.js +297 -0
  358. package/dist/web-prefs.js.map +1 -0
  359. package/dist/web-preview.d.ts +14 -1
  360. package/dist/web-preview.js +35 -13
  361. package/dist/web-preview.js.map +1 -1
  362. package/dist/web-profile.d.ts +32 -0
  363. package/dist/web-profile.js +132 -0
  364. package/dist/web-profile.js.map +1 -0
  365. package/dist/web-reply-files.d.ts +45 -0
  366. package/dist/web-reply-files.js +223 -0
  367. package/dist/web-reply-files.js.map +1 -0
  368. package/dist/web-schedules.d.ts +12 -0
  369. package/dist/web-schedules.js +34 -0
  370. package/dist/web-schedules.js.map +1 -0
  371. package/dist/web-server-drain.d.ts +10 -0
  372. package/dist/web-server-drain.js +50 -0
  373. package/dist/web-server-drain.js.map +1 -0
  374. package/dist/web-session.d.ts +14 -0
  375. package/dist/web-session.js +11 -1
  376. package/dist/web-session.js.map +1 -1
  377. package/dist/web-settings-patch.d.ts +3 -1
  378. package/dist/web-settings-patch.js +4 -1
  379. package/dist/web-settings-patch.js.map +1 -1
  380. package/dist/web-shell-routes.d.ts +4 -0
  381. package/dist/web-shell-routes.js +9 -0
  382. package/dist/web-shell-routes.js.map +1 -1
  383. package/dist/web-upload.d.ts +135 -7
  384. package/dist/web-upload.js +315 -51
  385. package/dist/web-upload.js.map +1 -1
  386. package/launcher/install-admission.cjs +61 -6
  387. package/package.json +3 -3
  388. package/templates/launchd.plist.ejs +3 -1
  389. package/templates/systemd.service.ejs +2 -1
@@ -20,13 +20,15 @@
20
20
  */
21
21
  import { readFile, writeFile, access, constants } from "node:fs/promises";
22
22
  import { readFileSync, readdirSync } from "node:fs";
23
- import { join } from "node:path";
23
+ import { join, resolve, sep } from "node:path";
24
+ import { execFile } from "node:child_process";
24
25
  import { getAgendHome } from "../paths.js";
25
26
  import { loadFleetConfig } from "../config.js";
26
27
  import { classicProfile, profileName, readClassicBindings } from "../classic-bindings.js";
27
- import { credentialHomeSpec, credentialProfileStoreHome, instanceCredentialProfile, } from "../backend/credential-profile.js";
28
+ import { CHAT_PROFILE_LOGIN_BACKENDS, credentialHomeSpec, credentialProfileLoginCommand, credentialProfileStoreHome, instanceCredentialProfile, } from "../backend/credential-profile.js";
29
+ import { claudeKeychainService } from "../backend/claude-code.js";
28
30
  import { readKiroAuthTokens } from "../backend/kiro-auth-store.js";
29
- import { homedir } from "node:os";
31
+ import { homedir, userInfo } from "node:os";
30
32
  import { getProviderRateLimit } from "./provider-alerts.js";
31
33
  import { MUSE_USAGE_STALE_MS, readMuseUsageSnapshot } from "../muse-usage-relay.js";
32
34
  import { readStatuslineRateLimits, } from "./statusline-usage.js";
@@ -216,43 +218,163 @@ export function statuslineUsage(reading, plan, now = Date.now()) {
216
218
  metrics,
217
219
  };
218
220
  }
221
+ /** `claudeAiOauth` of a credentials document (the `.credentials.json` file, or the same JSON in a Keychain item). */
222
+ function claudeOAuthOf(json) {
223
+ try {
224
+ const value = JSON.parse(json)?.claudeAiOauth;
225
+ return value && typeof value === "object" ? value : null;
226
+ }
227
+ catch {
228
+ return null;
229
+ }
230
+ }
231
+ async function readClaudeCredentialsFile(dir) {
232
+ try {
233
+ return claudeOAuthOf(await readFile(join(dir, ".credentials.json"), "utf8"));
234
+ }
235
+ catch {
236
+ return null;
237
+ }
238
+ }
239
+ const readKeychainItem = (service, account) => new Promise(done => {
240
+ execFile("security", ["find-generic-password", "-a", account, "-w", "-s", service], { timeout: 5_000 }, (err, stdout) => {
241
+ done(err ? null : String(stdout).trim() || null);
242
+ });
243
+ });
244
+ const defaultKeychain = () => ({ platform: process.platform, read: readKeychainItem, username: () => userInfo().username });
245
+ let claudeKeychain = defaultKeychain();
246
+ /** Test seam (#1699): the platform, the Keychain read and the OS user name; null restores all three. */
247
+ export function setClaudeKeychainForTests(seam) {
248
+ claudeKeychain = seam ? { ...claudeKeychain, ...seam } : defaultKeychain();
249
+ }
219
250
  /**
220
- * Best-effort OAuth access token for direct Anthropic API calls (the /model
221
- * catalog probe). Same resolution order as the usage panel: credentials file →
222
- * CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists.
251
+ * The account claude files its Keychain item under (2.1.296, as Prism read it from the official darwin bundle, #1713
252
+ * review): `$USER`, else the OS user name; one that cannot be read or is not `[a-zA-Z0-9._-]+` is "claude-code-user".
223
253
  */
224
- export async function getClaudeOAuthToken() {
225
- const home = process.env.CLAUDE_HOME || join(homedir(), ".claude");
226
- let file;
254
+ function claudeKeychainAccount() {
255
+ let name;
227
256
  try {
228
- file = JSON.parse(await readFile(join(home, ".credentials.json"), "utf8")).claudeAiOauth ?? null;
257
+ name = process.env.USER || claudeKeychain.username();
229
258
  }
230
259
  catch {
231
- file = null;
260
+ name = undefined;
232
261
  }
233
- const auth = resolveClaudeAuth(file);
234
- return auth && "token" in auth ? auth.token : null;
262
+ return name && /^[a-zA-Z0-9._-]+$/.test(name) ? name : "claude-code-user";
235
263
  }
236
- /** Exported for tests — the statusline/API preference order is the subject. */
237
- export async function fetchClaudeUsage() {
238
- const home = process.env.CLAUDE_HOME || join(homedir(), ".claude");
239
- let file;
264
+ /**
265
+ * A credential profile's own Claude login (#1699) — and nothing else: on macOS the Keychain item claude keeps for
266
+ * exactly this config dir (claudeKeychainService; the account is $USER, as claude names it), else — or when that has
267
+ * none — the dir's `.credentials.json`. Never the shared login, `CLAUDE_CODE_OAUTH_TOKEN` or a shell rc: those are
268
+ * another account's, and their numbers on this row would be a lie about this subscription.
269
+ */
270
+ async function readClaudeProfileLogin(configDir) {
271
+ if (claudeKeychain.platform === "darwin") {
272
+ // As claude: a credentials document in the Keychain is THE login — one with no OAuth in it (say only MCP
273
+ // logins) means no OAuth login, and an older `.credentials.json` beside it is not consulted (#1713 review).
274
+ const secret = await claudeKeychain.read(claudeKeychainService(configDir), claudeKeychainAccount());
275
+ const document = secret ? credentialsDocument(secret) : null;
276
+ if (document)
277
+ return claudeOAuthOf(secret);
278
+ }
279
+ return readClaudeCredentialsFile(configDir);
280
+ }
281
+ /** A credentials document (any JSON object), or null — unparseable is no document, as claude reads its storage. */
282
+ function credentialsDocument(json) {
240
283
  try {
241
- file = JSON.parse(await readFile(join(home, ".credentials.json"), "utf8")).claudeAiOauth ?? null;
284
+ const v = JSON.parse(json);
285
+ return v && typeof v === "object" ? v : null;
242
286
  }
243
287
  catch {
244
- file = null;
288
+ return null;
289
+ }
290
+ }
291
+ /**
292
+ * Whether a token the profile's own login does not control can reach claude in a profile's pane: AgEnD sets only
293
+ * `CLAUDE_CONFIG_DIR` for a profile, so `CLAUDE_CODE_OAUTH_TOKEN` from the fleet's environment, or set in a shell rc
294
+ * the pane's shell reads, still signs it in — and outranks the stored login (#1713 review).
295
+ */
296
+ function envTokenReachesClaude() {
297
+ return !!process.env.CLAUDE_CODE_OAUTH_TOKEN?.trim() || shellRcSetsClaudeToken((path) => readFileSync(path, "utf-8"));
298
+ }
299
+ /**
300
+ * Whether a shell rc sets `CLAUDE_CODE_OAUTH_TOKEN` at all — any assignment, export or declaration that is not a
301
+ * comment, whatever its value: `"$OTHER"` or `${OTHER}` is a token once the pane's shell expands it, so unlike
302
+ * tokenFromShellRc (which must hand the API a literal bearer) this never discounts one it cannot read (#1713 review).
303
+ * Files those rcs `source` are not followed.
304
+ */
305
+ export function shellRcSetsClaudeToken(read, home = homedir(), files = SHELL_RC_FILES) {
306
+ const sets = [
307
+ /^[ \t]*(?:(?:export|readonly|local|declare|typeset)(?:[ \t]+-[a-zA-Z]+)*[ \t]+(?:[^#\n]*[ \t])?)?CLAUDE_CODE_OAUTH_TOKEN[ \t]*=/m,
308
+ /^[ \t]*(?:export|declare[ \t]+-[a-zA-Z]*x[a-zA-Z]*|typeset[ \t]+-[a-zA-Z]*x[a-zA-Z]*)[ \t]+(?:[^#\n]*[ \t])?CLAUDE_CODE_OAUTH_TOKEN\b/m,
309
+ /^[ \t]*setenv[ \t]+CLAUDE_CODE_OAUTH_TOKEN\b/m,
310
+ ];
311
+ for (const file of files) {
312
+ let content;
313
+ try {
314
+ content = read(join(home, file));
315
+ }
316
+ catch {
317
+ continue;
318
+ }
319
+ if (sets.some((re) => re.test(content)))
320
+ return true;
245
321
  }
322
+ return false;
323
+ }
324
+ /** `path` is `dir` or inside it. */
325
+ const isWithin = (path, dir) => { const p = resolve(path); return p === dir || p.startsWith(dir + sep); };
326
+ /**
327
+ * Best-effort OAuth access token for direct Anthropic API calls (the /model
328
+ * catalog probe). Same resolution order as the usage panel: credentials file →
329
+ * CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists. With
330
+ * `storeHome` (a credential profile's config dir, #1699): that profile's login only.
331
+ */
332
+ export async function getClaudeOAuthToken(storeHome) {
333
+ const auth = storeHome !== undefined
334
+ ? resolveClaudeAuth(await readClaudeProfileLogin(storeHome), {}, () => null)
335
+ : resolveClaudeAuth(await readClaudeCredentialsFile(process.env.CLAUDE_HOME || join(homedir(), ".claude")));
336
+ return auth && "token" in auth ? auth.token : null;
337
+ }
338
+ /**
339
+ * Exported for tests — the statusline/API preference order is the subject.
340
+ *
341
+ * `storeHome` (#1699): a credential profile's config dir — the row reads that profile's login and only the rate
342
+ * limits its own instances wrote (their conversations are under its `projects/`); a profile with no login says so,
343
+ * with the line that signs it in, and never shows the shared account's numbers. Without it: the shared login as
344
+ * always; beside profiles (`besideProfiles`), its statusline fallback leaves the profiles' instances out.
345
+ */
346
+ export async function fetchClaudeUsage(storeHome, scope = {}) {
347
+ const profileHome = storeHome !== undefined ? resolve(storeHome) : null;
348
+ const file = profileHome !== null
349
+ ? await readClaudeProfileLogin(profileHome)
350
+ : await readClaudeCredentialsFile(process.env.CLAUDE_HOME || join(homedir(), ".claude"));
246
351
  // Read before anything else: it costs one stat per instance, needs no token,
247
352
  // and it is what keeps the panel useful when the API path cannot run at all.
248
- const statusline = readStatuslineRateLimits();
249
- const auth = resolveClaudeAuth(file);
353
+ // A profile's: only readings written under its own `projects/` — and only when nothing but its own login can
354
+ // have signed those instances in. Where the conversation is says which config dir, not whose subscription: with
355
+ // a token in the environment the readings may be another account's, so none is this row's (#1713 review).
356
+ const profilesRoot = resolve(getAgendHome(), "credential-profiles", "claude-code");
357
+ const statusline = profileHome !== null
358
+ ? (envTokenReachesClaude() ? null : readStatuslineRateLimits(undefined, undefined, (path) => path !== null && isWithin(path, join(profileHome, "projects"))))
359
+ : readStatuslineRateLimits(undefined, undefined, scope.besideProfiles ? (path) => path === null || !isWithin(path, profilesRoot) : undefined);
360
+ const auth = profileHome !== null ? resolveClaudeAuth(file, {}, () => null) : resolveClaudeAuth(file);
250
361
  if (auth === null) {
251
362
  // No token anywhere — but the CLI itself is logged in somehow (including an
252
363
  // API key, which the usage endpoint rejects outright), and it wrote its
253
364
  // limits down. This is the case the whole statusline source exists for.
254
365
  if (statusline)
255
366
  return statuslineUsage(statusline, null);
367
+ if (profileHome !== null) {
368
+ // On screen (`ok`, as kiro's signed-out row), with what signs this profile in — never a fallback: from chat
369
+ // (`/login claude-code <profile>`, #1699 part 2), or the exact line on the host — the same words as the auth alert.
370
+ const host = (scope.profile && credentialProfileLoginCommand(getAgendHome(), "claude-code", scope.profile))
371
+ || `CLAUDE_CONFIG_DIR=${JSON.stringify(profileHome)} claude auth login`;
372
+ if (scope.profile && CHAT_PROFILE_LOGIN_BACKENDS.has("claude-code")) {
373
+ const chat = `/login claude-code ${scope.profile}`;
374
+ return { status: "ok", hint: `Not logged in — sign in with \`${chat}\` (or run \`${host}\` on the host).`, hintI18n: i18n("usage.hint.claude_profile_signed_out_chat", chat, host), metrics: [] };
375
+ }
376
+ return { status: "ok", hint: `Not logged in — sign in with: ${host}`, hintI18n: i18n("usage.hint.claude_profile_signed_out", host), metrics: [] };
377
+ }
256
378
  const hint = process.env.ANTHROPIC_API_KEY
257
379
  ? "API-key login has no subscription usage. Use `claude /login` or set CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`)."
258
380
  : "Log in with the Claude Code CLI (`claude`).";
@@ -427,42 +549,96 @@ function agyOAuthClient(env = process.env) {
427
549
  /** Refreshed bearer, cached until shortly before expiry. The CLI's token file is
428
550
  * never written back — it belongs to agy; refresh tokens are reusable. */
429
551
  let agyTokenCache = null;
552
+ /** The summary's buckets, each tagged with its group's name. The top-level list (deprecated in the proto) only counts
553
+ * when no group carries any bucket. */
554
+ export function agyQuotaBuckets(body) {
555
+ const grouped = (body.groups ?? []).flatMap(g => (g.buckets ?? []).map(b => ({ ...b, group: g.displayName?.trim() || undefined })));
556
+ return grouped.length ? grouped : (body.buckets ?? []);
557
+ }
558
+ const AGY_POOLED = {
559
+ "gemini-5h": { pool: "Gemini", window: "session" },
560
+ "gemini-weekly": { pool: "Gemini", window: "weekly" },
561
+ "3p-5h": { pool: "Claude & others", window: "session" },
562
+ "3p-weekly": { pool: "Claude & others", window: "weekly" },
563
+ };
564
+ /** The pool a bucket belongs to: its group when the summary names one (#1898), else a guess from the bucket id. */
565
+ function agyPool(b, id) {
566
+ const pooled = AGY_POOLED[id];
567
+ if (pooled)
568
+ return pooled.pool;
569
+ const group = b.group;
570
+ if (group) {
571
+ if (/gemini/i.test(group))
572
+ return "Gemini";
573
+ if (/claude|gpt|third.?party|\b3p\b/i.test(group))
574
+ return "Claude & others";
575
+ return group;
576
+ }
577
+ return id.startsWith("gemini") ? "Gemini" : "Claude & others";
578
+ }
579
+ /** The limit a bucket counts against ("Five Hour Limit", window "5h" …), or null for a per-model bucket. */
580
+ function agyWindow(b, id) {
581
+ const pooled = AGY_POOLED[id];
582
+ if (pooled)
583
+ return pooled.window;
584
+ // One source at a time, the most specific first: the bucket's own window, then its id, then — only inside a named
585
+ // group, where a per-model name ("Gemini 2.5 High") cannot occur — its display name. A word that merely appears in an
586
+ // opaque id never overrides a window the bucket states.
587
+ for (const text of [b.window, id, b.group ? b.displayName : undefined]) {
588
+ const window = text ? agyWindowOf(text) : null;
589
+ if (window)
590
+ return window;
591
+ }
592
+ return null;
593
+ }
594
+ /** "5h", "5 h", "5-hour", "5_hours", "Five Hour Limit", "session" → session; "weekly", "7d", "7 days" → weekly. */
595
+ function agyWindowOf(text) {
596
+ if (/(^|[^0-9.])5[\s_-]*h(ours?|rs?)?\b|five[\s_-]*h(ours?|rs?)\b|\bsession\b/i.test(text))
597
+ return "session";
598
+ if (/week|(^|[^0-9.])7[\s_-]*d(ays?)?\b|seven[\s_-]*days?\b/i.test(text))
599
+ return "weekly";
600
+ return null;
601
+ }
602
+ function agyLabel(pool, window) {
603
+ if (pool === "Claude & others") {
604
+ return window === "session" ? { text: "Claude & others (session)", i18n: i18n("usage.metric.agy_claude_others_session") }
605
+ : window === "weekly" ? { text: "Claude & others (weekly)", i18n: i18n("usage.metric.agy_claude_others_weekly") }
606
+ : { text: pool, i18n: i18n("usage.metric.agy_claude_others") };
607
+ }
608
+ return window === "session" ? { text: `${pool} (session)`, i18n: i18n("usage.metric.named_session", pool) }
609
+ : window === "weekly" ? { text: `${pool} (weekly)`, i18n: i18n("usage.metric.named_weekly", pool) }
610
+ : { text: pool, i18n: i18n("usage.metric.named", pool) };
611
+ }
430
612
  /**
431
- * Pool the summary's buckets into at most four metrics.
613
+ * Pool the summary's buckets into one metric per pool and limit.
432
614
  *
433
- * Two payload shapes exist. Older accounts report pooled ids (`gemini-5h`,
434
- * `gemini-weekly`, `3p-5h`, `3p-weekly`), which map 1:1. This machine's live
435
- * response instead lists PER-MODEL buckets (`gemini-3.6-flash-high`,
436
- * `claude-sonnet-4-6`, `gpt-oss-120b-medium`, …) — those aggregate into a
437
- * Gemini pool and an everything-else pool, keeping each pool's WORST remaining
438
- * fraction, because eleven per-model meters is noise and the binding constraint
439
- * is the one that runs out first.
615
+ * Three payload shapes exist:
616
+ * - pooled ids (`gemini-5h`, `gemini-weekly`, `3p-5h`, `3p-weekly`), which map 1:1;
617
+ * - PER-MODEL buckets (`gemini-3.6-flash-high`, `claude-sonnet-4-6`, …), aggregated into a Gemini pool and an
618
+ * everything-else pool;
619
+ * - (#1898, agy 2026-10) named groups ("Gemini Models", "Claude and GPT Models") whose buckets are the group's
620
+ * five-hour and weekly limits. The group decides the pool; the bucket's window, id or name decides the limit.
621
+ *
622
+ * Every metric keeps the WORST remaining fraction of its buckets, because the binding constraint is the one that runs
623
+ * out first. Within one pool a bucket with a known limit is authoritative over per-model buckets; one pool never hides
624
+ * another. Disabled buckets (agy dims them, no number) are left out.
440
625
  */
441
626
  export function agyPoolMetrics(buckets) {
442
- const POOLED = {
443
- "gemini-5h": { text: "Gemini (session)", i18n: i18n("usage.metric.named_session", "Gemini") },
444
- "gemini-weekly": { text: "Gemini (weekly)", i18n: i18n("usage.metric.named_weekly", "Gemini") },
445
- "3p-5h": { text: "Claude & others (session)", i18n: i18n("usage.metric.agy_claude_others_session") },
446
- "3p-weekly": { text: "Claude & others (weekly)", i18n: i18n("usage.metric.agy_claude_others_weekly") },
447
- };
448
- const direct = [];
449
- const pools = new Map();
627
+ const entries = new Map();
450
628
  for (const b of buckets) {
451
- if (!b.bucketId || typeof b.remainingFraction !== "number" || !Number.isFinite(b.remainingFraction))
629
+ const id = b.bucketId?.trim() || (b.group ? b.displayName?.trim() : undefined);
630
+ if (!id || b.disabled === true || typeof b.remainingFraction !== "number" || !Number.isFinite(b.remainingFraction))
452
631
  continue;
632
+ const pool = agyPool(b, id);
633
+ const window = agyWindow(b, id);
634
+ const key = `${pool}\u0000${window ?? ""}`;
453
635
  const reset = b.resetTime ?? null;
454
- const pooledLabel = POOLED[b.bucketId];
455
- if (pooledLabel) {
456
- direct.push({ label: pooledLabel.text, labelI18n: pooledLabel.i18n, type: "percent", used: (1 - b.remainingFraction) * 100, resetsAt: reset });
457
- continue;
458
- }
459
- const pool = b.bucketId.startsWith("gemini") ? "Gemini" : "Claude & others";
460
- const existing = pools.get(pool);
636
+ const existing = entries.get(key);
461
637
  if (!existing) {
462
- pools.set(pool, { fraction: b.remainingFraction, resetsAt: reset, models: 1 });
638
+ entries.set(key, { pool, window, fraction: b.remainingFraction, resetsAt: reset, models: 1 });
463
639
  continue;
464
640
  }
465
- // Count every model in the pool; track the worst separately. Replacing the
641
+ // Count every bucket in the entry; track the worst separately. Replacing the
466
642
  // whole entry on a new worst would restart the count at that bucket.
467
643
  existing.models += 1;
468
644
  if (b.remainingFraction < existing.fraction) {
@@ -470,22 +646,24 @@ export function agyPoolMetrics(buckets) {
470
646
  existing.resetsAt = reset;
471
647
  }
472
648
  }
473
- if (direct.length)
474
- return direct;
475
- return [...pools.entries()].map(([label, p]) => ({
476
- label,
477
- labelI18n: label === "Claude & others"
478
- ? i18n("usage.metric.agy_claude_others")
479
- : i18n("usage.metric.named", label),
480
- type: "percent",
481
- used: (1 - p.fraction) * 100,
482
- resetsAt: p.resetsAt,
649
+ const limited = new Set([...entries.values()].filter(e => e.window).map(e => e.pool));
650
+ const order = (w) => (w === "session" ? 0 : w === "weekly" ? 1 : 2);
651
+ const pools = [...new Set([...entries.values()].map(e => e.pool))];
652
+ return [...entries.values()]
653
+ .filter(e => e.window || !limited.has(e.pool))
654
+ .sort((a, b) => pools.indexOf(a.pool) - pools.indexOf(b.pool) || order(a.window) - order(b.window))
655
+ .map(e => {
656
+ const label = agyLabel(e.pool, e.window);
657
+ const metric = { label: label.text, labelI18n: label.i18n, type: "percent", used: (1 - e.fraction) * 100, resetsAt: e.resetsAt };
483
658
  // Which number this is: the highest usage across the pool's models. Without
484
659
  // it a flat 0% right after a weekly rollover is indistinguishable from a
485
660
  // broken reading — which is exactly how it was reported.
486
- note: `busiest of ${p.models} model${p.models === 1 ? "" : "s"}`,
487
- noteI18n: i18n(p.models === 1 ? "usage.note.busiest_model" : "usage.note.busiest_models", p.models),
488
- }));
661
+ if (!e.window || e.models > 1) {
662
+ metric.note = `busiest of ${e.models} model${e.models === 1 ? "" : "s"}`;
663
+ metric.noteI18n = i18n(e.models === 1 ? "usage.note.busiest_model" : "usage.note.busiest_models", e.models);
664
+ }
665
+ return metric;
666
+ });
489
667
  }
490
668
  /**
491
669
  * agy's token file, in either shape.
@@ -613,8 +791,7 @@ async function fetchAntigravityUsage() {
613
791
  catch {
614
792
  continue;
615
793
  }
616
- const buckets = (body.groups ?? []).flatMap(g => g.buckets ?? []);
617
- const metrics = agyPoolMetrics(buckets);
794
+ const metrics = agyPoolMetrics(agyQuotaBuckets(body ?? {}));
618
795
  return metrics.length
619
796
  ? { status: "ok", plan: null, metrics }
620
797
  : { status: "ok", plan: null, hint: "No quota information reported for this account.", hintI18n: i18n("usage.hint.no_quota"), metrics: [] };
@@ -1274,13 +1451,14 @@ export function providersForConfig(config, base = DEFAULT_PROVIDERS) {
1274
1451
  rows.push({
1275
1452
  id: provider.id,
1276
1453
  name: provider.id === "codex" ? `${provider.name} (default)` : provider.name,
1277
- fetch: () => provider.fetch(),
1454
+ // Claude's shared row keeps its statusline fallback to the shared instances (#1699); others ignore the scope.
1455
+ fetch: () => provider.fetch(undefined, { besideProfiles: true }),
1278
1456
  });
1279
1457
  }
1280
1458
  rows.push(...profiles.map(profile => ({
1281
1459
  id: `${provider.id}:${profile}`,
1282
1460
  name: `${provider.name} (${profile})`,
1283
- fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile)),
1461
+ fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile), { profile }),
1284
1462
  })));
1285
1463
  return rows;
1286
1464
  });
@@ -1302,7 +1480,7 @@ function hasEffectiveSharedBinding(config, backendName) {
1302
1480
  const instances = config.instances ?? {};
1303
1481
  let sawEffectiveBinding = false;
1304
1482
  for (const instance of Object.values(instances)) {
1305
- const backend = instance.backend ?? defaults?.backend;
1483
+ const backend = instance.backend ?? defaultBackend(defaults);
1306
1484
  if (backend !== backendName)
1307
1485
  continue;
1308
1486
  sawEffectiveBinding = true;
@@ -1313,12 +1491,20 @@ function hasEffectiveSharedBinding(config, backendName) {
1313
1491
  // backend is this provider and no profile was configured. With no known
1314
1492
  // binding at all, preserve the pre-profile shared-provider behaviour.
1315
1493
  if (!sawEffectiveBinding) {
1316
- if (defaults?.backend === backendName && !instanceCredentialProfile(undefined, defaults, backendName))
1494
+ if (defaultBackend(defaults) === backendName && !instanceCredentialProfile(undefined, defaults, backendName))
1317
1495
  return true;
1318
1496
  return Object.keys(instances).length === 0;
1319
1497
  }
1320
1498
  return false;
1321
1499
  }
1500
+ /**
1501
+ * The backend an instance without one runs: the fleet default, else Claude Code — as the fleet launches it
1502
+ * (fleet-manager's bindings). Claude Code is the backend instances most often leave unnamed, so without this a
1503
+ * Claude profile on such an instance had no row of its own (#1699).
1504
+ */
1505
+ function defaultBackend(defaults) {
1506
+ return defaults?.backend ?? "claude-code";
1507
+ }
1322
1508
  /** Profiles on effective bindings only (not dormant backend_options on another backend). */
1323
1509
  function effectiveCredentialProfiles(config, backendName) {
1324
1510
  if (!config)
@@ -1326,14 +1512,14 @@ function effectiveCredentialProfiles(config, backendName) {
1326
1512
  const found = new Set();
1327
1513
  const defaults = config.defaults;
1328
1514
  for (const instance of Object.values(config.instances ?? {})) {
1329
- const backend = instance.backend ?? defaults?.backend;
1515
+ const backend = instance.backend ?? defaultBackend(defaults);
1330
1516
  if (backend !== backendName)
1331
1517
  continue;
1332
1518
  const profile = bindingProfile(instance, defaults, backendName);
1333
1519
  if (profile)
1334
1520
  found.add(profile);
1335
1521
  }
1336
- if (Object.keys(config.instances ?? {}).length === 0 && defaults?.backend === backendName) {
1522
+ if (Object.keys(config.instances ?? {}).length === 0 && defaultBackend(defaults) === backendName) {
1337
1523
  const profile = instanceCredentialProfile(undefined, defaults, backendName);
1338
1524
  if (profile)
1339
1525
  found.add(profile);
@@ -1387,6 +1573,8 @@ function usageBackendForProviderId(id) {
1387
1573
  return "kiro-cli";
1388
1574
  if (id === "codex")
1389
1575
  return "codex";
1576
+ if (id === "claude")
1577
+ return "claude-code";
1390
1578
  return null;
1391
1579
  }
1392
1580
  let PROVIDERS = DEFAULT_PROVIDERS;