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
99 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.

Merge branch 'ask-g1t'1/**
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.2 * Ask g1t (components/ask-composer): where the person is when they ask,
3 * which goes with each question to their direct message with @g1t, so g1t
4 * is told the page and reads the issue or pull request on it. Pure, so it
5 * is tested on its own.
Merge branch 'ask-g1t'6 */
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.7import type { AskEvent, AskPage, AskSource, AskToolStatus } from "@g1t/contracts";
Merge branch 'ask-g1t'8
9/** First path segments that are g1t's own pages, never a workspace. */
10const RESERVED = new Set([
11 "settings", "u", "auth", "oauth", "integrations", "new", "invite", "workspaces", "device", "verify",
12 "confirm-email", "login", "register", "logout", "forgot", "reset", "search", "status", "avatars", "docs", "-",
13]);
14
15/** Where the person is: the page, and the repository, issue or pull request on it. */
16export function askPage(pathname: string): AskPage {
17 const path = pathname.split(/[?#]/)[0] ?? "";
18 const parts = path.split("/").filter(Boolean).map((part) => decodeURIComponent(part));
19 const page: AskPage = { path: path || "/" };
20 const [owner, name, section, number] = parts;
21 if (!owner || !name || RESERVED.has(owner.toLowerCase()) || name === "-") return page;
22 page.repo = { namespace: owner.toLowerCase(), name };
23 const numbered = number && /^\d+$/.test(number) ? Number(number) : null;
24 if (numbered != null && section === "issues") page.issue = numbered;
25 if (numbered != null && section === "pull") page.pull = numbered;
26 return page;
27}
28
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.29/** What the composer says about where the question is asked from. */
30export function askWhere(page: AskPage): string | null {
31 if (page.issue) return `On issue #${page.issue}`;
32 if (page.pull) return `On pull request #${page.pull}`;
33 if (page.repo) return `In ${page.repo.name}`;
34 return null;
35}
Merge branch 'ask-g1t'36
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.37/**
38 * A step an answer took: one of g1t's tools, run as the person asking. Its
39 * `tool` line comes when it starts and again, with the same id, when it ends.
40 */
41export type Step = {
Merge branch 'ask-g1t'42 id: string;
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.43 name: string;
44 action: string | null;
45 label: string;
46 status: AskToolStatus;
47 summary: string | null;
48 link: string | null;
Merge branch 'ask-g1t'49};
50
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.51/** A session g1t proposed in an answer: the person starts it, or copies its command. */
52export type Proposal = Extract<AskEvent, { type: "proposal" }>;
Merge branch 'ask-g1t'53
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.54/** What a proposal asks the session to do, in a line: "Implement #12 in acme/web". */
55export function proposalTitle(proposal: Proposal): string {
56 const verb = { plan: "Plan", implement: "Implement", review: "Review" }[proposal.mode] ?? "Work on";
57 return proposal.issue ? `${verb} #${proposal.issue} in ${proposal.repo}` : `${verb} “${proposal.title}” in ${proposal.repo}`;
Merge branch 'ask-g1t'58}
59
60/**
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.61 * An answer's steps and sources from the raw events kept with it (a chat
62 * message keeps the `tool` and `sources` lines it was streamed with):
63 * each step once, as it last was, in the order they started; the last
64 * `sources`; each proposal once. Anything else, or anything malformed, is skipped.
Merge branch 'ask-g1t'65 */
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.66export function foldAnswer(events: unknown): { steps: Step[]; sources: AskSource[]; proposals: Proposal[] } {
67 let steps: Step[] = [];
68 let sources: AskSource[] = [];
69 const proposals: Proposal[] = [];
70 for (const event of Array.isArray(events) ? events : []) {
71 if (!event || typeof event !== "object") continue;
72 const line = event as AskEvent;
73 if (line.type === "tool" && typeof line.id === "string" && typeof line.label === "string") steps = withStep(steps, line);
74 if (line.type === "sources" && Array.isArray(line.sources)) {
75 sources = line.sources.filter((source) => source && typeof source.url === "string" && typeof source.title === "string");
76 }
77 if (line.type === "proposal" && typeof line.id === "string" && typeof line.repo === "string" && (line.issue || line.title)) {
78 if (!proposals.some((known) => known.id === line.id)) proposals.push(line);
Merge branch 'ask-g1t'79 }
80 }
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.81 return { steps, sources, proposals };
Merge branch 'ask-g1t'82}
83
g1t coordinates the work and the person's own sessions do it: Ask g1t reads g1t with the same tools any agent gets, answers in one conversation shared with the @g1t direct message in Chat, and hands work to sessions in the person's own harness, whose subagents g1t records, ties to issues and pull requests, and lets see each other.84/** The steps with this one in its place: a new one at the end, a known one updated. */
85export function withStep(steps: Step[] | undefined, event: Extract<AskEvent, { type: "tool" }>): Step[] {
86 const step: Step = {
87 id: event.id,
88 name: event.name,
89 action: event.action ?? null,
90 label: event.label,
91 status: event.status,
92 summary: event.summary ?? null,
93 link: event.link ?? null,
94 };
95 const list = steps ?? [];
96 const at = list.findIndex((known) => known.id === step.id);
97 if (at === -1) return [...list, step];
98 return list.map((known, index) => (index === at ? step : known));
Merge branch 'ask-g1t'99}

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