@songsid/agend 2.1.5 → 2.1.6-beta.10

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 (184) hide show
  1. package/dist/agent-endpoint.d.ts +18 -0
  2. package/dist/agent-endpoint.js +53 -2
  3. package/dist/agent-endpoint.js.map +1 -1
  4. package/dist/apply-job.d.ts +114 -0
  5. package/dist/apply-job.js +214 -0
  6. package/dist/apply-job.js.map +1 -0
  7. package/dist/backend/claude-code.d.ts +25 -0
  8. package/dist/backend/claude-code.js +127 -0
  9. package/dist/backend/claude-code.js.map +1 -1
  10. package/dist/backend/codex.d.ts +57 -0
  11. package/dist/backend/codex.js +183 -0
  12. package/dist/backend/codex.js.map +1 -1
  13. package/dist/backend/credential-profile.d.ts +159 -0
  14. package/dist/backend/credential-profile.js +340 -0
  15. package/dist/backend/credential-profile.js.map +1 -0
  16. package/dist/backend/factory.js +4 -1
  17. package/dist/backend/factory.js.map +1 -1
  18. package/dist/backend/kiro-auth-store.d.ts +25 -0
  19. package/dist/backend/kiro-auth-store.js +61 -0
  20. package/dist/backend/kiro-auth-store.js.map +1 -0
  21. package/dist/backend/kiro.d.ts +8 -0
  22. package/dist/backend/kiro.js +31 -2
  23. package/dist/backend/kiro.js.map +1 -1
  24. package/dist/backend/muse.d.ts +90 -0
  25. package/dist/backend/muse.js +437 -0
  26. package/dist/backend/muse.js.map +1 -0
  27. package/dist/backend/types.d.ts +54 -0
  28. package/dist/backend/types.js.map +1 -1
  29. package/dist/channel/access-manager.d.ts +20 -0
  30. package/dist/channel/access-manager.js +25 -0
  31. package/dist/channel/access-manager.js.map +1 -1
  32. package/dist/channel/adapters/discord.d.ts +17 -0
  33. package/dist/channel/adapters/discord.js +72 -11
  34. package/dist/channel/adapters/discord.js.map +1 -1
  35. package/dist/channel/adapters/telegram.d.ts +6 -0
  36. package/dist/channel/adapters/telegram.js +36 -0
  37. package/dist/channel/adapters/telegram.js.map +1 -1
  38. package/dist/channel/markdown-chunk.d.ts +8 -3
  39. package/dist/channel/markdown-chunk.js +12 -3
  40. package/dist/channel/markdown-chunk.js.map +1 -1
  41. package/dist/channel/mcp-server.js +9 -12
  42. package/dist/channel/mcp-server.js.map +1 -1
  43. package/dist/channel/mcp-tools.d.ts +6 -2
  44. package/dist/channel/mcp-tools.js +6 -36
  45. package/dist/channel/mcp-tools.js.map +1 -1
  46. package/dist/channel/tool-router.js +32 -3
  47. package/dist/channel/tool-router.js.map +1 -1
  48. package/dist/channel/types.d.ts +18 -0
  49. package/dist/cli.js +113 -0
  50. package/dist/cli.js.map +1 -1
  51. package/dist/config-validator.js +45 -5
  52. package/dist/config-validator.js.map +1 -1
  53. package/dist/connection-secrets.d.ts +96 -0
  54. package/dist/connection-secrets.js +25 -0
  55. package/dist/connection-secrets.js.map +1 -0
  56. package/dist/daemon.d.ts +76 -0
  57. package/dist/daemon.js +489 -103
  58. package/dist/daemon.js.map +1 -1
  59. package/dist/event-log.d.ts +9 -0
  60. package/dist/event-log.js +21 -0
  61. package/dist/event-log.js.map +1 -1
  62. package/dist/fleet-level-config.d.ts +42 -0
  63. package/dist/fleet-level-config.js +78 -0
  64. package/dist/fleet-level-config.js.map +1 -0
  65. package/dist/fleet-lock.d.ts +21 -0
  66. package/dist/fleet-lock.js +42 -8
  67. package/dist/fleet-lock.js.map +1 -1
  68. package/dist/fleet-manager.d.ts +425 -2
  69. package/dist/fleet-manager.js +2055 -182
  70. package/dist/fleet-manager.js.map +1 -1
  71. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +145 -0
  72. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +11 -1
  73. package/dist/instance-config-impact.d.ts +55 -0
  74. package/dist/instance-config-impact.js +152 -0
  75. package/dist/instance-config-impact.js.map +1 -0
  76. package/dist/instance-lifecycle.js +8 -4
  77. package/dist/instance-lifecycle.js.map +1 -1
  78. package/dist/locale.js +24 -0
  79. package/dist/locale.js.map +1 -1
  80. package/dist/logger.js +42 -25
  81. package/dist/logger.js.map +1 -1
  82. package/dist/muse-usage-relay.d.ts +72 -0
  83. package/dist/muse-usage-relay.js +419 -0
  84. package/dist/muse-usage-relay.js.map +1 -0
  85. package/dist/outbound-handlers.d.ts +5 -1
  86. package/dist/outbound-handlers.js +199 -1
  87. package/dist/outbound-handlers.js.map +1 -1
  88. package/dist/outbound-schemas.d.ts +7 -5
  89. package/dist/outbound-schemas.js +3 -2
  90. package/dist/outbound-schemas.js.map +1 -1
  91. package/dist/provider-probe.d.ts +48 -0
  92. package/dist/provider-probe.js +121 -0
  93. package/dist/provider-probe.js.map +1 -0
  94. package/dist/provider-secret-registry.d.ts +98 -0
  95. package/dist/provider-secret-registry.js +334 -0
  96. package/dist/provider-secret-registry.js.map +1 -0
  97. package/dist/quickstart-api.d.ts +164 -0
  98. package/dist/quickstart-api.js +351 -0
  99. package/dist/quickstart-api.js.map +1 -0
  100. package/dist/quickstart.js +23 -50
  101. package/dist/quickstart.js.map +1 -1
  102. package/dist/scheduler/db.js +17 -5
  103. package/dist/scheduler/db.js.map +1 -1
  104. package/dist/scheduler/db.test.js +34 -1
  105. package/dist/scheduler/db.test.js.map +1 -1
  106. package/dist/scheduler/types.d.ts +4 -0
  107. package/dist/scheduler/types.js.map +1 -1
  108. package/dist/secret-store.d.ts +25 -0
  109. package/dist/secret-store.js +165 -0
  110. package/dist/secret-store.js.map +1 -0
  111. package/dist/self-restart-limit.d.ts +21 -0
  112. package/dist/self-restart-limit.js +129 -0
  113. package/dist/self-restart-limit.js.map +1 -0
  114. package/dist/settings-api.d.ts +116 -0
  115. package/dist/settings-api.js +530 -5
  116. package/dist/settings-api.js.map +1 -1
  117. package/dist/setup-auth.d.ts +113 -0
  118. package/dist/setup-auth.js +181 -0
  119. package/dist/setup-auth.js.map +1 -0
  120. package/dist/setup-form.d.ts +18 -0
  121. package/dist/setup-form.js +315 -0
  122. package/dist/setup-form.js.map +1 -0
  123. package/dist/setup-host.d.ts +162 -0
  124. package/dist/setup-host.js +496 -0
  125. package/dist/setup-host.js.map +1 -0
  126. package/dist/setup-marker.d.ts +8 -0
  127. package/dist/setup-marker.js +39 -0
  128. package/dist/setup-marker.js.map +1 -0
  129. package/dist/setup-tunnel-consent.d.ts +53 -0
  130. package/dist/setup-tunnel-consent.js +82 -0
  131. package/dist/setup-tunnel-consent.js.map +1 -0
  132. package/dist/setup-wizard.js +4 -0
  133. package/dist/setup-wizard.js.map +1 -1
  134. package/dist/steer-capability.js +4 -1
  135. package/dist/steer-capability.js.map +1 -1
  136. package/dist/tips.js +1 -1
  137. package/dist/tips.js.map +1 -1
  138. package/dist/tmux-manager.js +29 -4
  139. package/dist/tmux-manager.js.map +1 -1
  140. package/dist/tool-permissions-notice.d.ts +38 -0
  141. package/dist/tool-permissions-notice.js +92 -0
  142. package/dist/tool-permissions-notice.js.map +1 -0
  143. package/dist/tool-permissions.d.ts +120 -0
  144. package/dist/tool-permissions.js +277 -0
  145. package/dist/tool-permissions.js.map +1 -0
  146. package/dist/topic-commands.js +1 -0
  147. package/dist/topic-commands.js.map +1 -1
  148. package/dist/transcript-sources.d.ts +12 -1
  149. package/dist/transcript-sources.js +19 -3
  150. package/dist/transcript-sources.js.map +1 -1
  151. package/dist/tunnel/cloudflared.d.ts +71 -0
  152. package/dist/tunnel/cloudflared.js +447 -0
  153. package/dist/tunnel/cloudflared.js.map +1 -0
  154. package/dist/tunnel/lease.d.ts +75 -0
  155. package/dist/tunnel/lease.js +209 -0
  156. package/dist/tunnel/lease.js.map +1 -0
  157. package/dist/tunnel/manager.d.ts +56 -0
  158. package/dist/tunnel/manager.js +167 -0
  159. package/dist/tunnel/manager.js.map +1 -0
  160. package/dist/tunnel/types.d.ts +119 -0
  161. package/dist/tunnel/types.js +33 -0
  162. package/dist/tunnel/types.js.map +1 -0
  163. package/dist/types.d.ts +2 -0
  164. package/dist/ui/dashboard.html +4 -3
  165. package/dist/ui/settings.html +808 -156
  166. package/dist/ui/view.html +2 -2
  167. package/dist/usage/i18n-keys.d.ts +1 -1
  168. package/dist/usage/i18n-keys.js +1 -1
  169. package/dist/usage/i18n-keys.js.map +1 -1
  170. package/dist/usage/providers.d.ts +23 -14
  171. package/dist/usage/providers.js +220 -58
  172. package/dist/usage/providers.js.map +1 -1
  173. package/dist/usage/usage-api.d.ts +13 -0
  174. package/dist/usage/usage-api.js +69 -1
  175. package/dist/usage/usage-api.js.map +1 -1
  176. package/dist/web-api.js +8 -5
  177. package/dist/web-api.js.map +1 -1
  178. package/dist/web-auth.d.ts +75 -0
  179. package/dist/web-auth.js +208 -2
  180. package/dist/web-auth.js.map +1 -1
  181. package/dist/web-terminal.d.ts +30 -1
  182. package/dist/web-terminal.js +86 -3
  183. package/dist/web-terminal.js.map +1 -1
  184. package/package.json +2 -1
