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.

1,970 linesCodeBlameRaw
1import type { ChecksApi } from "./checks";
2import type { CodeownersReport, PullCodeOwners } from "./codeowners";
3import type { G1tEvent } from "./events";
4import type { User, Viewer } from "./identity";
5import type { PullBranchUpdate, RepoPath, UpdateMethod } from "./repos";
6import type { MergeMethod } from "./rules";
7import type { Result } from "./result";
8import type { MergeRules, RulesApi } from "./rules";
9
10/**
11 * The filter on lists of work items and pull requests. An open pull
12 * request is a draft or one ready for review; a closed one was merged or
13 * closed without merging.
14 */
15export type State = "open" | "closed";
16
17/** Why a work item was closed. */
18export type CloseReason = "completed" | "not_planned";
19
20/**
21 * How a work item is linked to a repository: where it was filed (`origin`,
22 * which keeps an old issue's number), where the work is meant to land
23 * (`target`), or where work for it landed or is under way (`touched`).
24 */
25export type LinkRole = "origin" | "target" | "touched";
26
27/** A repository a work item is linked to. */
28export type ItemRepo = {
29 repoId: string;
30 /** `owner/name`, as it is now, or as it was when the repository was deleted. */
31 path: string;
32 role: LinkRole;
33 /** For the origin of a work item moved from a repository's issues: its number there. */
34 legacyNumber: number | null;
35 /** A pull request or commit that closes it landed in this repository. */
36 landed: boolean;
37 /**
38 * The repository is deleted, and can still be restored until it is
39 * purged: `path` is where it was. It has nothing to open or read.
40 */
41 deleted?: boolean;
42};
43
44/** What resolved a work item in one repository: a pull request merged, or a commit pushed. */
45export type Resolution = {
46 /** `owner/name`. */
47 repo: string;
48 pull: number | null;
49 commit: string | null;
50 /** Who pushed that commit, by username. */
51 pushedBy: string | null;
52};
53
54/**
55 * Any tracked work of a workspace: a feature, a bug, a chore. Numbered in
56 * the workspace with its new pull requests, and linked to the repositories
57 * it concerns. It closes once what closes it has landed in every target,
58 * or, with no targets, once anything that closes it lands. Mirrors
59 * `crates/contracts/src/work/items.rs`.
60 */
61export type WorkItem = {
62 /** `wki_…`; one moved from an issue keeps its `iss_…`. */
63 id: string;
64 /** The workspace's slug. */
65 workspace: string;
66 /** Shown as `#12`; on the site at `/<workspace>/-/work/<number>`. */
67 number: number;
68 title: string;
69 /** Markdown. Also what an agent is given to work from. */
70 body: string;
71 labels: string[];
72 state: State;
73 /** Set when closed. */
74 reason: CloseReason | null;
75 /** What resolved it, in each repository it landed in, oldest first. */
76 resolutions: Resolution[];
77 /** Who opened it: a person, an integration, or g1t (`kind` `agent`) for one its agent filed while at work. */
78 author: User;
79 /**
80 * For one g1t's agent filed: the person it was working for. They may
81 * manage it as its author could. See `workOwner`.
82 */
83 requestedBy: User | null;
84 /** RFC 3339. */
85 createdAt: string;
86 /** RFC 3339. */
87 updatedAt: string;
88 /** RFC 3339. */
89 closedAt: string | null;
90 /** Pull requests made for it, in any state and repository. */
91 pullCount: number;
92 commentCount: number;
93 /** Usernames of the people it is assigned to. */
94 assignees: string[];
95 /** The numbers of the work items of the workspace that have to land before this one is worked on. */
96 blockedBy: number[];
97 /**
98 * The agent working on it now: the one behind its newest pull request
99 * that is still in progress in a fork, such as `g1t`.
100 */
101 agent: string | null;
102 /** The workspace milestone it is in, if any. */
103 milestone?: MilestoneRef | null;
104 /** The repositories it is linked to: its origin first, then targets, then those it touched. */
105 repos: ItemRepo[];
106};
107
108/** The targets of a work item that have not landed yet, by path. */
109export function missingTargets(repos: ItemRepo[]): string[] {
110 return repos.filter((repo) => repo.role === "target" && !repo.landed).map((repo) => repo.path);
111}
112
113/** A work item and everything on it. */
114export type WorkItemDetail = {
115 item: WorkItem;
116 /** Every pull request made for it, in the repositories the viewer may read, oldest first. */
117 pulls: Pull[];
118 comments: Comment[];
119 /** How people (and g1t) reacted to its description. */
120 reactions: ReactionGroup[];
121};
122
123/** What `#N` names (`resolveRef`): see `refs.ts` for the order it is read in. */
124export type RefTarget =
125 | { kind: "work_item"; workspace: string; number: number; itemId: string }
126 | { kind: "pull"; repo: string; number: number }
127 | { kind: "none" };
128
129/**
130 * What a comment, a reaction or a set of labels is on: a pull request of a
131 * repository, or a work item of a workspace.
132 */
133export type Thread = { repo: RepoPath; number: number } | { workspace: string; number: number };
134
135/**
136 * A label of a workspace: a name, a color and what it means. Work items and
137 * the pull requests of its repositories carry labels by name; names are
138 * lowercase.
139 */
140export type Label = {
141 name: string;
142 /** Six hex digits, without `#`. */
143 color: string;
144 description: string;
145 /** How many work items carry it, open or closed. */
146 items: number;
147 /** How many pull requests carry it, in any state. */
148 pulls: number;
149};
150
151/** A work item a commit resolved, as the commit page lists it. */
152export type ClosedItem = { workspace: string; number: number; title: string; closed: boolean };
153
154/** A milestone, as a work item or pull request names it. */
155export type MilestoneRef = { number: number; title: string };
156
157/**
158 * A goal of a workspace, with an optional due date, that work items and
159 * pull requests are gathered under. Its progress is how many of them are
160 * closed.
161 */
162export type Milestone = {
163 /** Numbered from 1 in each workspace, apart from work items. */
164 number: number;
165 title: string;
166 /** Markdown. */
167 description: string;
168 /** `YYYY-MM-DD`. */
169 dueOn: string | null;
170 state: State;
171 /** Open work items and pull requests in it. */
172 openItems: number;
173 /** Closed work items, and merged or closed pull requests, in it. */
174 closedItems: number;
175 createdAt: string;
176 updatedAt: string;
177 closedAt: string | null;
178 /** For one moved from a repository when work items moved to the workspace: its id. */
179 originRepoId?: string;
180};
181
182/** One milestone and what is in it that the viewer may see, newest first. */
183export type MilestoneDetail = { milestone: Milestone; items: WorkItem[]; pulls: Pull[] };
184
185/** How `setLabels` changes an item's labels. */
186export type LabelChange = "set" | "add" | "remove";
187
188/**
189 * Whose a work item or a pull request is to answer for: whoever asked g1t for
190 * it, or its author. They may change, close and steer it, are never asked to
191 * review it and cannot approve it, and see it as theirs. Mirrors
192 * `Pull::owner` in the Rust contracts.
193 */
194export function workOwner(item: Pick<Pull, "author" | "requestedBy">): User {
195 return item.requestedBy ?? item.author;
196}
197
198/** `draft` is still being worked on; `open` is ready for review. */
199export type PullStatus = "draft" | "open" | "merged" | "closed";
200
201/** Where the agent runs: on g1t's sandboxes, or in someone's own session. */
202export type Runtime = "hosted" | "external";
203
204/**
205 * A proposed change. It is made either in a fork created for it, which is
206 * how agents work, on a branch pushed to the repository itself, or on a
207 * branch of someone's fork of it (`headRepo`).
208 */
209export type Pull = {
210 id: string;
211 repoId: string;
212 /** Shown as `#12`. New ones are numbered in the workspace's sequence, which work items share. */
213 number: number;
214 /** The work item this is for, if any, by number in the workspace. */
215 item: number | null;
216 title: string;
217 /** Markdown: what changed and why. Set when marked ready. */
218 body: string | null;
219 /** A label for the agent doing the work, e.g. `claude-code`. */
220 agent: string;
221 runtime: Runtime;
222 status: PullStatus;
223 /** The fork holding the change, unless it is on a branch. */
224 fork: RepoPath | null;
225 /** The fork's repository id. */
226 forkRepoId: string | null;
227 /**
228 * The branch holding the change, unless it is in a working copy (`fork`):
229 * of `headRepo` when set, else of the repository.
230 */
231 branch: string | null;
232 /**
233 * A fork of the repository (its `parentId`, directly or through other
234 * forks) whose `branch` holds the change, when it was opened from one.
235 * Null for a branch of the repository itself and for a working copy.
236 */
237 headRepo?: RepoPath | null;
238 /** `headRepo`'s id. */
239 headRepoId?: string | null;
240 headCommit: string | null;
241 /**
242 * For a merged pull request, what the branch pointed to before the merge.
243 * Comparing against it shows what the pull request changed.
244 */
245 mergeBase: string | null;
246 /** Username of whoever merged it. */
247 mergedBy: string | null;
248 /** RFC 3339. */
249 mergedAt: string | null;
250 /** How it merged, once merged. */
251 mergeMethod?: MergeMethod | null;
252 /** Where its merge left the base: the merge or squash commit, the last rebased one, or its head. */
253 mergeCommit?: string | null;
254 /** Merge it on its own once everything it needs is met, as a person asked. */
255 autoMerge?: AutoMerge | null;
256 /**
257 * The work items it closes when it merges into the default branch, by
258 * number: its own and those its title and description name after a
259 * closing keyword (`Fixes #12`). Merging marks this repository's link to
260 * each as landed.
261 */
262 closes?: number[];
263 /** The work items it is part of (`Part of #12`, `Refs #12`): linked, never closed by it. */
264 parts?: number[];
265 /** Its branch was deleted after it merged or closed, and can be restored at `headCommit`. */
266 headBranchDeleted?: boolean;
267 /**
268 * Set on a pull request closed because another one for the same work item
269 * was merged: that one's number.
270 */
271 supersededBy: number | null;
272 /**
273 * Where the latest run of the work item's acceptance checks stands, if
274 * there has been one against the current head.
275 */
276 checkStatus: CheckStatus | null;
277 /** The files it changes, as of its latest push. */
278 files: ChangedFile[];
279 /** Usernames of the people it is assigned to. */
280 assignees: string[];
281 /**
282 * Those whose review was asked for: usernames, and `g1t` when a g1t
283 * agent was asked.
284 */
285 reviewers: string[];
286 /**
287 * Teams whose review was asked for, as `workspace/slug`. A team stays here
288 * after review assignment picks people from it, who are in `reviewers`.
289 */
290 teamReviewers?: string[];
291 /** The labels it carries, by name. */
292 labels?: string[];
293 /** The milestone it is in, if any. */
294 milestone?: MilestoneRef | null;
295 /**
296 * The branch it merges into. Lists and `getPull` name it; null only in
297 * what services pass between themselves, for the default branch.
298 */
299 base?: string | null;
300 /** Who opened it: a person, or g1t (`kind` `agent`, username `g1t`) for a change g1t made. */
301 author: User;
302 /**
303 * For a change g1t made: the person who asked for it, by assigning a work item
304 * or handing g1t the work. They answer for it as its author would. See
305 * `workOwner`.
306 */
307 requestedBy: User | null;
308 /** RFC 3339. */
309 createdAt: string;
310 /** RFC 3339. */
311 updatedAt: string;
312 /** Who last moved its head (a user id), and when; absent until a push after rulesets arrived. */
313 headPushedBy?: string;
314 headPushedAt?: string;
315};
316
317/** One file a pull request changes, and by how much. */
318export type ChangedFile = { path: string; additions: number; deletions: number };
319
320/**
321 * Another pull request in progress that changes some of the same files. Two
322 * for the same work item are alternatives; two for different ones are
323 * heading for a conflict.
324 */
325export type Overlap = {
326 number: number;
327 title: string;
328 /** The number of the work item the other pull request is for. */
329 item: number | null;
330 /** The files both change. */
331 paths: string[];
332};
333
334/**
335 * On a pull request, `failed` means the merge queue took it out, until its
336 * head moves. The other states are from runs of commands written on work items,
337 * which g1t no longer runs.
338 */
339export type CheckStatus = "queued" | "running" | "passed" | "failed" | "errored";
340
341/** How one command went, in a run recorded before checks were workflows. */
342export type CheckResult = {
343 command: string;
344 passed: boolean;
345 /** Null when the command was stopped for taking too long. */
346 exitCode: number | null;
347 /** What the command printed; the end of it, when there was a lot. */
348 output: string;
349 durationMs: number;
350};
351
352/**
353 * A record against a pull request's head: the merge queue taking it out,
354 * with why, or an earlier run of commands written on its work item.
355 */
356export type CheckRun = {
357 id: string;
358 /** The commit that was checked. */
359 headCommit: string;
360 status: CheckStatus;
361 results: CheckResult[];
362 /** Why the checks could not be run, when `status` is `errored`. */
363 error: string | null;
364 /** RFC 3339. */
365 createdAt: string;
366 /** RFC 3339. */
367 finishedAt: string | null;
368};
369
370/** A reviewer's decision on a pull request. */
371export type Verdict = "approve" | "request_changes";
372
373/**
374 * A comment on a work item or a pull request. On a pull request it can sit on
375 * one line of the change, and it can carry a reviewer's verdict.
376 */
377export type Comment = {
378 id: string;
379 /**
380 * Something a person or an agent wrote, or something that happened: an
381 * assignment, a review asked for, a close.
382 */
383 kind: "comment" | "event";
384 author: User;
385 /**
386 * Markdown. For an event, what its author did, as the rest of a sentence
387 * that starts with their name: "assigned ana".
388 */
389 body: string;
390 /** The file commented on, for a comment on a line. */
391 path: string | null;
392 /** The line of that file, as numbered after the change. */
393 line: number | null;
394 verdict: Verdict | null;
395 /** RFC 3339. */
396 createdAt: string;
397 /** When its text was last edited, RFC 3339; absent if it never was. */
398 editedAt?: string;
399 /**
400 * Set when one of the workspace's agents wrote it, as itself. `author`
401 * is then the agent (its id, its handle as `username`, kind `agent`):
402 * show it by `agent.displayName` with an Agent badge, never as a person.
403 */
404 agent?: AgentRef;
405 /**
406 * Who the agent acted for, whose access capped it. Set with `agent`, and
407 * when g1t (`author`) wrote it, or did what an event notes, in a session
408 * someone started: show "on behalf of @them".
409 */
410 actingFor?: User;
411 /**
412 * An agent's review. Its `verdict` (none for a review that only
413 * comments) is shown but advisory: it never counts toward required
414 * approvals or code owners, and never blocks a merge.
415 */
416 advisory?: boolean;
417 /** How people (and g1t) reacted to it. Absent when nobody has. */
418 reactions?: ReactionGroup[];
419};
420
421/** An emoji reaction: the same eight as everywhere else people react to code. */
422export type ReactionContent = "+1" | "-1" | "laugh" | "hooray" | "confused" | "heart" | "rocket" | "eyes";
423
424/** The reactions, in the order they are offered, with the emoji each shows. */
425export const REACTIONS: { content: ReactionContent; emoji: string; label: string }[] = [
426 { content: "+1", emoji: "👍", label: "Thumbs up" },
427 { content: "-1", emoji: "👎", label: "Thumbs down" },
428 { content: "laugh", emoji: "😄", label: "Laugh" },
429 { content: "hooray", emoji: "🎉", label: "Hooray" },
430 { content: "confused", emoji: "😕", label: "Confused" },
431 { content: "heart", emoji: "❤️", label: "Heart" },
432 { content: "rocket", emoji: "🚀", label: "Rocket" },
433 { content: "eyes", emoji: "👀", label: "Eyes" },
434];
435
436/** Everyone who reacted one way to the same thing, first to react first; `g1t` for g1t. */
437export type ReactionGroup = {
438 content: ReactionContent;
439 count: number;
440 users: string[];
441};
442
443/**
444 * One of a workspace's own agents, as a comment or review it wrote before
445 * g1t's agents were removed shows it: Margo (@margo), with the face drawn
446 * from `avatarSeed`. Kept so those comments still render.
447 */
448export type AgentRef = {
449 id: string;
450 handle: string;
451 displayName: string;
452 avatarSeed: string;
453};
454
455export type NewComment = {
456 /** May be empty when approving. */
457 body: string;
458 path?: string;
459 line?: number;
460 verdict?: Verdict;
461};
462
463export type CheckReport = { results?: CheckResult[]; error?: string; skip?: boolean };
464
465export type SessionEntryKind = "prompt" | "message" | "tool_call" | "tool_result" | "note" | "skill";
466
467/** One step of an agent's session: the "why" behind a pull request's commits. */
468export type SessionEntry = {
469 seq: number;
470 kind: SessionEntryKind;
471 text: string;
472 /** For tool calls and results. */
473 tool: string | null;
474 /** The fork's head commit when this entry was recorded, if known. */
475 commit: string | null;
476 /** RFC 3339. */
477 at: string;
478 /**
479 * Its text is not shown to this viewer (`text` is empty): a prompt shows
480 * only to whoever typed it, and a tool's output to whoever ran it.
481 */
482 withheld?: boolean;
483};
484
485export type NewSessionEntry = Pick<SessionEntry, "kind" | "text"> &
486 Partial<Pick<SessionEntry, "tool" | "commit">>;
487
488export type PullDetail = {
489 pull: Pull;
490 /** The work item it is for, if any. */
491 item: WorkItem | null;
492 comments: Comment[];
493 /** How people (and g1t) reacted to its description. */
494 reactions: ReactionGroup[];
495 /** The latest record against its head: the merge queue taking it out. */
496 checks: CheckRun | null;
497 /** Other pull requests in progress that change the same files. */
498 overlaps: Overlap[];
499 /**
500 * Whether the branch it would merge into has moved on without it, so that
501 * it has to catch up before it can merge.
502 */
503 behind: boolean;
504 /**
505 * Where it stands on its way to being merged, for a pull request g1t is
506 * seeing through. Null on anyone else's.
507 */
508 lifecycle: Lifecycle | null;
509 /**
510 * A merge was asked for while it was behind: g1t is bringing it up to
511 * date and will then land it.
512 */
513 landing: boolean;
514 /** Why g1t stopped working on it, if it did. */
515 stalled: string | null;
516 /** What workflow runs said about its head commit, one per workflow. */
517 statuses?: CommitStatus[];
518 /**
519 * Whether it merges cleanly into the branch it targets, worked out ahead
520 * of time whenever either side moves.
521 */
522 mergeable?: Mergeable;
523 /** When `mergeable` is `conflicting`: the files that conflict. */
524 conflicts?: string[];
525 /** Earlier records like `checks`, newest first, without their output. */
526 earlierChecks?: CheckRun[];
527 /**
528 * The checks the default branch's protection requires, each as it stands
529 * on the head commit. Empty when none are required.
530 */
531 requiredChecks?: RequiredCheck[];
532 /**
533 * Who owns the files it changes (the CODEOWNERS file of the branch it
534 * merges into) and whose approval is still needed. Absent without one.
535 */
536 codeOwners?: PullCodeOwners | null;
537 /**
538 * The rules of the branch it merges into it does not meet yet, for whoever
539 * is looking: what refuses the merge, what they may bypass, and what rulesets
540 * in evaluate would refuse. Absent once it is closed or merged.
541 */
542 rules?: MergeRules | null;
543};
544
545/** Where a required check stands on a commit; `expected` when nothing has reported it yet. */
546export type RequiredState = "success" | "failure" | "pending" | "expected";
547
548/** One check a branch's protection requires, as it stands on a commit. */
549export type RequiredCheck = {
550 /** A workflow's name, such as `CI`, or another status's context. */
551 name: string;
552 state: RequiredState;
553 description: string | null;
554 /** Where to see more: the workflow run, for one a workflow reported. */
555 targetUrl: string | null;
556};
557
558/** A check name reported on a repository's commits lately, for choosing required checks. */
559export type SeenCheck = {
560 name: string;
561 /** The events it was reported for, such as `pull_request`; empty for a status that names none. */
562 events: string[];
563 /** RFC 3339. */
564 lastSeen: string;
565};
566
567/**
568 * A status context's check name: `CI / pull_request` is the `CI` check,
569 * reported for a `pull_request` event. A context that does not end in an
570 * event, such as `g1t / deploy`, is its own name. As the work service reads it.
571 */
572export function checkName(context: string): string {
573 const at = context.lastIndexOf(" / ");
574 if (at <= 0) return context;
575 return STATUS_EVENTS.has(context.slice(at + 3)) ? context.slice(0, at) : context;
576}
577
578const STATUS_EVENTS = new Set([
579 "push",
580 "pull_request",
581 "pull_request_target",
582 "pull_request_review",
583 "merge_group",
584 "workflow_dispatch",
585 "workflow_run",
586 "workflow_call",
587 "schedule",
588 "release",
589 "issues",
590 "issue_comment",
591 "work_item",
592 "work_item_comment",
593 "repository_dispatch",
594]);
595
596/**
597 * Whether a pull request merges cleanly into the branch it targets:
598 * `unknown` when it was never worked out or could not be, `checking` while
599 * a probe merges the two.
600 */
601export type Mergeable = "clean" | "conflicting" | "unknown" | "checking";
602
603/** What a sandbox needs to find out whether a pull request merges cleanly. */
604export type MergecheckJob = {
605 pullId: string;
606 /** Lets the sandbox, and nothing else, report this probe. */
607 token: string;
608 repo: RepoPath;
609 number: number;
610 defaultBranch: string;
611 /** The default branch's commit to merge into. */
612 base: string;
613 /** The repository holding the change: its fork, or the repository. */
614 source: RepoPath;
615 /** The branch of `source` holding it. */
616 branch: string;
617 /** The change's commit. */
618 head: string;
619 /** Who the pull request is for (`workOwner`: whoever asked g1t for it, or its author), and so can read its source. */
620 author: User;
621};
622
623/** What a workflow run (or another tool) says about a commit. */
624export type CommitStatus = {
625 /** What reported it, such as `CI / push`. */
626 context: string;
627 state: "pending" | "success" | "failure" | "error";
628 description: string | null;
629 targetUrl: string | null;
630 updatedAt: string;
631 /** The integration that reported it: `actions`, `deployments`, `security`, `g1t` or `api`. */
632 source?: string;
633 /** Set on the status a check run stands as: the check run's id. */
634 checkRunId?: string;
635};
636
637/**
638 * A step on the way from an assigned work item to a pull request that is ready
639 * to merge. g1t takes each one without being asked: `working` (the agent is
640 * making the change), `checking`, `reviewing`, `revising` (the agent is
641 * addressing failed checks or a review), `catching_up` (merging in the
642 * branch it would land on), `answering` (woken to answer another agent),
643 * then `ready` for a person to merge. `needs_you`
644 * means g1t has stopped and a person decides what happens next.
645 */
646export type Stage =
647 | "working"
648 | "checking"
649 | "reviewing"
650 | "revising"
651 | "catching_up"
652 | "answering"
653 | "queued"
654 | "ready"
655 | "needs_you";
656
657export type Lifecycle = {
658 stage: Stage;
659 /** One sentence saying what is happening, or why it stopped. */
660 detail: string;
661 /** How many times the agent has been sent back to revise it. */
662 revisions: number;
663};
664
665/**
666 * How a repository wants its pull requests handled. A repository that has
667 * changed nothing has the defaults.
668 */
669export type RepoSettings = {
670 /**
671 * Land a g1t agent's pull request without a person once it is ready:
672 * checks passed and approved as the settings below require.
673 */
674 autoMerge: boolean;
675 /**
676 * The checks that must pass on a pull request's head before it may merge
677 * into the default branch, by name: a workflow's name (`CI`) or another
678 * status's context (`g1t / deploy`). The same for people and agents, and
679 * for the merge queue.
680 */
681 requiredChecks: string[];
682 /**
683 * Refuse to merge a pull request that does not contain the default
684 * branch's latest commits, so that what merges is what was checked. When
685 * off, merging one that is behind brings it up to date first.
686 */
687 requireUpToDate: boolean;
688 /**
689 * How many approving reviews a pull request needs before it may merge. A
690 * reviewer who has since asked for changes blocks it.
691 */
692 requiredApprovals: number;
693 /** Whether a g1t agent's approval counts towards `requiredApprovals`. */
694 countAgentApprovals: boolean;
695 /** Whether someone who may merge can bypass required checks that have not passed. */
696 allowIgnoringChecks: boolean;
697 /**
698 * Merge through a queue: pull requests are tested together with those
699 * ahead of them, and only a combination that passed reaches the default
700 * branch.
701 */
702 mergeQueue: boolean;
703 /**
704 * Refuse to merge until the code owners of every file it changes have
705 * approved, as many as each section asks. People only; `g1t` only where
706 * the file names `@g1t`.
707 */
708 requireCodeOwnerReview?: boolean;
709 /**
710 * Whether work items can be filed from it (as their origin): null for the
711 * default, which is on for a repository and off for a fork of one. Those
712 * filed from it before stay readable, and it can always be a target.
713 */
714 hasWorkItems?: boolean | null;
715 /** Whether work items can be filed from it now: `hasWorkItems`, or its default. */
716 workItemsEnabled?: boolean;
717 /** Which merge methods pull requests may use (at least one); rules can narrow them per branch. */
718 allowMergeCommit: boolean;
719 allowSquashMerge: boolean;
720 allowRebaseMerge: boolean;
721 allowFastForward: boolean;
722 /** The method offered first, and used when none is named. */
723 defaultMergeMethod: MergeMethod;
724 /** What merge and squash commits say unless their merger writes it. */
725 mergeCommitMessage: CommitMessageDefault;
726 squashCommitMessage: CommitMessageDefault;
727 /**
728 * For `custom`: templates whose `{title}`, `{number}`, `{body}`, `{branch}`,
729 * `{head_repo}`, `{base}`, `{author}`, `{commits}`, `{items}` and
730 * `{co_authors}` are filled in.
731 */
732 mergeCommitTemplate: string | null;
733 squashCommitTemplate: string | null;
734 /** Offer to bring a pull request up to date whenever its base has new commits. */
735 suggestUpdatingBranches: boolean;
736 /** Let people turn on auto-merge for a pull request. */
737 allowAutoMerge: boolean;
738 /** Delete a pull request's branch once it merges (restorable from it). */
739 deleteBranchOnMerge: boolean;
740 /** Commits made on g1t.sh carry a `Signed-off-by:` trailer for whoever made them. */
741 requireWebCommitSignOff: boolean;
742 /** Let anyone who can read it comment on its commits. */
743 allowCommitComments: boolean;
744 /**
745 * Land the work items a pull request names in this repository when it
746 * merges into the default branch (and those a commit pushed there names),
747 * closing those with nothing else left to land.
748 */
749 autoCloseItems: boolean;
750 /** Username of the member who last changed the settings, if anyone has. */
751 updatedBy: string | null;
752 /** RFC 3339. */
753 updatedAt: string | null;
754};
755
756/** What a merge or squash commit's message says by default (`pull_title_and_commits` is squash only). */
757export type CommitMessageDefault = "default" | "pull_title" | "pull_title_and_description" | "pull_title_and_commits" | "custom";
758
759/** A person's request that a pull request merge on its own once it may. */
760export type AutoMerge = {
761 method: MergeMethod;
762 commitTitle: string | null;
763 commitMessage: string | null;
764 /** Username of who asked. */
765 enabledBy: string;
766 /** RFC 3339. */
767 enabledAt: string;
768};
769
770/** A comment on a commit, or on one line (`path`, `line`) of a file it changed. */
771export type CommitComment = {
772 id: string;
773 repoId: string;
774 /** The commit's full hash. */
775 commit: string;
776 path: string | null;
777 line: number | null;
778 /** Username. */
779 author: string;
780 /** Markdown. */
781 body: string;
782 /** RFC 3339. */
783 createdAt: string;
784 updatedAt: string | null;
785};
786
787/** How a pull request may merge now, for whoever is looking (`mergeChoices`). */
788export type MergeChoices = {
789 /** The methods it may merge by: the repository's, as the rules for its base allow. In the order offered. */
790 methods: MergeMethod[];
791 /** The one offered first: the repository's default when it may be used, else the first of `methods`. */
792 defaultMethod: MergeMethod | null;
793 /** Each of `methods`, with its default commit message and whether it can be used now. */
794 options: MergeChoice[];
795 /** Its base has commits it does not have. */
796 behind: boolean;
797 /** It contains its base's head, so it can fast-forward as it is. */
798 canFastForward: boolean;
799 /** Offer to bring it up to date: it is behind, and the repository suggests (or requires) it. */
800 suggestUpdate: boolean;
801 /** The repository requires it to be up to date before it merges. */
802 requireUpToDate: boolean;
803 /** It merges through the merge queue, which lands it as tested whatever method is chosen. */
804 mergeQueue: boolean;
805 /** The viewer may turn on auto-merge for it. */
806 autoMergeAllowed: boolean;
807 /** Whether "delete the branch" starts ticked. */
808 deleteBranchDefault: boolean;
809 /** Its branch can be deleted once it merges (never a working copy's). */
810 canDeleteBranch: boolean;
811 /** Commits made merging it carry a `Signed-off-by:` trailer for the merger. */
812 signOff: boolean;
813};
814
815/** One way a pull request may merge. */
816export type MergeChoice = {
817 method: MergeMethod;
818 /** For `merge` and `squash`: the commit's default title and the rest of its message. */
819 commitTitle: string | null;
820 commitMessage: string | null;
821 /** Why it cannot merge this way now, if it cannot. */
822 unavailable: string | null;
823};
824
825/** How a pull request merges, as the merger chose. */
826export type MergeOptions = {
827 /** Leave its work item open: this pull request is only part of the work. */
828 keepItemOpen?: boolean;
829 /** Merge although required checks have not passed, where the rule requiring them allows it. */
830 ignoreChecks?: boolean;
831 /** Merge past rules a ruleset lets the actor bypass. Recorded as a bypass. */
832 bypassRules?: boolean;
833 /** The repository's default when absent. */
834 mergeMethod?: MergeMethod;
835 /** For `merge` and `squash`: the commit's title and the rest of its message. */
836 commitTitle?: string;
837 commitMessage?: string;
838 /** Refuse if its head is no longer this commit. */
839 expectedHead?: string;
840 /** Delete its branch once merged; the repository's setting when absent. */
841 deleteBranch?: boolean;
842};
843
844/** The settings a member can change. */
845export type RepoSettingsInput = Omit<RepoSettings, "updatedBy" | "updatedAt" | "workItemsEnabled">;
846
847/**
848 * What the runner is to do next for a pull request: always nothing now,
849 * since no step of a pull request is carried out in a sandbox any more.
850 */
851export type Advance = { action: "none" };
852
853export type OpenWorkItemInput = {
854 /** The workspace; may be left out with `repo`, meaning the repository's. */
855 workspace?: string;
856 /** The repository it is filed from, its origin. Without one, only a member of the workspace may file it. */
857 repo?: RepoPath;
858 /** Repositories of the workspace where the work is meant to land. */
859 targets?: RepoPath[];
860 title: string;
861 body: string;
862 labels?: string[];
863 /** The number of the workspace milestone to put it in. Needs the Triage role. */
864 milestone?: number;
865};
866
867export type UpdateWorkItemInput = {
868 title?: string;
869 body?: string;
870 labels?: string[];
871 /** Usernames of the people it is assigned to; replaces the whole set. */
872 assignees?: string[];
873 /** The number of the workspace milestone to put it in; 0 takes it out. */
874 milestone?: number;
875 /** The work items of the workspace that have to land first, by number; replaces the whole set. */
876 blocked_by?: number[];
877};
878
879/** How many `listWorkItems` and `listPulls` give at most in one call. */
880export const LIST_PAGE = 100;
881
882/** The filters on `listWorkItems`. */
883export type WorkItemFilter = {
884 /** Only those linked to this repository (in any role, or in `role`). */
885 repo?: RepoPath;
886 role?: LinkRole;
887 state?: State;
888 label?: string;
889 milestone?: number;
890 /** Only those assigned to this username. */
891 assignee?: string;
892 /** Only those closed at or after this time (RFC 3339), the most recently closed first instead of the newest. */
893 closedSince?: string;
894 /** Only those numbered below this: the next page, after one whose lowest number this is. */
895 before?: number;
896};
897
898export type OpenPullInput = {
899 /** The work item this is for, by number in the repository's workspace. */
900 item?: number;
901 /** Defaults to the work item's title; required without one. */
902 title?: string;
903 /** What changed and why. Usually set later, when a draft is marked ready. */
904 body?: string;
905 /**
906 * A branch of the repository that already holds the change. The pull
907 * request is then ready for review at once and has no fork.
908 */
909 branch?: string;
910 /**
911 * A fork of the repository (directly or through other forks) whose
912 * `branch` holds the change. Needs `branch`.
913 */
914 headRepo?: RepoPath;
915 agent: string;
916 runtime: Runtime;
917 /** The branch to merge into: the default branch when left out. */
918 base?: string;
919 /**
920 * Opened from a branch as a draft, still being worked on: it can't merge
921 * until it is marked ready.
922 */
923 draft?: boolean;
924};
925
926/** One repository's pull requests from `pullsForRepos`, newest first. */
927export type RepoPulls = {
928 repoId: string;
929 /** Draft and open. */
930 open: Pull[];
931 /** Merged and closed. */
932 closed: Pull[];
933};
934
935/** Where a comment is kept, for changing it: a repository's pull requests, or a workspace's work items. */
936export type CommentScope = { repo: RepoPath } | { workspace: string };
937
938/**
939 * Where an image put in Markdown is kept (`upload_attachment`): a
940 * repository, for its pull requests, commits and the work items filed
941 * from it, or a work item, which keeps its own (one filed with no
942 * repository takes images too, once it is open).
943 */
944export type AttachmentScope = { repo: RepoPath } | { workspace: string; number: number };
945
946/** An image kept for Markdown: `path` is under the usercontent origin (`/attachments/<id>`). */
947export type Attachment = { id: string; name: string; content_type: string; size: number; path: string };
948
949/** Work items, pull requests, comments and sessions. */
950export interface WorkApi extends RulesApi, ChecksApi, CoordinationApi {
951 /**
952 * Files a work item: from `repo` (its origin) by anyone who may take part
953 * there, or in the workspace alone by a member. `targets` are where it is
954 * meant to land.
955 */
956 openWorkItem(actor: User, input: OpenWorkItemInput): Promise<Result<WorkItem>>;
957 /** A workspace's work items the viewer may see, newest first, at most [`LIST_PAGE`] (`before` pages on). */
958 listWorkItems(workspace: string, viewer: Viewer, filter?: WorkItemFilter): Promise<Result<WorkItem[]>>;
959 getWorkItem(workspace: string, number: number, viewer: Viewer): Promise<Result<WorkItemDetail>>;
960 /** Its owner, or someone with the Triage role on it, may. */
961 updateWorkItem(actor: User, workspace: string, number: number, input: UpdateWorkItemInput): Promise<Result<WorkItem>>;
962 /**
963 * Closes it; with `by`, as the commit there (on its repository's default
964 * branch, naming it after a closing keyword) would have: it lands there,
965 * and closes once nothing else is left to land.
966 */
967 closeWorkItem(
968 actor: User,
969 workspace: string,
970 number: number,
971 reason?: CloseReason,
972 by?: { repo: RepoPath; commit: string },
973 ): Promise<Result<WorkItem>>;
974 reopenWorkItem(actor: User, workspace: string, number: number): Promise<Result<WorkItem>>;
975 /** Links a repository of the workspace as a target (or as touched), or changes how it is linked. Needs Triage. */
976 linkWorkItem(actor: User, workspace: string, number: number, repo: RepoPath, role?: LinkRole): Promise<Result<WorkItem>>;
977 /** Removes a repository's link (never its origin's). Needs Triage. */
978 unlinkWorkItem(actor: User, workspace: string, number: number, repo: RepoPath): Promise<Result<WorkItem>>;
979 /** What `#number` names for the viewer, read in a repository (and its workspace) or a workspace alone. */
980 resolveRef(viewer: Viewer, context: { repo: RepoPath } | { workspace: string }, number: number): Promise<RefTarget>;
981 /** The work items that a commit pushed to the repository's default branch resolved, of those the viewer may read. */
982 closedByCommit(repo: RepoPath, commit: string, viewer: Viewer): Promise<Result<ClosedItem[]>>;
983 /** A workspace's labels, by name, each with how many work items and pull requests carry it. */
984 listLabels(workspace: string, viewer: Viewer): Promise<Result<Label[]>>;
985 /**
986 * Creates a label, or with `name` changes one; renaming it renames it on
987 * everything that carries it. Needs the Write role in the workspace.
988 */
989 saveLabel(
990 actor: User,
991 workspace: string,
992 label: { name?: string; newName?: string; color?: string; description?: string },
993 ): Promise<Result<Label>>;
994 /** Removes a label from the workspace and everything carrying it. */
995 deleteLabel(actor: User, workspace: string, name: string): Promise<Result<boolean>>;
996 /** Adds the default labels the workspace does not have yet; returns them all. */
997 addDefaultLabels(actor: User, workspace: string): Promise<Result<Label[]>>;
998 /**
999 * The labels of a work item or a pull request, replaced, added to or
1000 * taken from. Labels the workspace lacks are created for someone who may
1001 * manage labels. Returns its labels now.
1002 */
1003 setLabels(actor: User, thread: Thread, labels: string[], change?: LabelChange): Promise<Result<string[]>>;
1004 /** A workspace's, open ones by due date, then closed ones; both unless `state` says. */
1005 listMilestones(workspace: string, viewer: Viewer, state?: State): Promise<Result<Milestone[]>>;
1006 getMilestone(workspace: string, number: number, viewer: Viewer): Promise<Result<MilestoneDetail>>;
1007 /** Creates a milestone, or with `number` changes the fields given. Needs the Write role in the workspace. */
1008 saveMilestone(
1009 actor: User,
1010 workspace: string,
1011 milestone: { number?: number; title?: string; description?: string; dueOn?: string; state?: State },
1012 ): Promise<Result<Milestone>>;
1013 deleteMilestone(actor: User, workspace: string, number: number): Promise<Result<boolean>>;
1014 /** How many work items linked to the repository, and how many of its pull requests, are open. */
1015 counts(repo: RepoPath, viewer: Viewer): Promise<Result<{ items: number; pulls: number }>>;
1016 /** Moves on the job that moves issues into work items; does nothing once done. */
1017 migrateWorkItems(): Promise<{ done: boolean; repos: number; numbered: number; unplaced: number }>;
1018
1019 /**
1020 * On a work item or a pull request. On a pull request it may name a line
1021 * of the change and carry a verdict; nobody can give a verdict on their own.
1022 */
1023 addComment(actor: User, thread: Thread, comment: NewComment): Promise<Result<Comment>>;
1024 /**
1025 * Changes a comment's text. Its author may, and so may anyone with the
1026 * Maintain role or higher; notes of what happened cannot be changed.
1027 */
1028 editComment(actor: User, scope: CommentScope, commentId: string, body: string): Promise<Result<Comment>>;
1029 /**
1030 * Deletes a comment: its author, or anyone with the Maintain role or
1031 * higher. A review that gave a verdict cannot be deleted, only edited.
1032 */
1033 deleteComment(actor: User, scope: CommentScope, commentId: string): Promise<Result<boolean>>;
1034 /**
1035 * Keeps an image to show in Markdown there, for anyone who may comment
1036 * on the repository or take part in the work item. `data` is the file in
1037 * base64; its type is read from its bytes. PNG, JPEG, GIF or WebP of at
1038 * most 10 MB: larger is `too_large`, another type `unsupported_type`.
1039 */
1040 uploadAttachment(actor: User, scope: AttachmentScope, file: { name: string; contentType?: string; data: string }): Promise<Result<Attachment>>;
1041 /**
1042 * Reacts to comment `commentId` on a work item or pull request, or to its
1043 * description without one; with `remove`, takes it back. Anyone who can
1044 * read it may. What it has now.
1045 */
1046 react(
1047 actor: User,
1048 thread: Thread,
1049 reaction: { commentId?: string; content: ReactionContent; remove?: boolean },
1050 ): Promise<Result<ReactionGroup[]>>;
1051
1052 /**
1053 * What a sandbox says about a run from before checks were workflows: so
1054 * one still finishing is recorded.
1055 */
1056 reportChecks(runId: string, token: string, report: CheckReport): Promise<Result<CheckRun>>;
1057 /**
1058 * Claims the probe of whether a pull request merges cleanly that a
1059 * `pull.mergecheck` event asked for. Refused when it is no longer wanted
1060 * or the repository has as many running as it may. For the runner service.
1061 */
1062 startMergecheck(pullId: string): Promise<Result<MergecheckJob>>;
1063 /** Records that a probe could not be carried out. For the runner service. */
1064 failMergecheck(pullId: string, token: string, error: string): Promise<Result<Mergeable>>;
1065
1066 /**
1067 * Works out the next step for a pull request g1t is seeing through and,
1068 * if there is one to take now, claims it, so that it is taken once
1069 * however often this is called. For the runner service.
1070 */
1071 advance(pullId: string): Promise<Advance>;
1072 /**
1073 * Ids of the open pull requests to move along: those g1t merges by itself
1074 * or someone set to auto-merge; with `repoId`, also every open one whose
1075 * lifecycle is remembered, to bring it up to date after a merge there.
1076 */
1077 managedPulls(repoId?: string): Promise<string[]>;
1078
1079 /** A repository's merge queue: what is in it, in order, and what recently left. */
1080 queue(repo: RepoPath, viewer: Viewer): Promise<Result<QueueView>>;
1081 /**
1082 * The next batch of combined states to test for a repository, one per
1083 * entry; empty while a batch is being tested or nothing waits.
1084 */
1085 queueBuild(repoId: string): Promise<QueueJob[]>;
1086 /** Reports that a combined state could not be built or checked. */
1087 failQueue(entryId: string, token: string, error: string): Promise<Result<QueueState>>;
1088 /** Takes a pull request out of the merge queue. Members only. */
1089 removeFromQueue(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1090
1091 getSettings(repo: RepoPath, viewer: Viewer): Promise<Result<RepoSettings>>;
1092 /** The check names reported on the repository's commits in the last 30 days, most recent first. */
1093 seenChecks(repo: RepoPath, viewer: Viewer): Promise<Result<SeenCheck[]>>;
1094 /** Members of the repository's workspace only. */
1095 updateSettings(actor: User, repo: RepoPath, settings: RepoSettingsInput): Promise<Result<RepoSettings>>;
1096 /** The CODEOWNERS file at a branch (the default when left out), checked. Needs Read. */
1097 codeownersErrors(repo: RepoPath, viewer: Viewer, ref?: string | null): Promise<Result<CodeownersReport>>;
1098
1099 /**
1100 * Opens a pull request: a draft with a fork to push to, or, given a
1101 * branch, one ready for review.
1102 */
1103 openPull(actor: User, repo: RepoPath, input: OpenPullInput): Promise<Result<Pull>>;
1104 /** Newest first, at most [`LIST_PAGE`] (`before` pages on). */
1105 listPulls(
1106 repo: RepoPath,
1107 viewer: Viewer,
1108 state?: State,
1109 filter?: {
1110 label?: string;
1111 milestone?: number;
1112 base?: string;
1113 /** Only those numbered below this: the next page, after one whose lowest number this is. */
1114 before?: number;
1115 /** Only those merged at or after this time (RFC 3339). */
1116 mergedSince?: string;
1117 },
1118 ): Promise<Result<Pull[]>>;
1119 /**
1120 * Delivery for up to 100 repositories over UTC days `from` through
1121 * `until`, over their whole history. Repositories the viewer cannot read,
1122 * and forks, are left out of `projects`.
1123 */
1124 deliveryInsights(repoIds: string[], viewer: Viewer, from: string, until: string): Promise<DeliveryInsights>;
1125 /**
1126 * What up to 100 of a workspace's repositories' work says over the last
1127 * weeks, for Home's daily signal and the Workspace overview: each row is
1128 * one repository's, so batches add up. Repositories the viewer cannot
1129 * read are left out.
1130 */
1131 workspaceSignals(args: WorkspaceSignalsArgs, viewer: Viewer): Promise<WorkspaceSignals>;
1132 /**
1133 * The newest `limit` open and closed pull requests of each repository,
1134 * in one call. Repositories the viewer cannot read, and forks, are left
1135 * out: ask those with `listPulls`.
1136 */
1137 pullsForRepos(repoIds: string[], viewer: Viewer, limit: number): Promise<RepoPulls[]>;
1138 getPull(repo: RepoPath, number: number, viewer: Viewer): Promise<Result<PullDetail>>;
1139 /**
1140 * Changes who a pull request is assigned to and whose review is asked
1141 * for; each list given replaces the whole set. Asking for `g1t`'s
1142 * review does not by itself start one: the runner's `review` does.
1143 */
1144 updatePull(
1145 actor: User,
1146 repo: RepoPath,
1147 number: number,
1148 changes: {
1149 assignees?: string[];
1150 reviewers?: string[];
1151 labels?: string[];
1152 /** 0 takes it out of its milestone. */
1153 milestone?: number;
1154 /** The branch it merges into. Needs the Write role. */
1155 base?: string;
1156 },
1157 ): Promise<Result<Pull>>;
1158 /**
1159 * Brings a pull request up to date with the default branch in seconds,
1160 * without a sandbox, when the two changed different files: the merge
1161 * commit is pushed to its branch as `actor`, who must be whoever opened
1162 * it (for a fork) or a member (for a branch). Otherwise `needs_agent`, and
1163 * nothing is pushed: the runner's `update` is the way on.
1164 */
1165 catchUpPull(
1166 actor: User,
1167 repo: RepoPath,
1168 number: number,
1169 options?: { updateMethod?: UpdateMethod; expectedHead?: string },
1170 ): Promise<Result<PullBranchUpdate>>;
1171 /**
1172 * Turns a pull request's auto-merge on (with how to merge) or off. On needs
1173 * Write, since it merges as whoever turned it on; its author may also turn
1174 * it off. Refused where the repository does not allow auto-merge or the
1175 * method. One that may merge already merges at once.
1176 */
1177 setAutoMerge(
1178 actor: User,
1179 repo: RepoPath,
1180 number: number,
1181 enabled: boolean,
1182 options?: { mergeMethod?: MergeMethod; commitTitle?: string; commitMessage?: string },
1183 ): Promise<Result<Pull>>;
1184 /** How a pull request may merge now: methods, default messages, auto-merge and branch deletion. */
1185 mergeChoices(viewer: Viewer, repo: RepoPath, number: number): Promise<Result<MergeChoices>>;
1186 /** Deletes a merged or closed pull request's branch (Push on where it is). */
1187 deleteHeadBranch(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1188 /** Makes a deleted pull request branch again at its head. */
1189 restoreHeadBranch(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1190 /** A commit's comments, oldest first; with no commit, the repository's, newest first, 30 a page. */
1191 commitComments(viewer: Viewer, repo: RepoPath, commit?: string | null, page?: number): Promise<Result<CommitComment[]>>;
1192 /** Comments on a commit, or on one line of a file it changed. Needs Read, where commit comments are on. */
1193 addCommitComment(
1194 actor: User,
1195 repo: RepoPath,
1196 commit: string,
1197 body: string,
1198 at?: { path: string; line: number },
1199 ): Promise<Result<CommitComment>>;
1200 editCommitComment(actor: User, repo: RepoPath, id: string, body: string): Promise<Result<CommitComment>>;
1201 deleteCommitComment(actor: User, repo: RepoPath, id: string): Promise<Result<boolean>>;
1202 /** Marks a draft ready for review and sets its description. */
1203 readyPull(actor: User, repo: RepoPath, number: number, summary: string): Promise<Result<Pull>>;
1204 closePull(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1205 /** Opens a closed pull request again, as the draft it was if it was closed as one. Never a merged one. */
1206 reopenPull(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1207 /** Turns an open pull request back into a draft; it leaves the merge queue. */
1208 convertPullToDraft(actor: User, repo: RepoPath, number: number): Promise<Result<Pull>>;
1209 /**
1210 * Lands the pull request on the repository's default branch. Unless
1211 * `keepItemOpen`, that lands the work items it closes in this repository
1212 * (each closing once nothing else is left to land), and the others still
1213 * in progress here for its own close as superseded. Only members of the
1214 * repository's workspace may merge.
1215 *
1216 * If the default branch has moved, the pull request is brought up to date
1217 * first and lands when that is done; it comes back still open, and
1218 * `PullDetail.landing` is true meanwhile. A repository that requires pull
1219 * requests to be up to date refuses instead.
1220 */
1221 mergePull(actor: User, repo: RepoPath, number: number, options?: MergeOptions): Promise<Result<Pull>>;
1222 /**
1223 * Drafts and open pull requests the viewer started, most recently active
1224 * first, each with where it stands if g1t is seeing it through.
1225 */
1226 listActivePulls(
1227 viewer: Viewer,
1228 ): Promise<{ pull: Pull; item: WorkItem | null; lifecycle: Lifecycle | null }[]>;
1229 /**
1230 * The work items and pull requests a person opened, a page at a time,
1231 * only those the viewer may read. Not found for no such account.
1232 */
1233 byAuthor(username: string, viewer: Viewer, filter?: AuthoredFilter): Promise<Result<Authored>>;
1234 /**
1235 * What a person did each day of the last year (work items and pull requests
1236 * opened, reviews given), only on repositories the viewer may read: the
1237 * calendar on their profile. Not found for no such account.
1238 */
1239 contributions(username: string, viewer: Viewer): Promise<Result<Contributions>>;
1240
1241
1242
1243 appendSession(actor: User, repo: RepoPath, number: number, entries: NewSessionEntry[]): Promise<Result<{ count: number }>>;
1244 readSession(repo: RepoPath, number: number, viewer: Viewer, afterSeq?: number): Promise<Result<SessionEntry[]>>;
1245}
1246
1247/**
1248 * What to pass `ReposApi.compare` to see what a pull request changes.
1249 *
1250 * A working copy is compared as a whole. A branch, of the repository or of
1251 * a fork of it, is compared by name while the pull request is open, and by
1252 * the commit it was merged or closed at afterwards, so later pushes to the
1253 * branch do not change the record. A fork's branch is compared from the
1254 * repository it merges into (`targetId`).
1255 */
1256export function pullComparison(pull: Pull): {
1257 repoId: string;
1258 base: string | null;
1259 head: string | null;
1260 /** The branch it merges into, which it is compared from. */
1261 baseBranch: string | null;
1262 /** For a fork's branch: the repository it merges into. */
1263 targetId: string | null;
1264} {
1265 const baseBranch = pull.base ?? null;
1266 if (pull.forkRepoId) return { repoId: pull.forkRepoId, base: pull.mergeBase, head: null, baseBranch, targetId: null };
1267 const settled = pull.status === "merged" || pull.status === "closed";
1268 return {
1269 repoId: pull.headRepoId ?? pull.repoId,
1270 base: pull.mergeBase,
1271 // A fork's branch by the commit it was last seen at, which the repository
1272 // it merges into holds too, so those who read that repository can read it.
1273 head: ((settled || pull.headRepoId) && pull.headCommit) || pull.branch,
1274 baseBranch,
1275 targetId: pull.headRepoId ? pull.repoId : null,
1276 };
1277}
1278
1279/** The id of the repository holding a pull request's change: its working copy, its fork, or the repository. */
1280export function pullSourceId(pull: Pull): string {
1281 return pull.forkRepoId ?? pull.headRepoId ?? pull.repoId;
1282}
1283
1284
1285export type QueueState = "waiting" | "testing" | "passed" | "failed" | "landed" | "removed";
1286
1287/** One pull request's place in a merge queue. */
1288export type QueueEntry = {
1289 id: string;
1290 number: number;
1291 title: string;
1292 agent: string;
1293 state: QueueState;
1294 /** The pull requests merged ahead of it in the state being tested, in order. */
1295 ahead: number[];
1296 baseCommit: string | null;
1297 combinedCommit: string | null;
1298 error: string | null;
1299 results: CheckResult[];
1300 /** Username of whoever merged it into the queue: a person, or `g1t`. */
1301 enqueuedBy: string;
1302 /** RFC 3339. */
1303 createdAt: string;
1304 /** RFC 3339. */
1305 finishedAt: string | null;
1306};
1307
1308/** A repository's merge queue: what is in it, in order, and what recently left. */
1309export type QueueView = {
1310 enabled: boolean;
1311 active: QueueEntry[];
1312 /** Newest first. */
1313 recent: QueueEntry[];
1314};
1315
1316export type QueueStackItem = {
1317 number: number;
1318 title: string;
1319 /** The repository holding the change, and its branch. */
1320 source: RepoPath;
1321 branch: string;
1322 commit: string;
1323 /** How it lands: the state is built with its commits made this way. */
1324 method?: MergeMethod;
1325 /** For merge and squash: the commit's message. */
1326 message?: string;
1327 /** For squash: who the commit is by. */
1328 author?: User;
1329};
1330
1331/** What a sandbox needs to build and check one combined state. */
1332export type QueueJob = {
1333 entryId: string;
1334 token: string;
1335 repo: RepoPath;
1336 defaultBranch: string;
1337 baseCommit: string;
1338 branch: string;
1339 stack: QueueStackItem[];
1340 /** Always empty: the state is checked by the merge_group workflows run on it. */
1341 checks: string[];
1342 /** Always empty, as `checks`. */
1343 contractChecks: string[];
1344 actor: User;
1345};
1346
1347// --- A person's work ---------------------------------------------------------
1348// Mirrors the `Authored*` types in `crates/contracts/src/work.rs`.
1349
1350export type AuthoredKind = "item" | "pull";
1351/** `closed` takes in merged pull requests too; `merged` is only those. */
1352export type AuthoredState = "open" | "closed" | "merged";
1353/** `created` is newest first, `updated` most recently changed, `oldest` oldest first. */
1354export type AuthoredSort = "created" | "updated" | "oldest";
1355
1356/** The most items one `byAuthor` page holds. */
1357export const AUTHORED_PAGE = 25;
1358
1359export type AuthoredFilter = {
1360 kind?: AuthoredKind;
1361 state?: AuthoredState;
1362 /** `namespace/name`. */
1363 repo?: string;
1364 sort?: AuthoredSort;
1365 /** The `next` of the page before. */
1366 before?: string;
1367 limit?: number;
1368};
1369
1370export type AuthoredItem = {
1371 kind: AuthoredKind;
1372 /** The workspace it is numbered in. */
1373 workspace: string;
1374 /** A pull request's repository, or the repository a work item was filed from, if it was. */
1375 repo: RepoPath | null;
1376 number: number;
1377 title: string;
1378 /** A merged pull request is closed. */
1379 state: State;
1380 /** A pull request's own status; null on a work item. */
1381 status: PullStatus | null;
1382 /** Why a work item was closed. */
1383 reason: CloseReason | null;
1384 draft: boolean;
1385 merged: boolean;
1386 /** RFC 3339. */
1387 createdAt: string;
1388 /** RFC 3339. */
1389 updatedAt: string;
1390 /** RFC 3339. */
1391 mergedAt: string | null;
1392};
1393
1394/** Over every repository the viewer may read, whatever the filters. */
1395export type AuthoredCounts = {
1396 pullsMerged: number;
1397 pullsOpen: number;
1398 pulls: number;
1399 items: number;
1400 itemsOpen: number;
1401};
1402
1403export type Authored = {
1404 items: AuthoredItem[];
1405 /** Pass as `before` for the next page; null on the last. */
1406 next: string | null;
1407 counts: AuthoredCounts;
1408 /** The repositories they worked in that the viewer may read, most work first. */
1409 repos: { repo: RepoPath; count: number }[];
1410};
1411
1412// Mirrors `Contributions` in `crates/contracts/src/work.rs`.
1413
1414/** How many days `contributions` covers: today and the 364 before it. */
1415export const CONTRIBUTION_DAYS = 365;
1416
1417/** One day with something on it; days with nothing are left out. */
1418export type ContributionDay = {
1419 /** `YYYY-MM-DD`, UTC. */
1420 date: string;
1421 /** Everything that day, commits included. */
1422 count: number;
1423 /** How many of `count` are commits they pushed to a default branch. */
1424 commits?: number;
1425};
1426
1427/** A person's year, as far as the viewer may see. */
1428export type Contributions = {
1429 /** Oldest first. */
1430 days: ContributionDay[];
1431 total: number;
1432 /** The first day counted, `YYYY-MM-DD`; the last is today (UTC). */
1433 from: string;
1434};
1435
1436// --- Coordinating work: sessions, claims and dependencies -----------------
1437// Mirrors `crates/contracts/src/work/coordination.rs`.
1438
1439/** The harness a session runs in. */
1440export type Harness = "claude_code" | "claude_managed_agents" | "codex" | "cursor" | "copilot" | "other";
1441
1442/** A session as a mark on something it made. */
1443export type SessionRef = { id: string; harness: Harness };
1444
1445/** The sessions tied to one pull request (`pullSessions`). */
1446export type PullSessions = { number: number; sessions: SessionRef[] };
1447
1448/** Active: heard from in 15 minutes; idle: not since; ended: ended, or quiet for 30 minutes. */
1449export type SessionState = "active" | "idle" | "ended";
1450
1451/** One run of someone's own harness on a repository. */
1452export type WorkSession = {
1453 /** `ses_…`. */
1454 id: string;
1455 repoId: string;
1456 /** The work item it works on, by number in the repository's workspace. */
1457 item: number | null;
1458 pull: number | null;
1459 branch: string | null;
1460 actor: { id: string; username: string };
1461 harness: Harness;
1462 harnessSessionId: string | null;
1463 title: string | null;
1464 state: SessionState;
1465 headCommit: string | null;
1466 startedAt: string;
1467 lastSeenAt: string;
1468 endedAt: string | null;
1469 /** What the harness said, or `timed_out`. */
1470 endReason: string | null;
1471 /** For a subagent: the session that started it. */
1472 parentId?: string | null;
1473 /** For a subagent: its kind (Explore, security-reviewer). */
1474 agentType?: string | null;
1475 /** For a subagent: the task it was given, in a few words. */
1476 task?: string | null;
1477 /** For a subagent: the prompt its parent gave it. */
1478 prompt?: string | null;
1479 /** What it reported when it finished: a subagent's final message. */
1480 result?: string | null;
1481 model?: string | null;
1482 /** How many subagents it started. */
1483 subagents?: number;
1484 /** In a list, for one with no title: the start of the first prompt it recorded. */
1485 firstPrompt?: string | null;
1486 /** Where its title came from; none for one with no title, or from before titles said. */
1487 titleSource?: TitleSource | null;
1488 /** When its title was last settled. */
1489 titleSettledAt?: string | null;
1490 /**
1491 * What it cost, estimated at Anthropic's list price from the token usage
1492 * its harness reported, in US dollars; none until it reports usage for a
1493 * model with a known price. Only the workspace's members see it.
1494 */
1495 costUsd?: number | null;
1496 /** Some of its usage was for models priced as unknown, which `costUsd` leaves out. */
1497 costPartial?: boolean;
1498};
1499
1500/**
1501 * Where a session's title came from. g1t settles a title from the whole of
1502 * the session's record: `prompt` is provisional (its first prompt's
1503 * intent) until it does; `person` is pinned from the site and never
1504 * replaced; `agent` is its agent's own (`g1t session attach --title`);
1505 * `item`, `pull` and `summary` are g1t's.
1506 */
1507export type TitleSource = "prompt" | "agent" | "person" | "item" | "pull" | "summary";
1508
1509// --- Sessions across a workspace ------------------------------------------
1510// Mirrors `crates/contracts/src/work/workspace_sessions.rs`.
1511
1512/**
1513 * What kind of session one in a workspace's list is: someone's own
1514 * `harness`, one g1t started for someone on the workspace's Anthropic
1515 * provider (`hosted`), g1t's own `agent` on a pull request, or what a coding
1516 * agent `recorded` on a pull request with no session of its own.
1517 */
1518export type SessionKind = "harness" | "hosted" | "agent" | "recorded";
1519
1520/** Which of a workspace's sessions to list: those going now, every one, or those that ended. */
1521export type SessionsShown = "live" | "recent" | "ended";
1522
1523/** One session of a workspace, whatever its kind. */
1524export type WorkspaceSession = {
1525 kind: SessionKind;
1526 /** `ses_…`, `run_…` for g1t's agent, the pull request's id for a recorded one. */
1527 id: string;
1528 /** `owner/name`. */
1529 repo: string;
1530 repoId: string;
1531 title: string | null;
1532 /** Who runs it; `g1t` for g1t's own. */
1533 actor: string | null;
1534 harness: Harness | null;
1535 /** For g1t's agent and a recorded one: the agent label. */
1536 agent: string | null;
1537 branch: string | null;
1538 item: number | null;
1539 itemTitle: string | null;
1540 pull: number | null;
1541 pullTitle: string | null;
1542 pullStatus: PullStatus | null;
1543 state: SessionState;
1544 startedAt: string;
1545 lastActivityAt: string;
1546 subagents: number;
1547 /** For g1t's agent: what it is doing now. */
1548 step: string | null;
1549 /** For a harness or hosted session: the session itself. */
1550 session: WorkSession | null;
1551 /** With `subagents`: its subagents and theirs. */
1552 children?: WorkSession[];
1553};
1554
1555/** A repository of the workspace the viewer may read. */
1556export type SessionsRepo = { id: string; path: string; defaultBranch: string };
1557
1558/** One repository's merge queue, when something waits in it. */
1559export type RepoQueue = QueueView & { repo: string; defaultBranch: string };
1560
1561/** A pull request with the repository it is in. */
1562export type RepoPull = Pull & { repo: string };
1563
1564/** `listWorkspaceSessions`. */
1565export type WorkspaceSessions = {
1566 sessions: WorkspaceSession[];
1567 queue: RepoQueue[];
1568 landed: RepoPull[];
1569 repos: SessionsRepo[];
1570};
1571
1572export type WorkspaceSessionsFilter = {
1573 shown?: SessionsShown;
1574 kind?: SessionKind;
1575 harness?: Harness;
1576 person?: string;
1577 repo?: string;
1578 item?: number;
1579 subagents?: boolean;
1580 sessionsOnly?: boolean;
1581 limit?: number;
1582};
1583
1584/** A session and the repository it runs in. */
1585export type WorkspaceSessionDetail = WorkSessionDetail & { repo: string };
1586
1587/** What kind of thing a session touched. */
1588export type TouchKind = "file" | "commit" | "branch" | "pull" | "item";
1589
1590/** Something a session touched, kept once per session. A work item's `value` is its number. */
1591export type SessionTouch = { sessionId: string; kind: TouchKind; value: string; at: string };
1592
1593/** How a session was tied to a work item or pull request. */
1594export type LinkVia = "attached" | "claim" | "branch" | "commit" | "trailer" | "opened" | "ref";
1595
1596/** A work item or pull request a session, or one of its subagents, worked on. */
1597export type SessionLink = {
1598 kind: "item" | "pull";
1599 number: number;
1600 title: string;
1601 /** The work item's state or the pull request's status. */
1602 state: string;
1603 via: LinkVia[];
1604 sessionIds: string[];
1605};
1606
1607/** A skill a session used, by name. */
1608export type SessionSkill = { sessionId: string; name: string; uses: number };
1609
1610export type ClaimState = "active" | "released" | "expired" | "handed_off";
1611
1612/** An advisory, expiring "I'm working on #N". Never a lock. */
1613export type Claim = {
1614 /** `clm_…`. */
1615 id: string;
1616 /** The repository of the checkout it was made from, if any. */
1617 repoId: string | null;
1618 /** The work item it is on: its workspace and number. */
1619 workspace: string;
1620 item: number;
1621 sessionId: string | null;
1622 actor: { id: string; username: string };
1623 harness: Harness | null;
1624 note: string | null;
1625 state: ClaimState;
1626 createdAt: string;
1627 expiresAt: string;
1628 endedAt: string | null;
1629 endReason: string | null;
1630 /** For a hand-off: who it was handed to; null for anyone. */
1631 handoffTo: string | null;
1632};
1633
1634/** `session.started` and `session.ended`. */
1635export type SessionEventData = { repoId: string; number?: number; item?: number; session: WorkSession };
1636
1637/** `work.claimed`, `work.released`, `work.claim_expired` and `work.handoff_requested`. */
1638export type ClaimEventData = {
1639 repoId?: string;
1640 workspace: string;
1641 number: number;
1642 item: number;
1643 /** The repositories the work item is linked to. */
1644 repoIds: string[];
1645 claim: Claim;
1646 others?: Claim[];
1647 tookOver?: string;
1648 reason?: string;
1649 from?: string;
1650 to?: string;
1651 note?: string;
1652};
1653
1654/** `dependency.changed`. */
1655export type DependencyChangedData = {
1656 workspace: string;
1657 number: number;
1658 item: number;
1659 repoIds: string[];
1660 blockedBy: number[];
1661 added: number[];
1662 removed: number[];
1663 cleared: number[];
1664 remaining: number[];
1665 mergedPull?: number;
1666};
1667
1668/** `overlap.detected` between two pull requests, sent once for each side of a new overlap. */
1669export type PullOverlapData = {
1670 repoId: string;
1671 number: number;
1672 pull: number;
1673 otherPull: number;
1674 files: string[];
1675 item?: number;
1676 otherItem?: number;
1677};
1678
1679/** `overlap.detected` between two sessions that touched the same files (siblings included), once for each side. */
1680export type SessionOverlapData = {
1681 repoId: string;
1682 number?: number;
1683 sessionId: string;
1684 otherSessionId: string;
1685 otherActor: string;
1686 files: string[];
1687 item?: number;
1688 otherItem?: number;
1689};
1690
1691/** `overlap.detected`: between pull requests, or between sessions (with `sessionId`). */
1692export type OverlapDetectedData = PullOverlapData | SessionOverlapData;
1693
1694/** `session.progressed`: a session recorded more (at most every few seconds). */
1695export type SessionProgressedData = { repoId: string; number?: number; sessionId: string; rootId?: string };
1696
1697/** A work item in brief. */
1698export type ItemBrief = { number: number; title: string; state: State };
1699
1700/** A pull request in brief. */
1701export type PullBrief = { number: number; title: string; status: PullStatus };
1702
1703/** A work item another is blocked by, and where it stands. */
1704export type Blocker = {
1705 number: number;
1706 title: string;
1707 state: State;
1708 /** Active claims on it. */
1709 claims: Claim[];
1710 pulls: PullBrief[];
1711};
1712
1713/** A pull request's place in the merge queue; `position` 1 is the front. */
1714export type QueuePlace = { state: QueueState; position: number };
1715
1716/** One of a work item's pull requests, with where it stands. */
1717export type WorkPull = {
1718 /** Its repository, `owner/name`. */
1719 repo: string;
1720 number: number;
1721 title: string;
1722 status: PullStatus;
1723 branch: string | null;
1724 headCommit: string | null;
1725 author: { id: string; username: string };
1726 /** `failed` when the merge queue took it out, until its head moves. */
1727 checkStatus: CheckStatus | null;
1728 requiredChecks: RequiredCheck[];
1729 mergeable: Mergeable;
1730 /** Other pull requests in progress changing the same files. */
1731 overlaps: Overlap[];
1732 /** Its place in the merge queue, while it is in it. */
1733 queue: QueuePlace | null;
1734};
1735
1736// --- Decision records (crates/contracts/src/decisions.rs) ------------------
1737
1738export type DecisionKind =
1739 | "proposal"
1740 | "claim"
1741 | "integration_failure"
1742 | "integration_passed"
1743 | "fix"
1744 | "approval"
1745 | "merge"
1746 | "note";
1747
1748/** Claimed: someone said so. Tested: a check or the merge queue proved it. Approved: a person approved it. */
1749export type DecisionConfidence = "claimed" | "tested" | "approved";
1750
1751/** A structured reason kept on a work item or pull request, with how sure it is. */
1752export type Decision = {
1753 /** `dec_…`. */
1754 id: string;
1755 /** The work item it is about, by number in its workspace. */
1756 item: number | null;
1757 pull: number | null;
1758 sessionId: string | null;
1759 /** Username of who recorded it; null when g1t did. */
1760 actor: string | null;
1761 kind: DecisionKind;
1762 confidence: DecisionConfidence;
1763 summary: string;
1764 /**
1765 * What it rests on, kept as recorded, in snake_case: `commit`, `check`
1766 * (`name`, `conclusion`, `url`), `combination`, `other_pulls`,
1767 * `suspects`, `bisected`, `merge_queue`.
1768 */
1769 evidence: Record<string, unknown>;
1770 /** RFC 3339. */
1771 createdAt: string;
1772};
1773
1774/** One repository a work item is linked to, with what landed there and its pull requests for it. */
1775export type WorkRepo = ItemRepo & {
1776 /** The checks every pull request into its default branch must pass. */
1777 requiredChecks: string[];
1778 /** Its pull requests for the work item, oldest first. */
1779 pulls: WorkPull[];
1780};
1781
1782/** A repository of the workspace the work may belong in; confirming it is `linkWorkItem` as a target. */
1783export type SuggestedTarget = { repoId: string; path: string; why: string; score: number };
1784
1785/** Everything about a work item an agent needs to pick it up: `get_work`. */
1786export type WorkContext = {
1787 item: WorkItem;
1788 /** The items under its "Definition of done" heading. */
1789 definitionOfDone: string[];
1790 /** Its repositories: origin, then targets, then touched. */
1791 repos: WorkRepo[];
1792 /** The targets it has not landed in yet, by path. */
1793 missing: string[];
1794 /** Repositories it may belong in, likeliest first, each with why. */
1795 suggestedTargets: SuggestedTarget[];
1796 /** Active claims on it. */
1797 claims: Claim[];
1798 /** Sessions on it or its pull requests, most recently heard from first. */
1799 sessions: WorkSession[];
1800 blockedBy: Blocker[];
1801 /** The work items it blocks. */
1802 blocks: ItemBrief[];
1803 /** On it and its pull requests, newest first. */
1804 decisions: Decision[];
1805 /** The latest `integration_failure` decision among them. */
1806 lastIntegrationFailure: Decision | null;
1807 /** Its latest coordination events, newest first. */
1808 recent: G1tEvent[];
1809};
1810
1811/** A harness session and what it recorded. */
1812export type WorkSessionDetail = {
1813 /** Pending repository coordination events; reading does not acknowledge them. */
1814 updates?: { id: string; kind: string; data: unknown; at: string }[];
1815 session: WorkSession;
1816 entries: SessionEntry[];
1817 /** Its subagents and theirs, in the order they started. */
1818 children?: WorkSession[];
1819 /** What it and its subagents touched. */
1820 touched?: SessionTouch[];
1821 /** The work items and pull requests it and its subagents worked on. */
1822 links?: SessionLink[];
1823 skills?: SessionSkill[];
1824 /** For a subagent: the session at the top of its tree. */
1825 root?: WorkSession | null;
1826 /**
1827 * The viewer is not a member of the repository's workspace: the session
1828 * shows that it runs, who runs it and what it is tied to, nothing more.
1829 */
1830 limited?: boolean;
1831};
1832
1833/** Reading coordination: work service methods (services/work/src/coordination, decisions.rs). */
1834export interface CoordinationApi {
1835 getWork(workspace: string, number: number, viewer: Viewer): Promise<Result<WorkContext>>;
1836 /**
1837 * A workspace's claims on the work items the viewer may see, newest
1838 * first; active ones unless `state` says otherwise. With `repo`, those
1839 * made from it or on work items linked to it.
1840 */
1841 listClaims(
1842 workspace: string,
1843 viewer: Viewer,
1844 filter?: { state?: ClaimState; item?: number; repo?: RepoPath },
1845 ): Promise<Result<Claim[]>>;
1846 /** Most recently heard from first; `item` is a work item of the repository's workspace. */
1847 listWorkSessions(
1848 repo: RepoPath,
1849 viewer: Viewer,
1850 filter?: { state?: SessionState; item?: number; pull?: number; path?: string; subagents?: boolean },
1851 ): Promise<Result<WorkSession[]>>;
1852 getWorkSession(repo: RepoPath, id: string, viewer: Viewer, afterSeq?: number): Promise<Result<WorkSessionDetail>>;
1853 /** The sessions of every repository of a workspace the viewer may read, with its merge queues and what landed. */
1854 listWorkspaceSessions(workspace: string, viewer: Viewer, filter?: WorkspaceSessionsFilter): Promise<Result<WorkspaceSessions>>;
1855 /** One harness or hosted session of a workspace, in whichever of its repositories it runs. */
1856 getWorkspaceSession(workspace: string, id: string, viewer: Viewer, afterSeq?: number): Promise<Result<WorkspaceSessionDetail>>;
1857 /**
1858 * Ends a session by hand, from the site: the actor's own, or anyone's
1859 * when they have write access to the repository. It ends as
1860 * `ended by hand by @actor`, with its subagents still going
1861 * (`end_session` with `by_hand`; g1t_contracts::work::session_end_reason).
1862 */
1863 endWorkSession(actor: User, repo: RepoPath, id: string): Promise<Result<WorkSession>>;
1864 /**
1865 * A person names a session from the site, pinning its title: neither
1866 * g1t nor its agent replaces it. No title unpins it, and g1t names it
1867 * again from its record. The actor's own, or anyone's with write access
1868 * to the repository (`title_session`).
1869 */
1870 titleWorkSession(actor: User, repo: RepoPath, id: string, title: string | null): Promise<Result<WorkSession>>;
1871 /**
1872 * The harness sessions tied to some pull requests (at most 100), any way
1873 * a session is tied to one; a subagent's as the session that started it.
1874 * Only pull requests with any are listed.
1875 */
1876 pullSessions(repo: RepoPath, viewer: Viewer, numbers: number[]): Promise<Result<PullSessions[]>>;
1877 /** A work item's (with its pull requests') or a pull request's, oldest first. */
1878 listDecisions(thread: Thread, viewer: Viewer): Promise<Result<Decision[]>>;
1879}
1880
1881/**
1882 * Delivery counts cover the requested UTC days; waiting counts are current.
1883 * `checking` and `failed` count each open pull request once, by its head's
1884 * checks (statuses, check runs and g1t Actions jobs); one with none is in neither.
1885 */
1886export type DeliveryMetrics = { repoId: string; opened: number; merged: number; active: number; unreviewed: number; checking: number; failed: number; queued: number; leadSeconds: number; reviewSeconds: number; reviewed: number };
1887/** `checksUnavailable`: g1t Actions could not be read, so `checking` and `failed` are not known. */
1888export type DeliveryInsights = { projects: DeliveryMetrics[]; days: { day: string; merged: number }[]; checksUnavailable: boolean };
1889
1890/**
1891 * What a workspace's work says over the last weeks (crates/contracts
1892 * work/signals.rs). A pull request is an agent's when g1t's agent opened
1893 * it, it was opened as an agent's, or a harness session is tied to it; its
1894 * owner is the person who asked for it, else its author.
1895 */
1896export type WorkspaceSignalsArgs = {
1897 workspace: string;
1898 repoIds: string[];
1899 /** The last UTC day covered, `YYYY-MM-DD`. */
1900 until: string;
1901 /** Weeks of seven UTC days ending with `until`: 1 through 13. */
1902 weeks: number;
1903 /** UTC days ending with `until` for `days`: 1 through 28. */
1904 days: number;
1905 /** The first UTC day `pulls` reaches back to: at most 400 days before `until`. */
1906 since: string;
1907};
1908/**
1909 * One repository's week from UTC day `start`; empty weeks are left out.
1910 * `stalled`: open when the week ended (now, for this week), opened three
1911 * days or more before, and no activity (comment, review, timeline event,
1912 * its latest push, a check or status on its current head, an acceptance
1913 * check, a session entry, a tied session or its subagent running) in the
1914 * three days before it ended.
1915 * `sessionCostUsd`: what the harness sessions started in the week cost,
1916 * estimated at list price from the token usage they reported.
1917 */
1918export type SignalWeek = {
1919 repoId: string;
1920 start: string;
1921 merged: number;
1922 agentMerged: number;
1923 /** Of `agentMerged`, the ones a person asked for changes on first. */
1924 agentReworked: number;
1925 agentDrafted: number;
1926 agentDraftSeconds: number;
1927 reviewed: number;
1928 reviewSeconds: number;
1929 stalled: number;
1930 sessionCostUsd: number;
1931};
1932export type SignalDay = { repoId: string; day: string; opened: number; merged: number; agentMerged: number; reworked: number; reviews: number; sessions: number };
1933/** An open pull request no one has reviewed, oldest first; `blocks`: the open work items waiting on its work item. */
1934export type WaitingPull = { repoId: string; number: number; title: string; createdAt: string; agent: boolean; draftSeconds: number | null; item: number | null; blocks: number[] };
1935export type SignalPull = {
1936 repoId: string;
1937 number: number;
1938 title: string;
1939 status: "draft" | "open" | "merged" | "closed";
1940 agent: boolean;
1941 ownerId: string;
1942 ownerName: string;
1943 createdAt: string;
1944 mergedAt: string | null;
1945 item: number | null;
1946 milestone: number | null;
1947 /**
1948 * Its share of its harness sessions' cost: each session's split evenly
1949 * among the pull requests it is tied to (a subagent tied to none counts
1950 * with its root session's).
1951 */
1952 sessionCostUsd: number;
1953};
1954/** One person's use of one harness in one repository, root sessions only. */
1955export type SignalHarness = { repoId: string; ownerId: string; ownerName: string; harness: string; firstAt: string; sessions: number };
1956/** One person's merged pull requests in one repository over its history; `recent`: in the 90 days ending with `until`. */
1957export type SignalAuthor = { repoId: string; ownerId: string; ownerName: string; firstMergedAt: string; lastMergedAt: string; merged: number; recent: number };
1958export type SignalItem = { number: number; title: string; state: string; milestone: number | null };
1959export type SignalMilestone = { number: number; title: string; state: string; dueOn: string | null; createdAt: string; closedAt: string | null };
1960export type WorkspaceSignals = {
1961 weeks: SignalWeek[];
1962 days: SignalDay[];
1963 waiting: WaitingPull[];
1964 pulls: SignalPull[];
1965 pullsCapped: boolean;
1966 authors: SignalAuthor[];
1967 harnesses: SignalHarness[];
1968 items: SignalItem[];
1969 milestones: SignalMilestone[];
1970};