@songsid/agend 2.1.2-beta.8 → 2.1.2
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/access-path.js +15 -6
- package/dist/access-path.js.map +1 -1
- package/dist/agent-cli-instructions.md +1 -0
- package/dist/agent-cli.js +14 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +2 -0
- package/dist/agent-endpoint.js +25 -1
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/backend/antigravity.d.ts +20 -0
- package/dist/backend/antigravity.js +51 -4
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +59 -0
- package/dist/backend/claude-code.js +67 -1
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +26 -0
- package/dist/backend/codex.js +100 -0
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.d.ts +25 -0
- package/dist/backend/grok.js +51 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +23 -0
- package/dist/backend/kiro.js +120 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +58 -0
- package/dist/backend/types.js +13 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +15 -0
- package/dist/channel/adapters/discord.js +120 -8
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +21 -0
- package/dist/channel/adapters/telegram.js +86 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +9 -1
- package/dist/channel/ipc-bridge.js +12 -3
- package/dist/channel/ipc-bridge.js.map +1 -1
- package/dist/channel/ipc-timeouts.d.ts +46 -0
- package/dist/channel/ipc-timeouts.js +65 -0
- package/dist/channel/ipc-timeouts.js.map +1 -0
- package/dist/channel/mcp-server.js +25 -14
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.js +30 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/reconnect-backoff.d.ts +17 -0
- package/dist/channel/reconnect-backoff.js +21 -0
- package/dist/channel/reconnect-backoff.js.map +1 -0
- package/dist/channel/types.d.ts +29 -0
- package/dist/classic-channel-manager.js +1 -5
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +242 -91
- package/dist/cli.js.map +1 -1
- package/dist/completion.d.ts +27 -0
- package/dist/completion.js +121 -0
- package/dist/completion.js.map +1 -0
- package/dist/config-validator.js +21 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/cost-guard.d.ts +3 -1
- package/dist/cost-guard.js +3 -1
- package/dist/cost-guard.js.map +1 -1
- package/dist/daemon.d.ts +299 -7
- package/dist/daemon.js +1152 -311
- package/dist/daemon.js.map +1 -1
- package/dist/event-log.d.ts +31 -0
- package/dist/event-log.js +96 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-context.d.ts +14 -0
- package/dist/fleet-lock.d.ts +28 -0
- package/dist/fleet-lock.js +130 -0
- package/dist/fleet-lock.js.map +1 -0
- package/dist/fleet-manager.d.ts +348 -6
- package/dist/fleet-manager.js +1860 -262
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-instance.d.ts +9 -0
- package/dist/general-instance.js +11 -0
- package/dist/general-instance.js.map +1 -0
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +22 -0
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +14 -23
- package/dist/general-knowledge/skills/session-management/SKILL.md +15 -34
- package/dist/hang-detector.d.ts +19 -13
- package/dist/hang-detector.js +19 -49
- package/dist/hang-detector.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +58 -2
- package/dist/instance-lifecycle.js +231 -46
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +7 -1
- package/dist/locale.js.map +1 -1
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -1
- package/dist/mcp-liveness.d.ts +21 -0
- package/dist/mcp-liveness.js +27 -0
- package/dist/mcp-liveness.js.map +1 -0
- package/dist/outbound-handlers.d.ts +9 -0
- package/dist/outbound-handlers.js +194 -31
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +11 -3
- package/dist/outbound-schemas.js +16 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-write-lock.d.ts +48 -0
- package/dist/pane-write-lock.js +73 -0
- package/dist/pane-write-lock.js.map +1 -0
- package/dist/process-memory.d.ts +31 -0
- package/dist/process-memory.js +79 -0
- package/dist/process-memory.js.map +1 -0
- package/dist/quickstart.js +17 -16
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-dedup.d.ts +41 -0
- package/dist/reply-dedup.js +0 -0
- package/dist/reply-dedup.js.map +1 -0
- package/dist/restart-progress.d.ts +41 -0
- package/dist/restart-progress.js +97 -0
- package/dist/restart-progress.js.map +1 -0
- package/dist/scheduler/db.js +3 -0
- package/dist/scheduler/db.js.map +1 -1
- package/dist/sd-notify.d.ts +27 -0
- package/dist/sd-notify.js +33 -1
- package/dist/sd-notify.js.map +1 -1
- package/dist/secret-file.d.ts +33 -0
- package/dist/secret-file.js +36 -0
- package/dist/secret-file.js.map +1 -0
- package/dist/service-installer.d.ts +28 -0
- package/dist/service-installer.js +72 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.js +5 -3
- package/dist/settings-api.js.map +1 -1
- package/dist/setup-wizard.js +9 -7
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tmux-control.d.ts +58 -5
- package/dist/tmux-control.js +102 -14
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +31 -1
- package/dist/tmux-manager.js +40 -11
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.d.ts +49 -9
- package/dist/topic-commands.js +270 -109
- package/dist/topic-commands.js.map +1 -1
- package/dist/tui-glyphs.d.ts +5 -1
- package/dist/tui-glyphs.js +6 -2
- package/dist/tui-glyphs.js.map +1 -1
- package/dist/types.d.ts +19 -2
- package/dist/ui/settings.html +1 -1
- package/dist/ui/view.html +123 -2
- package/dist/update-marker.d.ts +15 -0
- package/dist/update-marker.js +69 -0
- package/dist/update-marker.js.map +1 -0
- package/dist/usage/format-rich.d.ts +11 -0
- package/dist/usage/format-rich.js +121 -0
- package/dist/usage/format-rich.js.map +1 -0
- package/dist/usage/provider-alerts.d.ts +33 -0
- package/dist/usage/provider-alerts.js +57 -0
- package/dist/usage/provider-alerts.js.map +1 -0
- package/dist/usage/providers.d.ts +130 -0
- package/dist/usage/providers.js +1063 -0
- package/dist/usage/providers.js.map +1 -0
- package/dist/usage/statusline-usage.d.ts +20 -0
- package/dist/usage/statusline-usage.js +120 -0
- package/dist/usage/statusline-usage.js.map +1 -0
- package/dist/usage/usage-api.d.ts +50 -0
- package/dist/usage/usage-api.js +197 -0
- package/dist/usage/usage-api.js.map +1 -0
- package/dist/view-api.js +8 -3
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.js +7 -3
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +6 -0
- package/dist/web-auth.js +54 -0
- package/dist/web-auth.js.map +1 -0
- package/package.json +4 -1
- package/dist/channel/tool-tracker.d.ts +0 -13
- package/dist/channel/tool-tracker.js +0 -58
- package/dist/channel/tool-tracker.js.map +0 -1
- package/dist/daemon-entry.d.ts +0 -1
- package/dist/daemon-entry.js +0 -30
- package/dist/daemon-entry.js.map +0 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const BAR_WIDTH = 10;
|
|
2
|
+
/** `████░░░░░░` for 40%. Clamped — a vendor "105% used" must not overflow. */
|
|
3
|
+
export function usageBar(percent) {
|
|
4
|
+
const filled = Math.round(Math.min(100, Math.max(0, percent)) / 100 * BAR_WIDTH);
|
|
5
|
+
return "█".repeat(filled) + "░".repeat(BAR_WIDTH - filled);
|
|
6
|
+
}
|
|
7
|
+
function statusDot(p) {
|
|
8
|
+
if (p.status === "error")
|
|
9
|
+
return "🔴";
|
|
10
|
+
if (p.status === "no-credentials")
|
|
11
|
+
return "⚪";
|
|
12
|
+
// Highest metric drives the colour: the reader scans for "which one is hot".
|
|
13
|
+
const hottest = Math.max(0, ...p.metrics.map(metricPercent).filter((v) => v !== null));
|
|
14
|
+
return hottest >= 90 ? "🔴" : hottest >= 70 ? "🟡" : "🟢";
|
|
15
|
+
}
|
|
16
|
+
/** A metric's fill percentage, when one can honestly be computed. */
|
|
17
|
+
function metricPercent(m) {
|
|
18
|
+
if (m.type === "percent" && typeof m.used === "number")
|
|
19
|
+
return m.used;
|
|
20
|
+
if (m.type === "dollars" && typeof m.used === "number" && m.limit)
|
|
21
|
+
return (m.used / m.limit) * 100;
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function resetSuffix(resetsAt) {
|
|
25
|
+
if (!resetsAt)
|
|
26
|
+
return "";
|
|
27
|
+
const at = new Date(resetsAt);
|
|
28
|
+
if (Number.isNaN(at.getTime()))
|
|
29
|
+
return "";
|
|
30
|
+
const hours = Math.round((at.getTime() - Date.now()) / 3_600_000);
|
|
31
|
+
if (hours <= 0)
|
|
32
|
+
return "";
|
|
33
|
+
return hours >= 48 ? ` · resets in ${Math.round(hours / 24)}d` : ` · resets in ${hours}h`;
|
|
34
|
+
}
|
|
35
|
+
function metricLine(m) {
|
|
36
|
+
const pct = metricPercent(m);
|
|
37
|
+
switch (m.type) {
|
|
38
|
+
case "percent":
|
|
39
|
+
return {
|
|
40
|
+
bar: usageBar(pct ?? 0),
|
|
41
|
+
// note explains WHICH number this is (e.g. "busiest of 8 models"); it is
|
|
42
|
+
// what stops a legitimate 0% from reading as a broken meter.
|
|
43
|
+
text: `${Math.round(m.used ?? 0)}% ${m.label}${m.note ? ` (${m.note})` : ""}${resetSuffix(m.resetsAt)}`,
|
|
44
|
+
};
|
|
45
|
+
case "dollars": {
|
|
46
|
+
const used = `$${(m.used ?? 0).toFixed(2)}`;
|
|
47
|
+
return m.limit
|
|
48
|
+
? { bar: usageBar(pct ?? 0), text: `${used}/$${m.limit.toFixed(2)} ${m.label}` }
|
|
49
|
+
: { bar: null, text: `${used} ${m.label}` };
|
|
50
|
+
}
|
|
51
|
+
case "count":
|
|
52
|
+
return { bar: null, text: `${m.label}: ${m.value ?? "?"}${m.unit ? ` ${m.unit}` : ""}` };
|
|
53
|
+
case "text":
|
|
54
|
+
return m.value != null ? { bar: null, text: `${m.label}: ${m.value}` } : null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function toBlocks(payload) {
|
|
58
|
+
return payload.providers.map(p => ({
|
|
59
|
+
dot: statusDot(p),
|
|
60
|
+
name: p.name,
|
|
61
|
+
plan: p.plan ?? null,
|
|
62
|
+
// An ok row can carry a hint too — e.g. "cached 3m ago — live query is rate
|
|
63
|
+
// limited" from the stale fallback. Shown under the metrics, not instead of
|
|
64
|
+
// them, so old numbers still read as numbers.
|
|
65
|
+
note: p.status === "no-credentials" ? "not logged in"
|
|
66
|
+
: p.status === "error" ? `⚠️ ${p.error ?? "error"}`
|
|
67
|
+
: null,
|
|
68
|
+
okHint: p.status === "ok" && p.hint ? p.hint : null,
|
|
69
|
+
lines: p.status === "ok" ? p.metrics.map(metricLine).filter((l) => l !== null) : [],
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
/** Discord: native Markdown in plain message content. */
|
|
73
|
+
export function renderUsageMarkdown(payload) {
|
|
74
|
+
const out = ["📊 **AI Subscription Usage**"];
|
|
75
|
+
for (const b of toBlocks(payload)) {
|
|
76
|
+
out.push("", `${b.dot} **${b.name}**${b.plan ? ` (${b.plan})` : ""}`);
|
|
77
|
+
if (b.note) {
|
|
78
|
+
out.push(`> ${b.note}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (b.lines.length === 0) {
|
|
82
|
+
out.push(b.okHint ? `> ${b.okHint}` : "> no data");
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
for (const l of b.lines) {
|
|
86
|
+
out.push(l.bar ? `\`${l.bar}\` ${l.text}` : l.text);
|
|
87
|
+
}
|
|
88
|
+
if (b.okHint)
|
|
89
|
+
out.push(`> ${b.okHint}`);
|
|
90
|
+
}
|
|
91
|
+
return out.join("\n");
|
|
92
|
+
}
|
|
93
|
+
function escapeHtml(s) {
|
|
94
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Telegram: HTML parse mode. Every payload-derived string is entity-escaped —
|
|
98
|
+
* provider errors and metric labels come from vendor responses, and one stray
|
|
99
|
+
* `<` would make Telegram reject the whole message.
|
|
100
|
+
*/
|
|
101
|
+
export function renderUsageHtml(payload) {
|
|
102
|
+
const out = ["📊 <b>AI Subscription Usage</b>"];
|
|
103
|
+
for (const b of toBlocks(payload)) {
|
|
104
|
+
out.push("", `${b.dot} <b>${escapeHtml(b.name)}</b>${b.plan ? ` (${escapeHtml(b.plan)})` : ""}`);
|
|
105
|
+
if (b.note) {
|
|
106
|
+
out.push(escapeHtml(b.note));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (b.lines.length === 0) {
|
|
110
|
+
out.push(b.okHint ? escapeHtml(b.okHint) : "no data");
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
for (const l of b.lines) {
|
|
114
|
+
out.push(l.bar ? `<code>${l.bar}</code> ${escapeHtml(l.text)}` : escapeHtml(l.text));
|
|
115
|
+
}
|
|
116
|
+
if (b.okHint)
|
|
117
|
+
out.push(escapeHtml(b.okHint));
|
|
118
|
+
}
|
|
119
|
+
return out.join("\n");
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=format-rich.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-rich.js","sourceRoot":"","sources":["../../src/usage/format-rich.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate-limit state that only the CLI can see, remembered for the usage panel.
|
|
3
|
+
*
|
|
4
|
+
* Antigravity's quota summary API reports per-model bucket pools — and those
|
|
5
|
+
* can read "0% used" while the account-level individual cap is exhausted.
|
|
6
|
+
* Verified live (2026-08-02, same minute): `agy -p` returned "Individual quota
|
|
7
|
+
* reached … Resets in 139h12m12s" while `retrieveUserQuotaSummary` reported
|
|
8
|
+
* every bucket at remainingFraction 1.0. No Google API exposes the individual
|
|
9
|
+
* cap; the generation error relayed through a running instance's pane is the
|
|
10
|
+
* only place it surfaces. So the daemon's error monitor reports it here, and
|
|
11
|
+
* the usage provider overlays it on the row that would otherwise say 🟢 0%.
|
|
12
|
+
*
|
|
13
|
+
* In-memory on purpose: the fleet process hosts both the error monitor and the
|
|
14
|
+
* usage provider, and a restart just means the alert reappears the next time an
|
|
15
|
+
* instance hits the cap.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `Resets in 139h12m12s` → milliseconds. Null when the text carries no such
|
|
19
|
+
* phrase — the caller falls back to a default TTL rather than guessing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseResetsIn(text: string): number | null;
|
|
22
|
+
/**
|
|
23
|
+
* Record a CLI-observed rate limit for a usage provider. The alert expires by
|
|
24
|
+
* itself at the reset time the message names (or after an hour when it names
|
|
25
|
+
* none), which is what makes "reset 後警示消失" true without a cleanup job.
|
|
26
|
+
*/
|
|
27
|
+
export declare function reportProviderRateLimit(providerId: string, message: string, now?: number): void;
|
|
28
|
+
/** The live alert for a provider, or null once its reset time has passed. */
|
|
29
|
+
export declare function getProviderRateLimit(providerId: string, now?: number): {
|
|
30
|
+
message: string;
|
|
31
|
+
resetsAtMs: number;
|
|
32
|
+
} | null;
|
|
33
|
+
export declare function clearProviderRateLimitsForTests(): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate-limit state that only the CLI can see, remembered for the usage panel.
|
|
3
|
+
*
|
|
4
|
+
* Antigravity's quota summary API reports per-model bucket pools — and those
|
|
5
|
+
* can read "0% used" while the account-level individual cap is exhausted.
|
|
6
|
+
* Verified live (2026-08-02, same minute): `agy -p` returned "Individual quota
|
|
7
|
+
* reached … Resets in 139h12m12s" while `retrieveUserQuotaSummary` reported
|
|
8
|
+
* every bucket at remainingFraction 1.0. No Google API exposes the individual
|
|
9
|
+
* cap; the generation error relayed through a running instance's pane is the
|
|
10
|
+
* only place it surfaces. So the daemon's error monitor reports it here, and
|
|
11
|
+
* the usage provider overlays it on the row that would otherwise say 🟢 0%.
|
|
12
|
+
*
|
|
13
|
+
* In-memory on purpose: the fleet process hosts both the error monitor and the
|
|
14
|
+
* usage provider, and a restart just means the alert reappears the next time an
|
|
15
|
+
* instance hits the cap.
|
|
16
|
+
*/
|
|
17
|
+
const alerts = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* `Resets in 139h12m12s` → milliseconds. Null when the text carries no such
|
|
20
|
+
* phrase — the caller falls back to a default TTL rather than guessing.
|
|
21
|
+
*/
|
|
22
|
+
export function parseResetsIn(text) {
|
|
23
|
+
const m = text.match(/Resets? in (?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?/i);
|
|
24
|
+
if (!m || (!m[1] && !m[2] && !m[3]))
|
|
25
|
+
return null;
|
|
26
|
+
return (Number(m[1] ?? 0) * 3600 + Number(m[2] ?? 0) * 60 + Number(m[3] ?? 0)) * 1000;
|
|
27
|
+
}
|
|
28
|
+
/** A cap with no parseable reset still should not alarm forever. */
|
|
29
|
+
const DEFAULT_ALERT_TTL_MS = 60 * 60_000;
|
|
30
|
+
/**
|
|
31
|
+
* Record a CLI-observed rate limit for a usage provider. The alert expires by
|
|
32
|
+
* itself at the reset time the message names (or after an hour when it names
|
|
33
|
+
* none), which is what makes "reset 後警示消失" true without a cleanup job.
|
|
34
|
+
*/
|
|
35
|
+
export function reportProviderRateLimit(providerId, message, now = Date.now()) {
|
|
36
|
+
const resetInMs = parseResetsIn(message);
|
|
37
|
+
alerts.set(providerId, {
|
|
38
|
+
message,
|
|
39
|
+
resetsAtMs: now + (resetInMs ?? DEFAULT_ALERT_TTL_MS),
|
|
40
|
+
reportedAtMs: now,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** The live alert for a provider, or null once its reset time has passed. */
|
|
44
|
+
export function getProviderRateLimit(providerId, now = Date.now()) {
|
|
45
|
+
const alert = alerts.get(providerId);
|
|
46
|
+
if (!alert)
|
|
47
|
+
return null;
|
|
48
|
+
if (now >= alert.resetsAtMs) {
|
|
49
|
+
alerts.delete(providerId);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return { message: alert.message, resetsAtMs: alert.resetsAtMs };
|
|
53
|
+
}
|
|
54
|
+
export function clearProviderRateLimitsForTests() {
|
|
55
|
+
alerts.clear();
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=provider-alerts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-alerts.js","sourceRoot":"","sources":["../../src/usage/provider-alerts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAChF,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACjD,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AACxF,CAAC;AAED,oEAAoE;AACpE,MAAM,oBAAoB,GAAG,EAAE,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAkB,EAAE,OAAe,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC3F,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE;QACrB,OAAO;QACP,UAAU,EAAE,GAAG,GAAG,CAAC,SAAS,IAAI,oBAAoB,CAAC;QACrD,YAAY,EAAE,GAAG;KAClB,CAAC,CAAC;AACL,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEvE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,GAAG,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,+BAA+B;IAC7C,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { type StatuslineRateLimits } from "./statusline-usage.js";
|
|
2
|
+
export interface UsageMetric {
|
|
3
|
+
label: string;
|
|
4
|
+
type: "percent" | "dollars" | "count" | "text";
|
|
5
|
+
used?: number;
|
|
6
|
+
limit?: number;
|
|
7
|
+
value?: number | string;
|
|
8
|
+
unit?: string;
|
|
9
|
+
note?: string;
|
|
10
|
+
resetsAt?: string | null;
|
|
11
|
+
windowMs?: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ProviderUsage {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
status: "ok" | "error" | "no-credentials";
|
|
17
|
+
plan?: string | null;
|
|
18
|
+
error?: string;
|
|
19
|
+
hint?: string;
|
|
20
|
+
metrics: UsageMetric[];
|
|
21
|
+
}
|
|
22
|
+
/** `CLAUDE_CODE_OAUTH_TOKEN` as exported in a shell rc file, or null. */
|
|
23
|
+
export declare function tokenFromShellRc(read: (path: string) => string, home?: string, files?: readonly string[]): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Where the Claude OAuth bearer comes from, in preference order:
|
|
26
|
+
*
|
|
27
|
+
* 1. `~/.claude/.credentials.json` (`claudeAiOauth.accessToken`) when present and
|
|
28
|
+
* unexpired — the interactive `/login` flow. Carries plan metadata.
|
|
29
|
+
* 2. `CLAUDE_CODE_OAUTH_TOKEN` — the long-lived (annual) token minted by
|
|
30
|
+
* `claude setup-token`. Users on this flow often have NO credentials file at
|
|
31
|
+
* all (or a stale one from an old login), which is why /usage showed them
|
|
32
|
+
* "not logged in" / "token expired" while their CLI worked fine. Same token
|
|
33
|
+
* family (`sk-ant-oat…`), same usage endpoint; it just carries no plan
|
|
34
|
+
* metadata, so plan shows unknown.
|
|
35
|
+
* 3. The same variable as exported in a shell rc file. A systemd-launched daemon
|
|
36
|
+
* inherits none of the user's interactive shell, so a `setup-token` login was
|
|
37
|
+
* invisible to /usage unless the user duplicated it into ~/.agend/.env.
|
|
38
|
+
* 4. An expired file token with no other source stays an explicit error.
|
|
39
|
+
* 5. `ANTHROPIC_API_KEY` alone is named in the hint but NOT used: console API
|
|
40
|
+
* keys are pay-per-token and have no subscription usage to query — the OAuth
|
|
41
|
+
* endpoint rejects them, and pretending otherwise would render a misleading
|
|
42
|
+
* error instead of an accurate "log in" hint.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveClaudeAuth(file: {
|
|
45
|
+
accessToken?: string;
|
|
46
|
+
expiresAt?: number;
|
|
47
|
+
subscriptionType?: string;
|
|
48
|
+
rateLimitTier?: string;
|
|
49
|
+
} | null, env?: NodeJS.ProcessEnv, rcLookup?: () => string | null): {
|
|
50
|
+
token: string;
|
|
51
|
+
plan: string | null;
|
|
52
|
+
} | {
|
|
53
|
+
error: string;
|
|
54
|
+
plan: string | null;
|
|
55
|
+
} | null;
|
|
56
|
+
/**
|
|
57
|
+
* Render a statusline reading as provider metrics.
|
|
58
|
+
*
|
|
59
|
+
* Kept deliberately close to the API path's shape so the panel looks the same
|
|
60
|
+
* wherever the numbers came from — the hint is what tells the difference, and
|
|
61
|
+
* it names the source because a number with no provenance invites "is this
|
|
62
|
+
* even live?".
|
|
63
|
+
*/
|
|
64
|
+
export declare function statuslineUsage(reading: StatuslineRateLimits, plan: string | null, now?: number): Omit<ProviderUsage, "id" | "name">;
|
|
65
|
+
/** Exported for tests — the statusline/API preference order is the subject. */
|
|
66
|
+
export declare function fetchClaudeUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
67
|
+
interface AgyBucket {
|
|
68
|
+
bucketId?: string;
|
|
69
|
+
displayName?: string;
|
|
70
|
+
remainingFraction?: number;
|
|
71
|
+
resetTime?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Pool the summary's buckets into at most four metrics.
|
|
75
|
+
*
|
|
76
|
+
* Two payload shapes exist. Older accounts report pooled ids (`gemini-5h`,
|
|
77
|
+
* `gemini-weekly`, `3p-5h`, `3p-weekly`), which map 1:1. This machine's live
|
|
78
|
+
* response instead lists PER-MODEL buckets (`gemini-3.6-flash-high`,
|
|
79
|
+
* `claude-sonnet-4-6`, `gpt-oss-120b-medium`, …) — those aggregate into a
|
|
80
|
+
* Gemini pool and an everything-else pool, keeping each pool's WORST remaining
|
|
81
|
+
* fraction, because eleven per-model meters is noise and the binding constraint
|
|
82
|
+
* is the one that runs out first.
|
|
83
|
+
*/
|
|
84
|
+
export declare function agyPoolMetrics(buckets: AgyBucket[]): UsageMetric[];
|
|
85
|
+
interface AgyStoredToken {
|
|
86
|
+
access_token?: string;
|
|
87
|
+
refresh_token?: string;
|
|
88
|
+
expiry?: string;
|
|
89
|
+
expiry_date?: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* agy's token file, in either shape.
|
|
93
|
+
*
|
|
94
|
+
* This machine writes it nested (`{ token: {...}, id_token, auth_method }`),
|
|
95
|
+
* which is what the provider was built against. Flat (`{ access_token, ... }`)
|
|
96
|
+
* is accepted too — it costs one `??` and other installs or future agy versions
|
|
97
|
+
* may differ. `expiry_date` (epoch ms, the shape ~/.gemini/oauth_creds.json
|
|
98
|
+
* uses) is read alongside `expiry` (RFC3339) for the same reason.
|
|
99
|
+
*/
|
|
100
|
+
export declare function readAgyToken(file: unknown): AgyStoredToken;
|
|
101
|
+
interface KiroToken {
|
|
102
|
+
access_token?: string;
|
|
103
|
+
expires_at?: string;
|
|
104
|
+
region?: string;
|
|
105
|
+
profile_arn?: string;
|
|
106
|
+
/** IAM Identity Center portal URL — present only for Q Developer Pro logins. */
|
|
107
|
+
start_url?: string;
|
|
108
|
+
/** Social login provider (google/github/…) — present only for free-tier logins. */
|
|
109
|
+
provider?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Which Kiro login is in use. Verified against a real kiro-cli auth store:
|
|
113
|
+
* - IAM Identity Center (Amazon Q Developer Pro) tokens carry `start_url`
|
|
114
|
+
* (e.g. `https://d-xxxx.awsapps.com/start/`) and no social `provider`.
|
|
115
|
+
* - Free-tier social logins (Builder ID / Google / GitHub) carry `provider`
|
|
116
|
+
* and a `profile_arn`.
|
|
117
|
+
* Q Developer Pro is a seat-licensed subscription, so the credit/usage endpoint
|
|
118
|
+
* that Builder ID reports against does not describe it.
|
|
119
|
+
*/
|
|
120
|
+
export type KiroAuthKind = "q-developer-pro" | "builder-id";
|
|
121
|
+
export declare function kiroAuthKind(token: KiroToken): KiroAuthKind;
|
|
122
|
+
/** Exported for tests: the Q-Pro and expired paths return without any network call. */
|
|
123
|
+
export declare function fetchKiroUsage(): Promise<Omit<ProviderUsage, "id" | "name">>;
|
|
124
|
+
/** Fetch every provider in parallel. Providers without local credentials are
|
|
125
|
+
* skipped (per the panel's contract: absent CLIs simply don't show). */
|
|
126
|
+
export declare function fetchAllUsage(): Promise<{
|
|
127
|
+
fetchedAt: string;
|
|
128
|
+
providers: ProviderUsage[];
|
|
129
|
+
}>;
|
|
130
|
+
export {};
|