package/dist/ui/view.html CHANGED
@@ -211,7 +211,7 @@
211
211
  "usage.metric.overage_charges": "Overage charges", "usage.metric.pay_per_use": "Pay-per-use",
212
212
  "usage.metric.usage_monthly": "Usage (monthly)",
213
213
  "usage.unit.available": "available", "usage.unit.credits": "credits",
214
- "usage.value.disabled": "Disabled", "usage.value.cap": "{0} cap",
214
+ "usage.value.disabled": "Disabled", "usage.value.cap": "{0} cap", "usage.value.unlimited": "♾️ Unlimited",
215
215
  "usage.note.binding": "binding", "usage.note.binding_severity": "binding · {0}",
216
216
  "usage.note.busiest_model": "busiest of {0} model", "usage.note.busiest_models": "busiest of {0} models",
217
217
  "usage.note.used_limit_unit": "{0} / {1} {2}", "usage.note.bonus_codes": "{0} / {1} {2} · {3} codes",
@@ -274,7 +274,7 @@
274
274
  "usage.metric.overage_charges": "超額費用", "usage.metric.pay_per_use": "隨用隨付",
275
275
  "usage.metric.usage_monthly": "用量(每月)",
276
276
  "usage.unit.available": "可用", "usage.unit.credits": "額度",
