Archived
126 lines
3.4 KiB
TypeScript
126 lines
3.4 KiB
TypeScript
import type { DatabaseSync } from "node:sqlite";
|
|
import type { Mode, Result } from "../../core/contracts.js";
|
|
|
|
export type JobState =
|
|
| "admitted"
|
|
| "queued"
|
|
| "running"
|
|
| "publishing"
|
|
| "succeeded"
|
|
| "failed"
|
|
| "cancelled";
|
|
export type TriggerKind = "label" | "command";
|
|
export type Row = Record<string, string | number | bigint | null>;
|
|
|
|
export interface DatabaseContext {
|
|
db: DatabaseSync;
|
|
transaction<T>(operation: () => T): T;
|
|
audit(jobId: string | null, event: string, detail: string): void;
|
|
}
|
|
|
|
export interface Job {
|
|
id: string;
|
|
repositoryId: number;
|
|
issueNumber: number;
|
|
mode: Mode;
|
|
triggerKind: TriggerKind;
|
|
triggerKey: string;
|
|
triggerLabel?: string;
|
|
actorId: number;
|
|
actorLogin: string;
|
|
instruction: string;
|
|
state: JobState;
|
|
cancelRequested: boolean;
|
|
attempts: number;
|
|
leaseOwner?: string;
|
|
leaseExpiresAt?: number;
|
|
workspace?: string;
|
|
result?: Result;
|
|
error?: string;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface NewJob {
|
|
repositoryId: number;
|
|
issueNumber: number;
|
|
mode: Mode;
|
|
triggerKind: TriggerKind;
|
|
triggerKey: string;
|
|
triggerLabel?: string;
|
|
actorId: number;
|
|
actorLogin: string;
|
|
instruction?: string;
|
|
}
|
|
|
|
export interface Delivery {
|
|
id: string;
|
|
event: string;
|
|
eventType: string;
|
|
bodyHash: string;
|
|
payload: unknown;
|
|
attempts: number;
|
|
}
|
|
|
|
export interface OutboxItem {
|
|
id: string;
|
|
jobId: string;
|
|
kind: "claim" | "publish";
|
|
attempts: number;
|
|
}
|
|
|
|
export interface Conversation {
|
|
repositoryId: number;
|
|
issueNumber: number;
|
|
role: "planner" | "implementer";
|
|
scope: string;
|
|
sessionId: string;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export const now = (): number => Date.now();
|
|
|
|
export function mapJob(row: Row): Job {
|
|
const resultJson =
|
|
row.result_json === null ? undefined : String(row.result_json);
|
|
return {
|
|
id: String(row.id),
|
|
repositoryId: Number(row.repository_id),
|
|
issueNumber: Number(row.issue_number),
|
|
mode: String(row.mode) as Mode,
|
|
triggerKind: String(row.trigger_kind) as TriggerKind,
|
|
triggerKey: String(row.trigger_key),
|
|
...(row.trigger_label === null
|
|
? {}
|
|
: { triggerLabel: String(row.trigger_label) }),
|
|
actorId: Number(row.actor_id),
|
|
actorLogin: String(row.actor_login),
|
|
instruction: String(row.instruction),
|
|
state: String(row.state) as JobState,
|
|
cancelRequested: Number(row.cancel_requested) === 1,
|
|
attempts: Number(row.attempts),
|
|
...(row.lease_owner === null
|
|
? {}
|
|
: { leaseOwner: String(row.lease_owner) }),
|
|
...(row.lease_expires_at === null
|
|
? {}
|
|
: { leaseExpiresAt: Number(row.lease_expires_at) }),
|
|
...(row.workspace === null ? {} : { workspace: String(row.workspace) }),
|
|
...(resultJson ? { result: JSON.parse(resultJson) as Result } : {}),
|
|
...(row.error === null ? {} : { error: String(row.error) }),
|
|
createdAt: Number(row.created_at),
|
|
updatedAt: Number(row.updated_at),
|
|
};
|
|
}
|
|
|
|
export function mapConversation(row: Row): Conversation {
|
|
return {
|
|
repositoryId: Number(row.repository_id),
|
|
issueNumber: Number(row.issue_number),
|
|
role: String(row.role) as Conversation["role"],
|
|
scope: String(row.scope),
|
|
sessionId: String(row.session_id),
|
|
updatedAt: Number(row.updated_at),
|
|
};
|
|
}
|