Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

123 lines · 4.2 KBRaw History
1/**
2 * JSON-safe values. Typed loosely on purpose: a recursive JSON type is too deep
3 * for the Durable Object RPC type mapping, and `unknown` is not serialisable.
4 */
5// biome-ignore lint/suspicious/noExplicitAny: see above
6export type Json = any;
7
8/**
9 * Contract between the Diffinery control plane (Worker) and the runner agent
10 * that executes a single job inside a Cloudflare Container.
11 *
12 * All runner endpoints live under `${apiUrl}/runner/jobs/:jobId/...` and are
13 * authenticated with `Authorization: Bearer <job token>`. The job token is
14 * scoped to one job, one repository (read access for clone) and expires when
15 * the job's timeout elapses.
16 */
17
18export type Conclusion = "success" | "failure" | "cancelled" | "skipped";
19
20export type StepSpec = {
21 id?: string;
22 name?: string;
23 if?: string;
24 run?: string;
25 uses?: string;
26 with?: Record<string, string>;
27 env?: Record<string, string>;
28 shell?: string;
29 "working-directory"?: string;
30 "continue-on-error"?: boolean | string;
31 "timeout-minutes"?: number;
32};
33
34/** `jobs.<id>.container` or one of `jobs.<id>.services`; values may contain `${{ }}`. */
35export type ContainerSpec = {
36 image: string;
37 credentials?: { username?: string; password?: string };
38 env?: Record<string, string>;
39 ports?: Array<string | number>;
40 volumes?: string[];
41 options?: string;
42};
43
44export interface NeedsResult {
45 result: Conclusion;
46 outputs: Record<string, string>;
47}
48
49export type JobSpec = {
50 runId: string;
51 jobId: string;
52 /** Key of the job in the workflow file, e.g. `build`. */
53 jobKey: string;
54 /** Display name, already evaluated (matrix values substituted). */
55 name: string;
56 repo: { owner: string; name: string; cloneUrl: string; defaultBranch: string };
57 sha: string;
58 ref: string;
59 workflowPath: string;
60 /** The full `github` context (event name, payload, actor, sha, ref, ...). */
61 github: Record<string, Json>;
62 /** Workflow-level env merged with job-level env; values may contain `${{ }}`. */
63 env: Record<string, string>;
64 defaults?: { run?: { shell?: string; "working-directory"?: string } };
65 matrix: Record<string, Json>;
66 strategy: { "fail-fast": boolean; "job-index": number; "job-total": number; "max-parallel"?: number };
67 needs: Record<string, NeedsResult>;
68 inputs: Record<string, Json>;
69 vars: Record<string, string>;
70 /** Only the secrets this job may see. Values must be masked in logs. */
71 secrets: Record<string, string>;
72 /** Job `outputs:` map; values are expressions evaluated after the steps. */
73 outputs: Record<string, string>;
74 steps: StepSpec[];
75 /** Job container: steps run inside it (needs Docker on the runner). */
76 container?: ContainerSpec;
77 /** Service containers, reachable by name from a job container or via mapped ports. */
78 services?: Record<string, ContainerSpec>;
79 timeoutMinutes: number;
80 continueOnError: boolean;
81 /** Whether `permissions: id-token: write` was granted. */
82 idToken: boolean;
83 /** Base URL of the Diffinery API, e.g. `https://diffinery.com`. */
84 apiUrl: string;
85 /** Bearer token for runner endpoints and for `git clone` (as password). */
86 token: string;
87};
88
89export type LogLine = {
90 /** ISO timestamp. */
91 t: string;
92 /** Index of the step this line belongs to; -1 for job setup/teardown. */
93 step: number;
94 text: string;
95};
96
97export type StepReport = {
98 status: "in_progress" | "completed";
99 conclusion?: Conclusion;
100 name: string;
101 startedAt?: string;
102 completedAt?: string;
103};
104
105export type JobCompletion = {
106 conclusion: Conclusion;
107 outputs: Record<string, string>;
108 /** Markdown written to $GITHUB_STEP_SUMMARY, if any. */
109 summary?: string;
110 /** Short machine-readable reason when the job failed (for agents). */
111 failure?: { step?: number; message: string };
112};
113
114/** Runner API paths, relative to `${apiUrl}/runner/jobs/${jobId}`. */
115export const RunnerPaths = {
116 spec: "",
117 logs: "/logs", // POST { lines: LogLine[] }
118 step: (index: number) => `/steps/${index}`, // POST StepReport
119 complete: "/complete", // POST JobCompletion
120 cache: "/cache", // GET ?key=&restore=a,b -> { key, url } | 404 ; PUT /cache/:key body=tar.gz
121 artifacts: "/artifacts", // PUT /artifacts/:name body=zip|tar ; GET /artifacts/:name
122 oidc: "/oidc", // POST { audience } -> { value }
123} as const;