277
- "usage.value.disabled": "已停用", "usage.value.cap": "上限 {0}",
277
+ "usage.value.disabled": "已停用", "usage.value.cap": "上限 {0}", "usage.value.unlimited": "♾️ 無限",
278
278
  "usage.note.binding": "生效", "usage.note.binding_severity": "生效 · {0}",
279
279
  "usage.note.busiest_model": "{0} 個模型中用量最高者", "usage.note.busiest_models": "{0} 個模型中用量最高者",
280
280
  "usage.note.used_limit_unit": "{0} / {1} {2}", "usage.note.bonus_codes": "{0} / {1} {2} · {3} 組代碼",
@@ -3,5 +3,5 @@
3
3
  * Keep this list explicit: the parity test rejects a key missing from either
4
4
  * locale surface before a mixed-language release can ship.
5
5
  */
6
- export declare const USAGE_I18N_KEYS: readonly ["usage.title", "usage.title_plain", "usage.empty_active", "usage.not_logged_in", "usage.error_fallback", "usage.no_data", "usage.reset.in", "usage.reset.soon", "usage.duration.days_hours", "usage.duration.hours_minutes", "usage.duration.minutes", "usage.metric.session", "usage.metric.weekly", "usage.metric.monthly", "usage.metric.days_window", "usage.metric.named", "usage.metric.named_session", "usage.metric.named_weekly", "usage.metric.named_monthly", "usage.metric.named_days", "usage.metric.extra_usage", "usage.metric.rate_limit_resets", "usage.metric.credits", "usage.metric.weekly_limit", "usage.metric.pay_as_you_go", "usage.metric.bonus_credits", "usage.metric.overage_charges", "usage.metric.pay_per_use", "usage.unit.available", "usage.unit.credits", "usage.metric.usage_monthly", "usage.note.used_limit_unit", "usage.note.bonus_codes", "usage.value.disabled", "usage.value.cap", "usage.note.binding", "usage.note.binding_severity", "usage.note.busiest_model", "usage.note.busiest_models", "usage.metric.agy_claude_others", "usage.metric.agy_claude_others_session", "usage.metric.agy_claude_others_weekly", "usage.hint.statusline_now", "usage.hint.statusline_minutes", "usage.hint.claude_api_key", "usage.hint.login_claude", "usage.hint.login_agy", "usage.hint.no_quota", "usage.hint.login_codex", "usage.hint.codex_no_oauth", "usage.hint.login_grok", "usage.hint.grok_no_login", "usage.hint.login_kiro", "usage.hint.kiro_signed_out", "usage.hint.token_refreshing", "usage.hint.subscription_no_credit", "usage.hint.no_quota_account", "usage.error.unreachable", "usage.error.token_rejected", "usage.error.rate_limited", "usage.error.http", "usage.error.billing_http", "usage.error.invalid_response", "usage.error.invalid_billing_response", "usage.error.invalid_kiro_response", "usage.error.claude_token_expired", "usage.error.codex_token_expired", "usage.error.grok_expired", "usage.error.grok_response_changed", "usage.error.agy_cap", "usage.error.agy_no_refresh", "usage.error.agy_token_expired", "usage.error.agy_login_expired", "usage.error.agy_refresh_empty", "usage.error.grok_auth_readonly", "usage.error.grok_no_refresh", "usage.error.grok_refresh_unreachable", "usage.error.grok_invalid_refresh", "usage.error.grok_persist"];
6
+ export declare const USAGE_I18N_KEYS: readonly ["usage.title", "usage.title_plain", "usage.empty_active", "usage.not_logged_in", "usage.error_fallback", "usage.no_data", "usage.reset.in", "usage.reset.soon", "usage.duration.days_hours", "usage.duration.hours_minutes", "usage.duration.minutes", "usage.metric.session", "usage.metric.weekly", "usage.metric.monthly", "usage.metric.days_window", "usage.metric.named", "usage.metric.named_session", "usage.metric.named_weekly", "usage.metric.named_monthly", "usage.metric.named_days", "usage.metric.extra_usage", "usage.metric.rate_limit_resets", "usage.metric.credits", "usage.metric.weekly_limit", "usage.metric.pay_as_you_go", "usage.metric.bonus_credits", "usage.metric.overage_charges", "usage.metric.pay_per_use", "usage.unit.available", "usage.unit.credits", "usage.metric.usage_monthly", "usage.note.used_limit_unit", "usage.note.bonus_codes", "usage.value.disabled", "usage.value.cap", "usage.value.unlimited", "usage.note.binding", "usage.note.binding_severity", "usage.note.busiest_model", "usage.note.busiest_models", "usage.metric.agy_claude_others", "usage.metric.agy_claude_others_session", "usage.metric.agy_claude_others_weekly", "usage.hint.statusline_now", "usage.hint.statusline_minutes", "usage.hint.claude_api_key", "usage.hint.login_claude", "usage.hint.login_agy", "usage.hint.no_quota", "usage.hint.login_codex", "usage.hint.codex_no_oauth", "usage.hint.login_grok", "usage.hint.grok_no_login", "usage.hint.login_kiro", "usage.hint.kiro_signed_out", "usage.hint.token_refreshing", "usage.hint.subscription_no_credit", "usage.hint.no_quota_account", "usage.error.unreachable", "usage.error.token_rejected", "usage.error.rate_limited", "usage.error.http", "usage.error.billing_http", "usage.error.invalid_response", "usage.error.invalid_billing_response", "usage.error.invalid_kiro_response", "usage.error.claude_token_expired", "usage.error.codex_token_expired", "usage.error.grok_expired", "usage.error.grok_response_changed", "usage.error.agy_cap", "usage.error.agy_no_refresh", "usage.error.agy_token_expired", "usage.error.agy_login_expired", "usage.error.agy_refresh_empty", "usage.error.grok_auth_readonly", "usage.error.grok_no_refresh", "usage.error.grok_refresh_unreachable", "usage.error.grok_invalid_refresh", "usage.error.grok_persist"];
7
7
  export type UsageI18nKey = typeof USAGE_I18N_KEYS[number];
