Review threads
Calls
const threads = await forge.threads.list("owner", "repo", 1234, {
state: "unresolved",
perPage: 20,
});
const thread = await forge.threads.get("owner", "repo", 1234, threads.items[0]!.id);
await forge.threads.reply("owner", "repo", 1234, thread.id, { body: "Fixed in the next push." });
await forge.threads.resolve("owner", "repo", 1234, thread.id);
await forge.threads.unresolve("owner", "repo", 1234, thread.id);
ListThreadOptions is page, perPage and state, and state is unresolved, resolved or all.
The shape
interface Thread {
id: string; // opaque; pass it back unchanged
isResolved: boolean;
isOutdated: boolean;
path: string;
line: number | null;
startLine: number | null;
comments: {
id: string;
body: string;
author: { login: string };
url: string;
createdAt: string;
}[];
}
What each platform means by a thread
| Platform | Source | isResolved | isOutdated |
|---|---|---|---|
| GitHub | GraphQL review threads | real | real |
| GitLab | REST merge request discussions | real | always false |
| Gitea, Forgejo | review comments | real | always false |
| GitBucket | nothing | unsupported | unsupported |
GitHub's REST API has no resolved flag at all, so list, get and resolve go through GraphQL. A reply still goes through the REST endpoint for comment replies. That is also why GitHub threads need a token: GraphQL has no anonymous access, full stop.
GitLab answers 401 for discussions without a token, even on a public project. With one, each discussion is a thread. There is no outdated flag in the API, so the field is false and stays false.
Gitea has no parent id on review comments, so every review comment is its own thread with one comment. A reply creates a new review comment on the same line and shows up as another thread. Not pretty, but honest about what the API has.
GitBucket serves REST v3 only. Thread calls against it fail with an explicit unsupported endpoint error rather than a bare 404 you would spend an hour on.
Writes
reply, resolve and unresolve need a credential. Resolving an already resolved thread changes nothing. Replying twice leaves two replies. The agent tools advertise exactly that, so a client can retry one and not the other.
Pull requests
Merge requests and pull requests as one PullRequest, with branches, head SHA, mergeability, changed files and checks.
Commits and CI
Commit history without patches, one commit with its changed files, and CI runs with one status and one conclusion across GitHub Actions, GitLab pipelines and Gitea Actions.