@songsid/agend 2.2.0-beta.4 → 2.2.0-beta.6
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/backend/claude-carry.d.ts +22 -0
- package/dist/backend/claude-carry.js +170 -0
- package/dist/backend/claude-carry.js.map +1 -0
- package/dist/backend/claude-code.d.ts +23 -0
- package/dist/backend/claude-code.js +102 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +7 -0
- package/dist/backend/credential-profile.js +7 -1
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/kiro.js +5 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.d.ts +41 -0
- package/dist/backend/muse.js +239 -44
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/background-work-ended.d.ts +18 -0
- package/dist/background-work-ended.js +30 -0
- package/dist/background-work-ended.js.map +1 -0
- package/dist/channel/adapters/telegram.d.ts +4 -5
- package/dist/channel/adapters/telegram.js +33 -17
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/message-edit-errors.d.ts +5 -0
- package/dist/channel/message-edit-errors.js +24 -0
- package/dist/channel/message-edit-errors.js.map +1 -0
- package/dist/cli.js +60 -10
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +3 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +41 -0
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-context.d.ts +4 -1
- package/dist/fleet-manager.d.ts +112 -5
- package/dist/fleet-manager.js +516 -52
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +44 -9
- package/dist/locale.js +18 -2
- package/dist/locale.js.map +1 -1
- package/dist/needs-you-hub.js +2 -0
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +6 -0
- package/dist/needs-you-live.js +23 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/outbound-handlers.d.ts +7 -0
- package/dist/outbound-handlers.js +19 -10
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/public-preview.d.ts +100 -0
- package/dist/public-preview.js +233 -0
- package/dist/public-preview.js.map +1 -0
- package/dist/public-web-gateway.js +4 -3
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +20 -0
- package/dist/public-web-link.js +26 -1
- package/dist/public-web-link.js.map +1 -1
- package/dist/restart-progress.d.ts +33 -0
- package/dist/restart-progress.js +30 -0
- package/dist/restart-progress.js.map +1 -1
- package/dist/service-installer.d.ts +31 -0
- package/dist/service-installer.js +41 -2
- package/dist/service-installer.js.map +1 -1
- package/dist/topic-commands.js +3 -1
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +5 -1
- package/dist/tunnel/purpose-lane.js +14 -7
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/ui/chat-strings.js +14 -2
- package/dist/ui/chat-thread.js +2 -2
- package/dist/ui/panel-chat.js +9 -2
- package/dist/ui/panel-fleet.js +148 -35
- package/dist/ui/panel-needs.js +4 -3
- package/dist/ui/panel-settings.js +1 -1
- package/dist/ui/preview-status.js +28 -0
- package/dist/ui/preview.js +35 -2
- package/dist/ui/shared/app-i18n.js +4 -0
- package/dist/ui/shared/app-prefs.js +1 -0
- package/dist/ui/shared/app-shell.js +146 -2
- package/dist/ui/shared/app-stream.js +21 -4
- package/dist/ui/shared/app.css +41 -15
- package/dist/ui/shared/instance-nav.js +47 -16
- package/dist/ui/shared/usage-dialog.js +10 -1
- package/dist/ui/shared/view-strings.js +4 -0
- package/dist/update-install.d.ts +13 -1
- package/dist/update-install.js +16 -4
- package/dist/update-install.js.map +1 -1
- package/dist/update-marker.d.ts +51 -0
- package/dist/update-marker.js +61 -0
- package/dist/update-marker.js.map +1 -1
- 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 +34 -5
- package/dist/usage/providers.js +160 -27
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.d.ts +6 -2
- package/dist/usage/statusline-usage.js +10 -4
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/web-api.d.ts +20 -1
- package/dist/web-api.js +101 -13
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +2 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-prefs.js +2 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +14 -1
- package/dist/web-preview.js +35 -13
- package/dist/web-preview.js.map +1 -1
- package/dist/web-schedules.d.ts +12 -0
- package/dist/web-schedules.js +34 -0
- package/dist/web-schedules.js.map +1 -0
- package/dist/web-server-drain.d.ts +10 -0
- package/dist/web-server-drain.js +50 -0
- package/dist/web-server-drain.js.map +1 -0
- package/package.json +1 -1
- package/templates/launchd.plist.ejs +3 -1
- package/templates/systemd.service.ejs +2 -1
package/dist/update-marker.js
CHANGED
|
@@ -23,6 +23,64 @@ import { atomicWriteFileSync } from "./atomic-write.js";
|
|
|
23
23
|
*/
|
|
24
24
|
export const UPDATE_MARKER_MAX_AGE_MS = 15 * 60_000;
|
|
25
25
|
const FILE = "update-in-progress.json";
|
|
26
|
+
export function updateReceiptOf(marker) {
|
|
27
|
+
if (!marker?.progress?.target?.messageId)
|
|
28
|
+
return null;
|
|
29
|
+
return { startedAt: marker.startedAt, messageId: marker.progress.target.messageId, operation: updateProgressOperation(marker.progress) };
|
|
30
|
+
}
|
|
31
|
+
function sameReceipt(a, b) {
|
|
32
|
+
return !!a && !!b && a.startedAt === b.startedAt && a.messageId === b.messageId && a.operation === b.operation;
|
|
33
|
+
}
|
|
34
|
+
export function updateMarkerIdentity(dataDir) {
|
|
35
|
+
const marker = readMarker(dataDir);
|
|
36
|
+
if (!marker)
|
|
37
|
+
return null;
|
|
38
|
+
return { startedAt: marker.startedAt, receipt: marker.progress ? updateReceiptOf(marker) : null };
|
|
39
|
+
}
|
|
40
|
+
/** The same marker: started at the same time, with the same receipt (or none on both). */
|
|
41
|
+
export function sameUpdateMarker(a, b) {
|
|
42
|
+
if (!a || !b || a.startedAt !== b.startedAt)
|
|
43
|
+
return false;
|
|
44
|
+
return a.receipt === null ? b.receipt === null : sameReceipt(a.receipt, b.receipt);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Mark the current update as owing its retire outcome, before the restart
|
|
48
|
+
* that may let a new fleet consume this receipt. Returns the receipt the
|
|
49
|
+
* later write must still match.
|
|
50
|
+
*/
|
|
51
|
+
export function markCleanupPending(dataDir) {
|
|
52
|
+
const marker = readUpdateProgress(dataDir);
|
|
53
|
+
const receipt = updateReceiptOf(marker);
|
|
54
|
+
if (!receipt || !marker)
|
|
55
|
+
return null;
|
|
56
|
+
marker.pid = process.pid;
|
|
57
|
+
marker.progress = { ...marker.progress, cleanup: "pending" };
|
|
58
|
+
return writeMarker(dataDir, marker) ? receipt : null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Record a retire outcome against the receipt captured before the restart.
|
|
62
|
+
* Refuses when the marker is gone (the new fleet already consumed it) or
|
|
63
|
+
* belongs to another operation (e.g. a later full-restart adopted it) — the
|
|
64
|
+
* warning was already printed to the updater's own output, so refusing here
|
|
65
|
+
* loses nothing the operator saw.
|
|
66
|
+
*/
|
|
67
|
+
export function writeCleanupOutcome(dataDir, receipt, outcome) {
|
|
68
|
+
if (!receipt)
|
|
69
|
+
return false;
|
|
70
|
+
const marker = readUpdateProgress(dataDir);
|
|
71
|
+
if (!marker || !sameReceipt(updateReceiptOf(marker), receipt))
|
|
72
|
+
return false;
|
|
73
|
+
marker.pid = process.pid;
|
|
74
|
+
marker.progress = {
|
|
75
|
+
...marker.progress,
|
|
76
|
+
// Prose follows the same rule as setUpdateProgressStage; the command is
|
|
77
|
+
// verbatim so quoted paths survive byte-exact.
|
|
78
|
+
...(outcome?.warning !== undefined ? { warning: outcome.warning.replace(/\s+/g, " ").trim().slice(0, 300) } : {}),
|
|
79
|
+
...(outcome?.cleanupCommand !== undefined ? { cleanupCommand: outcome.cleanupCommand } : {}),
|
|
80
|
+
cleanup: "done",
|
|
81
|
+
};
|
|
82
|
+
return writeMarker(dataDir, marker);
|
|
83
|
+
}
|
|
26
84
|
function markerPath(dataDir) {
|
|
27
85
|
return join(dataDir, FILE);
|
|
28
86
|
}
|
|
@@ -91,6 +149,9 @@ export function setUpdateProgressStage(dataDir, stage, details = {}) {
|
|
|
91
149
|
stage,
|
|
92
150
|
...(details.version !== undefined ? { version: details.version } : {}),
|
|
93
151
|
...(details.error !== undefined ? { error: details.error.replace(/\s+/g, " ").trim().slice(0, 300) } : {}),
|
|
152
|
+
...(details.warning !== undefined ? { warning: details.warning.replace(/\s+/g, " ").trim().slice(0, 300) } : {}),
|
|
153
|
+
...(details.cleanupCommand !== undefined ? { cleanupCommand: details.cleanupCommand } : {}),
|
|
154
|
+
...(details.cleanup !== undefined ? { cleanup: details.cleanup } : {}),
|
|
94
155
|
...(stage === "failed" ? { failedStage: previousStage } : {}),
|
|
95
156
|
};
|
|
96
157
|
return writeMarker(dataDir, marker);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-marker.js","sourceRoot":"","sources":["../src/update-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAc,UAAU,EAAiB,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,MAAM,CAAC;AAEpD,MAAM,IAAI,GAAG,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"update-marker.js","sourceRoot":"","sources":["../src/update-marker.ts"],"names":[],"mappings":"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"}
|
|
@@ -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.ticket_expiry", "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.rate_limited_transient", "usage.stale_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.ticket_expiry", "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.claude_profile_signed_out", "usage.hint.claude_profile_signed_out_chat", "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.rate_limited_transient", "usage.stale_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
|
@@ -20,7 +20,7 @@ export const USAGE_I18N_KEYS = [
|
|
|
20
20
|
"usage.hint.statusline_now", "usage.hint.statusline_minutes", "usage.hint.claude_api_key",
|
|
21
21
|
"usage.hint.login_claude", "usage.hint.login_agy", "usage.hint.no_quota",
|
|
22
22
|
"usage.hint.login_codex", "usage.hint.codex_no_oauth", "usage.hint.login_grok",
|
|
23
|
-
"usage.hint.grok_no_login", "usage.hint.login_kiro", "usage.hint.kiro_signed_out",
|
|
23
|
+
"usage.hint.grok_no_login", "usage.hint.login_kiro", "usage.hint.kiro_signed_out", "usage.hint.claude_profile_signed_out", "usage.hint.claude_profile_signed_out_chat",
|
|
24
24
|
"usage.hint.token_refreshing", "usage.hint.subscription_no_credit", "usage.hint.no_quota_account",
|
|
25
25
|
"usage.error.unreachable", "usage.error.token_rejected", "usage.error.rate_limited", "usage.error.rate_limited_transient", "usage.stale_rate_limited",
|
|
26
26
|
"usage.error.http", "usage.error.billing_http", "usage.error.invalid_response",
|
|
@@ -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,qBAAqB,EAAE,sBAAsB,EAAE,2BAA2B;IAC5G,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;
|
|
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,qBAAqB,EAAE,sBAAsB,EAAE,2BAA2B;IAC5G,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,EAAE,sCAAsC,EAAE,2CAA2C;IACtK,6BAA6B,EAAE,mCAAmC,EAAE,6BAA6B;IACjG,yBAAyB,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,oCAAoC,EAAE,0BAA0B;IACrJ,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"}
|
|
@@ -106,14 +106,43 @@ export declare function resolveClaudeAuth(file: {
|
|
|
106
106
|
* even live?".
|
|
107
107
|
*/
|
|
108
108
|
export declare function statuslineUsage(reading: StatuslineRateLimits, plan: string | null, now?: number): Omit<ProviderUsage, "id" | "name">;
|
|
109
|
+
/** `security find-generic-password -w`: the item's secret, or null (no such item, locked, not macOS). */
|
|
110
|
+
type KeychainRead = (service: string, account: string) => Promise<string | null>;
|
|
111
|
+
declare let claudeKeychain: {
|
|
112
|
+
platform: NodeJS.Platform;
|
|
113
|
+
read: KeychainRead;
|
|
114
|
+
username: () => string;
|
|
115
|
+
};
|
|
116
|
+
/** Test seam (#1699): the platform, the Keychain read and the OS user name; null restores all three. */
|
|
117
|
+
export declare function setClaudeKeychainForTests(seam: Partial<typeof claudeKeychain> | null): void;
|
|
118
|
+
/**
|
|
119
|
+
* Whether a shell rc sets `CLAUDE_CODE_OAUTH_TOKEN` at all — any assignment, export or declaration that is not a
|
|
120
|
+
* comment, whatever its value: `"$OTHER"` or `${OTHER}` is a token once the pane's shell expands it, so unlike
|
|
121
|
+
* tokenFromShellRc (which must hand the API a literal bearer) this never discounts one it cannot read (#1713 review).
|
|
122
|
+
* Files those rcs `source` are not followed.
|
|
123
|
+
*/
|
|
124
|
+
export declare function shellRcSetsClaudeToken(read: (path: string) => string, home?: string, files?: readonly string[]): boolean;
|
|
109
125
|
/**
|
|
110
126
|
* Best-effort OAuth access token for direct Anthropic API calls (the /model
|
|
111
127
|
* catalog probe). Same resolution order as the usage panel: credentials file →
|
|
112
|
-
* CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists.
|
|
128
|
+
* CLAUDE_CODE_OAUTH_TOKEN → shell rc. Null when nothing usable exists. With
|
|
129
|
+
* `storeHome` (a credential profile's config dir, #1699): that profile's login only.
|
|
130
|
+
*/
|
|
131
|
+
export declare function getClaudeOAuthToken(storeHome?: string): Promise<string | null>;
|
|
132
|
+
/** Which subscription a Claude row is (#1699): a profile's (with its name), or the shared one beside profiles. */
|
|
133
|
+
export interface ClaudeUsageScope {
|
|
134
|
+
profile?: string;
|
|
135
|
+
besideProfiles?: boolean;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Exported for tests — the statusline/API preference order is the subject.
|
|
139
|
+
*
|
|
140
|
+
* `storeHome` (#1699): a credential profile's config dir — the row reads that profile's login and only the rate
|
|
141
|
+
* limits its own instances wrote (their conversations are under its `projects/`); a profile with no login says so,
|
|
142
|
+
* with the line that signs it in, and never shows the shared account's numbers. Without it: the shared login as
|
|
143
|
+
* always; beside profiles (`besideProfiles`), its statusline fallback leaves the profiles' instances out.
|
|
113
144
|
*/
|
|
114
|
-
export declare function
|
|
115
|
-
/** Exported for tests — the statusline/API preference order is the subject. */
|
|
116
|
-
export declare function fetchClaudeUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
145
|
+
export declare function fetchClaudeUsage(storeHome?: string, scope?: ClaudeUsageScope): Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
117
146
|
interface AgyBucket {
|
|
118
147
|
bucketId?: string;
|
|
119
148
|
displayName?: string;
|
|
@@ -172,7 +201,7 @@ export declare function fetchKiroUsage(storeHome?: string): Promise<Omit<Provide
|
|
|
172
201
|
type UsageProvider = {
|
|
173
202
|
id: string;
|
|
174
203
|
name: string;
|
|
175
|
-
fetch: (storeHome?: string) => Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
204
|
+
fetch: (storeHome?: string, scope?: ClaudeUsageScope) => Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
176
205
|
};
|
|
177
206
|
type UsageFleetConfig = Parameters<typeof listConfiguredProfiles>[0];
|
|
178
207
|
/** Read the daemon-written, token-free Muse relay snapshot for active Muse instances. */
|
package/dist/usage/providers.js
CHANGED
|
@@ -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
|
-
*
|
|
221
|
-
*
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
let file;
|
|
254
|
+
function claudeKeychainAccount() {
|
|
255
|
+
let name;
|
|
227
256
|
try {
|
|
228
|
-
|
|
257
|
+
name = process.env.USER || claudeKeychain.username();
|
|
229
258
|
}
|
|
230
259
|
catch {
|
|
231
|
-
|
|
260
|
+
name = undefined;
|
|
232
261
|
}
|
|
233
|
-
|
|
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
|
-
/**
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
284
|
+
const v = JSON.parse(json);
|
|
285
|
+
return v && typeof v === "object" ? v : null;
|
|
242
286
|
}
|
|
243
287
|
catch {
|
|
244
|
-
|
|
288
|
+
return null;
|
|
245
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;
|
|
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
|
-
|
|
249
|
-
|
|
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`).";
|
|
@@ -1274,13 +1396,14 @@ export function providersForConfig(config, base = DEFAULT_PROVIDERS) {
|
|
|
1274
1396
|
rows.push({
|
|
1275
1397
|
id: provider.id,
|
|
1276
1398
|
name: provider.id === "codex" ? `${provider.name} (default)` : provider.name,
|
|
1277
|
-
|
|
1399
|
+
// Claude's shared row keeps its statusline fallback to the shared instances (#1699); others ignore the scope.
|
|
1400
|
+
fetch: () => provider.fetch(undefined, { besideProfiles: true }),
|
|
1278
1401
|
});
|
|
1279
1402
|
}
|
|
1280
1403
|
rows.push(...profiles.map(profile => ({
|
|
1281
1404
|
id: `${provider.id}:${profile}`,
|
|
1282
1405
|
name: `${provider.name} (${profile})`,
|
|
1283
|
-
fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile)),
|
|
1406
|
+
fetch: () => provider.fetch(credentialProfileStoreHome(getAgendHome(), backendName, profile), { profile }),
|
|
1284
1407
|
})));
|
|
1285
1408
|
return rows;
|
|
1286
1409
|
});
|
|
@@ -1302,7 +1425,7 @@ function hasEffectiveSharedBinding(config, backendName) {
|
|
|
1302
1425
|
const instances = config.instances ?? {};
|
|
1303
1426
|
let sawEffectiveBinding = false;
|
|
1304
1427
|
for (const instance of Object.values(instances)) {
|
|
1305
|
-
const backend = instance.backend ?? defaults
|
|
1428
|
+
const backend = instance.backend ?? defaultBackend(defaults);
|
|
1306
1429
|
if (backend !== backendName)
|
|
1307
1430
|
continue;
|
|
1308
1431
|
sawEffectiveBinding = true;
|
|
@@ -1313,12 +1436,20 @@ function hasEffectiveSharedBinding(config, backendName) {
|
|
|
1313
1436
|
// backend is this provider and no profile was configured. With no known
|
|
1314
1437
|
// binding at all, preserve the pre-profile shared-provider behaviour.
|
|
1315
1438
|
if (!sawEffectiveBinding) {
|
|
1316
|
-
if (defaults
|
|
1439
|
+
if (defaultBackend(defaults) === backendName && !instanceCredentialProfile(undefined, defaults, backendName))
|
|
1317
1440
|
return true;
|
|
1318
1441
|
return Object.keys(instances).length === 0;
|
|
1319
1442
|
}
|
|
1320
1443
|
return false;
|
|
1321
1444
|
}
|
|
1445
|
+
/**
|
|
1446
|
+
* The backend an instance without one runs: the fleet default, else Claude Code — as the fleet launches it
|
|
1447
|
+
* (fleet-manager's bindings). Claude Code is the backend instances most often leave unnamed, so without this a
|
|
1448
|
+
* Claude profile on such an instance had no row of its own (#1699).
|
|
1449
|
+
*/
|
|
1450
|
+
function defaultBackend(defaults) {
|
|
1451
|
+
return defaults?.backend ?? "claude-code";
|
|
1452
|
+
}
|
|
1322
1453
|
/** Profiles on effective bindings only (not dormant backend_options on another backend). */
|
|
1323
1454
|
function effectiveCredentialProfiles(config, backendName) {
|
|
1324
1455
|
if (!config)
|
|
@@ -1326,14 +1457,14 @@ function effectiveCredentialProfiles(config, backendName) {
|
|
|
1326
1457
|
const found = new Set();
|
|
1327
1458
|
const defaults = config.defaults;
|
|
1328
1459
|
for (const instance of Object.values(config.instances ?? {})) {
|
|
1329
|
-
const backend = instance.backend ?? defaults
|
|
1460
|
+
const backend = instance.backend ?? defaultBackend(defaults);
|
|
1330
1461
|
if (backend !== backendName)
|
|
1331
1462
|
continue;
|
|
1332
1463
|
const profile = bindingProfile(instance, defaults, backendName);
|
|
1333
1464
|
if (profile)
|
|
1334
1465
|
found.add(profile);
|
|
1335
1466
|
}
|
|
1336
|
-
if (Object.keys(config.instances ?? {}).length === 0 && defaults
|
|
1467
|
+
if (Object.keys(config.instances ?? {}).length === 0 && defaultBackend(defaults) === backendName) {
|
|
1337
1468
|
const profile = instanceCredentialProfile(undefined, defaults, backendName);
|
|
1338
1469
|
if (profile)
|
|
1339
1470
|
found.add(profile);
|
|
@@ -1387,6 +1518,8 @@ function usageBackendForProviderId(id) {
|
|
|
1387
1518
|
return "kiro-cli";
|
|
1388
1519
|
if (id === "codex")
|
|
1389
1520
|
return "codex";
|
|
1521
|
+
if (id === "claude")
|
|
1522
|
+
return "claude-code";
|
|
1390
1523
|
return null;
|
|
1391
1524
|
}
|
|
1392
1525
|
let PROVIDERS = DEFAULT_PROVIDERS;
|