@@ -14,7 +14,7 @@ export const USAGE_I18N_KEYS = [
14
14
  "usage.metric.pay_as_you_go", "usage.metric.bonus_credits", "usage.metric.overage_charges",
15
15
  "usage.metric.pay_per_use", "usage.unit.available", "usage.unit.credits",
16
16
  "usage.metric.usage_monthly", "usage.note.used_limit_unit", "usage.note.bonus_codes",
17
- "usage.value.disabled", "usage.value.cap", "usage.note.binding",
17
+ "usage.value.disabled", "usage.value.cap", "usage.value.unlimited", "usage.note.binding",
18
18
  "usage.note.binding_severity", "usage.note.busiest_model", "usage.note.busiest_models",
19
19
  "usage.metric.agy_claude_others", "usage.metric.agy_claude_others_session", "usage.metric.agy_claude_others_weekly",
20
20
  "usage.hint.statusline_now", "usage.hint.statusline_minutes", "usage.hint.claude_api_key",
@@ -1 +1 @@
1
- {"version":3,"file":"i18n-keys.js","sourceRoot":"","sources":["../../src/usage/i18n-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,qBAAqB;IAC/E,sBAAsB,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB;IAC7E,2BAA2B,EAAE,8BAA8B,EAAE,wBAAwB;IACrF,sBAAsB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,0BAA0B;IACjG,oBAAoB,EAAE,4BAA4B,EAAE,2BAA2B;IAC/E,4BAA4B,EAAE,yBAAyB,EAAE,0BAA0B;IACnF,gCAAgC,EAAE,sBAAsB,EAAE,2BAA2B;IACrF,4BAA4B,EAAE,4BAA4B,EAAE,8BAA8B;IAC1F,0BAA0B,EAAE,sBAAsB,EAAE,oBAAoB;IACxE,4BAA4B,EAAE,4BAA4B,EAAE,wBAAwB;IACpF,sBAAsB,EAAE,iBAAiB,EAAE,oBAAoB;IAC/D,6BAA6B,EAAE,0BAA0B,EAAE,2BAA2B;IACtF,gCAAgC,EAAE,wCAAwC,EAAE,uCAAuC;IACnH,2BAA2B,EAAE,+BAA+B,EAAE,2BAA2B;IACzF,yBAAyB,EAAE,sBAAsB,EAAE,qBAAqB;IACxE,wBAAwB,EAAE,2BAA2B,EAAE,uBAAuB;IAC9E,0BAA0B,EAAE,uBAAuB,EAAE,4BAA4B;IACjF,6BAA6B,EAAE,mCAAmC,EAAE,6BAA6B;IACjG,yBAAyB,EAAE,4BAA4B,EAAE,0BAA0B;IACnF,kBAAkB,EAAE,0BAA0B,EAAE,8BAA8B;IAC9E,sCAAsC,EAAE,mCAAmC;IAC3E,kCAAkC,EAAE,iCAAiC;IACrE,0BAA0B,EAAE,mCAAmC,EAAE,qBAAqB;IACtF,4BAA4B,EAAE,+BAA+B,EAAE,+BAA+B;IAC9F,+BAA+B,EAAE,gCAAgC,EAAE,6BAA6B;IAChG,sCAAsC,EAAE,kCAAkC,EAAE,0BAA0B;CAC9F,CAAC"}
1
+ {"version":3,"file":"i18n-keys.js","sourceRoot":"","sources":["../../src/usage/i18n-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,aAAa,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,qBAAqB;IAC/E,sBAAsB,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB;IAC7E,2BAA2B,EAAE,8BAA8B,EAAE,wBAAwB;IACrF,sBAAsB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,0BAA0B;IACjG,oBAAoB,EAAE,4BAA4B,EAAE,2BAA2B;IAC/E,4BAA4B,EAAE,yBAAyB,EAAE,0BAA0B;IACnF,gCAAgC,EAAE,sBAAsB,EAAE,2BAA2B;IACrF,4BAA4B,EAAE,4BAA4B,EAAE,8BAA8B;IAC1F,0BAA0B,EAAE,sBAAsB,EAAE,oBAAoB;IACxE,4BAA4B,EAAE,4BAA4B,EAAE,wBAAwB;IACpF,sBAAsB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,oBAAoB;IACxF,6BAA6B,EAAE,0BAA0B,EAAE,2BAA2B;IACtF,gCAAgC,EAAE,wCAAwC,EAAE,uCAAuC;IACnH,2BAA2B,EAAE,+BAA+B,EAAE,2BAA2B;IACzF,yBAAyB,EAAE,sBAAsB,EAAE,qBAAqB;IACxE,wBAAwB,EAAE,2BAA2B,EAAE,uBAAuB;IAC9E,0BAA0B,EAAE,uBAAuB,EAAE,4BAA4B;IACjF,6BAA6B,EAAE,mCAAmC,EAAE,6BAA6B;IACjG,yBAAyB,EAAE,4BAA4B,EAAE,0BAA0B;IACnF,kBAAkB,EAAE,0BAA0B,EAAE,8BAA8B;IAC9E,sCAAsC,EAAE,mCAAmC;IAC3E,kCAAkC,EAAE,iCAAiC;IACrE,0BAA0B,EAAE,mCAAmC,EAAE,qBAAqB;IACtF,4BAA4B,EAAE,+BAA+B,EAAE,+BAA+B;IAC9F,+BAA+B,EAAE,gCAAgC,EAAE,6BAA6B;IAChG,sCAAsC,EAAE,kCAAkC,EAAE,0BAA0B;CAC9F,CAAC"}
@@ -1,3 +1,5 @@
1
+ import { listConfiguredProfiles } from "../backend/credential-profile.js";
2
+ import { type KiroStoredToken } from "../backend/kiro-auth-store.js";
1
3
  import { type StatuslineRateLimits } from "./statusline-usage.js";
2
4
  import type { UsageI18nKey } from "./i18n-keys.js";
3
5
  export interface UsageMetric {
@@ -22,6 +24,8 @@ export interface ProviderUsage {
22
24
  id: string;
23
25
  name: string;
24
26
  status: "ok" | "error" | "no-credentials";
27
+ /** A non-metered subscription whose entitlement is unlimited (not 0/100%). */
28
+ unlimited?: boolean;
25
29
  plan?: string | null;
26
30
  error?: string;
27
31
  errorI18n?: UsageI18nRef;
@@ -118,17 +122,8 @@ interface AgyStoredToken {
118
122
  * uses) is read alongside `expiry` (RFC3339) for the same reason.
119
123
  */
120
124
  export declare function readAgyToken(file: unknown): AgyStoredToken;
121
- export declare function fetchCodexUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
122
- interface KiroToken {
123
- access_token?: string;
124
- expires_at?: string;
125
- region?: string;
126
- profile_arn?: string;
127
- /** IAM Identity Center portal URL — present only for Q Developer Pro logins. */
128
- start_url?: string;
129
- /** Social login provider (google/github/…) — present only for free-tier logins. */
130
- provider?: string;
131
- }
125
+ export declare function fetchCodexUsage(storeHome?: string): Promise<Omit<ProviderUsage, "id" | "name">>;
126
+ type KiroToken = KiroStoredToken;
132
127
  /**
133
128
  * Which Kiro login is in use. Verified against a real kiro-cli auth store:
134
129
  * - IAM Identity Center (Amazon Q Developer Pro) tokens carry `start_url`
@@ -141,12 +136,26 @@ interface KiroToken {
141
136
  export type KiroAuthKind = "q-developer-pro" | "builder-id";
142
137
  export declare function kiroAuthKind(token: KiroToken): KiroAuthKind;
143
138
  /** Exported for tests: the Q-Pro and expired paths return without any network call. */
144
- export declare function fetchKiroUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
139
+ export declare function fetchKiroUsage(storeHome?: string): Promise<Omit<ProviderUsage, "id" | "name">>;
145
140
  type UsageProvider = {
146
141
  id: string;
147
142
  name: string;
148
- fetch: () => Promise<Omit<ProviderUsage, "id" | "name">>;
143
+ fetch: (storeHome?: string) => Promise<Omit<ProviderUsage, "id" | "name">>;
149
144
  };
145
+ type UsageFleetConfig = Parameters<typeof listConfiguredProfiles>[0];
146
+ /** Read the daemon-written, token-free Muse relay snapshot for active Muse instances. */
147
+ export declare function fetchMuseUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
148
+ /**
149
+ * One row per subscription, not one row per backend.
150
+ *
151
+ * A fleet running two kiro/codex logins has two quotas, and a single row could
152
+ * only ever show one of them — or worse, add them together and show a number
153
+ * that is true of neither. Each effective credential profile reads its own
154
+ * store and gets its own row; a mixed fleet also keeps one row for effective
155
+ * legacy shared bindings. Instance-private homes are never scanned: their
156
+ * auth files point at these same logical sources.
157
+ */
158
+ export declare function providersForConfig(config: UsageFleetConfig, base?: UsageProvider[]): UsageProvider[];
150
159
  /** Test seam: a provider that hangs cannot be simulated with real vendors. */
151
160
  export declare function setUsageProvidersForTests(providers: UsageProvider[] | null): void;
152
161
  /**
@@ -183,7 +192,7 @@ export declare const LONGEST_SINGLE_FETCH_MS = 15000;
183
192
  export declare function setUsageProviderDeadlineForTests(ms: number | null): void;
184
193
  /** Fetch every provider in parallel. Providers without local credentials are
185
194
  * skipped (per the panel's contract: absent CLIs simply don't show). */
186
- export declare function fetchAllUsage(): Promise<{
195
+ export declare function fetchAllUsage(config?: Parameters<typeof listConfiguredProfiles>[0]): Promise<{
187
196
  fetchedAt: string;
188
197
  providers: ProviderUsage[];
189
198
  }>;
@@ -19,12 +19,16 @@
19
19
  * refresh at all when the file isn't writable, rather than risk the login.
20
20
  */
21
21
  import { readFile, writeFile, access, constants } from "node:fs/promises";
22
- import { readFileSync } from "node:fs";
22
+ import { readFileSync, readdirSync } from "node:fs";
23
23
  import { join } from "node:path";
24
+ import { getAgendHome } from "../paths.js";
25
+ import { loadFleetConfig } from "../config.js";
26
+ import { credentialHomeSpec, credentialProfileStoreHome, instanceCredentialProfile, } from "../backend/credential-profile.js";
27
+ import { readKiroAuthTokens } from "../backend/kiro-auth-store.js";
24
28
  import { homedir } from "node:os";
25
29
  import { getProviderRateLimit } from "./provider-alerts.js";
30
+ import { readMuseUsageSnapshot } from "../muse-usage-relay.js";
26
31
  import { readStatuslineRateLimits, } from "./statusline-usage.js";
27
- import Database from "better-sqlite3";
28
32
  const i18n = (key, ...args) => args.length ? { key, args } : { key };
29
33
  const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
30
34
  const SESSION_MS = 5 * 60 * 60 * 1000;
@@ -654,8 +658,10 @@ function codexPlan(planType) {
654
658
  default: return planType.trim().split("_").map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
655
659
  }
656
660
  }
657
- export async function fetchCodexUsage() {
658
- const home = process.env.CODEX_HOME || join(homedir(), ".codex");
661
+ export async function fetchCodexUsage(storeHome) {
662
+ // A credential profile owns its own auth.json; without one this is the shared
663
+ // login, exactly as before.
664
+ const home = storeHome ?? process.env.CODEX_HOME ?? join(homedir(), ".codex");
659
665
  let auth;
660
666
  try {
661
667
  auth = JSON.parse(await readFile(join(home, "auth.json"), "utf8"));
@@ -931,56 +937,31 @@ export function kiroAuthKind(token) {
931
937
  * case where the provider should vanish from the panel. `missing` means kiro-cli
932
938
  * IS installed but no login we recognise is stored: a real state the user needs
933
939
  * to see, not a reason to hide the row.
940
+ *
941
+ * A credential profile can only ever be `missing`, never `notInstalled`: the
942
+ * profile exists because the fleet configured it, so the CLI is demonstrably
943
+ * here and the absent store means *this subscription* has never been logged in.
944
+ * That is the one thing the user must see — running two subscriptions, the one
945
+ * you still have to log into is precisely the row that must not disappear.
934
946
  */
935
- function readKiroToken() {
936
- const home = process.env.KIRO_CLI_HOME || join(homedir(), ".local", "share", "kiro-cli");
937
- let db;
938
- try {
939
- db = new Database(join(home, "data.sqlite3"), { readonly: true, fileMustExist: true });
940
- }
941
- catch {
942
- return { notInstalled: true };
943
- }
944
- try {
945
- // Read every token-shaped row rather than a fixed pair of keys: kiro names
946
- // its auth rows per login type (`kirocli:social:token`,
947
- // `codewhisperer:odic:token`, …), and an unlisted one used to read as
948
- // "not logged in" — which then removed Kiro from the panel entirely.
949
- const rows = db.prepare("SELECT key, value FROM auth_kv WHERE key LIKE '%:token'").all();
950
- const parse = (raw) => {
951
- if (!raw)
952
- return null;
953
- try {
954
- const t = JSON.parse(raw);
955
- return t.access_token ? t : null;
956
- }
957
- catch {
958
- return null;
959
- }
960
- };
961
- const candidates = rows
962
- .map(r => parse(r.value))
963
- .filter((t) => t !== null);
964
- if (candidates.length === 0)
965
- return { missing: true };
966
- // Switching login type leaves the old token behind, so "first key wins"
967
- // could report a stale account. Prefer a token that has not expired, then
968
- // the one that expires latest.
969
- const expiry = (t) => (t.expires_at ? new Date(t.expires_at).getTime() : 0);
970
- const now = Date.now();
971
- const live = candidates.filter(t => expiry(t) > now);
972
- const token = (live.length ? live : candidates).sort((a, b) => expiry(b) - expiry(a))[0];
973
- return { token, kind: kiroAuthKind(token) };
974
- }
975
- catch {
947
+ function readKiroToken(storeHome) {
948
+ // A credential profile keeps its own store; without one this is the shared
949
+ // login, exactly as before.
950
+ const home = storeHome ?? process.env.KIRO_CLI_HOME ?? join(homedir(), ".local", "share", "kiro-cli");
951
+ const read = readKiroAuthTokens(home);
952
+ if (read.kind === "no-store")
953
+ return storeHome ? { missing: true } : { notInstalled: true };
954
+ const candidates = read.tokens;
955
+ if (candidates.length === 0)
976
956
  return { missing: true };
977
- }
978
- finally {
979
- try {
980
- db.close();
981
- }
982
- catch { /* best-effort */ }
983
- }
957
+ // Switching login type leaves the old token behind, so "first key wins"
958
+ // could report a stale account. Prefer a token that has not expired, then
959
+ // the one that expires latest.
960
+ const expiry = (t) => (t.expires_at ? new Date(t.expires_at).getTime() : 0);
961
+ const now = Date.now();
962
+ const live = candidates.filter(t => expiry(t) > now);
963
+ const token = (live.length ? live : candidates).sort((a, b) => expiry(b) - expiry(a))[0];
964
+ return { token, kind: kiroAuthKind(token) };
984
965
  }
985
966
  function kiroTitleCase(s) {
986
967
  return s.toLowerCase().replace(/(^|\s)\S/g, c => c.toUpperCase());
@@ -991,8 +972,8 @@ function kiroEpochIso(sec) {
991
972
  : null;
992
973
  }
993
974
  /** Exported for tests: the Q-Pro and expired paths return without any network call. */
994
- export async function fetchKiroUsage() {
995
- const { token, kind, missing, notInstalled } = readKiroToken();
975
+ export async function fetchKiroUsage(storeHome) {
976
+ const { token, kind, missing, notInstalled } = readKiroToken(storeHome);
996
977
  if (notInstalled) {
997
978
  // The one case that should disappear from the panel: kiro-cli isn't here.
998
979
  return { status: "no-credentials", hint: "Log in with the Kiro CLI (`kiro-cli`).", hintI18n: i18n("usage.hint.login_kiro"), metrics: [] };
@@ -1016,8 +997,9 @@ export async function fetchKiroUsage() {
1016
997
  return {
1017
998
  status: "ok",
1018
999
  plan: "Q Developer Pro",
1019
- hint: "Subscription — no credit usage to report.",
1020
- hintI18n: i18n("usage.hint.subscription_no_credit"),
1000
+ unlimited: true,
1001
+ hint: "♾️ Unlimited",
1002
+ hintI18n: i18n("usage.value.unlimited"),
1021
1003
  metrics: [],
1022
1004
  };
1023
1005
  }
@@ -1112,10 +1094,185 @@ export async function fetchKiroUsage() {
1112
1094
  const DEFAULT_PROVIDERS = [
1113
1095
  { id: "claude", name: "Claude", fetch: fetchClaudeUsage },
1114
1096
  { id: "codex", name: "Codex", fetch: fetchCodexUsage },
1097
+ { id: "muse", name: "Muse", fetch: fetchMuseUsage },
1115
1098
  { id: "grok", name: "Grok", fetch: fetchGrokUsage },
1116
1099
  { id: "kiro", name: "Kiro", fetch: fetchKiroUsage },
1117
1100
  { id: "antigravity", name: "Antigravity", fetch: fetchAntigravityUsage },
1118
1101
  ];
1102
+ const MUSE_SESSION_MS = 5 * 60 * 60 * 1000;
1103
+ /** Read the daemon-written, token-free Muse relay snapshot for active Muse instances. */
1104
+ export async function fetchMuseUsage() {
1105
+ let config = null;
1106
+ try {
1107
+ config = loadFleetConfig(join(getAgendHome(), "fleet.yaml"));
1108
+ }
1109
+ catch { /* unavailable config is an honest empty row */ }
1110
+ const instanceRoot = join(getAgendHome(), "instances");
1111
+ const configuredMuseNames = Object.entries(config?.instances ?? {})
1112
+ .filter(([, instance]) => (instance.backend ?? config?.defaults?.backend) === "muse")
1113
+ .map(([name]) => name);
1114
+ // Classic channels may own an instance that is not present in fleet.yaml.
1115
+ // Reading only daemon-written, token-free state files is not credential
1116
+ // discovery and keeps the usage row useful for those instances too.
1117
+ let stateNames = configuredMuseNames;
1118
+ try {
1119
+ const names = readdirSync(instanceRoot, { withFileTypes: true })
1120
+ .filter(entry => entry.isDirectory())
1121
+ .map(entry => entry.name);
1122
+ stateNames = [...new Set([...configuredMuseNames, ...names])];
1123
+ }
1124
+ catch { /* no instances directory yet */ }
1125
+ const snapshots = stateNames
1126
+ .map(name => readMuseUsageSnapshot(join(instanceRoot, name)))
1127
+ .filter((snapshot) => snapshot !== null)
1128
+ .sort((a, b) => b.observedAt - a.observedAt);
1129
+ const snapshot = snapshots[0];
1130
+ if (!snapshot) {
1131
+ return { status: "ok", plan: "Subscription", hint: "Muse usage unavailable — no response frame observed.", metrics: [] };
1132
+ }
1133
+ const metric = (label, window, windowMs) => {
1134
+ if (!window)
1135
+ return null;
1136
+ return {
1137
+ label,
1138
+ type: "percent",
1139
+ used: window.usedPercent,
1140
+ resetsAt: new Date(window.resetsAt * 1000).toISOString(),
1141
+ windowMs: window.windowMs ?? windowMs,
1142
+ };
1143
+ };
1144
+ const metrics = [
1145
+ metric("Session", snapshot.session, MUSE_SESSION_MS),
1146
+ metric("Weekly", snapshot.weekly, WEEK_MS),
1147
+ ].filter((m) => m !== null);
1148
+ return {
1149
+ status: "ok",
1150
+ plan: snapshot.plan || "Subscription",
1151
+ hint: metrics.length ? undefined : "Muse usage unavailable — no response frame observed.",
1152
+ metrics,
1153
+ };
1154
+ }
1155
+ /**
1156
+ * One row per subscription, not one row per backend.
1157
+ *
1158
+ * A fleet running two kiro/codex logins has two quotas, and a single row could
1159
+ * only ever show one of them — or worse, add them together and show a number
1160
+ * that is true of neither. Each effective credential profile reads its own
1161
+ * store and gets its own row; a mixed fleet also keeps one row for effective
1162
+ * legacy shared bindings. Instance-private homes are never scanned: their
1163
+ * auth files point at these same logical sources.
1164
+ */
1165
+ export function providersForConfig(config, base = DEFAULT_PROVIDERS) {
1166
+ return base.flatMap(provider => {
1167
+ const backendName = usageBackendForProviderId(provider.id);
1168
+ if (!backendName || !credentialHomeSpec(backendName))
1169
+ return [provider];
1170
+ const profiles = effectiveCredentialProfiles(config, backendName);
1171
+ if (profiles.length === 0)
1172
+ return [provider];
1173
+ // A fleet can mix profiled and legacy instances. The old expansion
1174
+ // returned only profile rows whenever *any* profile existed, which hid the
1175
+ // shared subscription from a running legacy instance. Include the shared
1176
+ // source only when an effective binding actually uses it; active-provider
1177
+ // filtering then removes sources that are stopped or otherwise unused.
1178
+ const rows = [];
1179
+ // Classic channels are stored separately from fleet.yaml and always use
1180
+ // the shared Codex login today. Keep the shared Codex row available so
1181
+ // active-provider filtering can retain that binding; unlike filesystem
1182
+ // scanning this row is harmless when no classic/shared instance is live.
1183
+ if (provider.id === "codex" || hasEffectiveSharedBinding(config, backendName)) {
1184
+ rows.push({
1185
+ id: provider.id,
1186
+ name: provider.id === "codex" ? `${provider.name} (default)` : provider.name,
1187
+ fetch: () => provider.fetch(),
1188
+ });
1189
+ }
1190
+ rows.push(...profiles.map(profile => ({
1191
+ id: `${provider.id}:${profile}`,
1192
+ name: `${provider.name} (${profile})`,
1193
+ fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile)),
1194
+ })));
1195
+ return rows;
1196
+ });
1197
+ }
1198
+ /**
1199
+ * Whether at least one effective fleet binding uses the legacy shared login.
1200
+ *
1201
+ * This deliberately follows effective backend/profile inheritance instead of
1202
+ * looking at directories on disk. Instance-private Codex homes are config
1203
+ * homes whose auth file points at this same shared/profile source; scanning
1204
+ * them would duplicate one quota and make usage depend on stale instance
1205
+ * directories. A missing/unknown config keeps the legacy shared row for
1206
+ * backwards compatibility.
1207
+ */
1208
+ function hasEffectiveSharedBinding(config, backendName) {
1209
+ if (!config)
1210
+ return true;
1211
+ const defaults = config.defaults;
1212
+ const instances = config.instances ?? {};
1213
+ let sawEffectiveBinding = false;
1214
+ for (const instance of Object.values(instances)) {
1215
+ const backend = instance.backend ?? defaults?.backend;
1216
+ if (backend !== backendName)
1217
+ continue;
1218
+ sawEffectiveBinding = true;
1219
+ if (!instanceCredentialProfile(instance, defaults, backendName))
1220
+ return true;
1221
+ }
1222
+ // A defaults-only fleet has one effective shared binding when the default
1223
+ // backend is this provider and no profile was configured. With no known
1224
+ // binding at all, preserve the pre-profile shared-provider behaviour.
1225
+ if (!sawEffectiveBinding) {
1226
+ if (defaults?.backend === backendName && !instanceCredentialProfile(undefined, defaults, backendName))
1227
+ return true;
1228
+ return Object.keys(instances).length === 0;
1229
+ }
1230
+ return false;
1231
+ }
1232
+ /** Profiles on effective bindings only (not dormant backend_options on another backend). */
1233
+ function effectiveCredentialProfiles(config, backendName) {
1234
+ if (!config)
1235
+ return [];
1236
+ const found = new Set();
1237
+ const defaults = config.defaults;
1238
+ for (const instance of Object.values(config.instances ?? {})) {
1239
+ const backend = instance.backend ?? defaults?.backend;
1240
+ if (backend !== backendName)
1241
+ continue;
1242
+ const profile = instanceCredentialProfile(instance, defaults, backendName);
1243
+ if (profile)
1244
+ found.add(profile);
1245
+ }
1246
+ if (Object.keys(config.instances ?? {}).length === 0 && defaults?.backend === backendName) {
1247
+ const profile = instanceCredentialProfile(undefined, defaults, backendName);
1248
+ if (profile)
1249
+ found.add(profile);
1250
+ }
1251
+ return [...found].sort();
1252
+ }
1253
+ /**
1254
+ * The fleet configuration, for working out which subscriptions exist.
1255
+ *
1256
+ * Usage runs in the fleet process and in the CLI, and it is never worth failing
1257
+ * a usage snapshot over an unreadable config — no config simply means no
1258
+ * profiles, which is the behaviour every fleet had before profiles existed.
1259
+ */
1260
+ function readFleetConfigForUsage() {
1261
+ try {
1262
+ return loadFleetConfig(join(getAgendHome(), "fleet.yaml"));
1263
+ }
1264
+ catch {
1265
+ return null;
1266
+ }
1267
+ }
1268
+ /** The backend a usage row reads its credentials from. */
1269
+ function usageBackendForProviderId(id) {
1270
+ if (id === "kiro")
1271
+ return "kiro-cli";
1272
+ if (id === "codex")
1273
+ return "codex";
1274
+ return null;
1275
+ }
1119
1276
  let PROVIDERS = DEFAULT_PROVIDERS;
1120
1277
  /** Test seam: a provider that hangs cannot be simulated with real vendors. */
1121
1278
  export function setUsageProvidersForTests(providers) {
@@ -1174,8 +1331,13 @@ async function withDeadline(work, ms) {
1174
1331
  }
1175
1332
  /** Fetch every provider in parallel. Providers without local credentials are
1176
1333
  * skipped (per the panel's contract: absent CLIs simply don't show). */
1177
- export async function fetchAllUsage() {
1178
- const results = await Promise.all(PROVIDERS.map(async (p) => {
1334
+ export async function fetchAllUsage(config) {
1335
+ // Expanded per call: a profile added through Settings or General should show
1336
+ // up on the next snapshot, not on the next restart. Callers that already hold
1337
+ // the config pass it; the rest get it read here, behind the same five-minute
1338
+ // cache as the snapshot itself.
1339
+ const providers = providersForConfig(config === undefined ? readFleetConfigForUsage() : config, PROVIDERS);
1340
+ const results = await Promise.all(providers.map(async (p) => {
1179
1341
  try {
1180
1342
  const outcome = await withDeadline(p.fetch(), providerDeadlineMs);
1181
1343
  if (outcome === DEADLINE_EXCEEDED) {