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.
85 lines • 4.79 kB
TypeScript
import { type LiveAgent, type AgentMeta } from '../store/index.js';
import type { ProjectSummary, ProjectionRead } from './projects.js';
import { type AgentHandoff } from './agent-handoff.js';
import { type PrLister } from './gh.js';
export { interventionKey } from './keys.js';
/**
* One item awaiting the human. Two kinds: an open `pr` to review/merge or close, and an
* `awaiting` run paused on a choice gate. The card, the browser hook, and the Discord watcher
* all iterate the flat list, branching on `kind` for the fields that differ.
*/
export interface Intervention {
projectId: string;
projectName: string;
/**
* `pr` = an open PR to review/merge or close; `awaiting` = an agent paused on a choice gate (#636);
* `unpushed` = a finished agent whose branch has commits that were never pushed (#860).
*/
kind: 'pr' | 'awaiting' | 'unpushed';
title: string;
/** Where to act: the PR on GitHub (`pr`), or the dashboard (the other two, when the URL is known). */
url: string;
/** The PR number (`pr` only). */
number?: number;
/** The parked gate's id (`awaiting` only) — its stable identity, so it notifies exactly once. */
awaitId?: string;
/** Which run this is about (`awaiting` #738 / `unpushed`): a project has several agents. */
agentId?: string;
/** The branch the work is sitting on (`unpushed` only). */
branch?: string;
/** How many commits are waiting (`unpushed` only). */
commits?: number;
/** When the PR was opened (`pr`) or the agent last updated (the other two), ISO, for ordering. */
createdAt?: string;
}
/** Injectable seam so {@link buildInterventions} is unit-testable off disk. */
export interface InterventionsDeps {
prs?: PrLister;
/** The live-agent reader (default {@link readLiveMetas}); drives the `awaiting` source (#636). */
liveAgents?: (cwd: string) => Promise<LiveAgent[]>;
/** The finished-agent reader (default {@link listAgents}); drives the `unpushed` source (#860). */
agents?: (cwd: string) => Promise<AgentMeta[]>;
/** Reads a branch's state (default {@link readAgentHandoff}); drives the `unpushed` source (#860). */
handoff?: (cwd: string, branch: string) => Promise<AgentHandoff | undefined>;
/**
* How many of a project's most recent finished agents to inspect for unpushed work. Each one costs
* a handful of git reads, and this runs on a poll, so old history is not re-walked every minute:
* work that has sat unpushed for dozens of agents is not news, and the agent list stays the record.
*/
handoffLimit?: number;
/**
* The dashboard's own URL, so an `awaiting` item can link back to it. Only the daemon knows
* it (the card path resolves the project client-side and needs no URL), so it is optional; an
* awaiting item's `url` is empty when it is unset.
*/
dashboardUrl?: string;
}
/**
* Build the cross-project interventions queue: every registered project's open PRs, plus any run
* currently paused on a choice gate (#636), newest first. Forgiving — a project with no remote
* (or an unreadable one) simply contributes nothing. Hand-opened draft PRs are excluded: they are
* not yet asking for review. A session's own draft is not (#1102), because that is how
* auto-handoff hands work back.
*
* Which projects were read whole comes back alongside the items (#1623): forgiveness here is what
* lets one unreachable project keep the queue useful, and it is also what would let that project's
* whole backlog announce itself as new the moment it came back. The queue's panels ignore this;
* the notification watcher is the caller that cannot.
*/
export declare function buildInterventions(projects: ProjectSummary[], deps?: InterventionsDeps): Promise<ProjectionRead<Intervention>>;
/**
* How one intervention reads on Discord. Beside {@link Intervention} rather than inside the
* watcher that posts it: it switches on every `kind`, so adding a kind is a change here, not in
* a transport module that has no other opinion about what an intervention is.
*
* A PR reads `#123 Title — url`; a paused agent (#636) has no number and only the dashboard url,
* so it reads `Title — awaiting your answer` with the link appended when the daemon knows it.
* Unpushed work (#860) names the branch, since that is the actionable part.
*/
export declare function interventionLine(item: Intervention): string;
/**
* Post the given interventions to a Discord webhook as one message, resolving whether Discord
* accepted it (#940). `fetch` is injectable for tests.
*/
export declare function postInterventionsDiscord(webhook: string, items: Intervention[], fetchImpl?: typeof fetch): Promise<boolean>;
//# sourceMappingURL=interventions.d.ts.map