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.
84 lines • 3.99 kB
JavaScript
import { contextAutoPm, contextAutoPmSweep, contextQuota } from './context.js';
// The usage panel's read surface (#533): where the account's subscription quota stands,
// and where it stands against the quota boundary (#879). The source is threaded through
// the Telefunc request context by the daemon, which polls for its whole life; a public
// host (the relay) leaves it unwired, so the panel reports it has no reading rather than
// an empty one.
/** An honest empty view: no reading, and so no boundary to measure against. */
function noReading() {
// No windows and no boundary rather than zeroes: an empty bar reads as
// "nothing used", which is the one thing this panel must never imply.
return { windows: [], unavailable: 'fetch-failed' };
}
/** Where the account's quota stands against its boundary. */
export async function onQuota() {
const source = contextQuota();
if (!source)
return noReading();
return source.read().catch(() => noReading());
}
/**
* What auto PM last decided (#1161), for the line under the panel's toggle. It sits beside
* `onQuota` because it is the same panel and the same gate: auto PM spends against exactly the
* boundary drawn above it.
*
* `undefined` on a host with no sweep (the relay), which the panel reads as "nothing to say"
* rather than as an idle sweep — the distinction this whole read exists to make.
*/
export async function onAutoPm() {
const report = contextAutoPm();
if (!report)
return undefined;
try {
return report();
}
catch {
return undefined;
}
}
/**
* Sweep now rather than at the next interval (#1210). The loop already had this — it is what a
* write that switches the preference on triggers (#1167) — but until now nothing could ask for
* it directly, so the only way to fast-forward was to tick the box off and on again.
*
* The `autoPm` preference does not gate it: that preference is consent to spend quota *unasked*,
* and this call is asking. So with auto-run off the daemon still sweeps once — every other
* stand-down reason in force — and the schedule stays wherever the box says.
*
* Awaits the sweep and returns what it decided, one line per project (#1433): the click used to
* be fire-and-forget, so two presses could show literally nothing — no loading state, no
* outcome, and the stand-down reason recoverable only from the source. The outcomes are read
* off the loop's own report once the tick resolves, so the card can say them without a poll
* having to race the sweep. `false` still means a host with no loop (the relay), which the
* button reads as "nothing here to trigger".
*
* `drainOnly` narrows the sweep to working the queue (#1204): the drain routine's Run now spins
* agents up on the queue's entries — the fan-out only the sweep can do — and an empty queue is
* reported rather than borrowed for a rotation job.
*/
export async function sendAutoPmSweep(opts) {
const sweep = contextAutoPmSweep();
// The reporter is captured BEFORE the sweep is awaited: the Telefunc request context does not
// survive an await, so a post-await `contextAutoPm()` found nothing on every real request and
// the card fell back to "The sweep ran." — the very fallback this RPC exists to avoid. The
// captured closure needs no context to be called later.
const reporter = contextAutoPm();
if (!sweep)
return { ok: false };
try {
await sweep(opts?.drainOnly ? { drainOnly: true } : undefined);
}
catch {
return { ok: false };
}
// The outcomes live on the loop's report — the same lines `onAutoPm` polls — read once the
// tick has resolved, so they describe the sweep this click fired.
try {
const report = reporter?.();
return { ok: true, ...(report ? { outcomes: report.outcomes } : {}) };
}
catch {
return { ok: true };
}
}
//# sourceMappingURL=quota.telefunc.js.map