flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/packages/contracts/src/mentions.ts

88 lines3,649 bytesCodeBlame
1/**
2 * `@g1t-agent` in comments, and rules that put g1t-agent to work by
3 * itself. Kept by the work service; mirrors `services/work/src/mentions.rs`.
4 */
5import type { ServiceBinding } from "./clients";
6import type { User, Viewer } from "./identity";
7import type { RepoPath } from "./repos";
8import type { Result } from "./result";
9import type { LifecycleJob, PullStatus } from "./work";
10
11/** How g1t's agent is mentioned in a comment. */
12export const AGENT_HANDLE = "@g1t-agent";
13
14/** What someone who mentioned `@g1t-agent` wants. */
15export type MentionIntent = "work" | "question" | "review";
16
17/** What the runner needs to act on a comment that mentioned `@g1t-agent`. */
18export type MentionJob = {
19 commentId: string;
20 /** Who wrote it, with the memberships they had then. */
21 actor: User;
22 repo: RepoPath;
23 number: number;
24 /** The comment as written. */
25 body: string;
26 intent: MentionIntent;
27 /** Whether they belong to the repository's workspace. */
28 member: boolean;
29 defaultBranch: string;
30 /** Set when the comment is on an issue: whether it is still open. */
31 issueOpen: boolean | null;
32 /** On an issue: the pull request g1t-agent is already working on for it, if any. */
33 workingPull: number | null;
34 /** Set when the comment is on a pull request. */
35 pull: {
36 id: string;
37 status: PullStatus;
38 /** Made by g1t-agent, which g1t sees through. */
39 agentAuthored: boolean;
40 /** Where its change is: its fork, or the repository itself. */
41 source: RepoPath;
42 /** The head is a branch of the repository itself, not a fork. */
43 inRepo: boolean;
44 branch: string | null;
45 headCommit: string | null;
46 files: string[];
47 } | null;
48};
49
50/** A repository's rules for putting g1t-agent to work by itself. */
51export type AgentRules = {
52 /** When an issue is given this label, g1t-agent takes it. */
53 label: string | null;
54 updatedBy: string | null;
55 updatedAt: string | null;
56};
57
58export interface MentionsApi {
59 /** For the runner: claims a comment's mention, once. Null when there is none to take. */
60 takeMention(commentId: string): Promise<MentionJob | null>;
61 /** For the runner: sends the author of a g1t pull request back to address the comment. */
62 mentionRevision(commentId: string): Promise<Result<LifecycleJob>>;
63 /** For the runner: says something in the mention's thread as g1t-agent, once. */
64 replyMention(commentId: string, body: string): Promise<boolean>;
65 getAgentRules(repo: RepoPath, viewer: Viewer): Promise<Result<AgentRules>>;
66 /** Members only. A null or empty label turns the rule off. */
67 setAgentRules(actor: User, repo: RepoPath, rules: { label: string | null }): Promise<Result<AgentRules>>;
68}
69
70/** The mention and rule methods of the work service. */
71export function mentionsClient(service: ServiceBinding): MentionsApi {
72 const call = async <T>(method: string, args: object): Promise<T> => {
73 const response = await service.fetch(`https://service/rpc/${method}`, {
74 method: "POST",
75 headers: { "content-type": "application/json" },
76 body: JSON.stringify(args),
77 });
78 if (!response.ok) throw new Error(`${method} failed with status ${response.status}`);
79 return (await response.json()) as T;
80 };
81 return {
82 takeMention: (commentId) => call("take_mention", { commentId }),
83 mentionRevision: (commentId) => call("mention_revision", { commentId }),
84 replyMention: (commentId, body) => call("reply_mention", { commentId, body }),
85 getAgentRules: (repo, viewer) => call("get_agent_rules", { repo, viewer }),
86 setAgentRules: (actor, repo, rules) => call("set_agent_rules", { actor, repo, label: rules.label }),
87 };
88}