Skip to content

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.sh
172 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { LifecycleJob, MentionJob, Result } from "@g1t/contracts";
5
Merge branch 'worktree-agent-ad8a36dfcd4176015' into spend-guardrails6import { type MentionPorts, buildMentionPrompt, handleMention, jobTokenRefusal, planMention } from "./mentions.ts";
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas7
8const ana = { id: "usr_ana", username: "ana", verified: true, workspaces: [{ slug: "acme", role: "member" as const }] };
9
10function onIssue(intent: MentionJob["intent"], extra: Partial<MentionJob> = {}): MentionJob {
11 return {
12 commentId: "cmt_1",
13 actor: ana,
14 repo: { namespace: "acme", name: "site" },
15 number: 7,
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent16 body: "@g1t take this",
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas17 intent,
18 member: true,
19 defaultBranch: "main",
20 issueOpen: true,
21 workingPull: null,
22 pull: null,
23 ...extra,
24 };
25}
26
27function onPull(intent: MentionJob["intent"], pull: Partial<NonNullable<MentionJob["pull"]>> = {}): MentionJob {
28 return onIssue(intent, {
29 issueOpen: null,
30 pull: {
31 id: "pr_1",
32 status: "open",
33 agentAuthored: true,
34 source: { namespace: "acme", name: "site-pr-1" },
35 inRepo: false,
36 branch: null,
37 headCommit: "abc",
38 files: ["src/a.ts"],
39 ...pull,
40 },
41 });
42}
43
44test("on an issue, a request assigns it and a question is answered", () => {
45 assert.equal(planMention(onIssue("work")).kind, "assign");
46 assert.equal(planMention(onIssue("question")).kind, "answer");
47 assert.equal(planMention(onIssue("work", { issueOpen: false })).kind, "closed");
48 // Already at work on it: not a second attempt.
49 const busy = planMention(onIssue("work", { workingPull: 9 }));
50 assert.equal(busy.kind, "closed");
51 assert.match(busy.kind === "closed" ? busy.reason : "", /already working on this in #9/);
52 assert.equal(planMention(onIssue("question", { workingPull: 9 })).kind, "answer");
53});
54
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent55test("on g1t's pull request, a request sends it back", () => {
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas56 assert.equal(planMention(onPull("work")).kind, "revise");
57 assert.equal(planMention(onPull("work", { status: "draft" })).kind, "message");
58 assert.equal(planMention(onPull("question")).kind, "answer");
59 assert.equal(planMention(onPull("review")).kind, "review");
60 assert.equal(planMention(onPull("work", { status: "merged" })).kind, "closed");
61});
62
63test("on anyone else's pull request, it reviews or answers", () => {
64 assert.equal(planMention(onPull("review", { agentAuthored: false })).kind, "review");
65 assert.equal(planMention(onPull("work", { agentAuthored: false })).kind, "answer");
66 assert.equal(planMention(onPull("question", { agentAuthored: false, status: "closed" })).kind, "answer");
67});
68
69test("someone without Write on the repository is thanked and nothing starts", async () => {
70 const { ports, replies, started } = fakePorts();
71 const plan = await handleMention(onIssue("work", { member: false }), ports);
72 assert.equal(plan.kind, "not_member");
73 assert.deepEqual(started, []);
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent74 assert.match(replies[0], /Putting g1t to work needs the Write role on acme\/[^,]+, so I have left this/);
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas75});
76
77test("a workspace that cannot run agents is told why, and the run is recorded", async () => {
78 const { ports, replies, started, recorded } = fakePorts({ refusal: "Its free allowance is used up." });
79 await handleMention(onIssue("work"), ports);
80 assert.deepEqual(started, []);
81 assert.deepEqual(recorded, ["Its free allowance is used up."]);
82 assert.match(replies[0], /could not start on this: Its free allowance is used up/);
83});
84
85test("a request on an issue assigns it and says where the work is", async () => {
86 const { ports, replies, started } = fakePorts();
87 await handleMention(onIssue("work"), ports);
88 assert.deepEqual(started, ["assign"]);
89 assert.match(replies[0], /I opened #12/);
90});
91
92test("a revision already under way gets the comment as a message", async () => {
93 const { ports, replies, started } = fakePorts({ revision: { ok: false, error: { code: "conflict", message: "busy" } } });
94 await handleMention(onPull("work"), ports);
95 assert.deepEqual(started, ["message"]);
96 assert.match(replies[0], /passed your comment on/);
97});
98
99test("a revision starts with the comment, credited to whoever asked", async () => {
100 const { ports, started } = fakePorts();
101 await handleMention(onPull("work"), ports);
102 assert.deepEqual(started, ["revise:ana"]);
103});
104
105test("an answer is the reply, so nothing else is said", async () => {
106 const { ports, replies, started } = fakePorts();
107 await handleMention(onIssue("question"), ports);
108 assert.deepEqual(started, ["answer"]);
109 assert.deepEqual(replies, []);
110});
111
112test("the question is in the prompt, and nothing is to change", () => {
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent113 const prompt = buildMentionPrompt(onIssue("question", { body: "@g1t why is this slow?" }), {
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas114 title: "Search is slow",
115 body: "It takes 4s.",
116 thread: null,
117 });
118 assert.match(prompt, /issue #7/);
119 assert.match(prompt, /why is this slow\?/);
120 assert.match(prompt, /Do not change any files/);
121});
122
123function fakePorts(options: { refusal?: string; revision?: Result<LifecycleJob> } = {}) {
124 const replies: string[] = [];
125 const started: string[] = [];
126 const recorded: string[] = [];
127 const job = { pullId: "pr_1" } as LifecycleJob;
128 const ports: MentionPorts = {
129 mentions: {
130 takeMention: async () => null,
131 mentionRevision: async () => options.revision ?? { ok: true, value: job },
132 replyMention: async (_id, body) => {
133 replies.push(body);
134 return true;
135 },
136 getAgentRules: async () => ({ ok: true, value: { label: null, updatedBy: null, updatedAt: null } }),
137 setAgentRules: async () => ({ ok: true, value: { label: null, updatedBy: null, updatedAt: null } }),
138 },
139 refusal: async () => options.refusal ?? null,
140 assign: async () => {
141 started.push("assign");
142 return { ok: true, value: { number: 12 } as never };
143 },
144 revise: async (_job, by) => {
145 started.push(`revise:${by}`);
146 },
147 review: async () => {
148 started.push("review");
149 return { ok: true, value: true };
150 },
151 answer: async () => {
152 started.push("answer");
153 return { ok: true, value: true };
154 },
155 message: async () => {
156 started.push("message");
157 return { ok: true, value: null };
158 },
159 record: async (_job, why) => {
160 recorded.push(why);
161 },
162 };
163 return { ports, replies, started, recorded };
164}
Merge branch 'worktree-agent-ad8a36dfcd4176015' into spend-guardrails165
166test("a workflow job's token never puts g1t to work; a person's own token can", () => {
167 const job = { ...ana, token: { scopes: ["repo"], job: { run_id: "run_9", job_id: "job_1" } } };
168 assert.match(jobTokenRefusal(job) ?? "", /job's token/);
169 assert.equal(jobTokenRefusal({ ...ana, token: { scopes: ["repo"] } }), null);
170 assert.equal(jobTokenRefusal(ana), null);
171 assert.equal(jobTokenRefusal(null), null);
172});

This file's history is long; its oldest lines are credited to the oldest commit read.