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.
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 1 | import type { ActionsApi } from "./actions"; |
| Billing accounts, terms and enterprises; g1t is no longer free | 2 | import type { BillingAdminApi, BillingApi } from "./billing"; |
| Deployments: a preview for every pull request, production on g1t.page | 3 | import type { DeploymentsApi } from "./deployments"; |
| Projects: what a workspace builds and runs, first on every page | 4 | import type { ProjectsApi } from "./projects"; |
| Webhooks: every event, to your own addresses, signed and retried | 5 | import type { EventsApi } from "./events"; |
| Billing on Stripe's pages, month-end charges, warnings; sudo by workspace | 6 | import type { IdentityAdminApi, IdentityApi } from "./identity"; |
| Webhooks: every event, to your own addresses, signed and retried | 7 | import type { IntegrationsApi } from "./integrations"; |
| Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member | 8 | import type { PackagesApi } from "./packages"; |
| Webhooks: every event, to your own addresses, signed and retried | 9 | import type { WebhooksApi } from "./webhooks"; |
| 10 | import type { ReposApi } from "./repos"; | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 11 | import type { PullDetail, WorkApi } from "./work"; |
| 12 | import type { Result } from "./result"; | |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 13 | import type { RunnersApi } from "./runners"; |
| Webhooks: every event, to your own addresses, signed and retried | 14 | |
| 15 | /** A service binding, as far as these clients need it. */ | |
| 16 | export 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 | */ | |
| 24 | async 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 | ||
| 41 | export 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 confirm | 44 | 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 look | 53 | signIn: (username, password, client) => call("sign_in", { username, password, client: client ?? null }), |
| Merge main (membership, two-factor, GitHub repo roles) into tokens | 54 | twoFactorSignIn: (challenge, code, client) => call("two_factor_sign_in", { challenge, code, client: client ?? null }), |
| Webhooks: every event, to your own addresses, signed and retried | 55 | 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 look | 58 | requestPasswordReset: (email, client) => call("request_password_reset", { email, client: client ?? null }), |
| Webhooks: every event, to your own addresses, signed and retried | 59 | 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 step | 73 | updateOAuthGrant: (user, id, grant) => |
| 74 | call("update_oauth_grant", { user, id, scopes: grant.scopes }), | |
| Webhooks: every event, to your own addresses, signed and retried | 75 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 79 | 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 tokens | 82 | 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" }), | |
| Webhooks: every event, to your own addresses, signed and retried | 90 | updateWorkspace: (actor, slug, details) => |
| 91 | call("update_workspace", { actor, slug, ...details }), | |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 92 | 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 look | 96 | 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 control | 98 | setWorkspaceAvatar: (actor, slug, image) => call("set_workspace_avatar", { actor, slug, image }), |
| 99 | setUserAvatar: (user, image) => call("set_user_avatar", { user, image }), | |
| Webhooks: every event, to your own addresses, signed and retried | 100 | 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 managers | 103 | 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 rules | 107 | 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 2 | 114 | website: input.website ?? false, |
| Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules | 115 | }), |
| One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers | 116 | updateToken: (actor, id, change, owner) => |
| 117 | call("update_token", { | |
| 118 | actor, | |
| Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules | 119 | 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 managers | 120 | owner: owner ?? null, |
| Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules | 121 | 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 2 | 126 | website: change.website ?? null, |
| Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules | 127 | }), |
| 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 managers | 133 | 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 rules | 135 | 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 managers | 141 | call("list_member_tokens", { actor, slug, status: filter.status ?? null }), |
| Settings: fine-grained tokens, workspace token Admin, workspace personal access token rules | 142 | 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" }), | |
| Webhooks: every event, to your own addresses, signed and retried | 146 | userForSession: (sessionToken) => call("user_for_session", { sessionToken }), |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 147 | 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 look | 151 | 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 quotas | 152 | 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 confirm | 158 | email_proof: options.emailProof ?? null, |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 159 | }), |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 160 | 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 look | 167 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 170 | 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 domains | 177 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 183 | 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 step | 188 | 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 | }), | |
| Webhooks: every event, to your own addresses, signed and retried | 196 | 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 API | 199 | 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 look | 202 | // 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-a16631325aecf58ca | 218 | // 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 bar | 223 | // 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 bar | 228 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 244 | }; |
| 245 | } | |
| 246 | ||
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 247 | /** |
| 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 | */ | |
| 252 | export 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`. */ | |
| 261 | export 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 look | 265 | /** |
| 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 | */ | |
| 270 | export 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`. */ | |
| 279 | export 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 | */ | |
| 290 | export type RepoMove = { repoId: string; paths: [string, string] }; | |
| 291 | ||
| 292 | export 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 | */ | |
| 308 | export 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`. */ | |
| 314 | export 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 workspace | 318 | /** Staff-only identity. Only sudo binds to it; see `IdentityAdminApi`. */ |
| 319 | export 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 look | 324 | 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 quotas | 325 | 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 look | 327 | 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 member | 344 | 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 workspace | 350 | }; |
| 351 | } | |
| 352 | ||
| Webhooks: every event, to your own addresses, signed and retried | 353 | export 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 incidents | 358 | readable: (ids, viewer) => call("readable", { ids, viewer }), |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 359 | publicNamespaces: (ownerId) => call("public_namespaces", { ownerId }), |
| Webhooks: every event, to your own addresses, signed and retried | 360 | 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 look | 363 | 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 look | 376 | resolvePath: (path) => call("resolve_path", { path }), |
| Webhooks: every event, to your own addresses, signed and retried | 377 | 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 files | 388 | 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 25 | 389 | 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 files | 390 | tags: (path, viewer) => call("tags", { path, viewer }), |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 391 | 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 paths | 404 | 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 address | 406 | rawFile: (repoId, ref, path, maxBytes) => call("raw_file", { repoId, ref, path, maxBytes }), |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 407 | commitFile: (repo, actor, file) => call("commit_file", { repo, actor, ...file }), |
| Webhooks: every event, to your own addresses, signed and retried | 408 | land: (sourceId, actor, branch) => call("land", { sourceId, actor, branch }), |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 409 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 413 | }; |
| 414 | } | |
| 415 | ||
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 416 | /** |
| 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 | */ | |
| 421 | const 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 | */ | |
| 434 | export 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 | ||
| Webhooks: every event, to your own addresses, signed and retried | 446 | export 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 step | 450 | delegateIssue: (actor, repo, input) => call("delegate_issue", { actor, repo, ...input }), |
| Webhooks: every event, to your own addresses, signed and retried | 451 | 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 bar | 459 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 468 | 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 timeouts | 471 | 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 calendar | 473 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 477 | 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 domains | 482 | startMergecheck: (pullId) => call("start_mergecheck", { pullId }), |
| 483 | failMergecheck: (pullId, token, error) => call("report_mergecheck", { pullId, token, error }), | |
| Webhooks: every event, to your own addresses, signed and retried | 484 | 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 answer | 493 | wakeForMessages: (pullId) => call("wake_for_messages", { pullId }), |
| Webhooks: every event, to your own addresses, signed and retried | 494 | getSettings: (repo, viewer) => call("get_settings", { repo, viewer }), |
| Merge rulesets: branch and tag rules, agent-first, enforced on push and merge | 495 | // 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 incidents | 503 | seenChecks: (repo, viewer) => call("seen_checks", { repo, viewer }), |
| Merge checks: statuses and check runs on every commit | 504 | 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 bar | 509 | codeownersErrors: (repo, viewer, ref) => call("codeowners_errors", { repo, viewer, ref: ref ?? null }), |
| Webhooks: every event, to your own addresses, signed and retried | 510 | 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 bar | 513 | listPulls: (repo, viewer, state, filter = {}) => call("list_pulls", { repo, viewer, state, ...filter }), |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 514 | 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 bar | 515 | // 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 | ), | |
| Webhooks: every event, to your own addresses, signed and retried | 520 | 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 files | 522 | catchUpPull: (actor, repo, number) => call("catch_up_pull", { actor, repo, number }), |
| Webhooks: every event, to your own addresses, signed and retried | 523 | 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 timeouts | 526 | reopenPull: (actor, repo, number) => call("reopen_pull", { actor, repo, number }), |
| 527 | convertPullToDraft: (actor, repo, number) => call("convert_pull_to_draft", { actor, repo, number }), | |
| Webhooks: every event, to your own addresses, signed and retried | 528 | 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 domains | 531 | byAuthor: (username, viewer, filter = {}) => call("by_author", { username, viewer, ...filter }), |
| Chat controls, public profiles, shadcn selects, and no Docs tab in a project | 532 | contributions: (username, viewer) => call("contributions", { username, viewer }), |
| Webhooks: every event, to your own addresses, signed and retried | 533 | 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 | ||
| 550 | export 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 charging | 556 | credits: (workspace, viewer) => call("credits", { workspace, viewer }), |
| The statement is a month at a time, a line per kind of charge | 557 | 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 | }), | |
| Webhooks: every event, to your own addresses, signed and retried | 568 | 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 mix | 569 | 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 tokens | 572 | gatewayModels: () => call("gateway_models", {}), |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 573 | 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 tokens | 575 | 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 look | 579 | checkout: (actor, workspace, amountCents, returnUrl, method = "card") => |
| 580 | call("checkout", { actor, workspace, amountCents, returnUrl, method }), | |
| Webhooks: every event, to your own addresses, signed and retried | 581 | 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 agents | 583 | trial: (workspace, exempt) => call("trial", { workspace, exempt }), |
| Webhooks: every event, to your own addresses, signed and retried | 584 | startRun: (run) => call("start_run", run), |
| Paid features: a workspace turns on Deployments with a monthly plan | 585 | 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 person | 593 | freeWorkspaces: (workspaces) => call("free_workspaces", { workspaces }), |
| Paid features: a workspace turns on Deployments with a monthly plan | 594 | chargeFeature: (charge) => call("charge_feature", charge), |
| Billing on Stripe's pages, month-end charges, warnings; sudo by workspace | 595 | billingPortal: (actor, workspace, returnUrl) => call("billing_portal", { actor, workspace, return_url: returnUrl }), |
| Every sandbox is metered by the second | 596 | recordSandbox: (usage) => call("record_sandbox", usage), |
| Usage limits: unpaid usage can only go so far | 597 | limit: (workspace, viewer) => call("limit", { workspace, viewer }), |
| 598 | checkLimit: (workspace) => call("check_limit", { workspace }), | |
| Prices keep themselves current with what g1t pays | 599 | prices: () => call("prices", {}), |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 600 | 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 look | 602 | 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 signals | 604 | 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 put | 605 | entitlements: (workspace) => call("entitlements", { workspace }), |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 606 | 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 audit | 614 | 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 }), | |
| Webhooks: every event, to your own addresses, signed and retried | 623 | }; |
| 624 | } | |
| 625 | ||
| Billing accounts, terms and enterprises; g1t is no longer free | 626 | export 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 put | 632 | setAllowances: (id, allowances, note, by) => call("admin_set_allowances", { id, allowances, note, by }), |
| Billing accounts, terms and enterprises; g1t is no longer free | 633 | 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 charging | 635 | 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's | 654 | resetBilling: (workspace, confirm, note, by) => call("admin_reset_billing", { workspace, confirm, note, by }), |
| Billing on Stripe's pages, month-end charges, warnings; sudo by workspace | 655 | 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 dashboard | 656 | stripe: (fix = false, by) => call("admin_stripe", { fix, by: by ?? null }), |
| Stripe webhooks, enterprise invoices, and sudo for both | 657 | 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 person | 658 | enterpriseAddress: (id, address, taxIdType, taxId, by) => call("admin_enterprise_address", { id, address, taxIdType, taxId, by }), |
| Stripe webhooks, enterprise invoices, and sudo for both | 659 | 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 signals | 661 | 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-ups | 675 | 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 look | 678 | 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 daily | 687 | 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 pays | 689 | 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 daily | 693 | 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-artifacts | 709 | 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 free | 743 | }; |
| 744 | } | |
| 745 | ||
| Webhooks: every event, to your own addresses, signed and retried | 746 | export 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 | ||
| 754 | export 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 tokens | 770 | gatewayUpstream: (workspace) => call("gateway_upstream", { workspace }), |
| AI Gateway: OpenAI's format, open models, and your own providers | 771 | gatewayProviders: (workspace) => call("gateway_providers", { workspace }), |
| Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily | 772 | 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 }), |
| Webhooks: every event, to your own addresses, signed and retried | 774 | routes: (workspace, viewer) => call("routes", { workspace, viewer }), |
| 775 | setRoutes: (actor, workspace, routes) => call("set_routes", { actor, workspace, routes }), | |
| 776 | }; | |
| 777 | } | |
| 778 | ||
| 779 | export 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 | } | |
| Automations: rules in .g1t/automations that act when something happens | 791 | |
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 792 | export 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 }), |
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 798 | 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 }), | |
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 802 | 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 }), | |
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 806 | 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 deployments | 809 | 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 R2 | 824 | 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 }), | |
| GitHub Actions on g1t, part three: .g1t/workflows, the pages, the docs | 828 | }; |
| 829 | } | |
| 830 | ||
| Deployments: a preview for every pull request, production on g1t.page | 831 | |
| Fast pages, required checks on the branch, self-hosted runners, honest incidents | 832 | /** Self-hosted runners, kept by the actions service. */ |
| 833 | export 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 }), | |
| 837 | list: (actor, owner) => call("runners", { actor, ...owner }), | |
| 838 | createToken: (actor, owner, group) => call("create_registration_token", { actor, ...owner, group }), | |
| 839 | remove: (actor, owner, id) => call("remove_runner", { actor, ...owner, id }), | |
| 840 | groups: (actor, workspace) => call("runner_groups", { actor, workspace }), | |
| 841 | setGroup: (actor, workspace, group) => call("set_runner_group", { actor, workspace, ...group }), | |
| 842 | deleteGroup: (actor, workspace, id) => call("delete_runner_group", { actor, workspace, id }), | |
| 843 | settings: (actor, owner) => call("runner_settings", { actor, ...owner }), | |
| 844 | setSettings: (actor, owner, change) => call("set_runner_settings", { actor, ...owner, ...change }), | |
| 845 | }; | |
| 846 | } | |
| 847 | ||
| Deployments: a preview for every pull request, production on g1t.page | 848 | export function deploymentsClient(service: ServiceBinding): DeploymentsApi { |
| 849 | const call = <T>(method: string, args: object) => rpc<T>(service, method, args); | |
| 850 | return { | |
| Projects: what a workspace builds and runs, first on every page | 851 | settings: (project, viewer) => call("settings", { project, viewer }), |
| 852 | updateSettings: (actor, project, changes) => call("update_settings", { actor, project, changes }), | |
| 853 | list: (project, viewer) => call("list", { project, viewer }), | |
| 854 | get: (project, id, viewer) => call("get", { project, id, viewer }), | |
| 855 | redeploy: (actor, project, branch) => call("redeploy", { actor, project, branch }), | |
| 856 | takeDown: (actor, project, branch) => call("take_down", { actor, project, branch }), | |
| 857 | overview: (workspace, viewer) => call("overview", { workspace, viewer }), | |
| Deployments: a preview for every pull request, production on g1t.page | 858 | usage: (workspace, viewer) => call("usage", { workspace, viewer }), |
| Agents and memory, checks and conflicts, profiles, slug renames, custom domains | 859 | domains: (project, viewer) => call("domains", { project, viewer }), |
| 860 | addDomain: (actor, project, hostname, options = {}) => | |
| 861 | call("add_domain", { actor, project, hostname, twin: !!options.twin }), | |
| 862 | removeDomain: (actor, project, id) => call("remove_domain", { actor, project, id }), | |
| 863 | refreshDomain: (actor, project, id) => call("refresh_domain", { actor, project, id }), | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 864 | repoDeployments: (repo, viewer, filter = {}) => call("list_deployments", { repo, viewer, ...filter }), |
| 865 | repoDeployment: (repo, id, viewer) => call("get_deployment", { repo, id, viewer }), | |
| 866 | environments: (repo, viewer) => call("list_environments", { repo, viewer }), | |
| 867 | createDeployment: (actor, repo, input) => call("create_deployment", { repo, actor, ...input }), | |
| 868 | createDeploymentStatus: (actor, repo, id, input) => call("create_deployment_status", { repo, actor, id, ...input }), | |
| Deployments: a preview for every pull request, production on g1t.page | 869 | }; |
| 870 | } | |
| Projects: what a workspace builds and runs, first on every page | 871 | |
| Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member | 872 | /** Packages: the registries beside the code (services/packages). */ |
| 873 | export function packagesClient(service: ServiceBinding): PackagesApi { | |
| 874 | const call = <T>(method: string, args: object) => rpc<T>(service, method, args); | |
| 875 | return { | |
| 876 | list: (workspace, viewer, filter = {}) => | |
| 877 | call("list_packages", { | |
| 878 | workspace, | |
| 879 | viewer, | |
| 880 | ecosystem: filter.ecosystem ?? null, | |
| 881 | repo_id: filter.repoId ?? null, | |
| 882 | query: filter.query ?? null, | |
| 883 | }), | |
| 884 | get: (workspace, ecosystem, name, viewer) => call("get_package", { workspace, ecosystem, name, viewer }), | |
| 885 | deleteVersion: (actor, workspace, ecosystem, name, version, surface) => | |
| 886 | call("delete_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }), | |
| 887 | deletePackage: (actor, workspace, ecosystem, name, surface) => | |
| 888 | call("delete_package", { actor, workspace, ecosystem, name, surface: surface ?? null }), | |
| 889 | set: (actor, workspace, ecosystem, name, change, surface) => | |
| 890 | call("set_package", { | |
| 891 | actor, | |
| 892 | workspace, | |
| 893 | ecosystem, | |
| 894 | name, | |
| 895 | visibility: change.visibility ?? null, | |
| 896 | link: change.link ?? null, | |
| 897 | unlink: change.unlink ?? false, | |
| Merge packages: roles, Actions access, source label, soft delete, API | 898 | inherit_access: change.inheritAccess ?? null, |
| 899 | surface: surface ?? null, | |
| 900 | }), | |
| 901 | settings: (workspace, ecosystem, name, viewer) => call("package_settings", { workspace, ecosystem, name, viewer }), | |
| 902 | deleted: (workspace, viewer) => call("deleted_packages", { workspace, viewer }), | |
| 903 | restorePackage: (actor, workspace, ecosystem, name, surface) => | |
| 904 | call("restore_package", { actor, workspace, ecosystem, name, surface: surface ?? null }), | |
| 905 | restoreVersion: (actor, workspace, ecosystem, name, version, surface) => | |
| 906 | call("restore_version", { actor, workspace, ecosystem, name, version, surface: surface ?? null }), | |
| 907 | setAccess: (actor, workspace, ecosystem, name, who, role, surface) => | |
| 908 | call("set_package_access", { | |
| 909 | actor, | |
| 910 | workspace, | |
| 911 | ecosystem, | |
| 912 | name, | |
| 913 | user: "user" in who ? who.user : null, | |
| 914 | team: "team" in who ? who.team : null, | |
| 915 | role, | |
| 916 | surface: surface ?? null, | |
| 917 | }), | |
| 918 | removeAccess: (actor, workspace, ecosystem, name, who, surface) => | |
| 919 | call("remove_package_access", { | |
| 920 | actor, | |
| 921 | workspace, | |
| 922 | ecosystem, | |
| 923 | name, | |
| 924 | user: "user" in who ? who.user : null, | |
| 925 | 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 member | 926 | surface: surface ?? null, |
| 927 | }), | |
| Merge packages: roles, Actions access, source label, soft delete, API | 928 | setActionsAccess: (actor, workspace, ecosystem, name, repo, role, surface) => |
| 929 | call("set_actions_access", { actor, workspace, ecosystem, name, repo, role, surface: surface ?? null }), | |
| 930 | removeActionsAccess: (actor, workspace, ecosystem, name, repo, surface) => | |
| 931 | 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 member | 932 | storage: (workspace) => call("storage", { workspace }), |
| 933 | storageAll: () => call("storage_all", {}), | |
| Composer from the workspace's own repositories, and go get from g1t.sh | 934 | 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 member | 935 | }; |
| 936 | } | |
| 937 | ||
| Projects: what a workspace builds and runs, first on every page | 938 | export function projectsClient(service: ServiceBinding): ProjectsApi { |
| 939 | const call = <T>(method: string, args: object) => rpc<T>(service, method, args); | |
| 940 | return { | |
| 941 | list: (workspace, viewer) => call("list", { workspace, viewer }), | |
| 942 | get: (workspace, slug, viewer) => call("get", { workspace, slug, viewer }), | |
| 943 | byRepo: (repoId) => call("by_repo", { repoId }), | |
| 944 | create: (actor, workspace, input) => call("create", { actor, workspace, input }), | |
| 945 | 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 production | 946 | deploymentsChanged: (projectId, enabled) => call("deployments_changed", { projectId, enabled }), |
| Projects: pinned and recent projects, per person per workspace | 947 | shortcuts: (workspace, viewer) => call("shortcuts", { workspace, viewer }), |
| 948 | pin: (actor, workspace, slug, position) => call("pin", { actor, workspace, slug, position: position ?? null }), | |
| 949 | unpin: (actor, workspace, slug) => call("unpin", { actor, workspace, slug }), | |
| 950 | reorderPins: (actor, workspace, slugs) => call("reorder_pins", { actor, workspace, slugs }), | |
| 951 | visited: (actor, projectId) => call("visited", { actor, projectId }), | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 952 | publicLinks: (repos) => call("public_links", { repos }), |
| Projects: what a workspace builds and runs, first on every page | 953 | }; |
| 954 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.