BIG pi update with claude chat

This commit is contained in:
Jonas H
2026-04-24 14:22:59 +02:00
parent fbb00a49ba
commit 248667468c
24 changed files with 4225 additions and 1112 deletions

View File

@@ -306,14 +306,27 @@ export default function (pi: ExtensionAPI) {
const active = state.activeProvider;
const data = active ? state[active] : null;
// Always emit event for other extensions (e.g. footer-display)
if (data && !data.error) {
// Always emit Claude usage for other extensions (e.g. footer-display)
// so S/W bars are visible regardless of active model.
const claudeData = state.claude;
if (claudeData && !claudeData.error) {
pi.events.emit("usage:update", {
session: claudeData.session,
weekly: claudeData.weekly,
sessionResetsIn: claudeData.sessionResetsIn,
sessionResetsAt: claudeData.sessionResetsAt,
weeklyResetsIn: claudeData.weeklyResetsIn,
weeklyResetsAt: claudeData.weeklyResetsAt,
});
} else if (data && !data.error) {
// Fallback to active provider data if Claude data unavailable
pi.events.emit("usage:update", {
session: data.session,
weekly: data.weekly,
sessionResetsIn: data.sessionResetsIn,
sessionResetsAt: data.sessionResetsAt,
weeklyResetsIn: data.weeklyResetsIn,
weeklyResetsAt: data.weeklyResetsAt,
});
}
@@ -372,6 +385,48 @@ export default function (pi: ExtensionAPI) {
const auth = readAuth();
const active = state.activeProvider;
// Always try to fetch Claude data so S/W bars show regardless of active provider
if (auth && canShowForProvider("claude", auth, endpoints)) {
try {
const cache = readUsageCache();
const now = Date.now();
const cacheTtl = options.cacheTtl ?? CACHE_TTL_MS;
const claudeBlockedUntil = cache?.rateLimitedUntil?.claude ?? 0;
if (now < claudeBlockedUntil) {
if (cache?.data?.claude) state.claude = cache.data.claude;
} else {
const claudeCacheFresh = cache && now - cache.timestamp < cacheTtl && cache.data?.claude;
if (claudeCacheFresh && !options.forceFresh) {
state.claude = cache.data.claude;
} else {
const claudeAccess = auth.anthropic?.access;
if (claudeAccess) {
const claudeResult = await fetchClaudeUsage(claudeAccess);
state.claude = claudeResult;
if (!claudeResult.error) {
const nextCache: import("./core").UsageCache = {
timestamp: now,
data: { ...(cache?.data ?? {}), claude: claudeResult },
rateLimitedUntil: { ...(cache?.rateLimitedUntil ?? {}) },
};
delete nextCache.rateLimitedUntil!.claude;
writeUsageCache(nextCache);
} else if (claudeResult.error === "HTTP 429") {
// Record backoff even when Claude is not the active provider —
// without this the prefetch would hammer the API on every poll.
const nextCache: import("./core").UsageCache = {
timestamp: cache?.timestamp ?? now,
data: { ...(cache?.data ?? {}) },
rateLimitedUntil: { ...(cache?.rateLimitedUntil ?? {}), claude: now + RATE_LIMITED_BACKOFF_MS },
};
writeUsageCache(nextCache);
}
}
}
}
} catch {}
}
if (!canShowForProvider(active, auth, endpoints) || !auth || !active) {
state.lastPoll = Date.now(); updateStatus(); return;
}
@@ -478,7 +533,9 @@ export default function (pi: ExtensionAPI) {
await Promise.race([runPollInner(options), timeout]);
}
const POLL_TIMEOUT_MS = 30_000;
// Must be less than the 25 000 ms timeout inside runPoll so the guard fires
// before runPoll's finally-block clears pollInFlight.
const POLL_TIMEOUT_MS = 20_000;
async function poll(options: PollOptions = {}) {
// If a previous poll has been running longer than POLL_TIMEOUT_MS, abandon it
@@ -557,15 +614,6 @@ export default function (pi: ExtensionAPI) {
await poll({ cacheTtl: ACTIVE_CACHE_TTL_MS });
});
pi.events.on("claude-account:switched", () => {
const cache = readUsageCache();
if (cache?.data?.claude) {
const nextCache: import("./core").UsageCache = { ...cache, data: { ...cache.data } };
delete nextCache.data.claude;
writeUsageCache(nextCache);
}
void poll({ forceFresh: true });
});
// Listen for OpenCode Go spend events from other extensions
pi.events.on("opencode-go:spend", async (amount: number) => {