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.
89 lines • 3.96 kB
JavaScript
/**
* The agent's lifecycle progress (#326): the latest `session-name` the agent set and whether
* a `ready-for-merge` has fired. Drives the dashboard status label + dot (orange building,
* green ready). Always returns a value — an untouched agent is `{ readyForMerge: false }`.
*/
export function agentProgress(events) {
const progress = { readyForMerge: false };
for (const event of events) {
if (event.kind === 'session-name')
progress.sessionName = event.name;
else if (event.kind === 'ready-for-merge')
progress.readyForMerge = true;
}
return progress;
}
/**
* Every error the agent reported (#1500), oldest first — the count the dashboard shows on the
* session, and the latest headline it shows beside it.
*
* A fold over the log rather than state of its own: an error is an event that happened, so the
* list only ever grows, and reopening a finished agent shows exactly what it showed while it ran.
*/
export function agentErrors(events) {
const errors = [];
for (const event of events) {
if (event.kind !== 'error')
continue;
errors.push({ headline: event.headline, ...(event.detail ? { detail: event.detail } : {}) });
}
return errors;
}
/**
* What the session is armed to hand back, folded from its own events (#1102).
*
* Both halves start armed, so an agent from before this existed — which emits no `handoff-armed` —
* reads as armed, which is what it will actually do once it is running new code. Latest wins: the
* checkboxes re-emit on every change.
*
* `initial` seeds the armed pair for a reader whose event stream missed the opening
* `handoff-armed` (#1376): the agent writes it as its very first event, before the live channel has
* attached, so a live tab can only learn the real state from the agent record's mirror
* (`AgentRecord.handoff`) — without it, a session the launcher armed push-only reads as "Open PR".
* A `handoff-armed` event in the stream still wins: it is newer than any record snapshot.
*/
export function handoffState(events, initial) {
const state = { push: initial?.push ?? true, pr: initial?.pr ?? true, merge: initial?.merge ?? false };
for (const event of events) {
if (event.kind === 'handoff-armed') {
state.push = event.push;
state.pr = event.pr;
// Absent on pre-#1382 events: keep the seed rather than flipping an armed merge off.
if (event.merge !== undefined)
state.merge = event.merge;
}
else if (event.kind === 'handoff') {
state.result =
event.outcome === 'done'
? { outcome: 'done', ...(event.url ? { url: event.url } : {}) }
: event.outcome === 'failed'
? { outcome: 'failed', error: event.error }
: { outcome: 'skipped', reason: event.reason };
}
}
return state;
}
/**
* The session behind the agent (#431): the driver + workspace from the opening `session`
* event, then the id and any deep link from the latest `session-update`. Null before the
* session opens. The link is what the old dashboard surfaced as "open session".
*/
export function sessionInfo(events) {
let info = null;
for (const event of events) {
if (event.kind === 'session') {
info = {
driver: event.driver,
fake: event.fake,
workspace: event.workspace,
...(event.sessionLink ? { sessionLink: event.sessionLink } : {}),
...(event.model ? { model: event.model } : {}),
};
}
else if (event.kind === 'session-update') {
info = { ...(info ?? {}), sessionId: event.sessionId, ...(event.sessionLink ? { sessionLink: event.sessionLink } : {}) };
}
}
return info;
}
//# sourceMappingURL=agent-view.js.map