framework
Version:
The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.
60 lines • 2.94 kB
JavaScript
import { QuotaPoller } from '../quota-poller.js';
import { quotaBoundaryStatus } from '../quota-boundary.js';
import { ClaudeCodeDriver } from '../driver/index.js';
import { readPreferences } from '../registry.js';
import { DEFAULT_SPEND_OFFSET } from '../preference-defaults.js';
/**
* A {@link QuotaSource} backed by a live poller.
*
* Both questions are measured per call rather than captured: the boundary moves with the clock,
* so a cached one would be stale the moment the week's day rolls over. Neither costs a reading —
* the poller's last good windows are measured again, so asking per project is free.
*
* The panel's own boundary names no model on purpose: the bar is about the account, and a model's
* own week only narrows the gate for a run that has chosen one (#879/#1619).
*/
export function pollerQuotaSource(poller, now = () => Date.now(),
/** The user's slider position, read per call so moving it takes effect without a restart (#960). */
limitOffset = () => DEFAULT_SPEND_OFFSET) {
const measure = async (model) => {
const windows = poller.current().lastGood?.windows ?? [];
return quotaBoundaryStatus({ windows, now: now(), ...(model ? { model } : {}), limitOffset: await limitOffset() });
};
return {
stop: () => poller.stop(),
boundaryFor: model => measure(model),
read: async () => {
const envelope = poller.current();
const windows = envelope.lastGood?.windows ?? [];
const boundary = await measure();
const view = {
windows,
...(boundary ? { boundary } : {}),
...(envelope.lastGoodAt !== undefined ? { readAt: envelope.lastGoodAt } : {}),
...(envelope.latest && !envelope.latest.available ? { unavailable: envelope.latest.reason } : {}),
};
return view;
},
};
}
/**
* The daemon's own quota source: it polls for the whole life of the dashboard,
* not just during an agent, because the panel has to show where the account stands
* even when nothing is running.
*
* Separate from the per-agent guard on purpose — that one exists to pause an agent
* and dies with it, this one exists to draw a bar.
*/
export function defaultQuotaSource(env = process.env) {
const driver = new ClaudeCodeDriver();
const poller = new QuotaPoller({ read: () => driver.readQuota() });
poller.start();
// One source, so the bar the user reads and the line auto PM obeys cannot disagree (#960): the
// slider is read here rather than in each consumer. An unreadable registry means the default
// policy, which is what a fresh install runs anyway.
return pollerQuotaSource(poller, undefined, async () => {
const prefs = await readPreferences(undefined, env).catch(() => ({}));
return prefs.autoSpendOffset ?? DEFAULT_SPEND_OFFSET;
});
}
//# sourceMappingURL=quota.js.map