Skip to content
955 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.

Docs in the shape of docs.continue.dev1import type { ActionsApi } from "./actions";
Billing accounts, terms and enterprises; g1t is no longer free2import type { BillingAdminApi, BillingApi } from "./billing";
Deployments: a preview for every pull request, production on g1t.page3import type { DeploymentsApi } from "./deployments";
Projects: what a workspace builds and runs, first on every page4import type { ProjectsApi } from "./projects";
Docs in the shape of docs.continue.dev5import type { EventsApi } from "./events";
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace6import type { IdentityAdminApi, IdentityApi } from "./identity";
Docs in the shape of docs.continue.dev7import type { IntegrationsApi } from "./integrations";
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member8import type { PackagesApi } from "./packages";
Docs in the shape of docs.continue.dev9import type { WebhooksApi } from "./webhooks";
10import type { ReposApi } from "./repos";
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar11import type { PullDetail, WorkApi } from "./work";
12import type { Result } from "./result";
Fast pages, required checks on the branch, self-hosted runners, honest incidents13import type { RunnersApi } from "./runners";
Docs in the shape of docs.continue.dev14
15/** A service binding, as far as these clients need it. */
16export type ServiceBinding = {
17 fetch(input: string, init?: RequestInit): Promise<Response>;
18};
19
20/**
21 * Calls a method on a service that speaks the JSON protocol used by the
22 * Rust services: `POST /rpc/<method>` with the arguments as the body.
23 */
24async function rpc<T>(
25 service: ServiceBinding,
26 method: string,
27 args: object,
28): Promise<T> {
29 // The hostname is ignored; a service binding always reaches its service.
30 const response = await service.fetch(`https://service/rpc/${method}`, {
31 method: "POST",
32 headers: { "content-type": "application/json" },
33 body: JSON.stringify(args),
34 });
35 if (!response.ok) {
36 throw new Error(`${method} failed with status ${response.status}`);
37 }
38 return (await response.json()) as T;
39}
40
41export function identityClient(service: ServiceBinding): IdentityApi {
42 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
43 return {
Merge invite emails that confirm the address: the emailed link carries a proof only that email has, so signing up from it needs no code; shared links and typed codes still confirm44 register: (username, email, password, inviteCode, client, emailProof) =>
45 call("register", {
46 username,
47 email,
48 password,
49 invite_code: inviteCode ?? null,
50 email_proof: emailProof ?? null,
51 client: client ?? null,
52 }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look53 signIn: (username, password, client) => call("sign_in", { username, password, client: client ?? null }),
Merge main (membership, two-factor, GitHub repo roles) into tokens54 twoFactorSignIn: (challenge, code, client) => call("two_factor_sign_in", { challenge, code, client: client ?? null }),
Docs in the shape of docs.continue.dev55 signOut: (sessionToken) => call("sign_out", { sessionToken }),
56 resendVerification: (user) => call("resend_verification", { user }),
57 verifyEmail: (token) => call("verify_email", { token }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look58 requestPasswordReset: (email, client) => call("request_password_reset", { email, client: client ?? null }),
Docs in the shape of docs.continue.dev59 resetPassword: (token, password) =>
60 call("reset_password", { token, password }),
61 deviceStart: (clientName) => call("device_start", { clientName }),
62 deviceLookup: (userCode) => call("device_lookup", { userCode }),
63 deviceResolve: (userCode, user, approve) =>
64 call("device_resolve", { userCode, user, approve }),
65 deviceClaim: (deviceCode) => call("device_claim", { deviceCode }),
66 oauthAuthorize: (user, approval) => call("oauth_authorize", { user, ...approval }),
67 oauthExchange: (code, codeVerifier, clientId, redirectUri) =>
68 call("oauth_exchange", { code, codeVerifier, clientId, redirectUri }),
69 oauthRefresh: (refreshToken, clientId) =>
70 call("oauth_refresh", { refreshToken, clientId }),
71 listOAuthGrants: (user) => call("list_oauth_grants", { user }),
72 revokeOAuthGrant: (user, id) => call("revoke_oauth_grant", { user, id }),
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step73 updateOAuthGrant: (user, id, grant) =>
74 call("update_oauth_grant", { user, id, scopes: grant.scopes }),
Docs in the shape of docs.continue.dev75 createWorkspace: (user, slug, name) => call("create_workspace", { user, slug, name }),
76 getWorkspace: (slug) => call("get_workspace", { slug }),
Merge branch 'worktree-agent-a2013627e5ea4ab13'77 workspaceResidency: (slug) => call("workspace_residency", { slug }),
78 setWorkspaceResidency: (actor, slug, residency) => call("set_workspace_residency", { actor, slug, residency }),
Docs in the shape of docs.continue.dev79 listMembers: (slug, viewer) => call("list_members", { slug, viewer }),
80 addMember: (actor, slug, username) => call("add_member", { actor, slug, username }),
81 removeMember: (actor, slug, username) =>
Merge main (membership, two-factor, GitHub repo roles) into tokens82 call("remove_member", { actor, slug, username, surface: "web" }),
83 updateMember: (actor, slug, username, change) =>
84 call("update_member", { actor, slug, username, role: change.role ?? null, org_roles: change.org_roles ?? null, surface: "web" }),
85 transferOwnership: (actor, slug, username) => call("transfer_ownership", { actor, slug, username, surface: "web" }),
86 leaveWorkspace: (user, slug) => call("leave_workspace", { user, slug, surface: "web" }),
87 setMemberPrivileges: (actor, slug, change) => call("set_member_privileges", { actor, slug, privileges: change, surface: "web" }),
88 setTwoFactorRequirement: (actor, slug, required) =>
89 call("set_two_factor_requirement", { actor, slug, required, surface: "web" }),
Docs in the shape of docs.continue.dev90 updateWorkspace: (actor, slug, details) =>
91 call("update_workspace", { actor, slug, ...details }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains92 renameWorkspace: (actor, slug, newSlug) => call("rename_workspace", { actor, slug, newSlug }),
93 checkWorkspaceRename: (actor, slug, newSlug) =>
94 call("check_workspace_rename", { actor, slug, newSlug }),
95 resolveSlug: (slug) => call("resolve_slug", { slug }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look96 deleteWorkspace: (actor, slug, confirm) => call("delete_workspace", { actor, slug, confirm }),
97 checkWorkspaceDeletion: (actor, slug) => call("check_workspace_deletion", { actor, slug }),
Workspace names and icons, and a component kit for every control98 setWorkspaceAvatar: (actor, slug, image) => call("set_workspace_avatar", { actor, slug, image }),
99 setUserAvatar: (user, image) => call("set_user_avatar", { user, image }),
Docs in the shape of docs.continue.dev100 listWorkspaceTokens: (slug, viewer) => call("list_workspace_tokens", { slug, viewer }),
101 removeWorkspaceToken: (actor, slug, id) =>
102 call("remove_workspace_token", { actor, slug, id }),
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers103 createToken: (actor, input) =>
104 call("create_token", {
105 actor,
106 owner: input.owner ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules107 name: input.name,
108 description: input.description ?? null,
109 ttl_seconds: input.ttlSeconds,
110 workspace: input.workspace,
111 repository_selection: input.repositorySelection,
112 repositories: input.repositories,
113 permissions: input.permissions,
Merge main into Artifacts Phase 2114 website: input.website ?? false,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules115 }),
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers116 updateToken: (actor, id, change, owner) =>
117 call("update_token", {
118 actor,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules119 id,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers120 owner: owner ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules121 name: change.name ?? null,
122 description: change.description ?? null,
123 repository_selection: change.repositorySelection ?? null,
124 repositories: change.repositories ?? null,
125 permissions: change.permissions ?? null,
Merge main into Artifacts Phase 2126 website: change.website ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules127 }),
128 getTokenPolicy: (slug, viewer) => call("get_token_policy", { slug, viewer }),
129 setTokenPolicy: (actor, slug, change) =>
130 call("set_token_policy", {
131 actor,
132 slug,
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers133 allow_tokens_for_all_workspaces: change.allowTokensForAllWorkspaces ?? null,
134 allow_tokens_for_this_workspace: change.allowTokensForThisWorkspace ?? null,
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules135 require_approval: change.requireApproval ?? null,
136 max_lifetime_days: change.maxLifetimeDays ?? null,
137 forbid_no_expiry: change.forbidNoExpiry ?? null,
138 surface: "web",
139 }),
140 listMemberTokens: (actor, slug, filter = {}) =>
One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers141 call("list_member_tokens", { actor, slug, status: filter.status ?? null }),
Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules142 reviewTokenRequest: (actor, slug, id, approve, reason) =>
143 call("review_token_request", { actor, slug, id, approve, reason: reason ?? null, surface: "web" }),
144 revokeMemberToken: (actor, slug, id, reason) =>
145 call("revoke_member_token", { actor, slug, id, reason: reason ?? null, surface: "web" }),
Docs in the shape of docs.continue.dev146 userForSession: (sessionToken) => call("user_for_session", { sessionToken }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look147 registration: () => call("registration", {}),
148 listInvites: (user) => call("list_invites", { user }),
149 createInvite: (user, options = {}) =>
Merge two kinds of invite, kept apart: an invite to g1t (Settings, invite-only only, no workspace unless asked) and an invitation to a workspace (its People page)150 call("create_invite", { user, email: options.email ?? null, workspace: options.workspace ?? null, join: options.join ?? null, join_role: options.join ? (options.joinRole ?? null) : null }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look151 revokeInvite: (user, id) => call("revoke_invite", { user, id }),
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas152 checkInvite: (code, client, options = {}) =>
153 call("check_invite", {
154 code,
155 client: client ?? null,
156 viewer: options.viewer ?? null,
157 any_status: options.anyStatus ?? false,
Merge invite emails that confirm the address: the emailed link carries a proof only that email has, so signing up from it needs no code; shared links and typed codes still confirm158 email_proof: options.emailProof ?? null,
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas159 }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look160 acceptInvite: (user, code) => call("accept_invite", { user, code }),
Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040)161 inviteMember: (actor, slug, who) =>
162 call("invite_member", { actor, slug, email: who.email ?? "", username: who.username ?? null, role: who.role ?? null }),
163 listInvitations: (user) => call("list_invitations", { user }),
164 acceptInvitation: (user, id) => call("accept_invitation", { user, id, surface: "web" }),
165 declineInvitation: (user, id) => call("decline_invitation", { user, id, surface: "web" }),
166 findPeople: (query, limit) => call("find_people", { query, limit: limit ?? null }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look167 workspaceInvites: (slug, viewer) => call("workspace_invites", { slug, viewer }),
168 revokeWorkspaceInvite: (actor, slug, id) => call("revoke_workspace_invite", { actor, slug, id }),
169 requestAccess: (email, about, client) => call("request_access", { email, about, client: client ?? null }),
Docs in the shape of docs.continue.dev170 userForGitCredentials: (username, secret) =>
171 call("user_for_git_credentials", { username, secret }),
172 userForAccessToken: (token) => call("user_for_access_token", { token }),
173 userForSshKey: (fingerprint) => call("user_for_ssh_key", { fingerprint }),
174 userByUsername: (username) => call("user_by_username", { username }),
175 usernames: (ids) => call("usernames", { ids }),
Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002)176 usersForAudience: (ids) => call("users_for_audience", { ids }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains177 profile: (username) => call("profile", { username }),
178 updateProfile: (actor, fields) => call("update_profile", { actor, ...fields }),
179 profileWorkspaces: (username, viewer, publicIn) =>
180 call("profile_workspaces", { username, viewer, public: publicIn }),
The apps you pin to your dock are kept with your account, per workspace and in your order, so the dock is the same on every device: identity keeps them in dock_pins and answers dock_pins and set_dock_pins, the dock reads them with the rest of the page, pins kept only on this device carry over with your first change, this device's copy still draws the dock when identity can't be reached, a pin that can't be saved says so, and they go when you or the workspace do; the workspaces guide says how.181 dockPins: (user, workspace) => call("dock_pins", { user, workspace }),
182 setDockPins: (user, workspace, apps) => call("set_dock_pins", { user, workspace, apps }),
Docs in the shape of docs.continue.dev183 listSshKeys: (user) => call("list_ssh_keys", { user }),
184 addSshKey: (user, title, publicKey) =>
185 call("add_ssh_key", { user, title, publicKey }),
186 removeSshKey: (user, id) => call("remove_ssh_key", { user, id }),
187 listAccessTokens: (user) => call("list_access_tokens", { user }),
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step188 createAccessToken: (user, name, ttlSeconds, grant) =>
189 call("create_access_token", {
190 user,
191 name,
192 ttlSeconds,
193 scopes: grant?.scopes ?? null,
194 listed: grant?.listed ?? false,
195 }),
Docs in the shape of docs.continue.dev196 createAgentToken: (onBehalfOf, scope, ttlSeconds) =>
197 call("create_agent_token", { onBehalfOf, scope, ttlSeconds }),
198 removeAccessToken: (user, id) => call("remove_access_token", { user, id }),
Agents get guardrails, run credentials, an audit log, a context hub, repository instructions and mentions; security upkeep; snake_case API199 createRunCredential: (input) => call("create_run_credential", input),
200 bindRunCredentials: (tokenHashes, runId) => call("bind_run_credentials", { tokenHashes, runId }),
201 revokeRunCredentials: (target) => call("revoke_run_credentials", target),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look202 // Who has access to a repository; see access.ts.
203 repoAccess: (owner, name, viewer) => call("repo_access", { viewer, path: { namespace: owner, name } }),
204 addCollaborator: (actor, owner, name, invitee, role) =>
205 call("add_collaborator", { actor, path: { namespace: owner, name }, invitee, role }),
206 setCollaboratorRole: (actor, owner, name, username, role) =>
207 call("set_collaborator_role", { actor, path: { namespace: owner, name }, username, role }),
208 removeCollaborator: (actor, owner, name, username) =>
209 call("remove_collaborator", { actor, path: { namespace: owner, name }, username }),
210 collaboratorPermission: (viewer, owner, name, username) =>
211 call("collaborator_permission", { viewer, path: { namespace: owner, name }, username }),
212 myRepoInvitations: (user) => call("my_repo_invitations", { user }),
213 respondRepoInvitation: (user, id, accept) => call("respond_repo_invitation", { user, id, accept }),
214 revokeRepoInvitation: (actor, owner, name, id) =>
215 call("revoke_repo_invitation", { actor, path: { namespace: owner, name }, id }),
216 setBasePermission: (actor, slug, base) => call("set_base_permission", { actor, slug, base_permission: base }),
217 outsideCollaborators: (viewer, slug) => call("outside_collaborators", { viewer, slug }),
Merge branch 'worktree-agent-a5a5de74d8863d554' into worktree-agent-a16631325aecf58ca218 // A repository's deploy keys; see deploy-keys.ts.
219 listDeployKeys: (viewer, owner, name) => call("list_deploy_keys", { viewer, path: { namespace: owner, name } }),
220 addDeployKey: (actor, owner, name, key) =>
221 call("add_deploy_key", { actor, path: { namespace: owner, name }, title: key.title, key: key.key, read_only: key.readOnly }),
222 removeDeployKey: (actor, owner, name, id) => call("remove_deploy_key", { actor, path: { namespace: owner, name }, id }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar223 // Teams; see teams.ts.
224 listTeams: (viewer, workspace, query) => call("list_teams", { viewer, workspace, query: query ?? null }),
225 getTeam: (viewer, workspace, team) => call("get_team", { viewer, workspace, team }),
226 createTeam: (actor, workspace, team) => call("create_team", { actor, workspace, ...team }),
Merge branch 'worktree-agent-ad7c6d88d93adc817'227 setTeamCreation: (actor, slug, setting) => call("set_team_creation", { actor, slug, team_creation: setting }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar228 updateTeam: (actor, workspace, team, changes) => call("update_team", { actor, workspace, team, ...changes }),
229 deleteTeam: (actor, workspace, team) => call("delete_team", { actor, workspace, team }),
230 teamMembers: (viewer, workspace, team, includeChildTeams) =>
231 call("team_members", { viewer, workspace, team, include_child_teams: includeChildTeams ?? false }),
232 setTeamMember: (actor, workspace, team, username, role) =>
233 call("set_team_member", { actor, workspace, team, username, role }),
234 removeTeamMember: (actor, workspace, team, username) =>
235 call("remove_team_member", { actor, workspace, team, username }),
236 childTeams: (viewer, workspace, team) => call("child_teams", { viewer, workspace, team }),
237 teamRepos: (viewer, workspace, team) => call("team_repos", { viewer, workspace, team }),
238 setTeamRepo: (actor, workspace, team, owner, name, role) =>
239 call("set_team_repo", { actor, workspace, team, repo: { namespace: owner, name }, role }),
240 removeTeamRepo: (actor, workspace, team, owner, name) =>
241 call("remove_team_repo", { actor, workspace, team, repo: { namespace: owner, name } }),
242 userTeams: (viewer, workspace, username) => call("user_teams", { viewer, workspace, username }),
243 teamMemberships: (viewer, workspace) => call("team_memberships", { viewer, workspace }),
Docs in the shape of docs.continue.dev244 };
245}
246
Agents and memory, checks and conflicts, profiles, slug renames, custom domains247/**
248 * The slug a renamed workspace has now, for a `workspace.renamed` handler:
249 * asked of identity by the workspace's id, so that renames delivered twice
250 * or out of order converge. Falls back to the event's `to`.
251 */
252export async function currentWorkspaceSlug(
253 identity: ServiceBinding,
254 renamed: { workspaceId: string; to: string },
255): Promise<string> {
256 const names = await identityClient(identity).usernames([renamed.workspaceId]);
257 return names[renamed.workspaceId] ?? renamed.to;
258}
259
260/** The slugs whose rows move to `current`: the two a rename names, less `current`. */
261export function staleSlugs(renamed: { from: string; to: string }, current: string): string[] {
262 return [...new Set([renamed.from, renamed.to])].filter((slug) => slug !== current);
263}
264
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look265/**
266 * Where a transferred repository is now, as `namespace/name`, for a
267 * `repo.transferred` handler: asked of repos by id, so transfers delivered
268 * twice or out of order converge. Falls back to the event's destination.
269 */
270export async function currentRepoPath(
271 repos: ServiceBinding,
272 transferred: { repoId: string; name: string; to: string },
273): Promise<string> {
274 const path = await rpc<{ namespace: string; name: string } | null>(repos, "path_by_id", { id: transferred.repoId });
275 return path ? `${path.namespace}/${path.name}` : `${transferred.to}/${transferred.name}`;
276}
277
278/** The paths whose rows move to `current`: the two a transfer names, less `current`. */
279export function stalePaths(transferred: { name: string; from: string; to: string }, current: string): string[] {
280 return [...new Set([transferred.from, transferred.to].map((ns) => `${ns}/${transferred.name}`))].filter(
281 (path) => path !== current,
282 );
283}
284
285/**
286 * A repository's path change, from `repo.transferred` or `repo.renamed`,
287 * read the same way: the two paths (`namespace/name`) the event names, old
288 * then new. Null for any other event.
289 */
290export type RepoMove = { repoId: string; paths: [string, string] };
291
292export function repoMove(event: { type: string; data: unknown }): RepoMove | null {
293 const data = event.data as Record<string, string>;
294 if (event.type === "repo.transferred") {
295 return { repoId: data.repoId!, paths: [`${data.from}/${data.name}`, `${data.to}/${data.name}`] };
296 }
297 if (event.type === "repo.renamed") {
298 return { repoId: data.repoId!, paths: [`${data.namespace}/${data.from}`, `${data.namespace}/${data.to}`] };
299 }
300 return null;
301}
302
303/**
304 * Where a moved repository is now, as `namespace/name`: asked of repos by
305 * id, so moves delivered twice or out of order converge. Falls back to the
306 * event's new path.
307 */
308export async function currentMovedPath(repos: ServiceBinding, move: RepoMove): Promise<string> {
309 const path = await rpc<{ namespace: string; name: string } | null>(repos, "path_by_id", { id: move.repoId });
310 return path ? `${path.namespace}/${path.name}` : move.paths[1];
311}
312
313/** The paths whose rows move to `current`: the two a move names, less `current`. */
314export function staleMovedPaths(move: RepoMove, current: string): string[] {
315 return [...new Set(move.paths)].filter((path) => path !== current);
316}
317
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace318/** Staff-only identity. Only sudo binds to it; see `IdentityAdminApi`. */
319export function identityAdminClient(service: ServiceBinding): IdentityAdminApi {
320 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
321 return {
322 workspaces: (query) => call("admin_workspaces", { query: query ?? null }),
323 workspace: (slug) => call("admin_workspace", { slug }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look324 waitlist: (query, status) => call("admin_waitlist", { query: query ?? null, status: status ?? null }),
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas325 waitlistPending: () => call("admin_waitlist_pending", {}),
326 decideWaitlist: (id, approve, staff, note) => call("admin_decide_waitlist", { id, approve, staff, note: note ?? null }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look327 invites: (query) => call("admin_invites", { query: query ?? null }),
328 revokeInvite: (id, staff) => call("admin_revoke_invite", { id, staff }),
329 mintInvite: (email, staff) => call("admin_mint_invite", { email, staff }),
330 grantInvites: (target, name, amount, note, staff) =>
331 call("admin_grant_invites", { target, name, amount, note, staff }),
332 inviteTree: (username) => call("admin_invite_tree", { username }),
333 workspaceInvites: (slug) => call("admin_workspace_invites", { slug }),
Merge shared invite links: label, uses, expiry, domains; joined through recorded (identity 0038)334 sharedInvites: () => call("admin_shared_invites", {}),
335 createSharedInvite: (link, staff) =>
336 call("admin_create_shared_invite", {
337 label: link.label,
338 max_uses: link.maxUses,
339 expires_on: link.expiresOn,
340 domains: link.domains,
341 staff,
342 }),
343 revokeSharedInvite: (id, staff) => call("admin_revoke_shared_invite", { id, staff }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member344 deletedWorkspaces: () => call("admin_deleted_workspaces", {}),
345 restoreWorkspace: (workspaceId, staff) => call("admin_restore_workspace", { workspaceId, staff }),
346 purgeWorkspace: (workspaceId, staff, confirm) => call("admin_purge_workspace", { workspaceId, staff, confirm }),
Merge branch 'worktree-agent-a8385d293d42c913a'347 aliases: () => call("admin_aliases", {}),
348 setAlias: (alias, workspace, note, staff) => call("admin_set_alias", { alias, workspace, note, staff }),
349 removeAlias: (alias, reason, staff) => call("admin_remove_alias", { alias, reason, staff }),
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace350 };
351}
352
Docs in the shape of docs.continue.dev353export function reposClient(service: ServiceBinding): ReposApi {
354 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
355 return {
356 get: (path, viewer) => call("get", { path, viewer }),
357 getById: (id, viewer) => call("get_by_id", { id, viewer }),
Fast pages, required checks on the branch, self-hosted runners, honest incidents358 readable: (ids, viewer) => call("readable", { ids, viewer }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains359 publicNamespaces: (ownerId) => call("public_namespaces", { ownerId }),
Docs in the shape of docs.continue.dev360 list: (viewer, options = {}) => call("list", { viewer, ...options }),
361 create: (owner, input) => call("create", { owner, ...input }),
362 update: (actor, path, changes) => call("update", { actor, path, ...changes }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look363 transfer: (actor, path, to) => call("transfer", { actor, path, to }),
364 delete: (actor, path, confirm) => call("delete", { actor, path, confirm }),
365 deleted: (viewer, namespace) => call("deleted", { viewer, namespace }),
366 restore: (actor, path) => call("restore", { actor, path }),
367 purge: (actor, path, confirm) => call("purge", { actor, path, confirm }),
368 rename: (actor, path, name) => call("rename", { actor, path, name }),
369 archive: (actor, path, archived) => call("archive", { actor, path, archived }),
370 setVisibility: (actor, path, isPrivate, confirm) => call("set_visibility", { actor, path, isPrivate, confirm }),
371 setDefaultBranch: (actor, path, branch) => call("set_default_branch", { actor, path, branch }),
372 renameBranch: (actor, path, from, to) => call("rename_branch", { actor, path, from, to }),
373 resolveBranch: (repoId, branch) => call("resolve_branch", { repoId, branch }),
374 statusById: (id) => call("status_by_id", { id }),
Merge branch 'worktree-agent-a2013627e5ea4ab13'375 storageOptions: () => call("storage_options", {}),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look376 resolvePath: (path) => call("resolve_path", { path }),
Docs in the shape of docs.continue.dev377 tree: (path, viewer, ref, treePath) =>
378 call("tree", { path, viewer, ref, treePath }),
379 blob: (path, viewer, ref, filePath) =>
380 call("blob", { path, viewer, ref, filePath }),
381 log: (path, viewer, ref, limit) => call("log", { path, viewer, ref, limit }),
382 blame: (path, viewer, ref, filePath) => call("blame", { path, viewer, ref, filePath }),
383 forkForPull: (sourceId, pullId, actor) =>
384 call("fork_for_pull", { sourceId, pullId, actor }),
385 gitAccess: (path, viewer, service) =>
386 call("git_access", { path, viewer, service }),
387 branches: (path, viewer) => call("branches", { path, viewer }),
Branches and Tags pages, each file's last commit, and the branch menu on files388 lastCommits: (path, viewer, ref, treePath) => call("last_commits", { path, viewer, ref, treePath }),
Merge project overview: one branch_drift call, spliced histories, cached tags, 6 repos calls instead of 25389 branchDrift: (path, viewer, base, heads) => call("branch_drift", { path, viewer, base, heads }),
Branches and Tags pages, each file's last commit, and the branch menu on files390 tags: (path, viewer) => call("tags", { path, viewer }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97391 about: (path, viewer) => call("about", { path, viewer }),
392 languages: (path, viewer) => call("languages", { path, viewer }),
393 contributors: (path, viewer) => call("contributors", { path, viewer }),
394 license: (path, viewer) => call("license", { path, viewer }),
395 stars: (path, viewer) => call("stars", { path, viewer }),
396 star: (actor, path, starred) => call("star", { path, actor, starred }),
397 stargazers: (path, viewer, page) => call("stargazers", { path, viewer, page: page ?? null }),
398 starred: (username, viewer) => call("starred", { username, viewer }),
399 releases: (path, viewer) => call("releases", { path, viewer }),
400 release: (path, viewer, which) => call("release", { path, viewer, id: which.id ?? null, tag: which.tag ?? null, latest: which.latest ?? false }),
401 createRelease: (actor, path, release) => call("create_release", { path, actor, ...release }),
402 updateRelease: (actor, path, id, change) => call("update_release", { path, actor, id, ...change }),
403 deleteRelease: (actor, path, id) => call("delete_release", { path, actor, id }),
Download ZIP from the Code button; a slimmer lifecycle panel; agent steps say what was done, not sandbox paths404 listFiles: (repoId, ref, limit) => call("list_files", { repoId, ref, skipDirs: [], limit }),
405 rawBlobs: (repoId, hashes, maxBytes) => call("raw_blobs", { repoId, hashes, maxBytes }),
Merge g1tusercontent.com: registry answers run nothing in a browser, the site's pages run only their own scripts, repository files and avatars on their own origin, raw files rate limited per address406 rawFile: (repoId, ref, path, maxBytes) => call("raw_file", { repoId, ref, path, maxBytes }),
Fast pages, required checks on the branch, self-hosted runners, honest incidents407 commitFile: (repo, actor, file) => call("commit_file", { repo, actor, ...file }),
Docs in the shape of docs.continue.dev408 land: (sourceId, actor, branch) => call("land", { sourceId, actor, branch }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar409 compare: (repoId, viewer, base, head, baseBranch) => call("compare", { repoId, viewer, base, head, baseBranch }),
Merge branch 'worktree-agent-ac5b181a013e54348'410 claimBackups: (limit, maxRunning) => call("claim_backups", { limit, maxRunning }),
411 // The sandbox's own calls are snake_case (they come through the API).
412 failBackup: (jobId, token, error) => call("backup_fail", { job_id: jobId, token, error }),
Docs in the shape of docs.continue.dev413 };
414}
415
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar416/**
417 * `PullDetail`'s own fields that the work service writes in snake_case:
418 * `g1t_contracts::work::PullDetail` has no camelCase renaming, though what
419 * it holds (`Pull`, `CheckRun` and the rest) does. Each with its name here.
420 */
421const PULL_DETAIL_FIELDS = [
422 ["review_pending", "reviewPending"],
423 ["earlier_checks", "earlierChecks"],
424 ["required_checks", "requiredChecks"],
425 ["code_owners", "codeOwners"],
426] as const;
427
428/**
429 * A pull request's detail as the work service sent it, with its own fields
430 * in the camelCase this package uses: read at the edge, by `workClient`'s
431 * `getPull`. Either spelling is taken, so a service that already sends
432 * camelCase reads the same.
433 */
434export function pullDetailFromWire(raw: Record<string, unknown>): PullDetail {
435 const detail: Record<string, unknown> = { ...raw };
436 for (const [snake, camel] of PULL_DETAIL_FIELDS) {
437 if (snake in detail) {
438 if (!(camel in detail)) detail[camel] = detail[snake];
439 delete detail[snake];
440 }
441 }
442 if (typeof detail.reviewPending !== "boolean") detail.reviewPending = false;
443 return detail as PullDetail;
444}
445
Docs in the shape of docs.continue.dev446export function workClient(service: ServiceBinding): WorkApi {
447 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
448 return {
449 openIssue: (actor, repo, input) => call("open_issue", { actor, repo, ...input }),
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step450 delegateIssue: (actor, repo, input) => call("delegate_issue", { actor, repo, ...input }),
Docs in the shape of docs.continue.dev451 listIssues: (repo, viewer, filter = {}) => call("list_issues", { repo, viewer, ...filter }),
452 getIssue: (repo, number, viewer) => call("get_issue", { repo, number, viewer }),
453 updateIssue: (actor, repo, number, input) =>
454 call("update_issue", { actor, repo, number, ...input }),
455 closeIssue: (actor, repo, number, reason) =>
456 call("close_issue", { actor, repo, number, reason }),
457 reopenIssue: (actor, repo, number) => call("reopen_issue", { actor, repo, number }),
458 listLabels: (repo, viewer) => call("list_labels", { repo, viewer }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar459 saveLabel: (actor, repo, label) => call("save_label", { actor, repo, ...label }),
460 deleteLabel: (actor, repo, name) => call("delete_label", { actor, repo, name }),
461 addDefaultLabels: (actor, repo) => call("add_default_labels", { actor, repo }),
462 setLabels: (actor, repo, number, labels, change = "set") =>
463 call("set_labels", { actor, repo, number, labels, change }),
464 listMilestones: (repo, viewer, state) => call("list_milestones", { repo, viewer, state }),
465 getMilestone: (repo, number, viewer) => call("get_milestone", { repo, number, viewer }),
466 saveMilestone: (actor, repo, milestone) => call("save_milestone", { actor, repo, ...milestone }),
467 deleteMilestone: (actor, repo, number) => call("delete_milestone", { actor, repo, number }),
Docs in the shape of docs.continue.dev468 counts: (repo, viewer) => call("counts", { repo, viewer }),
469 addComment: (actor, repo, number, comment) =>
470 call("add_comment", { actor, repo, number, ...comment }),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts471 editComment: (actor, repo, commentId, body) => call("edit_comment", { actor, repo, commentId, body }),
472 deleteComment: (actor, repo, commentId) => call("delete_comment", { actor, repo, commentId }),
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar473 workspaceAgentComment: (repo, number, agent, actingFor, body) =>
474 call("workspace_agent_comment", { repo, number, agent, acting_for: actingFor, body }),
475 workspaceAgentReview: (repo, number, agent, actingFor, verdict, body) =>
476 call("workspace_agent_review", { repo, number, agent, acting_for: actingFor, verdict, body }),
Docs in the shape of docs.continue.dev477 startChecks: (pullId) => call("start_checks", { pullId }),
478 reportChecks: (runId, token, report) =>
479 call("report_checks", { runId, token, ...report }),
480 startReview: (pullId) => call("start_review", { pullId }),
481 failReview: (runId, token, error) => call("report_review", { runId, token, error }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains482 startMergecheck: (pullId) => call("start_mergecheck", { pullId }),
483 failMergecheck: (pullId, token, error) => call("report_mergecheck", { pullId, token, error }),
Docs in the shape of docs.continue.dev484 advance: (pullId) => call("advance", { pullId }),
485 stall: (pullId, reason) => call("stall", { pullId, reason }),
486 managedPulls: (repoId) => call("managed_pulls", { repoId }),
487 queue: (repo, viewer) => call("queue", { repo, viewer }),
488 queueBuild: (repoId) => call("queue_build", { repoId }),
489 failQueue: (entryId, token, error) => call("report_queue", { entryId, token, error }),
490 removeFromQueue: (actor, repo, number) => call("remove_from_queue", { actor, repo, number }),
491 messageAgent: (actor, repo, number, body) => call("message_agent", { actor, repo, number, body }),
492 catchUpJob: (pullId) => call("catch_up_job", { pullId }),
Agents asked while not at work are woken to answer493 wakeForMessages: (pullId) => call("wake_for_messages", { pullId }),
Docs in the shape of docs.continue.dev494 getSettings: (repo, viewer) => call("get_settings", { repo, viewer }),
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge495 // Rulesets travel in snake_case (rules.ts).
496 listRulesets: (owner, viewer, includeParents = false) =>
497 call("list_rulesets", { viewer, ...owner, include_parents: includeParents }),
498 getRuleset: (owner, id, viewer) => call("get_ruleset", { viewer, ...owner, id }),
499 saveRuleset: (actor, owner, ruleset, id) => call("save_ruleset", { actor, ...owner, id: id ?? null, ruleset }),
500 deleteRuleset: (actor, owner, id) => call("delete_ruleset", { actor, ...owner, id }),
501 effectiveRules: (repo, name, viewer, target = "branch") => call("effective_rules", { viewer, repo, name, target }),
502 ruleEvaluations: (owner, viewer, filter = {}) => call("rule_evaluations", { viewer, ...owner, ...filter }),
Fast pages, required checks on the branch, self-hosted runners, honest incidents503 seenChecks: (repo, viewer) => call("seen_checks", { repo, viewer }),
Merge checks: statuses and check runs on every commit504 commitChecks: (repo, viewer, shas) => call("commit_checks", { repo, viewer, shas }),
505 getCheckRun: (repo, id, viewer) => call("get_check_run", { repo, id, viewer }),
506 checkRunAnnotations: (repo, id, viewer) => call("check_run_annotations", { repo, id, viewer }),
507 requestCheckAction: (actor, repo, id, identifier) => call("request_check_action", { actor, repo, id, identifier }),
508 rerequestCheckRun: (actor, repo, id) => call("rerequest_check_run", { actor, repo, id }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar509 codeownersErrors: (repo, viewer, ref) => call("codeowners_errors", { repo, viewer, ref: ref ?? null }),
Docs in the shape of docs.continue.dev510 updateSettings: (actor, repo, settings) =>
511 call("update_settings", { actor, repo, settings }),
512 openPull: (actor, repo, input) => call("open_pull", { actor, repo, ...input }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar513 listPulls: (repo, viewer, state, filter = {}) => call("list_pulls", { repo, viewer, state, ...filter }),
Fast pages, required checks on the branch, self-hosted runners, honest incidents514 pullsForRepos: (repoIds, viewer, limit) => call("pulls_for_repos", { repoIds, viewer, limit }),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar515 // Its own fields arrive in snake_case: read into camelCase here.
516 getPull: (repo, number, viewer) =>
517 call<Result<Record<string, unknown>>>("get_pull", { repo, number, viewer }).then(
518 (found): Result<PullDetail> => (found.ok ? { ok: true, value: pullDetailFromWire(found.value) } : found),
519 ),
Docs in the shape of docs.continue.dev520 updatePull: (actor, repo, number, changes) =>
521 call("update_pull", { actor, repo, number, ...changes }),
Catching up with main takes seconds when the two sides touched different files522 catchUpPull: (actor, repo, number) => call("catch_up_pull", { actor, repo, number }),
Docs in the shape of docs.continue.dev523 readyPull: (actor, repo, number, summary) =>
524 call("ready_pull", { actor, repo, number, summary }),
525 closePull: (actor, repo, number) => call("close_pull", { actor, repo, number }),
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts526 reopenPull: (actor, repo, number) => call("reopen_pull", { actor, repo, number }),
527 convertPullToDraft: (actor, repo, number) => call("convert_pull_to_draft", { actor, repo, number }),
Docs in the shape of docs.continue.dev528 mergePull: (actor, repo, number, options = {}) =>
529 call("merge_pull", { actor, repo, number, ...options }),
530 listActivePulls: (viewer) => call("list_active_pulls", { viewer }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains531 byAuthor: (username, viewer, filter = {}) => call("by_author", { username, viewer, ...filter }),
Chat controls, public profiles, shadcn selects, and no Docs tab in a project532 contributions: (username, viewer) => call("contributions", { username, viewer }),
Docs in the shape of docs.continue.dev533 startPlan: (actor, repo, brief) => call("start_plan", { actor, repo, brief }),
534 failPlan: (planId, token, error) => call("report_plan", { planId, token, error }),
535 getPlan: (repo, viewer, id) => call("get_plan", { repo, viewer, id }),
536 listPlans: (repo, viewer) => call("list_plans", { repo, viewer }),
537 applyPlan: (actor, repo, id, options = {}) =>
538 call("apply_plan", { actor, repo, id, ...options }),
539 queueIssue: (actor, repo, number, queued) =>
540 call("queue_issue", { actor, repo, number, queued }),
541 readyIssues: (repoId) => call("ready_issues", { repoId }),
542 listAssignedIssues: (viewer) => call("list_assigned_issues", { viewer }),
543 appendSession: (actor, repo, number, entries) =>
544 call("append_session", { actor, repo, number, entries }),
545 readSession: (repo, number, viewer, afterSeq = 0) =>
546 call("read_session", { repo, number, viewer, afterSeq }),
547 };
548}
549
550export function billingClient(service: ServiceBinding): BillingApi {
551 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
552 return {
553 status: () => call("status", {}),
554 account: (workspace, viewer) => call("account", { workspace, viewer }),
555 ledger: (workspace, viewer) => call("ledger", { workspace, viewer }),
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging556 credits: (workspace, viewer) => call("credits", { workspace, viewer }),
The statement is a month at a time, a line per kind of charge557 statement: (workspace, viewer, month = null, group = "day") => call("statement", { workspace, viewer, month, group }),
558 statementEntries: (workspace, viewer, filter) =>
559 call("statement_entries", {
560 workspace,
561 viewer,
562 month: filter.month,
563 kind: filter.kind,
564 day: filter.day ?? null,
565 project: filter.project ?? null,
566 before: filter.before ?? null,
567 }),
Docs in the shape of docs.continue.dev568 usage: (workspace, viewer, since) => call("usage", { workspace, viewer, since }),
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix569 tokenUsage: (workspace, viewer, options = {}) =>
570 call("token_usage", { workspace, viewer, person: options.person ?? null, days: options.days ?? null }),
571 recordTokens: (usage) => call("record_tokens", usage),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens572 gatewayModels: () => call("gateway_models", {}),
Merge branch 'main' into actions-toolkit-oidc-artifacts573 modelDefaults: () => call("model_defaults", {}),
574 recordDiscovery: (provider, models, by, error = null) => call("record_discovery", { provider, models, by, error }),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens575 gatewayAdmit: (workspace) => call("gateway_admit", { workspace }),
576 recordGateway: (record) => call("record_gateway", record),
577 gatewayRequests: (workspace, viewer, options = {}) =>
578 call("gateway_requests", { workspace, viewer, limit: options.limit ?? null, before: options.before ?? null }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look579 checkout: (actor, workspace, amountCents, returnUrl, method = "card") =>
580 call("checkout", { actor, workspace, amountCents, returnUrl, method }),
Docs in the shape of docs.continue.dev581 confirm: (workspace, viewer, session) => call("confirm", { workspace, viewer, session }),
582 canStart: (workspace) => call("can_start", { workspace }),
A free allowance on g1t's models, so anyone can try its agents583 trial: (workspace, exempt) => call("trial", { workspace, exempt }),
Docs in the shape of docs.continue.dev584 startRun: (run) => call("start_run", run),
Paid features: a workspace turns on Deployments with a monthly plan585 features: (workspace, viewer) => call("features", { workspace, viewer }),
586 subscribe: (actor, workspace, feature, returnUrl) =>
587 call("subscribe", { actor, workspace, feature, returnUrl }),
588 confirmSubscription: (workspace, viewer, session) =>
589 call("confirm_subscription", { workspace, viewer, session }),
590 cancelSubscription: (actor, workspace, feature, resume = false) =>
591 call("cancel_subscription", { actor, workspace, feature, resume }),
592 hasFeature: (workspace, feature) => call("has_feature", { workspace, feature }),
Merge Stripe Tax, the card fee on card payments, and one free workspace per person593 freeWorkspaces: (workspaces) => call("free_workspaces", { workspaces }),
Paid features: a workspace turns on Deployments with a monthly plan594 chargeFeature: (charge) => call("charge_feature", charge),
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace595 billingPortal: (actor, workspace, returnUrl) => call("billing_portal", { actor, workspace, return_url: returnUrl }),
Every sandbox is metered by the second596 recordSandbox: (usage) => call("record_sandbox", usage),
Usage limits: unpaid usage can only go so far597 limit: (workspace, viewer) => call("limit", { workspace, viewer }),
598 checkLimit: (workspace) => call("check_limit", { workspace }),
Prices keep themselves current with what g1t pays599 prices: () => call("prices", {}),
status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas600 notePending: (workspace, source, costMicros, detail = null) => call("note_pending", { workspace, source, costMicros, detail }),
601 usageMeters: (workspace, viewer) => call("usage_meters", { workspace, viewer }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look602 setSpendLimit: (actor, workspace, spendLimitMicros, useFullLimit = false, raiseOnce = false) =>
603 call("set_spend_limit", { actor, workspace, spendLimitMicros, use_full_limit: useFullLimit, raise_once: raiseOnce }),
Two limits, real invoices, trust that grows by itself, sales signals604 invoices: (workspace, viewer) => call("invoices", { workspace, viewer }),
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put605 entitlements: (workspace) => call("entitlements", { workspace }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look606 reserve: (reservation) => call("reserve", reservation),
607 settle: (reservationId, actualMicros) => call("settle", { reservationId, actualMicros }),
608 cardCheck: (actor, workspace, returnUrl) => call("card_check", { actor, workspace, returnUrl }),
609 confirmCardCheck: (workspace, viewer, session) => call("confirm_card_check", { workspace, viewer, session }),
610 requestLimit: (actor, workspace, request) => call("request_limit", { actor, workspace, ...request }),
611 limitRequests: (workspace, viewer) => call("limit_requests", { workspace, viewer }),
612 confirmSpike: (actor, workspace, keepGoing) => call("confirm_spike", { actor, workspace, keepGoing }),
613 setCaps: (actor, workspace, caps) => call("set_caps", { actor, workspace, ...caps }),
Usage, Billing settings and prepaid AI credit; fixes from the UX audit614 usageReport: (workspace, viewer, range) =>
615 call("usage_report", { workspace, viewer, from: range.from, until: range.until, products: range.products ?? [], projects: range.projects ?? [] }),
616 aiCredit: (workspace, viewer) => call("ai_credit", { workspace, viewer }),
617 buyAiCredit: (actor, workspace, amountCents, returnUrl) => call("buy_ai_credit", { actor, workspace, amountCents, returnUrl }),
618 confirmAiCredit: (workspace, viewer, session) => call("confirm_ai_credit", { workspace, viewer, session }),
619 setAiReload: (actor, workspace, reload) => call("set_ai_reload", { actor, workspace, ...reload }),
620 setBudget: (actor, workspace, budget) => call("set_budget", { actor, workspace, ...budget }),
621 billingDetails: (workspace, viewer) => call("billing_details", { workspace, viewer }),
622 setBillingDetails: (actor, workspace, details) => call("set_billing_details", { actor, workspace, ...details }),
Docs in the shape of docs.continue.dev623 };
624}
625
Billing accounts, terms and enterprises; g1t is no longer free626export function billingAdminClient(service: ServiceBinding): BillingAdminApi {
627 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
628 return {
629 accounts: (query) => call("admin_accounts", { query: query ?? null }),
630 account: (id) => call("admin_account", { id }),
631 setTerms: (id, terms, by) => call("admin_set_terms", { id, terms, by }),
Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put632 setAllowances: (id, allowances, note, by) => call("admin_set_allowances", { id, allowances, note, by }),
Billing accounts, terms and enterprises; g1t is no longer free633 createEnterprise: (name, workspaces, by) => call("admin_create_enterprise", { name, workspaces, by }),
634 attach: (workspace, account, by) => call("admin_attach", { workspace, account, by }),
Billing: credits with a kind and expiry, discounts instead of comped, and safer charging635 credit: (workspace, amountMicros, note, by, options = { kind: "goodwill" }) =>
636 call("admin_credit", {
637 workspace,
638 amount_micros: amountMicros,
639 note,
640 by,
641 kind: options.kind,
642 expires_at: options.expiresAt ?? null,
643 refund_for: options.refundFor ?? null,
644 refund_day: options.refundDay ?? null,
645 }),
646 credits: (filter = {}) =>
647 call("admin_credits", {
648 workspace: filter.workspace ?? null,
649 kind: filter.kind ?? null,
650 month: filter.month ?? null,
651 by: filter.by ?? null,
652 }),
653 revokeCredit: (id, note, by) => call("admin_revoke_credit", { id, note, by }),
sudo: reset a test workspace's billing so it starts again as a new customer; refused on a live Stripe key, for comped workspaces and for an enterprise's654 resetBilling: (workspace, confirm, note, by) => call("admin_reset_billing", { workspace, confirm, note, by }),
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace655 billingLink: (workspace, by) => call("admin_billing_link", { workspace, by }),
Stripe's webhook secret is a Worker secret, STRIPE_WEBHOOK_SECRET, from a destination made in Stripe's dashboard656 stripe: (fix = false, by) => call("admin_stripe", { fix, by: by ?? null }),
Stripe webhooks, enterprise invoices, and sudo for both657 enterpriseBilling: (id, email, by) => call("admin_enterprise_billing", { id, email, by }),
Merge Stripe Tax, the card fee on card payments, and one free workspace per person658 enterpriseAddress: (id, address, taxIdType, taxId, by) => call("admin_enterprise_address", { id, address, taxIdType, taxId, by }),
Stripe webhooks, enterprise invoices, and sudo for both659 invoiceEnterprise: (id, by) => call("admin_invoice_enterprise", { id, by }),
660 accountsFor: (workspaces) => call("admin_accounts", { query: null, workspaces }),
Two limits, real invoices, trust that grows by itself, sales signals661 signals: () => call("admin_signals", {}),
662 overview: () => call("admin_overview", {}),
663 sales: (workspace) => call("admin_sales", { workspace }),
664 setSales: (workspace, record, by) =>
665 call("admin_set_sales", {
666 workspace,
667 stage: record.stage,
668 owner: record.owner ?? null,
669 next_step: record.nextStep ?? null,
670 next_at: record.nextAt ?? null,
671 by,
672 }),
673 addNote: (workspace, text, by) => call("admin_add_note", { workspace, text, by }),
674 workspaceInvoices: (workspace) => call("admin_workspace_invoices", { workspace }),
Billing lists every invoice and every staff change; signals carry follow-ups675 allInvoices: (filter = {}) => call("admin_invoices", { status: filter.status ?? null, month: filter.month ?? null }),
676 audit: (filter = {}) =>
677 call("admin_audit", { by: filter.by ?? null, action: filter.action ?? null, before: filter.before ?? null }),
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look678 limitRequests: (status = "open") => call("admin_limit_requests", { status }),
679 decideLimitRequest: (id, decision, amountMicros, note, by) =>
680 call("admin_decide_limit_request", { id, decision, amount_micros: amountMicros, note, by }),
681 overages: () => call("admin_overages", {}),
682 goodwill: (workspace, amountMicros, reason, by, day = null) =>
683 call("admin_goodwill", { workspace, amount_micros: amountMicros, reason, by, day }),
684 velocity: () => call("admin_velocity", {}),
685 recordPayment: (workspace, amountMicros, reference, note, by) =>
686 call("admin_record_payment", { workspace, amount_micros: amountMicros, reference, note, by }),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily687 costs: (days) => call("admin_costs", { days: days ?? null }),
688 costAlerts: () => call("admin_cost_alerts", {}),
Spend caps: a monthly budget for comped workspaces and a daily breaker on what g1t pays689 spendCaps: () => call("admin_spend_caps", {}),
690 liftBreaker: (note, by) => call("admin_lift_breaker", { note, by }),
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)691 platformGuard: () => call("admin_platform_guard", {}),
692 setPause: (level, paused, note, by) => call("admin_set_pause", { level, paused, note, by }),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily693 decideProposal: (id, decision, note, by) => call("admin_decide_proposal", { id, decision, note, by }),
694 setCostSettings: (settings, by) => call("admin_set_cost_settings", { settings, by }),
695 setCostMapping: (mapping, by) =>
696 call("admin_set_cost_mapping", {
697 product: mapping.product,
698 meter: mapping.meter,
699 bucket: mapping.bucket ?? "",
700 price_meter: mapping.priceMeter ?? null,
701 own_meter: mapping.ownMeter ?? null,
702 scale_to_own: mapping.scaleToOwn ?? false,
703 drift_percent: mapping.driftPercent ?? null,
704 note: mapping.note ?? "",
705 remove: mapping.remove ?? false,
706 by,
707 }),
708 runCosts: (by) => call("admin_run_costs", { by }),
Merge branch 'main' into actions-toolkit-oidc-artifacts709 models: () => call("admin_models", {}),
710 decideModel: (model, decision, details, reason, by) =>
711 call("admin_decide_model", {
712 model,
713 decision,
714 name: details.name ?? null,
715 tier_hint: details.tierHint ?? null,
716 prices: details.prices
717 ? {
718 input_micros: details.prices.inputMicros,
719 output_micros: details.prices.outputMicros,
720 cache_read_micros: details.prices.cacheReadMicros,
721 cache_write_micros: details.prices.cacheWriteMicros,
722 cache_write_1h_micros: details.prices.cacheWrite1hMicros,
723 threshold: details.prices.threshold,
724 over_input_micros: details.prices.overInputMicros,
725 over_output_micros: details.prices.overOutputMicros,
726 over_cache_read_micros: details.prices.overCacheReadMicros,
727 over_cache_write_micros: details.prices.overCacheWriteMicros,
728 over_cache_write_1h_micros: details.prices.overCacheWrite1hMicros,
729 }
730 : null,
731 reason,
732 by,
733 }),
734 setModelDefault: (purpose, value, reason, by) =>
735 call("admin_set_model_default", {
736 purpose,
737 model: value.model ?? null,
738 tier: value.tier ?? null,
739 effort: value.effort ?? null,
740 reason,
741 by,
742 }),
Billing accounts, terms and enterprises; g1t is no longer free743 };
744}
745
Docs in the shape of docs.continue.dev746export function eventsClient(service: ServiceBinding): EventsApi {
747 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
748 return {
749 publish: (events) => call("publish", { events }),
750 list: (query) => call("list", query),
751 };
752}
753
754export function integrationsClient(service: ServiceBinding): IntegrationsApi {
755 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
756 return {
757 list: (workspace, viewer) => call("list", { workspace, viewer }),
758 connect: (actor, workspace, input) => call("connect", { actor, workspace, ...input }),
759 update: (actor, workspace, id, input) => call("update", { actor, workspace, id, ...input }),
760 disconnect: (actor, workspace, id) => call("disconnect", { actor, workspace, id }),
761 test: (actor, workspace, id) => call("test", { actor, workspace, id }),
762 deliveries: (workspace, viewer, id) => call("deliveries", { workspace, viewer, id }),
763 resolve: (workspace, viewer, reference) => call("resolve", { workspace, viewer, reference }),
764 references: (workspace, text, limit) => call("references", { workspace, text, limit }),
765 import: (actor, repo, reference, assign) => call("import", { actor, repo, reference, assign }),
766 links: (repo, number) => call("links", { repo, number }),
767 modelProvider: (workspace) => call("model_provider", { workspace }),
768 openModelSession: (run) => call("open_model_session", run),
769 modelUpstream: (token) => call("model_upstream", { token }),
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens770 gatewayUpstream: (workspace) => call("gateway_upstream", { workspace }),
AI Gateway: OpenAI's format, open models, and your own providers771 gatewayProviders: (workspace) => call("gateway_providers", { workspace }),
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily772 closeModelSessions: (tokenHashes) => call("close_model_sessions", { token_hashes: tokenHashes }),
Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006)773 capModelSessions: (tokenHashes, capMicros) => call("cap_model_sessions", { token_hashes: tokenHashes, cap_micros: capMicros }),
Docs in the shape of docs.continue.dev774 routes: (workspace, viewer) => call("routes", { workspace, viewer }),
775 setRoutes: (actor, workspace, routes) => call("set_routes", { actor, workspace, routes }),
776 };
777}
778
779export function webhooksClient(service: ServiceBinding): WebhooksApi {
780 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
781 return {
782 list: (viewer, owner) => call("list", { viewer, ...owner }),
783 create: (actor, owner, input) => call("create", { actor, ...owner, ...input }),
784 update: (actor, owner, id, input) => call("update", { actor, ...owner, id, ...input }),
785 delete: (actor, owner, id) => call("delete", { actor, ...owner, id }),
786 ping: (actor, owner, id) => call("ping", { actor, ...owner, id }),
787 deliveries: (viewer, owner, id) => call("deliveries", { viewer, ...owner, id }),
788 redeliver: (actor, owner, deliveryId) => call("redeliver", { actor, ...owner, deliveryId }),
789 };
790}
791
792export function actionsClient(service: ServiceBinding): ActionsApi {
793 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
794 return {
795 workflows: (repo, viewer) => call("workflows", { repo, viewer }),
796 runs: (repo, viewer, filter = {}) => call("runs", { repo, viewer, ...filter }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)797 run: (repo, viewer, id, attempt) => call("run", { repo, viewer, id, attempt: attempt ?? null }),
Docs in the shape of docs.continue.dev798 logs: (repo, viewer, job, after = 0) => call("logs", { repo, viewer, job, after }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)799 summaries: (repo, viewer, id, attempt) => call("summaries", { repo, viewer, id, attempt: attempt ?? null }),
800 jobLogText: (repo, viewer, job) => call("job_log_text", { repo, viewer, job }),
801 runLogs: (repo, viewer, id, attempt) => call("run_logs", { repo, viewer, id, attempt: attempt ?? null }),
Docs in the shape of docs.continue.dev802 dispatch: (actor, repo, workflow, ref, inputs) => call("dispatch", { actor, repo, workflow, ref, inputs }),
Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009)803 cancel: (actor, repo, id, force = false) => call("cancel", { actor, repo, id, force }),
804 rerun: (actor, repo, id, failedOnly = false, options = {}) =>
805 call("rerun", { actor, repo, id, failed_only: failedOnly, job: options.job ?? null, debug: options.debug ?? false }),
Docs in the shape of docs.continue.dev806 setWorkflowEnabled: (actor, repo, workflow, enabled) =>
807 call("set_workflow_enabled", { actor, repo, workflow, enabled }),
808 settings: (actor, owner, kind) => call("settings", { actor, ...owner, kind }),
Secrets and variables: one list, rows per environment, for workflows and deployments809 setSetting: (actor, owner, kind, name, value, options = {}) =>
810 call("set_setting", { actor, ...owner, kind, name, value, ...options }),
811 deleteSetting: (actor, owner, kind, name, id) => call("delete_setting", { actor, ...owner, kind, name, id }),
Merge branch 'worktree-agent-a3abfcce648e87dca'812 approveRun: (actor, repo, id) => call("approve_run", { actor, repo, id }),
813 pendingDeployments: (repo, viewer, id) => call("pending_deployments", { repo, viewer, id }),
814 reviewDeployments: (actor, repo, id, state, environments = [], comment) =>
815 call("review_deployments", { actor, repo, id, state, environments, comment: comment ?? null }),
816 actionsSettings: (repo, viewer) => call("actions_settings", { repo, viewer }),
817 setActionsSettings: (actor, repo, change) => call("set_actions_settings", { actor, repo, ...change }),
818 workspaceActionsSettings: (workspace, viewer) => call("workspace_actions_settings", { workspace, viewer }),
819 setWorkspaceActionsSettings: (actor, workspace, change) =>
820 call("set_workspace_actions_settings", { actor, workspace, ...change }),
821 environments: (repo, viewer) => call("environments", { repo, viewer }),
822 setEnvironment: (actor, repo, name, change) => call("set_environment", { actor, repo, name, ...change }),
823 deleteEnvironment: (actor, repo, name) => call("delete_environment", { actor, repo, name }),
Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2824 artifacts: (repo, viewer, filter = {}) => call("artifacts", { repo, viewer, ...filter }),
825 artifactDownload: (repo, viewer, by) => call("artifact_download", { repo, viewer, ...by }),
826 deleteArtifact: (actor, repo, id) => call("delete_artifact", { actor, repo, id }),
827 artifactRetention: (repo, viewer, days) => call("artifact_retention", { repo, viewer, days }),
Docs in the shape of docs.continue.dev828 };
829}
830
Deployments: a preview for every pull request, production on g1t.page831
Fast pages, required checks on the branch, self-hosted runners, honest incidents832/** Self-hosted runners, kept by the actions service. */
833export function runnersClient(service: ServiceBinding): RunnersApi {
834 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
835 return {
836 stuck: (viewer) => call("stuck_jobs", { viewer }),
The Runners page shows the machines a workspace's agents and workflow jobs run on, in Workspace under Compute: g1t's cloud beside your own runners, what each is running now with a link to it, what's waiting, this month's machine time and its cost (your own runners' free), where agent work and workflow jobs run, adding a runner, and groups; runner_activity in Actions says what runs where, work handed to your runners keeps its agent run, and the self-hosted runners guide says how.837 activity: (actor, workspace) => call("runner_activity", { actor, workspace }),
Fast pages, required checks on the branch, self-hosted runners, honest incidents838 list: (actor, owner) => call("runners", { actor, ...owner }),
839 createToken: (actor, owner, group) => call("create_registration_token", { actor, ...owner, group }),
840 remove: (actor, owner, id) => call("remove_runner", { actor, ...owner, id }),
841 groups: (actor, workspace) => call("runner_groups", { actor, workspace }),
842 setGroup: (actor, workspace, group) => call("set_runner_group", { actor, workspace, ...group }),
843 deleteGroup: (actor, workspace, id) => call("delete_runner_group", { actor, workspace, id }),
844 settings: (actor, owner) => call("runner_settings", { actor, ...owner }),
845 setSettings: (actor, owner, change) => call("set_runner_settings", { actor, ...owner, ...change }),
846 };
847}
848
Deployments: a preview for every pull request, production on g1t.page849export function deploymentsClient(service: ServiceBinding): DeploymentsApi {
850 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
851 return {
Projects: what a workspace builds and runs, first on every page852 settings: (project, viewer) => call("settings", { project, viewer }),
853 updateSettings: (actor, project, changes) => call("update_settings", { actor, project, changes }),
854 list: (project, viewer) => call("list", { project, viewer }),
855 get: (project, id, viewer) => call("get", { project, id, viewer }),
856 redeploy: (actor, project, branch) => call("redeploy", { actor, project, branch }),
857 takeDown: (actor, project, branch) => call("take_down", { actor, project, branch }),
858 overview: (workspace, viewer) => call("overview", { workspace, viewer }),
Deployments: a preview for every pull request, production on g1t.page859 usage: (workspace, viewer) => call("usage", { workspace, viewer }),
Agents and memory, checks and conflicts, profiles, slug renames, custom domains860 domains: (project, viewer) => call("domains", { project, viewer }),
861 addDomain: (actor, project, hostname, options = {}) =>
862 call("add_domain", { actor, project, hostname, twin: !!options.twin }),
863 removeDomain: (actor, project, id) => call("remove_domain", { actor, project, id }),
864 refreshDomain: (actor, project, id) => call("refresh_domain", { actor, project, id }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97865 repoDeployments: (repo, viewer, filter = {}) => call("list_deployments", { repo, viewer, ...filter }),
866 repoDeployment: (repo, id, viewer) => call("get_deployment", { repo, id, viewer }),
867 environments: (repo, viewer) => call("list_environments", { repo, viewer }),
868 createDeployment: (actor, repo, input) => call("create_deployment", { repo, actor, ...input }),
869 createDeploymentStatus: (actor, repo, id, input) => call("create_deployment_status", { repo, actor, id, ...input }),
Deployments: a preview for every pull request, production on g1t.page870 };
871}
Projects: what a workspace builds and runs, first on every page872
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member873/** Packages: the registries beside the code (services/packages). */
874export function packagesClient(service: ServiceBinding): PackagesApi {
875 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
876 return {
877 list: (workspace, viewer, filter = {}) =>
878 call("list_packages", {
879 workspace,
880 viewer,
881 ecosystem: filter.ecosystem ?? null,
882 repo_id: filter.repoId ?? null,
883 query: filter.query ?? null,
884 }),
885 get: (workspace, ecosystem, name, viewer) => call("get_package", { workspace, ecosystem, name, viewer }),
886 deleteVersion: (actor, workspace, ecosystem, name, version, surface) =>
887 call("delete_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }),
888 deletePackage: (actor, workspace, ecosystem, name, surface) =>
889 call("delete_package", { actor, workspace, ecosystem, name, surface: surface ?? null }),
890 set: (actor, workspace, ecosystem, name, change, surface) =>
891 call("set_package", {
892 actor,
893 workspace,
894 ecosystem,
895 name,
896 visibility: change.visibility ?? null,
897 link: change.link ?? null,
898 unlink: change.unlink ?? false,
Merge packages: roles, Actions access, source label, soft delete, API899 inherit_access: change.inheritAccess ?? null,
900 surface: surface ?? null,
901 }),
902 settings: (workspace, ecosystem, name, viewer) => call("package_settings", { workspace, ecosystem, name, viewer }),
903 deleted: (workspace, viewer) => call("deleted_packages", { workspace, viewer }),
904 restorePackage: (actor, workspace, ecosystem, name, surface) =>
905 call("restore_package", { actor, workspace, ecosystem, name, surface: surface ?? null }),
906 restoreVersion: (actor, workspace, ecosystem, name, version, surface) =>
907 call("restore_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }),
908 setAccess: (actor, workspace, ecosystem, name, who, role, surface) =>
909 call("set_package_access", {
910 actor,
911 workspace,
912 ecosystem,
913 name,
914 user: "user" in who ? who.user : null,
915 team: "team" in who ? who.team : null,
916 role,
917 surface: surface ?? null,
918 }),
919 removeAccess: (actor, workspace, ecosystem, name, who, surface) =>
920 call("remove_package_access", {
921 actor,
922 workspace,
923 ecosystem,
924 name,
925 user: "user" in who ? who.user : null,
926 team: "team" in who ? who.team : null,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member927 surface: surface ?? null,
928 }),
Merge packages: roles, Actions access, source label, soft delete, API929 setActionsAccess: (actor, workspace, ecosystem, name, repo, role, surface) =>
930 call("set_actions_access", { actor, workspace, ecosystem, name, repo, role, surface: surface ?? null }),
931 removeActionsAccess: (actor, workspace, ecosystem, name, repo, surface) =>
932 call("remove_actions_access", { actor, workspace, ecosystem, name, repo, surface: surface ?? null }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member933 storage: (workspace) => call("storage", { workspace }),
934 storageAll: () => call("storage_all", {}),
Composer from the workspace's own repositories, and go get from g1t.sh935 syncComposer: (repoId) => call("sync_composer", { repo_id: repoId }),
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member936 };
937}
938
Projects: what a workspace builds and runs, first on every page939export function projectsClient(service: ServiceBinding): ProjectsApi {
940 const call = <T>(method: string, args: object) => rpc<T>(service, method, args);
941 return {
942 list: (workspace, viewer) => call("list", { workspace, viewer }),
943 get: (workspace, slug, viewer) => call("get", { workspace, slug, viewer }),
944 byRepo: (repoId) => call("by_repo", { repoId }),
945 create: (actor, workspace, input) => call("create", { actor, workspace, input }),
946 update: (actor, workspace, slug, changes) => call("update", { actor, workspace, slug, changes }),
A project is an app or a library: libraries show their package and how to ship a release, not production947 deploymentsChanged: (projectId, enabled) => call("deployments_changed", { projectId, enabled }),
Projects: pinned and recent projects, per person per workspace948 shortcuts: (workspace, viewer) => call("shortcuts", { workspace, viewer }),
949 pin: (actor, workspace, slug, position) => call("pin", { actor, workspace, slug, position: position ?? null }),
950 unpin: (actor, workspace, slug) => call("unpin", { actor, workspace, slug }),
951 reorderPins: (actor, workspace, slugs) => call("reorder_pins", { actor, workspace, slugs }),
952 visited: (actor, projectId) => call("visited", { actor, projectId }),
Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97953 publicLinks: (repos) => call("public_links", { repos }),
Projects: what a workspace builds and runs, first on every page954 };
955}

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