UNPKG

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.

62 lines 3.52 kB
import type { ProjectSummary, ProjectionRead } from './projects.js'; /** * Tracks which items have been announced, so only new ones notify. Identity is the caller's * (`keyOf`), since what makes two items "the same" is a property of what is being watched. * Testable without timers. * * The baseline is kept per project (`scopeOf`), not once for the whole poll (#1623). A poll that * reached three projects out of four knows what already existed on those three and knows nothing * about the fourth, and announcing is a per-project decision anyway. Held globally, one project * that can never be read — a registered repo with no remote is an ordinary case — would either * silence every project's notifications or hand the whole set a baseline it had not earned. */ export declare class SeenTracker<T> { private readonly keyOf; private readonly scopeOf; private readonly seen; private readonly warmedUp; constructor(keyOf: (item: T) => string, scopeOf: (item: T) => string); /** * Fold a poll's items into the baseline and return the ones worth announcing: the items not seen * before, from projects this watcher has a real baseline for. `whole` names the projects the poll * read completely, and only those earn a baseline — so whatever already existed at start-up is * never announced, and a project that could not be read stays quiet until it can be. * * Items keep being folded in either way: a partial read can only under-report, never invent, so * anything it did see is still something the user should not later hear about as new. */ observe(items: T[], whole: Iterable<string>): T[]; } /** A running watcher; call {@link KeyedWatcher.stop} to end it. */ export interface KeyedWatcher { stop: () => void; /** Run one poll now. Exposed so the daemon and tests can drive it deterministically. */ poll: () => Promise<void>; } /** Options for {@link startKeyedWatcher}. */ export interface KeyedWatcherOptions<T> { /** The projects to scan each poll (the daemon passes the registry, mapped to summaries). */ projects: () => Promise<ProjectSummary[]>; /** * Project the scanned projects into the items being watched, and name the projects that were read * whole — the ones whose share of the items is all of it, rather than all that could be reached. */ build: (projects: ProjectSummary[]) => Promise<ProjectionRead<T>>; /** The stable identity of an item, so the same one is only ever announced once. */ keyOf: (item: T) => string; /** Which project an item belongs to: the baseline is kept per project (#1623). */ scopeOf: (item: T) => string; /** Called with the genuinely-new items each poll (empty polls are skipped). */ onNew: (items: T[]) => void | Promise<void>; } /** * Watch a projection and hand each poll's new items to `onNew`. A project's first *whole* read only * seeds that project's baseline. Forgiving — a failed project scan or projection just yields no new * items that cycle, and earns no baseline: the baseline must come from a real read, or a first poll * that could not reach GitHub would make the next good one announce everything pre-existing as new. * * Owns no timer (E4): the daemon's one clock calls {@link KeyedWatcher.poll}, so the cadence is * declared where every other background job's is. */ export declare function startKeyedWatcher<T>(opts: KeyedWatcherOptions<T>): KeyedWatcher; //# sourceMappingURL=keyed-watcher.d.ts.map