pr_01m47d15m3e54sn21z27rpy5n9/packages/contracts/src/work.ts

105 lines3,937 bytesCodeBlame
1import type { User, Viewer } from "./identity";
2import type { RepoPath } from "./repos";
3import type { Result } from "./result";
4
5export type IntentStatus = "open" | "shipped" | "withdrawn";
6
7/** A goal stated against a repo. Replaces the issue and the pull request. */
8export type Intent = {
9 id: string;
10 repoId: string;
11 /** Sequential per repo, shown as `#12`. */
12 number: number;
13 title: string;
14 /** The goal in prose: what an agent is given to work from. */
15 brief: string;
16 /** Commands that must pass for an attempt to be accepted. */
17 checks: string[];
18 status: IntentStatus;
19 author: User;
20 /** RFC 3339. */
21 createdAt: string;
22 attemptCount: number;
23};
24
25export type AttemptStatus = "working" | "submitted" | "shipped" | "abandoned";
26
27/** Where the agent runs: on g1t's sandboxes, or in someone's own session. */
28export type AttemptRuntime = "hosted" | "external";
29
30/** One agent's run at an intent, in its own fork. */
31export type Attempt = {
32 id: string;
33 intentId: string;
34 repoId: string;
35 /** Sequential per intent. */
36 number: number;
37 /** A label for the agent doing the work, e.g. `claude-code`. */
38 agent: string;
39 runtime: AttemptRuntime;
40 status: AttemptStatus;
41 /** The agent's own account of what it did, set on submit. */
42 summary: string | null;
43 fork: RepoPath;
44 /** The fork's repository id. */
45 forkRepoId: string;
46 headCommit: string | null;
47 /**
48 * For a shipped attempt, what the branch pointed to before it landed.
49 * Comparing against it shows what the attempt changed.
50 */
51 landedBase: string | null;
52 startedBy: User;
53 /** RFC 3339. */
54 createdAt: string;
55 /** RFC 3339. */
56 updatedAt: string;
57};
58
59export type SessionEntryKind = "prompt" | "message" | "tool_call" | "tool_result" | "note";
60
61/** One step of an agent's session: the "why" behind an attempt's commits. */
62export type SessionEntry = {
63 seq: number;
64 kind: SessionEntryKind;
65 text: string;
66 /** For tool calls and results. */
67 tool: string | null;
68 /** The fork's head commit when this entry was recorded, if known. */
69 commit: string | null;
70 /** RFC 3339. */
71 at: string;
72};
73
74export type NewSessionEntry = Pick<SessionEntry, "kind" | "text"> &
75 Partial<Pick<SessionEntry, "tool" | "commit">>;
76
77export type IntentDetail = { intent: Intent; attempts: Attempt[] };
78
79export type OpenIntentInput = { title: string; brief: string; checks?: string[] };
80
81export type StartAttemptInput = { agent: string; runtime: AttemptRuntime };
82
83/** Intents, attempts and sessions. */
84export interface WorkApi {
85 openIntent(actor: User, repo: RepoPath, input: OpenIntentInput): Promise<Result<Intent>>;
86 listIntents(repo: RepoPath, viewer: Viewer, status?: IntentStatus): Promise<Result<Intent[]>>;
87 getIntent(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<IntentDetail>>;
88 withdrawIntent(actor: User, intentId: string): Promise<Result<Intent>>;
89
90 /** Forks the repo for the agent and returns the attempt to push to. */
91 startAttempt(actor: User, intentId: string, input: StartAttemptInput): Promise<Result<Attempt>>;
92 getAttempt(attemptId: string, viewer: Viewer): Promise<Result<{ attempt: Attempt; intent: Intent }>>;
93 submitAttempt(actor: User, attemptId: string, summary: string): Promise<Result<Attempt>>;
94 abandonAttempt(actor: User, attemptId: string): Promise<Result<Attempt>>;
95 /**
96 * Lands the attempt on the repository's default branch and closes its
97 * intent as shipped. Only the repository's owner may ship.
98 */
99 shipAttempt(actor: User, attemptId: string): Promise<Result<Attempt>>;
100 /** Attempts in progress that the viewer started, newest first. */
101 listActiveAttempts(viewer: Viewer): Promise<{ attempt: Attempt; intent: Intent }[]>;
102
103 appendSession(actor: User, attemptId: string, entries: NewSessionEntry[]): Promise<Result<{ count: number }>>;
104 readSession(attemptId: string, viewer: Viewer, afterSeq?: number): Promise<Result<SessionEntry[]>>;
105}