@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.
- package/dist/agent-endpoint.d.ts +18 -0
- package/dist/agent-endpoint.js +53 -2
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/apply-job.d.ts +114 -0
- package/dist/apply-job.js +214 -0
- package/dist/apply-job.js.map +1 -0
- package/dist/backend/claude-code.d.ts +25 -0
- package/dist/backend/claude-code.js +127 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +57 -0
- package/dist/backend/codex.js +183 -0
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +159 -0
- package/dist/backend/credential-profile.js +340 -0
- package/dist/backend/credential-profile.js.map +1 -0
- package/dist/backend/factory.js +4 -1
- package/dist/backend/factory.js.map +1 -1
- package/dist/backend/kiro-auth-store.d.ts +25 -0
- package/dist/backend/kiro-auth-store.js +61 -0
- package/dist/backend/kiro-auth-store.js.map +1 -0
- package/dist/backend/kiro.d.ts +8 -0
- package/dist/backend/kiro.js +31 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.d.ts +90 -0
- package/dist/backend/muse.js +437 -0
- package/dist/backend/muse.js.map +1 -0
- package/dist/backend/types.d.ts +54 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/access-manager.d.ts +20 -0
- package/dist/channel/access-manager.js +25 -0
- package/dist/channel/access-manager.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +17 -0
- package/dist/channel/adapters/discord.js +72 -11
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -0
- package/dist/channel/adapters/telegram.js +36 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/markdown-chunk.d.ts +8 -3
- package/dist/channel/markdown-chunk.js +12 -3
- package/dist/channel/markdown-chunk.js.map +1 -1
- package/dist/channel/mcp-server.js +9 -12
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +6 -2
- package/dist/channel/mcp-tools.js +6 -36
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.js +32 -3
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +18 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +45 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/connection-secrets.d.ts +96 -0
- package/dist/connection-secrets.js +25 -0
- package/dist/connection-secrets.js.map +1 -0
- package/dist/daemon.d.ts +76 -0
- package/dist/daemon.js +489 -103
- package/dist/daemon.js.map +1 -1
- package/dist/event-log.d.ts +9 -0
- package/dist/event-log.js +21 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-level-config.d.ts +42 -0
- package/dist/fleet-level-config.js +78 -0
- package/dist/fleet-level-config.js.map +1 -0
- package/dist/fleet-lock.d.ts +21 -0
- package/dist/fleet-lock.js +42 -8
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +425 -2
- package/dist/fleet-manager.js +2055 -182
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +145 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +11 -1
- package/dist/instance-config-impact.d.ts +55 -0
- package/dist/instance-config-impact.js +152 -0
- package/dist/instance-config-impact.js.map +1 -0
- package/dist/instance-lifecycle.js +8 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +24 -0
- package/dist/locale.js.map +1 -1
- package/dist/logger.js +42 -25
- package/dist/logger.js.map +1 -1
- package/dist/muse-usage-relay.d.ts +72 -0
- package/dist/muse-usage-relay.js +419 -0
- package/dist/muse-usage-relay.js.map +1 -0
- package/dist/outbound-handlers.d.ts +5 -1
- package/dist/outbound-handlers.js +199 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +7 -5
- package/dist/outbound-schemas.js +3 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +48 -0
- package/dist/provider-probe.js +121 -0
- package/dist/provider-probe.js.map +1 -0
- package/dist/provider-secret-registry.d.ts +98 -0
- package/dist/provider-secret-registry.js +334 -0
- package/dist/provider-secret-registry.js.map +1 -0
- package/dist/quickstart-api.d.ts +164 -0
- package/dist/quickstart-api.js +351 -0
- package/dist/quickstart-api.js.map +1 -0
- package/dist/quickstart.js +23 -50
- package/dist/quickstart.js.map +1 -1
- package/dist/scheduler/db.js +17 -5
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/db.test.js +34 -1
- package/dist/scheduler/db.test.js.map +1 -1
- package/dist/scheduler/types.d.ts +4 -0
- package/dist/scheduler/types.js.map +1 -1
- package/dist/secret-store.d.ts +25 -0
- package/dist/secret-store.js +165 -0
- package/dist/secret-store.js.map +1 -0
- package/dist/self-restart-limit.d.ts +21 -0
- package/dist/self-restart-limit.js +129 -0
- package/dist/self-restart-limit.js.map +1 -0
- package/dist/settings-api.d.ts +116 -0
- package/dist/settings-api.js +530 -5
- package/dist/settings-api.js.map +1 -1
- package/dist/setup-auth.d.ts +113 -0
- package/dist/setup-auth.js +181 -0
- package/dist/setup-auth.js.map +1 -0
- package/dist/setup-form.d.ts +18 -0
- package/dist/setup-form.js +315 -0
- package/dist/setup-form.js.map +1 -0
- package/dist/setup-host.d.ts +162 -0
- package/dist/setup-host.js +496 -0
- package/dist/setup-host.js.map +1 -0
- package/dist/setup-marker.d.ts +8 -0
- package/dist/setup-marker.js +39 -0
- package/dist/setup-marker.js.map +1 -0
- package/dist/setup-tunnel-consent.d.ts +53 -0
- package/dist/setup-tunnel-consent.js +82 -0
- package/dist/setup-tunnel-consent.js.map +1 -0
- package/dist/setup-wizard.js +4 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/steer-capability.js +4 -1
- package/dist/steer-capability.js.map +1 -1
- package/dist/tips.js +1 -1
- package/dist/tips.js.map +1 -1
- package/dist/tmux-manager.js +29 -4
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions-notice.d.ts +38 -0
- package/dist/tool-permissions-notice.js +92 -0
- package/dist/tool-permissions-notice.js.map +1 -0
- package/dist/tool-permissions.d.ts +120 -0
- package/dist/tool-permissions.js +277 -0
- package/dist/tool-permissions.js.map +1 -0
- package/dist/topic-commands.js +1 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +12 -1
- package/dist/transcript-sources.js +19 -3
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +71 -0
- package/dist/tunnel/cloudflared.js +447 -0
- package/dist/tunnel/cloudflared.js.map +1 -0
- package/dist/tunnel/lease.d.ts +75 -0
- package/dist/tunnel/lease.js +209 -0
- package/dist/tunnel/lease.js.map +1 -0
- package/dist/tunnel/manager.d.ts +56 -0
- package/dist/tunnel/manager.js +167 -0
- package/dist/tunnel/manager.js.map +1 -0
- package/dist/tunnel/types.d.ts +119 -0
- package/dist/tunnel/types.js +33 -0
- package/dist/tunnel/types.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/ui/dashboard.html +4 -3
- package/dist/ui/settings.html +808 -156
- package/dist/ui/view.html +2 -2
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +1 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/providers.d.ts +23 -14
- package/dist/usage/providers.js +220 -58
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/usage-api.d.ts +13 -0
- package/dist/usage/usage-api.js +69 -1
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/web-api.js +8 -5
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +75 -0
- package/dist/web-auth.js +208 -2
- package/dist/web-auth.js.map +1 -1
- package/dist/web-terminal.d.ts +30 -1
- package/dist/web-terminal.js +86 -3
- package/dist/web-terminal.js.map +1 -1
- 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];
|
package/dist/usage/i18n-keys.js
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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
|
}>;
|
package/dist/usage/providers.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
-
|
|
1020
|
-
|
|
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
|
-
|
|
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) {
|