@mastra/factory 0.17.3-alpha.6 → 0.18.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boards/review.d.ts +2 -0
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +16 -6
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/work-transition-policy.d.ts.map +1 -1
- package/dist/boards/work-transition-policy.js +10 -0
- package/dist/boards/work-transition-policy.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +9 -1
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/default-rules.d.ts +17 -1
- package/dist/integrations/github/default-rules.d.ts.map +1 -1
- package/dist/integrations/github/default-rules.js +30 -6
- package/dist/integrations/github/default-rules.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +48 -2
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/gitlab/api.d.ts.map +1 -1
- package/dist/integrations/gitlab/api.js.map +1 -1
- package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/default-rules.js +1 -0
- package/dist/integrations/gitlab/default-rules.js.map +1 -1
- package/dist/integrations/gitlab/reconciler.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciler.js.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -1
- package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
- package/dist/integrations/gitlab/rules.d.ts.map +1 -1
- package/dist/integrations/gitlab/rules.js +66 -0
- package/dist/integrations/gitlab/rules.js.map +1 -1
- package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
- package/dist/integrations/gitlab/version-control.js.map +1 -1
- package/dist/integrations/incidentio/api.d.ts.map +1 -1
- package/dist/integrations/incidentio/api.js.map +1 -1
- package/dist/integrations/incidentio/intake.d.ts.map +1 -1
- package/dist/integrations/incidentio/intake.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js.map +1 -1
- package/dist/integrations/slack/emoji-shortcodes.generated.js.map +1 -1
- package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
- package/dist/integrations/slack/feed-publisher.js.map +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +11 -2
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/review-source-tool.d.ts +103 -0
- package/dist/rules/review-source-tool.d.ts.map +1 -0
- package/dist/rules/review-source-tool.js +109 -0
- package/dist/rules/review-source-tool.js.map +1 -0
- package/dist/rules/tools.d.ts +1 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +107 -32
- package/dist/rules/tools.js.map +1 -1
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +16 -6
- package/dist/skills/service.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +11 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +21 -0
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/supervisor/session-messaging.d.ts +4 -1
- package/dist/supervisor/session-messaging.d.ts.map +1 -1
- package/dist/supervisor/session-messaging.js +8 -2
- package/dist/supervisor/session-messaging.js.map +1 -1
- package/dist/supervisor/write-tools.d.ts +2 -1
- package/dist/supervisor/write-tools.d.ts.map +1 -1
- package/dist/supervisor/write-tools.js +9 -2
- package/dist/supervisor/write-tools.js.map +1 -1
- package/dist/workspace.d.ts +7 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +45 -7
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-gitlab-rereview/SKILL.md +3 -2
- package/factory-skills/factory-gitlab-review/SKILL.md +19 -3
- package/factory-skills/factory-rereview/SKILL.md +30 -11
- package/factory-skills/factory-review/SKILL.md +30 -11
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","names":[],"sources":["../../../src/integrations/github/sandbox.ts"],"sourcesContent":["/**\n * Repo materialization for GitHub-backed repositories.\n *\n * A GitHub repo is never cloned onto the server host. The repo is cloned\n * *inside* the session's sandbox, so the agent's file tools and command tools\n * operate entirely against the remote checkout.\n *\n * - `materializeRepo(row, token)` clones the repo inside the sandbox when no\n * checkout exists yet (a base-image boot, a wiped disk), supplying the\n * short-lived token only in that Git process's environment. A checkout that\n * is already there, from a repo template image or an earlier start, is left\n * exactly as it is.\n *\n * This module owns everything git/GitHub: clone, commit/push, setup/teardown commands,\n * and `gh pr create`. Workdir layout lives in `../sandbox/workdir`.\n */\n\nimport type { RepositoryAccess } from '../../capabilities/version-control.js';\nimport { isValidGitRef } from '../../sandbox/git-ref.js';\nimport type { ExecutableSandbox, SandboxCommandResult } from '../../sandbox/materialization.js';\nimport type { SourceControlStorageHandle } from '../../storage/domains/source-control/base.js';\nimport { timedPhase } from '../../timing.js';\n\ntype MaterializationStore = Pick<SourceControlStorageHandle['sessions'], 'markMaterialized'>;\n\ninterface RepoMaterializationBinding {\n id: string;\n sandboxWorkdir: string;\n materializedAt: Date | null;\n}\n\n/**\n * Single-quote a string for safe POSIX shell interpolation. Wraps the value in\n * single quotes and escapes any embedded single quote using the canonical\n * close-quote / escaped-quote / reopen-quote sequence (`'\\''`). This is the\n * standard POSIX-safe construction and prevents the quoted string from being\n * terminated early.\n */\nexport function shellQuote(value: string): string {\n // Replace each ' with the four-character sequence: ' \\ ' '\n return `'` + value.split(`'`).join(`'\\\\''`) + `'`;\n}\n\n/**\n * Default hang guard for sandbox shell commands. Generous by design — large\n * clones and dependency installs legitimately take minutes; the guard exists\n * so a wedged sandbox surfaces a failure instead of hanging the request that\n * triggered materialization forever.\n */\nexport const DEFAULT_COMMAND_TIMEOUT_MS = 15 * 60_000;\n/** Branch checkout only fetches one ref — a much tighter budget applies. */\nexport const CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 60_000;\n\ninterface ShOptions {\n /** Override the hang-guard budget for this command. */\n timeoutMs?: number;\n /** Human-readable phase name included in the timeout error. */\n phase?: string;\n}\n\ninterface CommandOptions extends ShOptions {\n cwd?: string;\n env?: Record<string, string | undefined>;\n}\n\n/**\n * A thrown transport-level failure that is worth retrying: remote sandbox\n\n * providers (e.g. the platform workspace proxy) surface transient 5xx errors\n * as exceptions carrying an HTTP `status` — typically while a freshly\n * provisioned VM is still coming up. Command failures are NOT exceptions\n * (they resolve with a non-zero exit code), so retrying here never re-runs a\n * command that the sandbox already executed and rejected.\n */\nfunction isTransientTransportError(error: unknown): boolean {\n const status = (error as { status?: unknown })?.status;\n return typeof status === 'number' && status >= 500;\n}\n\nconst SH_RETRIES = 2;\nconst SH_RETRY_DELAY_MS = 2000;\n\n/**\n * Run a shell script in the sandbox via `sh -c`. This is reserved for the\n * explicitly configured repository lifecycle hooks; programmatic commands use\n * {@link execute} with an argv array.\n */\nexport async function sh(\n sandbox: ExecutableSandbox,\n script: string,\n options: ShOptions = {},\n): Promise<SandboxCommandResult> {\n return execute(sandbox, 'sh', ['-c', script], options);\n}\n\n/**\n * Execute one program with an argv array, bounded by a hang guard. Transient\n * sandbox transport failures are retried without ever interpolating arguments\n * into a shell command.\n */\nasync function execute(\n sandbox: ExecutableSandbox,\n command: string,\n args: string[],\n options: CommandOptions = {},\n): Promise<SandboxCommandResult> {\n const deadlineMs = Date.now() + (options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);\n for (let attempt = 0; ; attempt++) {\n const started = performance.now();\n try {\n const result = await executeOnce(sandbox, command, args, {\n ...options,\n timeoutMs: Math.max(deadlineMs - Date.now(), 1),\n });\n if (options.phase) {\n process.stderr.write(\n `[factory:timing] ${options.phase} attempt=${attempt + 1} exit=${result.exitCode} ${Math.round(performance.now() - started)}ms\\n`,\n );\n }\n return result;\n } catch (error) {\n if (options.phase) {\n process.stderr.write(\n `[factory:timing] ${options.phase} attempt=${attempt + 1} threw after ${Math.round(performance.now() - started)}ms: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n }\n if (attempt >= SH_RETRIES || !isTransientTransportError(error)) throw error;\n const delayMs = SH_RETRY_DELAY_MS * (attempt + 1);\n if (deadlineMs - Date.now() <= delayMs) throw error;\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n}\n\n/** Single structured command execution attempt, bounded by the hang guard. */\nasync function executeOnce(\n sandbox: ExecutableSandbox,\n command: string,\n args: string[],\n options: CommandOptions,\n): Promise<SandboxCommandResult> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const hangGuard = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n const phase = options.phase ? ` during ${options.phase}` : '';\n reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1000)}s${phase}.`));\n }, timeoutMs);\n timer.unref?.();\n });\n try {\n return await Promise.race([\n sandbox.executeCommand(command, args, {\n timeout: timeoutMs,\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n ...(options.env !== undefined ? { env: options.env } : {}),\n }),\n hangGuard,\n ]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nconst GIT_TRANSFER_RETRIES = 2;\nconst GIT_TRANSFER_RETRY_DELAY_MS = 2000;\n\n/**\n * True when a git transfer died mid-flight rather than being refused.\n *\n * `sh` already retries transport errors the sandbox provider *throws*, but a\n * git command that reaches the network and then loses it exits non-zero\n * instead — so a single HTTP/2 framing glitch or dropped connection to\n * github.com would otherwise permanently fail opening a workspace. These\n * patterns all mean \"the bytes stopped arriving\", which says nothing about\n * whether the operation would succeed if attempted again.\n *\n * Deliberately narrow: a refusal (bad credentials, missing repo, blocked\n * egress) is terminal and must surface immediately rather than be retried into\n * a slow failure.\n */\nfunction isTransientGitFailure(result: SandboxCommandResult): boolean {\n const output = `${result.stderr || ''}\\n${result.stdout || ''}`;\n return /HTTP2 framing layer|RPC failed; curl|RPC failed; HTTP 5\\d\\d|the remote end hung up unexpectedly|early EOF|unexpected disconnect|connection reset by peer|Recv failure|Send failure|GnuTLS recv error|TLS connection was non-properly terminated|502 Bad Gateway|503 Service Unavailable/i.test(\n output,\n );\n}\n\n/**\n * Run a git command that only *reads* from the remote, retrying it when the\n * transfer dies mid-flight. Restricted to read-only transfers on purpose:\n * re-running a clone or a fetch is free, whereas re-running a push could\n * duplicate work already accepted by the remote before the connection dropped.\n *\n * `beforeRetry` lets a call site clear whatever the aborted attempt left\n * behind — a half-written clone directory blocks the next `git clone` outright.\n */\nasync function gitTransfer(\n sandbox: ExecutableSandbox,\n args: string[],\n options: CommandOptions & { beforeRetry?: (attempt: number) => Promise<void> } = {},\n): Promise<SandboxCommandResult> {\n const { beforeRetry, ...commandOptions } = options;\n const deadlineMs = Date.now() + (commandOptions.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);\n for (let attempt = 0; ; attempt++) {\n const result = await execute(sandbox, 'git', args, {\n ...commandOptions,\n timeoutMs: Math.max(deadlineMs - Date.now(), 1),\n });\n if (result.exitCode === 0 || attempt >= GIT_TRANSFER_RETRIES || !isTransientGitFailure(result)) return result;\n process.stderr.write(\n `[factory:timing] git ${commandOptions.phase ?? 'transfer'} retrying after attempt ${attempt + 1}\\n`,\n );\n const delayMs = GIT_TRANSFER_RETRY_DELAY_MS * (attempt + 1);\n if (deadlineMs - Date.now() <= delayMs) return result;\n await new Promise(resolve => setTimeout(resolve, delayMs));\n await beforeRetry?.(attempt + 1);\n }\n}\n\n/** Error raised when the sandbox cannot materialize the repo (actionable). */\nexport class MaterializeError extends Error {\n constructor(\n message: string,\n readonly code:\n | 'git-missing'\n | 'egress-blocked'\n | 'clone-failed'\n | 'pull-failed'\n | 'push-failed'\n | 'commit-failed'\n | 'gh-missing'\n | 'pr-failed',\n ) {\n super(message);\n this.name = 'MaterializeError';\n }\n}\n\nfunction cleanUrl(repoFullName: string): string {\n return `https://github.com/${repoFullName}.git`;\n}\n\nfunction credentialScope(\n cloneUrl: string,\n code: 'clone-failed' | 'pull-failed' | 'push-failed' = 'clone-failed',\n): string {\n let url: URL;\n try {\n url = new URL(cloneUrl);\n } catch {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n if (url.protocol !== 'https:' || !url.hostname || url.username || url.password || url.search || url.hash) {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n const repositoryPath = url.pathname.replace(/\\/+$/, '');\n if (!repositoryPath || repositoryPath === '/') {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n return url.origin + repositoryPath;\n}\n\n/**\n * Provide HTTP Basic credentials to one Git process without putting a secret\n * in argv, a remote URL, or persistent git config. Git reads the URL-scoped\n * extra header from its process environment and discards it on exit.\n */\nfunction gitAuthenticationEnvironment(\n cloneUrl: string,\n token: string,\n username: string,\n code: 'clone-failed' | 'pull-failed' | 'push-failed' = 'clone-failed',\n): Record<string, string> {\n const scope = credentialScope(cloneUrl, code);\n if (!token || !username) {\n throw new MaterializeError('Repository access did not include usable credentials.', code);\n }\n const authorization = Buffer.from(`${username}:${token}`, 'utf8').toString('base64');\n return {\n GIT_CONFIG_COUNT: '1',\n GIT_CONFIG_KEY_0: `http.${scope}.extraHeader`,\n GIT_CONFIG_VALUE_0: `Authorization: Basic ${authorization}`,\n GIT_TERMINAL_PROMPT: '0',\n };\n}\n\nfunction normalizedRemoteUrl(value: string): string | null {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n if (url.protocol !== 'https:' || !url.hostname || url.search || url.hash) return null;\n const pathname = url.pathname.replace(/\\/+$/, '').replace(/\\.git$/i, '');\n const repositoryPath = url.hostname.toLowerCase() === 'github.com' ? pathname.toLowerCase() : pathname;\n return 'https://' + url.host.toLowerCase() + repositoryPath;\n}\n\n/** Repo metadata needed to materialize, read from the org-owned project row. */\nexport interface RepoMaterializeInfo {\n repoFullName: string;\n defaultBranch: string;\n /** Provider-supplied, credential-free HTTPS clone URL. */\n cloneUrl?: string;\n /** Username paired with the bearer token for git-over-HTTPS. */\n authUsername?: string;\n}\n\n/** Options for {@link materializeRepo}. */\nexport interface MaterializeRepoOptions {\n /** The per-(project,user) sandbox binding whose workdir this materializes into. */\n row: RepoMaterializationBinding;\n /** Repo metadata from the org-owned project row. */\n repoInfo: RepoMaterializeInfo;\n /** The live sandbox to run git inside. */\n sandbox: ExecutableSandbox;\n /** A freshly minted, short-lived installation access token. */\n token: string;\n storage: MaterializationStore;\n}\n\nasync function clearWorkdir(sandbox: ExecutableSandbox, workdir: string): Promise<void> {\n const mkdir = await execute(sandbox, 'mkdir', ['-p', workdir]);\n if (mkdir.exitCode !== 0) throw classifyGitFailure(mkdir, 'clone-failed');\n const clear = await execute(sandbox, 'find', [\n workdir,\n '-mindepth',\n '1',\n '-maxdepth',\n '1',\n '-exec',\n 'rm',\n '-rf',\n '--',\n '{}',\n '+',\n ]);\n if (clear.exitCode !== 0) throw classifyGitFailure(clear, 'clone-failed');\n}\n/**\n * Materialize the repo inside the user's sandbox: clone when no checkout of\n * this repo exists, otherwise nothing. Credentials are process-scoped and the\n * stored remote remains credential-free. Sets `materialized_at` on the\n * per-user sandbox binding row.\n */\nexport async function materializeRepo(options: MaterializeRepoOptions): Promise<void> {\n return timedPhase('workspace.materialize', () => materializeRepoImpl(options));\n}\n\nasync function materializeRepoImpl(options: MaterializeRepoOptions): Promise<void> {\n const { row: sandboxRow, repoInfo, sandbox, token, storage } = options;\n const workdir = sandboxRow.sandboxWorkdir;\n const repo = repoInfo.repoFullName;\n\n // 0. Defense in depth: never build a git command from values that aren't\n // strictly shaped, even if a malformed row reached the DB. Inputs are also\n // validated at the route boundary before storage.\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repo)) {\n throw new MaterializeError(`Refusing to materialize: invalid repo full name '${repo}'.`, 'clone-failed');\n }\n if (!/^[A-Za-z0-9_./-]+$/.test(repoInfo.defaultBranch)) {\n throw new MaterializeError(\n `Refusing to materialize: invalid default branch '${repoInfo.defaultBranch}'.`,\n 'clone-failed',\n );\n }\n\n // 1. Preflight: git must be installed in the sandbox template.\n const gitVersion = await execute(sandbox, 'git', ['--version']);\n if (gitVersion.exitCode !== 0) {\n throw new MaterializeError(\n 'git is not installed in the sandbox. The sandbox template must include git.',\n 'git-missing',\n );\n }\n\n // The DB's `materializedAt` can drift from disk in both directions: a fresh\n // binding row over an already-populated workdir (a repo template image,\n // local dev DB resets, repaired rows) must not fail `git clone` on the\n // non-empty directory, and a stale `materializedAt` over an empty sandbox\n // (an expired/recreated VM whose disk was wiped) must re-clone instead of\n // running `git -C <workdir>` against a directory that no longer exists.\n // Disk is the source of truth: detect the checkout instead of trusting the\n // row. An existing checkout is left as it is, whatever it is on: a template\n // image sits detached at its pinned commit, a resumed session on its\n // branch. Syncing with the remote is the session's business; the branch\n // checkout that follows fetches the base branch it needs.\n const cleanCloneUrl = repoInfo.cloneUrl ?? cleanUrl(repo);\n const existing = await existingCheckoutRemote(sandbox, workdir, cleanCloneUrl);\n if (existing !== null) {\n // A token an earlier start failed to scrub must not outlive it; the\n // remote already carries the plain URL otherwise, so this costs nothing\n // on the common path.\n if (/\\/\\/[^/]*@/.test(existing)) await scrubRemote(sandbox, workdir, repo, cleanCloneUrl);\n } else {\n // 2. First open: shallow-clone the default branch into the workdir, the\n // same clone a repo template bakes into its image. The workdir holds no\n // usable checkout of this repo, but it may not be empty: a checkpoint\n // seed or a clone that died partway (a crashed or OOM-killed server)\n // leaves a partial tree behind, and `git clone` refuses a non-empty\n // destination with a non-retryable fatal. Nothing here is recoverable,\n // the probe above already ruled out a checkout of this repo, so\n // clear its contents before cloning, exactly as the retry path does. Keep\n // the workdir itself because LocalSandbox runs commands with this\n // directory as the child process cwd.\n const authEnv = gitAuthenticationEnvironment(\n cleanCloneUrl,\n token,\n repoInfo.authUsername ?? 'x-access-token',\n 'clone-failed',\n );\n await clearWorkdir(sandbox, workdir);\n const clone = await gitTransfer(\n sandbox,\n ['clone', '--depth=1', '--single-branch', '--branch', repoInfo.defaultBranch, '--', cleanCloneUrl, workdir],\n {\n env: authEnv,\n phase: 'repository clone',\n beforeRetry: async () => {\n // A clone that died partway leaves the destination non-empty, which\n // git refuses to clone into. Clear its contents so the retry starts\n // clean without removing LocalSandbox's process cwd.\n await clearWorkdir(sandbox, workdir);\n },\n },\n );\n if (clone.exitCode !== 0) throw classifyGitFailure(clone, 'clone-failed');\n }\n\n // 4. Mark materialized.\n await storage.markMaterialized({ id: sandboxRow.id });\n}\n\nexport interface SessionBranchOptions {\n branch: string;\n baseBranch: string;\n token: string;\n repoFullName: string;\n cloneUrl?: string;\n authUsername?: string;\n /** A pull-request card's session starts on the PR head instead of the base tip. */\n pullRequestNumber?: number;\n /** A GitLab merge-request card's session starts on the MR head instead of the base tip. */\n mergeRequestNumber?: number;\n}\n\n/**\n * Past file contents of a blob-less history load on demand; git asks gh, which\n * answers from the session's `GH_TOKEN`, so no credential is ever written.\n */\nconst GH_CREDENTIAL_HELPER = '!gh auth git-credential';\n\nasync function fetchStartPoint(\n sandbox: ExecutableSandbox,\n workdir: string,\n { baseBranch, pullRequestNumber, mergeRequestNumber }: Pick<SessionBranchOptions, 'baseBranch' | 'pullRequestNumber' | 'mergeRequestNumber'>,\n shallowClone: boolean,\n env: Record<string, string>,\n): Promise<SandboxCommandResult> {\n const changeRequestRef = pullRequestNumber !== undefined\n ? `refs/pull/${pullRequestNumber}/head`\n : mergeRequestNumber !== undefined\n ? `refs/merge-requests/${mergeRequestNumber}/head`\n : undefined;\n const baseArgs = [\n '-C',\n workdir,\n 'fetch',\n ...(changeRequestRef && shallowClone ? ['--unshallow'] : []),\n ...(pullRequestNumber !== undefined ? ['--filter=blob:none'] : []),\n 'origin',\n baseBranch,\n ];\n const base = await gitTransfer(sandbox, baseArgs, {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout fetch',\n });\n if (base.exitCode !== 0 || !changeRequestRef) return base;\n return gitTransfer(\n sandbox,\n ['-C', workdir, 'fetch', ...(pullRequestNumber !== undefined ? ['--filter=blob:none'] : []), 'origin', changeRequestRef],\n {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'change request head fetch',\n },\n );\n}\n\n/** Check out a session's branch inside its isolated repository clone. */\nexport async function checkoutSessionBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n options: SessionBranchOptions,\n): Promise<void> {\n return timedPhase('workspace.checkout', () => checkoutSessionBranchImpl(sandbox, workdir, options));\n}\n\n/** Refresh an existing GitLab review checkout without exposing its credential to the agent. */\nexport async function refreshMergeRequestCheckout(\n sandbox: ExecutableSandbox,\n workdir: string,\n input: { branch: string; mergeRequestNumber: number; expectedHeadSha: string; access: RepositoryAccess },\n): Promise<{ headSha: string; changed: boolean }> {\n const { branch, mergeRequestNumber, expectedHeadSha, access } = input;\n if (!isValidGitRef(branch) || !Number.isSafeInteger(mergeRequestNumber) || mergeRequestNumber <= 0 ||\n !/^[0-9a-f]{40}$/i.test(expectedHeadSha)) {\n throw new Error('Refusing to refresh a GitLab review with invalid session or head metadata.');\n }\n const token = access.authorization?.token;\n if (!token) throw new Error('GitLab repository access did not include a bearer token.');\n const env = gitAuthenticationEnvironment(access.cloneUrl, token, access.authorization?.username ?? 'oauth2', 'pull-failed');\n const current = await execute(sandbox, 'git', ['-C', workdir, 'branch', '--show-current']);\n if (current.exitCode !== 0 || current.stdout.trim() !== branch) {\n throw new Error('The active checkout is not on its bound review branch.');\n }\n const status = await execute(sandbox, 'git', ['-C', workdir, 'status', '--porcelain', '--untracked-files=all']);\n if (status.exitCode !== 0 || status.stdout.trim()) {\n throw new Error('The review checkout has local changes; refusing to replace them.');\n }\n const before = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', 'HEAD']);\n if (before.exitCode !== 0) throw new Error('Could not read the current review checkout head.');\n const fetch = await gitTransfer(sandbox, ['-C', workdir, 'fetch', 'origin', `refs/merge-requests/${mergeRequestNumber}/head`], {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'GitLab review head refresh',\n });\n if (fetch.exitCode !== 0) throw classifyGitFailure(fetch, 'pull-failed');\n const fetched = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', 'FETCH_HEAD']);\n if (fetched.exitCode !== 0 || fetched.stdout.trim().toLowerCase() !== expectedHeadSha.toLowerCase()) {\n throw new Error('The fetched GitLab review head differs from the provider-reported head; retry after it settles.');\n }\n if (before.stdout.trim().toLowerCase() === expectedHeadSha.toLowerCase()) {\n return { headSha: expectedHeadSha, changed: false };\n }\n const updated = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-B', branch, 'FETCH_HEAD'], { env });\n if (updated.exitCode !== 0) throw classifyGitFailure(updated, 'pull-failed');\n return { headSha: expectedHeadSha, changed: true };\n}\n\nasync function checkoutSessionBranchImpl(\n sandbox: ExecutableSandbox,\n workdir: string,\n options: SessionBranchOptions,\n): Promise<void> {\n const { branch, baseBranch, token, repoFullName, pullRequestNumber, mergeRequestNumber, cloneUrl, authUsername } = options;\n if (!isValidGitRef(branch) || !isValidGitRef(baseBranch) ||\n (pullRequestNumber !== undefined && mergeRequestNumber !== undefined) ||\n (mergeRequestNumber !== undefined && (!Number.isSafeInteger(mergeRequestNumber) || mergeRequestNumber <= 0))) {\n throw new MaterializeError('Refusing to create a session from an invalid branch name.', 'clone-failed');\n }\n\n const changeRequestSession = pullRequestNumber !== undefined || mergeRequestNumber !== undefined;\n // GitHub delegates later authenticated operations to `gh`. Other providers\n // deliberately receive no persistent credential helper. Remove the legacy\n // helper when reopening an older checkout so a stale sandbox cannot retain\n // credentials injected by an earlier implementation.\n const cleanCloneUrl = cloneUrl ?? cleanUrl(repoFullName);\n const authEnv = gitAuthenticationEnvironment(cleanCloneUrl, token, authUsername ?? 'x-access-token', 'pull-failed');\n const credentialKey = authUsername ? 'credential.' + credentialScope(cleanCloneUrl) + '.helper' : 'credential.helper';\n if (authUsername) {\n await execute(sandbox, 'git', ['-C', workdir, 'config', '--unset-all', credentialKey]);\n } else {\n const configured = await execute(sandbox, 'git', ['-C', workdir, 'config', credentialKey, GH_CREDENTIAL_HELPER]);\n if (configured.exitCode !== 0) throw classifyGitFailure(configured, 'pull-failed');\n }\n\n const current = await execute(sandbox, 'git', ['-C', workdir, 'branch', '--show-current']);\n if (current.exitCode === 0 && current.stdout.trim() === branch) return;\n\n const local = await execute(sandbox, 'git', [\n '-C',\n workdir,\n 'show-ref',\n '--verify',\n '--quiet',\n `refs/heads/${branch}`,\n ]);\n if (local.exitCode === 0) {\n const checkout = await execute(sandbox, 'git', ['-C', workdir, 'checkout', branch], { env: authEnv });\n if (checkout.exitCode !== 0) {\n if (isBlockedByLocalWork(checkout)) return;\n throw classifyGitFailure(checkout, 'clone-failed');\n }\n return;\n }\n\n const shallowClone =\n changeRequestSession &&\n (await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', '--is-shallow-repository'])).stdout.trim() === 'true';\n const fetch = await fetchStartPoint(sandbox, workdir, options, shallowClone, authEnv);\n if (fetch.exitCode !== 0) throw classifyGitFailure(fetch, 'pull-failed');\n\n const create = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-b', branch, 'FETCH_HEAD'], {\n env: authEnv,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout',\n });\n if (create.exitCode === 0 || isBlockedByLocalWork(create)) return;\n if (!isBranchCollision(create)) throw classifyGitFailure(create, 'clone-failed');\n\n // The branch exists even though the show-ref probe missed it: either another\n // materialization created it concurrently (adopt it), or the sandbox carries\n // a broken loose ref (remove it and retry).\n const adopt = await execute(sandbox, 'git', ['-C', workdir, 'checkout', branch], { env: authEnv });\n if (adopt.exitCode === 0 || isBlockedByLocalWork(adopt)) return;\n\n let drop = await execute(sandbox, 'git', ['-C', workdir, 'update-ref', '--no-deref', '-d', `refs/heads/${branch}`]);\n if (drop.exitCode !== 0) {\n const gitDir = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', '--absolute-git-dir']);\n if (gitDir.exitCode !== 0 || !gitDir.stdout.trim()) throw classifyGitFailure(create, 'clone-failed');\n drop = await execute(sandbox, 'rm', ['-f', '--', `${gitDir.stdout.trim()}/refs/heads/${branch}`]);\n }\n if (drop.exitCode !== 0) throw classifyGitFailure(create, 'clone-failed');\n\n const retry = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-b', branch, 'FETCH_HEAD'], {\n env: authEnv,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout retry',\n });\n if (retry.exitCode !== 0) {\n if (isBlockedByLocalWork(retry)) return;\n throw classifyGitFailure(retry, 'clone-failed');\n }\n}\n\n/**\n * True when `git checkout -b` failed only because the branch ref already\n * exists — the collision Factory hits when a pooled sandbox carries a ref the\n * show-ref probe could not see (broken loose ref) or a concurrent\n * materialization created the branch after the probe ran.\n */\nfunction isBranchCollision(result: SandboxCommandResult): boolean {\n return /a branch named .* already exists/i.test(`${result.stderr || ''}\\n${result.stdout || ''}`);\n}\n\n/**\n * True when a failed `git checkout` just means uncommitted or untracked files\n * in the working tree would be clobbered by the branch switch. Those files are\n * a session's work in progress — the switch must yield to them, never the\n * other way around.\n */\nfunction isBlockedByLocalWork(result: SandboxCommandResult): boolean {\n const output = `${result.stderr || ''}\\n${result.stdout || ''}`;\n return /Your local changes to the following files would be overwritten by checkout|untracked working tree files would be overwritten by checkout/i.test(\n output,\n );\n}\n\n/**\n * Return the origin URL when the workdir contains this repository, including a\n * legacy checkout whose remote still embeds credentials.\n */\nasync function existingCheckoutRemote(\n sandbox: ExecutableSandbox,\n workdir: string,\n cloneUrl: string,\n): Promise<string | null> {\n const result = await execute(sandbox, 'git', ['-C', workdir, 'remote', 'get-url', 'origin']);\n if (result.exitCode !== 0) return null;\n const url = result.stdout.trim();\n const actual = normalizedRemoteUrl(url);\n const expected = normalizedRemoteUrl(cloneUrl);\n return actual !== null && expected !== null && actual === expected ? url : null;\n}\n\n/** Remove credentials persisted by an older implementation from origin. */\nasync function scrubRemote(\n sandbox: ExecutableSandbox,\n workdir: string,\n repoFullName: string,\n cloneUrl: string = cleanUrl(repoFullName),\n): Promise<void> {\n let failure: string;\n try {\n const result = await execute(sandbox, 'git', ['-C', workdir, 'remote', 'set-url', 'origin', cloneUrl]);\n if (result.exitCode === 0) return;\n failure = result.stderr.trim() || result.stdout.trim();\n } catch (error) {\n failure = error instanceof Error ? error.message : String(error);\n }\n throw new MaterializeError(`Failed to scrub installation token from git remote: ${failure}`, 'pull-failed');\n}\n\n/**\n * Turn a failed git command into an actionable error, detecting the common\n * \"cannot reach github.com\" egress failure.\n */\nfunction classifyGitFailure(\n result: SandboxCommandResult,\n fallback: 'clone-failed' | 'pull-failed' | 'push-failed',\n): MaterializeError {\n const stderr = result.stderr || '';\n if (/could not resolve host|failed to connect|network is unreachable|Connection timed out/i.test(stderr)) {\n return new MaterializeError(\n 'The sandbox could not reach github.com. The sandbox network must allow outbound egress to github.com.',\n 'egress-blocked',\n );\n }\n const verb = fallback === 'clone-failed' ? 'clone' : fallback === 'pull-failed' ? 'pull' : 'push';\n return new MaterializeError(`git ${verb} failed: ${stderr}`, fallback);\n}\n\n// ---------------------------------------------------------------------------\n// Phase 1 — git identity + token-scoped push primitive\n//\n// These helpers let the sandbox author and push commits safely. The install\n// token is short-lived, minted per-operation server-side, and supplied only to\n// the Git process through its environment. It never enters argv or persistent\n// repository configuration.\n// ---------------------------------------------------------------------------\n\nexport { isValidGitRef };\n\n/** Identity used to author commits inside the sandbox. */\nexport interface GitIdentity {\n name?: string | null;\n email?: string | null;\n /** GitHub login, used to derive a stable noreply identity when name/email are absent. */\n login?: string | null;\n}\n\n/**\n * Resolve a concrete `{ name, email }` for git authorship from a possibly-sparse\n * identity. Falls back to a GitHub-style noreply identity so commits are never\n * authored with an empty or host-derived identity.\n */\nexport function resolveGitIdentity(identity: GitIdentity): { name: string; email: string } {\n const login = (identity.login || '').trim();\n const name = (identity.name || '').trim() || login || 'Mastra Code';\n const email =\n (identity.email || '').trim() ||\n (login ? `${login}@users.noreply.github.com` : 'mastra-code@users.noreply.github.com');\n return { name, email };\n}\n\n/** Configure repository-local commit identity through direct Git argv calls. */\nexport async function configureGitIdentity(\n sandbox: ExecutableSandbox,\n workdir: string,\n identity: GitIdentity,\n): Promise<void> {\n const { name, email } = resolveGitIdentity(identity);\n const setName = await execute(sandbox, 'git', ['-C', workdir, 'config', 'user.name', name]);\n if (setName.exitCode !== 0) {\n throw new MaterializeError(`Failed to set git user.name: ${setName.stderr.trim()}`, 'commit-failed');\n }\n const setEmail = await execute(sandbox, 'git', ['-C', workdir, 'config', 'user.email', email]);\n if (setEmail.exitCode !== 0) {\n throw new MaterializeError(`Failed to set git user.email: ${setEmail.stderr.trim()}`, 'commit-failed');\n }\n}\n\nasync function pushAuthenticatedBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n cloneUrl: string,\n token: string,\n username: string,\n): Promise<void> {\n const env = gitAuthenticationEnvironment(cloneUrl, token, username, 'push-failed');\n const push = await execute(sandbox, 'git', ['-C', workdir, 'push', '-u', 'origin', branch], { env });\n if (push.exitCode !== 0) throw classifyGitFailure(push, 'push-failed');\n}\n\n/**\n * Push a branch back to GitHub with credentials scoped to the Git process.\n * The token never enters argv, a repository URL, or persistent configuration.\n */\nexport async function pushBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n token: string,\n repoFullName: string,\n): Promise<void> {\n if (!isValidGitRef(branch)) {\n throw new MaterializeError(`Refusing to push: invalid branch name '${branch}'.`, 'push-failed');\n }\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repoFullName)) {\n throw new MaterializeError(`Refusing to push: invalid repo full name '${repoFullName}'.`, 'push-failed');\n }\n await pushAuthenticatedBranch(sandbox, workdir, branch, cleanUrl(repoFullName), token, 'x-access-token');\n}\n\n/**\n * Push the active session branch through the provider-neutral repository\n * access contract without persisting or exposing provider credentials.\n */\nexport async function pushRepositoryBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n access: RepositoryAccess,\n repoFullName: string,\n): Promise<void> {\n if (!isValidGitRef(branch)) {\n throw new MaterializeError(`Refusing to push: invalid branch name '${branch}'.`, 'push-failed');\n }\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repoFullName)) {\n throw new MaterializeError(`Refusing to push: invalid repo full name '${repoFullName}'.`, 'push-failed');\n }\n const authorization = access.authorization;\n if (!authorization?.token) {\n throw new MaterializeError('Repository access did not include push credentials.', 'push-failed');\n }\n await pushAuthenticatedBranch(\n sandbox,\n workdir,\n branch,\n access.cloneUrl,\n authorization.token,\n authorization.username ?? 'x-access-token',\n );\n}\n\nexport interface CommitResult {\n /** True when a commit was created; false when there was nothing to commit. */\n committed: boolean;\n}\n\n/**\n * Stage every change in the working tree and create a commit inside the\n * sandbox. The git identity is configured first so authorship is correct. When\n * there is nothing to commit this is a no-op (`committed: false`) rather than an\n * error, so callers can safely commit-then-push without first diffing.\n *\n * @param sandbox the live sandbox containing the checkout\n * @param workdir the session workdir to commit in\n * @param message the commit message (passed as one argv value)\n * @param identity authorship identity for the commit\n */\nexport async function commitAll(\n sandbox: ExecutableSandbox,\n workdir: string,\n message: string,\n identity: GitIdentity,\n): Promise<CommitResult> {\n await configureGitIdentity(sandbox, workdir, identity);\n\n const add = await execute(sandbox, 'git', ['-C', workdir, 'add', '-A']);\n if (add.exitCode !== 0) {\n throw new MaterializeError(`git add failed: ${add.stderr.trim() || add.stdout.trim()}`, 'commit-failed');\n }\n\n // Nothing staged → nothing to commit. `git diff --cached --quiet` exits 1 when\n // there are staged changes, 0 when the index is clean.\n const staged = await execute(sandbox, 'git', ['-C', workdir, 'diff', '--cached', '--quiet']);\n if (staged.exitCode === 0) {\n return { committed: false };\n }\n\n const commit = await execute(sandbox, 'git', ['-C', workdir, 'commit', '-m', message]);\n if (commit.exitCode !== 0) {\n throw new MaterializeError(`git commit failed: ${commit.stderr.trim() || commit.stdout.trim()}`, 'commit-failed');\n }\n\n return { committed: true };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2 — setup / teardown lifecycle commands\n//\n// The org-configured setup and teardown shell commands run in the session's\n// materialized workdir. The workdir is always resolved server-side from the\n// live sandbox; client input never reaches a filesystem path.\n// ---------------------------------------------------------------------------\n\n/** Error raised when the org's setup or teardown command fails in the sandbox. */\nexport class SetupCommandError extends Error {\n constructor(\n message: string,\n readonly code: 'setup-failed' | 'teardown-failed',\n ) {\n super(message);\n this.name = 'SetupCommandError';\n }\n}\n\n/**\n * Run the project's setup command (e.g. `pnpm i && pnpm build`) inside the\n * freshly materialized session workdir. Called before the checkout is handed\n * to any agent run so it is ready to build/test. A non-zero exit is a hard\n * error — starting agent work in a half-set-up tree is worse than failing the\n * request.\n *\n * Security model: the command is intentionally arbitrary shell — that is the\n * feature (install deps, build, seed fixtures). It is only configurable by\n * authenticated org members (the settings route is gated by\n * `resolveOrgTenant` + org-scoped project lookup, with length and\n * control-character validation), and it executes exclusively inside the\n * project's isolated sandbox — the same environment where org members already\n * run arbitrary shell via the agent's command tool. It never runs on the web\n * server host, so it grants no privilege beyond what sandbox access already\n * provides.\n *\n * @param sandbox live sandbox containing the checkout\n * @param workdir the server-resolved session workdir the command runs in\n * @param command the org-configured setup shell command\n */\nasync function runLifecycleCommand(\n sandbox: ExecutableSandbox,\n workdir: string,\n command: string,\n options: { phase: 'setup' | 'teardown'; timeoutMs?: number },\n): Promise<void> {\n const result = await sh(sandbox, `cd ${shellQuote(workdir)} && { ${command}\\n}`, {\n phase: `${options.phase} command`,\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n if (result.exitCode !== 0) {\n const detail = (result.stderr.trim() || result.stdout.trim()).slice(-1800);\n const label = options.phase === 'setup' ? 'Setup' : 'Teardown';\n throw new SetupCommandError(\n `${label} command failed (exit ${result.exitCode}): ${detail}`,\n options.phase === 'setup' ? 'setup-failed' : 'teardown-failed',\n );\n }\n}\n\nexport async function runSetupCommand(sandbox: ExecutableSandbox, workdir: string, command: string): Promise<void> {\n return runLifecycleCommand(sandbox, workdir, command, { phase: 'setup' });\n}\n\n/**\n * Run the repository's best-effort teardown command from the materialized\n * session workdir. Callers own lifecycle policy: this helper reports failures\n * so the retirement coordinator can log them while still continuing with\n * scrub, pooling/destruction, cache invalidation, and row deletion.\n */\nexport async function runTeardownCommand(\n sandbox: ExecutableSandbox,\n workdir: string,\n command: string,\n options: { timeoutMs?: number } = {},\n): Promise<void> {\n return runLifecycleCommand(sandbox, workdir, command, {\n phase: 'teardown',\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n}\n\nexport interface CreatePullRequestArgs {\n /** Short-lived installation token, injected only into the `gh` process env. */\n token: string;\n /** Base branch the PR merges into. Ref-validated. */\n base: string;\n /** Head branch the PR is opened from. Ref-validated. */\n head: string;\n /** PR title. */\n title: string;\n /** PR body (optional). */\n body?: string;\n}\n\nexport interface CreatePullRequestResult {\n /** The PR URL parsed from `gh pr create` stdout. */\n url: string;\n}\n\n/**\n * Preflight that `gh` is installed in the sandbox. Only called on the PR path so\n * a missing `gh` never blocks clone/open. Surfaces an actionable error naming\n * the sandbox template requirement.\n */\nasync function assertGhAvailable(sandbox: ExecutableSandbox): Promise<void> {\n const version = await execute(sandbox, 'gh', ['--version']);\n if (version.exitCode !== 0) {\n throw new MaterializeError(\n 'The GitHub CLI (gh) is not installed in the sandbox. The sandbox template must include gh to open pull requests.',\n 'gh-missing',\n );\n }\n}\n\n/** Match the first GitHub PR URL in `gh pr create` output. */\nfunction parsePullRequestUrl(stdout: string): string | undefined {\n const match = stdout.match(/https:\\/\\/github\\.com\\/[^\\s]+\\/pull\\/\\d+/);\n return match?.[0];\n}\n\n/**\n * Open a pull request from inside the sandbox via `gh pr create`. The token is\n * passed only through a per-invocation `GH_TOKEN` env scoped to the single `gh`\n * process (never persisted), all arguments are passed as structured argv, and\n * the resulting PR URL is parsed from stdout.\n *\n * @param sandbox live sandbox containing the checkout\n * @param workdir the worktree (or repo) path the PR head branch is checked out in\n */\nexport async function createPullRequest(\n sandbox: ExecutableSandbox,\n workdir: string,\n { token, base, head, title, body }: CreatePullRequestArgs,\n): Promise<CreatePullRequestResult> {\n if (!isValidGitRef(base)) {\n throw new MaterializeError(`Refusing to open PR: invalid base branch '${base}'.`, 'pr-failed');\n }\n if (!isValidGitRef(head)) {\n throw new MaterializeError(`Refusing to open PR: invalid head branch '${head}'.`, 'pr-failed');\n }\n\n await assertGhAvailable(sandbox);\n\n const result = await execute(\n sandbox,\n 'gh',\n ['pr', 'create', '--base', base, '--head', head, '--title', title, '--body', body ?? ''],\n { cwd: workdir, env: { GH_TOKEN: token } },\n );\n if (result.exitCode !== 0) {\n const classified = classifyGitFailure(result, 'push-failed');\n if (classified.code === 'egress-blocked') {\n throw classified;\n }\n throw new MaterializeError(`gh pr create failed: ${result.stderr.trim() || result.stdout.trim()}`, 'pr-failed');\n }\n\n const url = parsePullRequestUrl(result.stdout);\n if (!url) {\n throw new MaterializeError(\n `gh pr create succeeded but no PR URL was found in its output: ${result.stdout.trim()}`,\n 'pr-failed',\n );\n }\n\n return { url };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sandbox.js","names":[],"sources":["../../../src/integrations/github/sandbox.ts"],"sourcesContent":["/**\n * Repo materialization for GitHub-backed repositories.\n *\n * A GitHub repo is never cloned onto the server host. The repo is cloned\n * *inside* the session's sandbox, so the agent's file tools and command tools\n * operate entirely against the remote checkout.\n *\n * - `materializeRepo(row, token)` clones the repo inside the sandbox when no\n * checkout exists yet (a base-image boot, a wiped disk), supplying the\n * short-lived token only in that Git process's environment. A checkout that\n * is already there, from a repo template image or an earlier start, is left\n * exactly as it is.\n *\n * This module owns everything git/GitHub: clone, commit/push, setup/teardown commands,\n * and `gh pr create`. Workdir layout lives in `../sandbox/workdir`.\n */\n\nimport type { RepositoryAccess } from '../../capabilities/version-control.js';\nimport { isValidGitRef } from '../../sandbox/git-ref.js';\nimport type { ExecutableSandbox, SandboxCommandResult } from '../../sandbox/materialization.js';\nimport type { SourceControlStorageHandle } from '../../storage/domains/source-control/base.js';\nimport { timedPhase } from '../../timing.js';\n\ntype MaterializationStore = Pick<SourceControlStorageHandle['sessions'], 'markMaterialized'>;\n\ninterface RepoMaterializationBinding {\n id: string;\n sandboxWorkdir: string;\n materializedAt: Date | null;\n}\n\n/**\n * Single-quote a string for safe POSIX shell interpolation. Wraps the value in\n * single quotes and escapes any embedded single quote using the canonical\n * close-quote / escaped-quote / reopen-quote sequence (`'\\''`). This is the\n * standard POSIX-safe construction and prevents the quoted string from being\n * terminated early.\n */\nexport function shellQuote(value: string): string {\n // Replace each ' with the four-character sequence: ' \\ ' '\n return `'` + value.split(`'`).join(`'\\\\''`) + `'`;\n}\n\n/**\n * Default hang guard for sandbox shell commands. Generous by design — large\n * clones and dependency installs legitimately take minutes; the guard exists\n * so a wedged sandbox surfaces a failure instead of hanging the request that\n * triggered materialization forever.\n */\nexport const DEFAULT_COMMAND_TIMEOUT_MS = 15 * 60_000;\n/** Branch checkout only fetches one ref — a much tighter budget applies. */\nexport const CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 60_000;\n\ninterface ShOptions {\n /** Override the hang-guard budget for this command. */\n timeoutMs?: number;\n /** Human-readable phase name included in the timeout error. */\n phase?: string;\n}\n\ninterface CommandOptions extends ShOptions {\n cwd?: string;\n env?: Record<string, string | undefined>;\n}\n\n/**\n * A thrown transport-level failure that is worth retrying: remote sandbox\n\n * providers (e.g. the platform workspace proxy) surface transient 5xx errors\n * as exceptions carrying an HTTP `status` — typically while a freshly\n * provisioned VM is still coming up. Command failures are NOT exceptions\n * (they resolve with a non-zero exit code), so retrying here never re-runs a\n * command that the sandbox already executed and rejected.\n */\nfunction isTransientTransportError(error: unknown): boolean {\n const status = (error as { status?: unknown })?.status;\n return typeof status === 'number' && status >= 500;\n}\n\nconst SH_RETRIES = 2;\nconst SH_RETRY_DELAY_MS = 2000;\n\n/**\n * Run a shell script in the sandbox via `sh -c`. This is reserved for the\n * explicitly configured repository lifecycle hooks; programmatic commands use\n * {@link execute} with an argv array.\n */\nexport async function sh(\n sandbox: ExecutableSandbox,\n script: string,\n options: ShOptions = {},\n): Promise<SandboxCommandResult> {\n return execute(sandbox, 'sh', ['-c', script], options);\n}\n\n/**\n * Execute one program with an argv array, bounded by a hang guard. Transient\n * sandbox transport failures are retried without ever interpolating arguments\n * into a shell command.\n */\nasync function execute(\n sandbox: ExecutableSandbox,\n command: string,\n args: string[],\n options: CommandOptions = {},\n): Promise<SandboxCommandResult> {\n const deadlineMs = Date.now() + (options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);\n for (let attempt = 0; ; attempt++) {\n const started = performance.now();\n try {\n const result = await executeOnce(sandbox, command, args, {\n ...options,\n timeoutMs: Math.max(deadlineMs - Date.now(), 1),\n });\n if (options.phase) {\n process.stderr.write(\n `[factory:timing] ${options.phase} attempt=${attempt + 1} exit=${result.exitCode} ${Math.round(performance.now() - started)}ms\\n`,\n );\n }\n return result;\n } catch (error) {\n if (options.phase) {\n process.stderr.write(\n `[factory:timing] ${options.phase} attempt=${attempt + 1} threw after ${Math.round(performance.now() - started)}ms: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n }\n if (attempt >= SH_RETRIES || !isTransientTransportError(error)) throw error;\n const delayMs = SH_RETRY_DELAY_MS * (attempt + 1);\n if (deadlineMs - Date.now() <= delayMs) throw error;\n await new Promise(resolve => setTimeout(resolve, delayMs));\n }\n }\n}\n\n/** Single structured command execution attempt, bounded by the hang guard. */\nasync function executeOnce(\n sandbox: ExecutableSandbox,\n command: string,\n args: string[],\n options: CommandOptions,\n): Promise<SandboxCommandResult> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const hangGuard = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n const phase = options.phase ? ` during ${options.phase}` : '';\n reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1000)}s${phase}.`));\n }, timeoutMs);\n timer.unref?.();\n });\n try {\n return await Promise.race([\n sandbox.executeCommand(command, args, {\n timeout: timeoutMs,\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n ...(options.env !== undefined ? { env: options.env } : {}),\n }),\n hangGuard,\n ]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nconst GIT_TRANSFER_RETRIES = 2;\nconst GIT_TRANSFER_RETRY_DELAY_MS = 2000;\n\n/**\n * True when a git transfer died mid-flight rather than being refused.\n *\n * `sh` already retries transport errors the sandbox provider *throws*, but a\n * git command that reaches the network and then loses it exits non-zero\n * instead — so a single HTTP/2 framing glitch or dropped connection to\n * github.com would otherwise permanently fail opening a workspace. These\n * patterns all mean \"the bytes stopped arriving\", which says nothing about\n * whether the operation would succeed if attempted again.\n *\n * Deliberately narrow: a refusal (bad credentials, missing repo, blocked\n * egress) is terminal and must surface immediately rather than be retried into\n * a slow failure.\n */\nfunction isTransientGitFailure(result: SandboxCommandResult): boolean {\n const output = `${result.stderr || ''}\\n${result.stdout || ''}`;\n return /HTTP2 framing layer|RPC failed; curl|RPC failed; HTTP 5\\d\\d|the remote end hung up unexpectedly|early EOF|unexpected disconnect|connection reset by peer|Recv failure|Send failure|GnuTLS recv error|TLS connection was non-properly terminated|502 Bad Gateway|503 Service Unavailable/i.test(\n output,\n );\n}\n\n/**\n * Run a git command that only *reads* from the remote, retrying it when the\n * transfer dies mid-flight. Restricted to read-only transfers on purpose:\n * re-running a clone or a fetch is free, whereas re-running a push could\n * duplicate work already accepted by the remote before the connection dropped.\n *\n * `beforeRetry` lets a call site clear whatever the aborted attempt left\n * behind — a half-written clone directory blocks the next `git clone` outright.\n */\nasync function gitTransfer(\n sandbox: ExecutableSandbox,\n args: string[],\n options: CommandOptions & { beforeRetry?: (attempt: number) => Promise<void> } = {},\n): Promise<SandboxCommandResult> {\n const { beforeRetry, ...commandOptions } = options;\n const deadlineMs = Date.now() + (commandOptions.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);\n for (let attempt = 0; ; attempt++) {\n const result = await execute(sandbox, 'git', args, {\n ...commandOptions,\n timeoutMs: Math.max(deadlineMs - Date.now(), 1),\n });\n if (result.exitCode === 0 || attempt >= GIT_TRANSFER_RETRIES || !isTransientGitFailure(result)) return result;\n process.stderr.write(\n `[factory:timing] git ${commandOptions.phase ?? 'transfer'} retrying after attempt ${attempt + 1}\\n`,\n );\n const delayMs = GIT_TRANSFER_RETRY_DELAY_MS * (attempt + 1);\n if (deadlineMs - Date.now() <= delayMs) return result;\n await new Promise(resolve => setTimeout(resolve, delayMs));\n await beforeRetry?.(attempt + 1);\n }\n}\n\n/** Error raised when the sandbox cannot materialize the repo (actionable). */\nexport class MaterializeError extends Error {\n constructor(\n message: string,\n readonly code:\n | 'git-missing'\n | 'egress-blocked'\n | 'clone-failed'\n | 'pull-failed'\n | 'push-failed'\n | 'commit-failed'\n | 'gh-missing'\n | 'pr-failed',\n ) {\n super(message);\n this.name = 'MaterializeError';\n }\n}\n\nfunction cleanUrl(repoFullName: string): string {\n return `https://github.com/${repoFullName}.git`;\n}\n\nfunction credentialScope(\n cloneUrl: string,\n code: 'clone-failed' | 'pull-failed' | 'push-failed' = 'clone-failed',\n): string {\n let url: URL;\n try {\n url = new URL(cloneUrl);\n } catch {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n if (url.protocol !== 'https:' || !url.hostname || url.username || url.password || url.search || url.hash) {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n const repositoryPath = url.pathname.replace(/\\/+$/, '');\n if (!repositoryPath || repositoryPath === '/') {\n throw new MaterializeError('Refusing to configure credentials for an invalid repository clone URL.', code);\n }\n return url.origin + repositoryPath;\n}\n\n/**\n * Provide HTTP Basic credentials to one Git process without putting a secret\n * in argv, a remote URL, or persistent git config. Git reads the URL-scoped\n * extra header from its process environment and discards it on exit.\n */\nfunction gitAuthenticationEnvironment(\n cloneUrl: string,\n token: string,\n username: string,\n code: 'clone-failed' | 'pull-failed' | 'push-failed' = 'clone-failed',\n): Record<string, string> {\n const scope = credentialScope(cloneUrl, code);\n if (!token || !username) {\n throw new MaterializeError('Repository access did not include usable credentials.', code);\n }\n const authorization = Buffer.from(`${username}:${token}`, 'utf8').toString('base64');\n return {\n GIT_CONFIG_COUNT: '1',\n GIT_CONFIG_KEY_0: `http.${scope}.extraHeader`,\n GIT_CONFIG_VALUE_0: `Authorization: Basic ${authorization}`,\n GIT_TERMINAL_PROMPT: '0',\n };\n}\n\nfunction normalizedRemoteUrl(value: string): string | null {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n if (url.protocol !== 'https:' || !url.hostname || url.search || url.hash) return null;\n const pathname = url.pathname.replace(/\\/+$/, '').replace(/\\.git$/i, '');\n const repositoryPath = url.hostname.toLowerCase() === 'github.com' ? pathname.toLowerCase() : pathname;\n return 'https://' + url.host.toLowerCase() + repositoryPath;\n}\n\n/** Repo metadata needed to materialize, read from the org-owned project row. */\nexport interface RepoMaterializeInfo {\n repoFullName: string;\n defaultBranch: string;\n /** Provider-supplied, credential-free HTTPS clone URL. */\n cloneUrl?: string;\n /** Username paired with the bearer token for git-over-HTTPS. */\n authUsername?: string;\n}\n\n/** Options for {@link materializeRepo}. */\nexport interface MaterializeRepoOptions {\n /** The per-(project,user) sandbox binding whose workdir this materializes into. */\n row: RepoMaterializationBinding;\n /** Repo metadata from the org-owned project row. */\n repoInfo: RepoMaterializeInfo;\n /** The live sandbox to run git inside. */\n sandbox: ExecutableSandbox;\n /** A freshly minted, short-lived installation access token. */\n token: string;\n storage: MaterializationStore;\n}\n\nasync function clearWorkdir(sandbox: ExecutableSandbox, workdir: string): Promise<void> {\n const mkdir = await execute(sandbox, 'mkdir', ['-p', workdir]);\n if (mkdir.exitCode !== 0) throw classifyGitFailure(mkdir, 'clone-failed');\n const clear = await execute(sandbox, 'find', [\n workdir,\n '-mindepth',\n '1',\n '-maxdepth',\n '1',\n '-exec',\n 'rm',\n '-rf',\n '--',\n '{}',\n '+',\n ]);\n if (clear.exitCode !== 0) throw classifyGitFailure(clear, 'clone-failed');\n}\n/**\n * Materialize the repo inside the user's sandbox: clone when no checkout of\n * this repo exists, otherwise nothing. Credentials are process-scoped and the\n * stored remote remains credential-free. Sets `materialized_at` on the\n * per-user sandbox binding row.\n */\nexport async function materializeRepo(options: MaterializeRepoOptions): Promise<void> {\n return timedPhase('workspace.materialize', () => materializeRepoImpl(options));\n}\n\nasync function materializeRepoImpl(options: MaterializeRepoOptions): Promise<void> {\n const { row: sandboxRow, repoInfo, sandbox, token, storage } = options;\n const workdir = sandboxRow.sandboxWorkdir;\n const repo = repoInfo.repoFullName;\n\n // 0. Defense in depth: never build a git command from values that aren't\n // strictly shaped, even if a malformed row reached the DB. Inputs are also\n // validated at the route boundary before storage.\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repo)) {\n throw new MaterializeError(`Refusing to materialize: invalid repo full name '${repo}'.`, 'clone-failed');\n }\n if (!/^[A-Za-z0-9_./-]+$/.test(repoInfo.defaultBranch)) {\n throw new MaterializeError(\n `Refusing to materialize: invalid default branch '${repoInfo.defaultBranch}'.`,\n 'clone-failed',\n );\n }\n\n // 1. Preflight: git must be installed in the sandbox template.\n const gitVersion = await execute(sandbox, 'git', ['--version']);\n if (gitVersion.exitCode !== 0) {\n throw new MaterializeError(\n 'git is not installed in the sandbox. The sandbox template must include git.',\n 'git-missing',\n );\n }\n\n // The DB's `materializedAt` can drift from disk in both directions: a fresh\n // binding row over an already-populated workdir (a repo template image,\n // local dev DB resets, repaired rows) must not fail `git clone` on the\n // non-empty directory, and a stale `materializedAt` over an empty sandbox\n // (an expired/recreated VM whose disk was wiped) must re-clone instead of\n // running `git -C <workdir>` against a directory that no longer exists.\n // Disk is the source of truth: detect the checkout instead of trusting the\n // row. An existing checkout is left as it is, whatever it is on: a template\n // image sits detached at its pinned commit, a resumed session on its\n // branch. Syncing with the remote is the session's business; the branch\n // checkout that follows fetches the base branch it needs.\n const cleanCloneUrl = repoInfo.cloneUrl ?? cleanUrl(repo);\n const existing = await existingCheckoutRemote(sandbox, workdir, cleanCloneUrl);\n if (existing !== null) {\n // A token an earlier start failed to scrub must not outlive it; the\n // remote already carries the plain URL otherwise, so this costs nothing\n // on the common path.\n if (/\\/\\/[^/]*@/.test(existing)) await scrubRemote(sandbox, workdir, repo, cleanCloneUrl);\n } else {\n // 2. First open: shallow-clone the default branch into the workdir, the\n // same clone a repo template bakes into its image. The workdir holds no\n // usable checkout of this repo, but it may not be empty: a checkpoint\n // seed or a clone that died partway (a crashed or OOM-killed server)\n // leaves a partial tree behind, and `git clone` refuses a non-empty\n // destination with a non-retryable fatal. Nothing here is recoverable,\n // the probe above already ruled out a checkout of this repo, so\n // clear its contents before cloning, exactly as the retry path does. Keep\n // the workdir itself because LocalSandbox runs commands with this\n // directory as the child process cwd.\n const authEnv = gitAuthenticationEnvironment(\n cleanCloneUrl,\n token,\n repoInfo.authUsername ?? 'x-access-token',\n 'clone-failed',\n );\n await clearWorkdir(sandbox, workdir);\n const clone = await gitTransfer(\n sandbox,\n ['clone', '--depth=1', '--single-branch', '--branch', repoInfo.defaultBranch, '--', cleanCloneUrl, workdir],\n {\n env: authEnv,\n phase: 'repository clone',\n beforeRetry: async () => {\n // A clone that died partway leaves the destination non-empty, which\n // git refuses to clone into. Clear its contents so the retry starts\n // clean without removing LocalSandbox's process cwd.\n await clearWorkdir(sandbox, workdir);\n },\n },\n );\n if (clone.exitCode !== 0) throw classifyGitFailure(clone, 'clone-failed');\n }\n\n // 4. Mark materialized.\n await storage.markMaterialized({ id: sandboxRow.id });\n}\n\nexport interface SessionBranchOptions {\n branch: string;\n baseBranch: string;\n token: string;\n repoFullName: string;\n cloneUrl?: string;\n authUsername?: string;\n /** A pull-request card's session starts on the PR head instead of the base tip. */\n pullRequestNumber?: number;\n /** A GitLab merge-request card's session starts on the MR head instead of the base tip. */\n mergeRequestNumber?: number;\n}\n\n/**\n * Past file contents of a blob-less history load on demand; git asks gh, which\n * answers from the session's `GH_TOKEN`, so no credential is ever written.\n */\nconst GH_CREDENTIAL_HELPER = '!gh auth git-credential';\n\nasync function fetchStartPoint(\n sandbox: ExecutableSandbox,\n workdir: string,\n {\n baseBranch,\n pullRequestNumber,\n mergeRequestNumber,\n }: Pick<SessionBranchOptions, 'baseBranch' | 'pullRequestNumber' | 'mergeRequestNumber'>,\n shallowClone: boolean,\n env: Record<string, string>,\n): Promise<SandboxCommandResult> {\n const changeRequestRef =\n pullRequestNumber !== undefined\n ? `refs/pull/${pullRequestNumber}/head`\n : mergeRequestNumber !== undefined\n ? `refs/merge-requests/${mergeRequestNumber}/head`\n : undefined;\n const baseArgs = [\n '-C',\n workdir,\n 'fetch',\n ...(changeRequestRef && shallowClone ? ['--unshallow'] : []),\n ...(pullRequestNumber !== undefined ? ['--filter=blob:none'] : []),\n 'origin',\n baseBranch,\n ];\n const base = await gitTransfer(sandbox, baseArgs, {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout fetch',\n });\n if (base.exitCode !== 0 || !changeRequestRef) return base;\n return gitTransfer(\n sandbox,\n [\n '-C',\n workdir,\n 'fetch',\n ...(pullRequestNumber !== undefined ? ['--filter=blob:none'] : []),\n 'origin',\n changeRequestRef,\n ],\n {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'change request head fetch',\n },\n );\n}\n\n/** Check out a session's branch inside its isolated repository clone. */\nexport async function checkoutSessionBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n options: SessionBranchOptions,\n): Promise<void> {\n return timedPhase('workspace.checkout', () => checkoutSessionBranchImpl(sandbox, workdir, options));\n}\n\n/** Refresh an existing GitLab review checkout without exposing its credential to the agent. */\nexport async function refreshMergeRequestCheckout(\n sandbox: ExecutableSandbox,\n workdir: string,\n input: { branch: string; mergeRequestNumber: number; expectedHeadSha: string; access: RepositoryAccess },\n): Promise<{ headSha: string; changed: boolean }> {\n const { branch, mergeRequestNumber, expectedHeadSha, access } = input;\n if (\n !isValidGitRef(branch) ||\n !Number.isSafeInteger(mergeRequestNumber) ||\n mergeRequestNumber <= 0 ||\n !/^[0-9a-f]{40}$/i.test(expectedHeadSha)\n ) {\n throw new Error('Refusing to refresh a GitLab review with invalid session or head metadata.');\n }\n const token = access.authorization?.token;\n if (!token) throw new Error('GitLab repository access did not include a bearer token.');\n const env = gitAuthenticationEnvironment(\n access.cloneUrl,\n token,\n access.authorization?.username ?? 'oauth2',\n 'pull-failed',\n );\n const current = await execute(sandbox, 'git', ['-C', workdir, 'branch', '--show-current']);\n if (current.exitCode !== 0 || current.stdout.trim() !== branch) {\n throw new Error('The active checkout is not on its bound review branch.');\n }\n const status = await execute(sandbox, 'git', ['-C', workdir, 'status', '--porcelain', '--untracked-files=all']);\n if (status.exitCode !== 0 || status.stdout.trim()) {\n throw new Error('The review checkout has local changes; refusing to replace them.');\n }\n const before = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', 'HEAD']);\n if (before.exitCode !== 0) throw new Error('Could not read the current review checkout head.');\n const fetch = await gitTransfer(\n sandbox,\n ['-C', workdir, 'fetch', 'origin', `refs/merge-requests/${mergeRequestNumber}/head`],\n {\n env,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'GitLab review head refresh',\n },\n );\n if (fetch.exitCode !== 0) throw classifyGitFailure(fetch, 'pull-failed');\n const fetched = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', 'FETCH_HEAD']);\n if (fetched.exitCode !== 0 || fetched.stdout.trim().toLowerCase() !== expectedHeadSha.toLowerCase()) {\n throw new Error('The fetched GitLab review head differs from the provider-reported head; retry after it settles.');\n }\n if (before.stdout.trim().toLowerCase() === expectedHeadSha.toLowerCase()) {\n return { headSha: expectedHeadSha, changed: false };\n }\n const updated = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-B', branch, 'FETCH_HEAD'], { env });\n if (updated.exitCode !== 0) throw classifyGitFailure(updated, 'pull-failed');\n return { headSha: expectedHeadSha, changed: true };\n}\n\nasync function checkoutSessionBranchImpl(\n sandbox: ExecutableSandbox,\n workdir: string,\n options: SessionBranchOptions,\n): Promise<void> {\n const { branch, baseBranch, token, repoFullName, pullRequestNumber, mergeRequestNumber, cloneUrl, authUsername } =\n options;\n if (\n !isValidGitRef(branch) ||\n !isValidGitRef(baseBranch) ||\n (pullRequestNumber !== undefined && mergeRequestNumber !== undefined) ||\n (mergeRequestNumber !== undefined && (!Number.isSafeInteger(mergeRequestNumber) || mergeRequestNumber <= 0))\n ) {\n throw new MaterializeError('Refusing to create a session from an invalid branch name.', 'clone-failed');\n }\n\n const changeRequestSession = pullRequestNumber !== undefined || mergeRequestNumber !== undefined;\n // GitHub delegates later authenticated operations to `gh`. Other providers\n // deliberately receive no persistent credential helper. Remove the legacy\n // helper when reopening an older checkout so a stale sandbox cannot retain\n // credentials injected by an earlier implementation.\n const cleanCloneUrl = cloneUrl ?? cleanUrl(repoFullName);\n const authEnv = gitAuthenticationEnvironment(cleanCloneUrl, token, authUsername ?? 'x-access-token', 'pull-failed');\n const credentialKey = authUsername ? 'credential.' + credentialScope(cleanCloneUrl) + '.helper' : 'credential.helper';\n if (authUsername) {\n await execute(sandbox, 'git', ['-C', workdir, 'config', '--unset-all', credentialKey]);\n } else {\n const configured = await execute(sandbox, 'git', ['-C', workdir, 'config', credentialKey, GH_CREDENTIAL_HELPER]);\n if (configured.exitCode !== 0) throw classifyGitFailure(configured, 'pull-failed');\n }\n\n const current = await execute(sandbox, 'git', ['-C', workdir, 'branch', '--show-current']);\n if (current.exitCode === 0 && current.stdout.trim() === branch) return;\n\n const local = await execute(sandbox, 'git', [\n '-C',\n workdir,\n 'show-ref',\n '--verify',\n '--quiet',\n `refs/heads/${branch}`,\n ]);\n if (local.exitCode === 0) {\n const checkout = await execute(sandbox, 'git', ['-C', workdir, 'checkout', branch], { env: authEnv });\n if (checkout.exitCode !== 0) {\n if (isBlockedByLocalWork(checkout)) return;\n throw classifyGitFailure(checkout, 'clone-failed');\n }\n return;\n }\n\n const shallowClone =\n changeRequestSession &&\n (await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', '--is-shallow-repository'])).stdout.trim() === 'true';\n const fetch = await fetchStartPoint(sandbox, workdir, options, shallowClone, authEnv);\n if (fetch.exitCode !== 0) throw classifyGitFailure(fetch, 'pull-failed');\n\n const create = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-b', branch, 'FETCH_HEAD'], {\n env: authEnv,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout',\n });\n if (create.exitCode === 0 || isBlockedByLocalWork(create)) return;\n if (!isBranchCollision(create)) throw classifyGitFailure(create, 'clone-failed');\n\n // The branch exists even though the show-ref probe missed it: either another\n // materialization created it concurrently (adopt it), or the sandbox carries\n // a broken loose ref (remove it and retry).\n const adopt = await execute(sandbox, 'git', ['-C', workdir, 'checkout', branch], { env: authEnv });\n if (adopt.exitCode === 0 || isBlockedByLocalWork(adopt)) return;\n\n let drop = await execute(sandbox, 'git', ['-C', workdir, 'update-ref', '--no-deref', '-d', `refs/heads/${branch}`]);\n if (drop.exitCode !== 0) {\n const gitDir = await execute(sandbox, 'git', ['-C', workdir, 'rev-parse', '--absolute-git-dir']);\n if (gitDir.exitCode !== 0 || !gitDir.stdout.trim()) throw classifyGitFailure(create, 'clone-failed');\n drop = await execute(sandbox, 'rm', ['-f', '--', `${gitDir.stdout.trim()}/refs/heads/${branch}`]);\n }\n if (drop.exitCode !== 0) throw classifyGitFailure(create, 'clone-failed');\n\n const retry = await execute(sandbox, 'git', ['-C', workdir, 'checkout', '-b', branch, 'FETCH_HEAD'], {\n env: authEnv,\n timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS,\n phase: 'branch checkout retry',\n });\n if (retry.exitCode !== 0) {\n if (isBlockedByLocalWork(retry)) return;\n throw classifyGitFailure(retry, 'clone-failed');\n }\n}\n\n/**\n * True when `git checkout -b` failed only because the branch ref already\n * exists — the collision Factory hits when a pooled sandbox carries a ref the\n * show-ref probe could not see (broken loose ref) or a concurrent\n * materialization created the branch after the probe ran.\n */\nfunction isBranchCollision(result: SandboxCommandResult): boolean {\n return /a branch named .* already exists/i.test(`${result.stderr || ''}\\n${result.stdout || ''}`);\n}\n\n/**\n * True when a failed `git checkout` just means uncommitted or untracked files\n * in the working tree would be clobbered by the branch switch. Those files are\n * a session's work in progress — the switch must yield to them, never the\n * other way around.\n */\nfunction isBlockedByLocalWork(result: SandboxCommandResult): boolean {\n const output = `${result.stderr || ''}\\n${result.stdout || ''}`;\n return /Your local changes to the following files would be overwritten by checkout|untracked working tree files would be overwritten by checkout/i.test(\n output,\n );\n}\n\n/**\n * Return the origin URL when the workdir contains this repository, including a\n * legacy checkout whose remote still embeds credentials.\n */\nasync function existingCheckoutRemote(\n sandbox: ExecutableSandbox,\n workdir: string,\n cloneUrl: string,\n): Promise<string | null> {\n const result = await execute(sandbox, 'git', ['-C', workdir, 'remote', 'get-url', 'origin']);\n if (result.exitCode !== 0) return null;\n const url = result.stdout.trim();\n const actual = normalizedRemoteUrl(url);\n const expected = normalizedRemoteUrl(cloneUrl);\n return actual !== null && expected !== null && actual === expected ? url : null;\n}\n\n/** Remove credentials persisted by an older implementation from origin. */\nasync function scrubRemote(\n sandbox: ExecutableSandbox,\n workdir: string,\n repoFullName: string,\n cloneUrl: string = cleanUrl(repoFullName),\n): Promise<void> {\n let failure: string;\n try {\n const result = await execute(sandbox, 'git', ['-C', workdir, 'remote', 'set-url', 'origin', cloneUrl]);\n if (result.exitCode === 0) return;\n failure = result.stderr.trim() || result.stdout.trim();\n } catch (error) {\n failure = error instanceof Error ? error.message : String(error);\n }\n throw new MaterializeError(`Failed to scrub installation token from git remote: ${failure}`, 'pull-failed');\n}\n\n/**\n * Turn a failed git command into an actionable error, detecting the common\n * \"cannot reach github.com\" egress failure.\n */\nfunction classifyGitFailure(\n result: SandboxCommandResult,\n fallback: 'clone-failed' | 'pull-failed' | 'push-failed',\n): MaterializeError {\n const stderr = result.stderr || '';\n if (/could not resolve host|failed to connect|network is unreachable|Connection timed out/i.test(stderr)) {\n return new MaterializeError(\n 'The sandbox could not reach github.com. The sandbox network must allow outbound egress to github.com.',\n 'egress-blocked',\n );\n }\n const verb = fallback === 'clone-failed' ? 'clone' : fallback === 'pull-failed' ? 'pull' : 'push';\n return new MaterializeError(`git ${verb} failed: ${stderr}`, fallback);\n}\n\n// ---------------------------------------------------------------------------\n// Phase 1 — git identity + token-scoped push primitive\n//\n// These helpers let the sandbox author and push commits safely. The install\n// token is short-lived, minted per-operation server-side, and supplied only to\n// the Git process through its environment. It never enters argv or persistent\n// repository configuration.\n// ---------------------------------------------------------------------------\n\nexport { isValidGitRef };\n\n/** Identity used to author commits inside the sandbox. */\nexport interface GitIdentity {\n name?: string | null;\n email?: string | null;\n /** GitHub login, used to derive a stable noreply identity when name/email are absent. */\n login?: string | null;\n}\n\n/**\n * Resolve a concrete `{ name, email }` for git authorship from a possibly-sparse\n * identity. Falls back to a GitHub-style noreply identity so commits are never\n * authored with an empty or host-derived identity.\n */\nexport function resolveGitIdentity(identity: GitIdentity): { name: string; email: string } {\n const login = (identity.login || '').trim();\n const name = (identity.name || '').trim() || login || 'Mastra Code';\n const email =\n (identity.email || '').trim() ||\n (login ? `${login}@users.noreply.github.com` : 'mastra-code@users.noreply.github.com');\n return { name, email };\n}\n\n/** Configure repository-local commit identity through direct Git argv calls. */\nexport async function configureGitIdentity(\n sandbox: ExecutableSandbox,\n workdir: string,\n identity: GitIdentity,\n): Promise<void> {\n const { name, email } = resolveGitIdentity(identity);\n const setName = await execute(sandbox, 'git', ['-C', workdir, 'config', 'user.name', name]);\n if (setName.exitCode !== 0) {\n throw new MaterializeError(`Failed to set git user.name: ${setName.stderr.trim()}`, 'commit-failed');\n }\n const setEmail = await execute(sandbox, 'git', ['-C', workdir, 'config', 'user.email', email]);\n if (setEmail.exitCode !== 0) {\n throw new MaterializeError(`Failed to set git user.email: ${setEmail.stderr.trim()}`, 'commit-failed');\n }\n}\n\nasync function pushAuthenticatedBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n cloneUrl: string,\n token: string,\n username: string,\n): Promise<void> {\n const env = gitAuthenticationEnvironment(cloneUrl, token, username, 'push-failed');\n const push = await execute(sandbox, 'git', ['-C', workdir, 'push', '-u', 'origin', branch], { env });\n if (push.exitCode !== 0) throw classifyGitFailure(push, 'push-failed');\n}\n\n/**\n * Push a branch back to GitHub with credentials scoped to the Git process.\n * The token never enters argv, a repository URL, or persistent configuration.\n */\nexport async function pushBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n token: string,\n repoFullName: string,\n): Promise<void> {\n if (!isValidGitRef(branch)) {\n throw new MaterializeError(`Refusing to push: invalid branch name '${branch}'.`, 'push-failed');\n }\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repoFullName)) {\n throw new MaterializeError(`Refusing to push: invalid repo full name '${repoFullName}'.`, 'push-failed');\n }\n await pushAuthenticatedBranch(sandbox, workdir, branch, cleanUrl(repoFullName), token, 'x-access-token');\n}\n\n/**\n * Push the active session branch through the provider-neutral repository\n * access contract without persisting or exposing provider credentials.\n */\nexport async function pushRepositoryBranch(\n sandbox: ExecutableSandbox,\n workdir: string,\n branch: string,\n access: RepositoryAccess,\n repoFullName: string,\n): Promise<void> {\n if (!isValidGitRef(branch)) {\n throw new MaterializeError(`Refusing to push: invalid branch name '${branch}'.`, 'push-failed');\n }\n if (!/^[\\w.-]+(?:\\/[\\w.-]+)+$/.test(repoFullName)) {\n throw new MaterializeError(`Refusing to push: invalid repo full name '${repoFullName}'.`, 'push-failed');\n }\n const authorization = access.authorization;\n if (!authorization?.token) {\n throw new MaterializeError('Repository access did not include push credentials.', 'push-failed');\n }\n await pushAuthenticatedBranch(\n sandbox,\n workdir,\n branch,\n access.cloneUrl,\n authorization.token,\n authorization.username ?? 'x-access-token',\n );\n}\n\nexport interface CommitResult {\n /** True when a commit was created; false when there was nothing to commit. */\n committed: boolean;\n}\n\n/**\n * Stage every change in the working tree and create a commit inside the\n * sandbox. The git identity is configured first so authorship is correct. When\n * there is nothing to commit this is a no-op (`committed: false`) rather than an\n * error, so callers can safely commit-then-push without first diffing.\n *\n * @param sandbox the live sandbox containing the checkout\n * @param workdir the session workdir to commit in\n * @param message the commit message (passed as one argv value)\n * @param identity authorship identity for the commit\n */\nexport async function commitAll(\n sandbox: ExecutableSandbox,\n workdir: string,\n message: string,\n identity: GitIdentity,\n): Promise<CommitResult> {\n await configureGitIdentity(sandbox, workdir, identity);\n\n const add = await execute(sandbox, 'git', ['-C', workdir, 'add', '-A']);\n if (add.exitCode !== 0) {\n throw new MaterializeError(`git add failed: ${add.stderr.trim() || add.stdout.trim()}`, 'commit-failed');\n }\n\n // Nothing staged → nothing to commit. `git diff --cached --quiet` exits 1 when\n // there are staged changes, 0 when the index is clean.\n const staged = await execute(sandbox, 'git', ['-C', workdir, 'diff', '--cached', '--quiet']);\n if (staged.exitCode === 0) {\n return { committed: false };\n }\n\n const commit = await execute(sandbox, 'git', ['-C', workdir, 'commit', '-m', message]);\n if (commit.exitCode !== 0) {\n throw new MaterializeError(`git commit failed: ${commit.stderr.trim() || commit.stdout.trim()}`, 'commit-failed');\n }\n\n return { committed: true };\n}\n\n// ---------------------------------------------------------------------------\n// Phase 2 — setup / teardown lifecycle commands\n//\n// The org-configured setup and teardown shell commands run in the session's\n// materialized workdir. The workdir is always resolved server-side from the\n// live sandbox; client input never reaches a filesystem path.\n// ---------------------------------------------------------------------------\n\n/** Error raised when the org's setup or teardown command fails in the sandbox. */\nexport class SetupCommandError extends Error {\n constructor(\n message: string,\n readonly code: 'setup-failed' | 'teardown-failed',\n ) {\n super(message);\n this.name = 'SetupCommandError';\n }\n}\n\n/**\n * Run the project's setup command (e.g. `pnpm i && pnpm build`) inside the\n * freshly materialized session workdir. Called before the checkout is handed\n * to any agent run so it is ready to build/test. A non-zero exit is a hard\n * error — starting agent work in a half-set-up tree is worse than failing the\n * request.\n *\n * Security model: the command is intentionally arbitrary shell — that is the\n * feature (install deps, build, seed fixtures). It is only configurable by\n * authenticated org members (the settings route is gated by\n * `resolveOrgTenant` + org-scoped project lookup, with length and\n * control-character validation), and it executes exclusively inside the\n * project's isolated sandbox — the same environment where org members already\n * run arbitrary shell via the agent's command tool. It never runs on the web\n * server host, so it grants no privilege beyond what sandbox access already\n * provides.\n *\n * @param sandbox live sandbox containing the checkout\n * @param workdir the server-resolved session workdir the command runs in\n * @param command the org-configured setup shell command\n */\nasync function runLifecycleCommand(\n sandbox: ExecutableSandbox,\n workdir: string,\n command: string,\n options: { phase: 'setup' | 'teardown'; timeoutMs?: number },\n): Promise<void> {\n const result = await sh(sandbox, `cd ${shellQuote(workdir)} && { ${command}\\n}`, {\n phase: `${options.phase} command`,\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n if (result.exitCode !== 0) {\n const detail = (result.stderr.trim() || result.stdout.trim()).slice(-1800);\n const label = options.phase === 'setup' ? 'Setup' : 'Teardown';\n throw new SetupCommandError(\n `${label} command failed (exit ${result.exitCode}): ${detail}`,\n options.phase === 'setup' ? 'setup-failed' : 'teardown-failed',\n );\n }\n}\n\nexport async function runSetupCommand(sandbox: ExecutableSandbox, workdir: string, command: string): Promise<void> {\n return runLifecycleCommand(sandbox, workdir, command, { phase: 'setup' });\n}\n\n/**\n * Run the repository's best-effort teardown command from the materialized\n * session workdir. Callers own lifecycle policy: this helper reports failures\n * so the retirement coordinator can log them while still continuing with\n * scrub, pooling/destruction, cache invalidation, and row deletion.\n */\nexport async function runTeardownCommand(\n sandbox: ExecutableSandbox,\n workdir: string,\n command: string,\n options: { timeoutMs?: number } = {},\n): Promise<void> {\n return runLifecycleCommand(sandbox, workdir, command, {\n phase: 'teardown',\n ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n });\n}\n\nexport interface CreatePullRequestArgs {\n /** Short-lived installation token, injected only into the `gh` process env. */\n token: string;\n /** Base branch the PR merges into. Ref-validated. */\n base: string;\n /** Head branch the PR is opened from. Ref-validated. */\n head: string;\n /** PR title. */\n title: string;\n /** PR body (optional). */\n body?: string;\n}\n\nexport interface CreatePullRequestResult {\n /** The PR URL parsed from `gh pr create` stdout. */\n url: string;\n}\n\n/**\n * Preflight that `gh` is installed in the sandbox. Only called on the PR path so\n * a missing `gh` never blocks clone/open. Surfaces an actionable error naming\n * the sandbox template requirement.\n */\nasync function assertGhAvailable(sandbox: ExecutableSandbox): Promise<void> {\n const version = await execute(sandbox, 'gh', ['--version']);\n if (version.exitCode !== 0) {\n throw new MaterializeError(\n 'The GitHub CLI (gh) is not installed in the sandbox. The sandbox template must include gh to open pull requests.',\n 'gh-missing',\n );\n }\n}\n\n/** Match the first GitHub PR URL in `gh pr create` output. */\nfunction parsePullRequestUrl(stdout: string): string | undefined {\n const match = stdout.match(/https:\\/\\/github\\.com\\/[^\\s]+\\/pull\\/\\d+/);\n return match?.[0];\n}\n\n/**\n * Open a pull request from inside the sandbox via `gh pr create`. The token is\n * passed only through a per-invocation `GH_TOKEN` env scoped to the single `gh`\n * process (never persisted), all arguments are passed as structured argv, and\n * the resulting PR URL is parsed from stdout.\n *\n * @param sandbox live sandbox containing the checkout\n * @param workdir the worktree (or repo) path the PR head branch is checked out in\n */\nexport async function createPullRequest(\n sandbox: ExecutableSandbox,\n workdir: string,\n { token, base, head, title, body }: CreatePullRequestArgs,\n): Promise<CreatePullRequestResult> {\n if (!isValidGitRef(base)) {\n throw new MaterializeError(`Refusing to open PR: invalid base branch '${base}'.`, 'pr-failed');\n }\n if (!isValidGitRef(head)) {\n throw new MaterializeError(`Refusing to open PR: invalid head branch '${head}'.`, 'pr-failed');\n }\n\n await assertGhAvailable(sandbox);\n\n const result = await execute(\n sandbox,\n 'gh',\n ['pr', 'create', '--base', base, '--head', head, '--title', title, '--body', body ?? ''],\n { cwd: workdir, env: { GH_TOKEN: token } },\n );\n if (result.exitCode !== 0) {\n const classified = classifyGitFailure(result, 'push-failed');\n if (classified.code === 'egress-blocked') {\n throw classified;\n }\n throw new MaterializeError(`gh pr create failed: ${result.stderr.trim() || result.stdout.trim()}`, 'pr-failed');\n }\n\n const url = parsePullRequestUrl(result.stdout);\n if (!url) {\n throw new MaterializeError(\n `gh pr create succeeded but no PR URL was found in its output: ${result.stdout.trim()}`,\n 'pr-failed',\n );\n }\n\n return { url };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":["#direct","#platform","#request"],"sources":["../../../src/integrations/gitlab/api.ts"],"sourcesContent":["import { PlatformApiClient, PlatformApiError } from '../platform/api-client.js';\n\nexport const GITLAB_PROJECTS_PAGE_SIZE = 100;\nexport const GITLAB_ISSUES_PAGE_SIZE = 30;\nexport const GITLAB_NOTES_PAGE_SIZE = 100;\nexport const GITLAB_MIN_ACCESS_LEVEL = 20;\nexport const GITLAB_MERGE_REQUESTS_PAGE_SIZE = 30;\nexport const GITLAB_DISCUSSIONS_PAGE_SIZE = 100;\n\nexport type GitLabApiErrorCode = 'gitlab_auth_failed' | 'gitlab_request_failed';\n\nexport class GitLabApiError extends Error {\n readonly status: number | null;\n readonly code: GitLabApiErrorCode;\n\n constructor(message: string, status: number | null) {\n super(message);\n this.name = 'GitLabApiError';\n this.status = status;\n this.code = status === 401 || status === 403 ? 'gitlab_auth_failed' : 'gitlab_request_failed';\n }\n}\n\nexport interface GitLabProject {\n id: number;\n name: string;\n path_with_namespace: string;\n web_url: string;\n default_branch?: string | null;\n}\n\nexport interface GitLabUser {\n id?: number;\n name?: string | null;\n username: string;\n}\n\nexport interface GitLabLabelDetail {\n name: string;\n color: string;\n text_color?: string;\n}\n\ntype GitLabIssueResponse = Omit<GitLabIssue, 'labels' | 'labelDetails'> & {\n labels?: Array<string | GitLabLabelDetail>;\n};\n\nexport interface GitLabIssue {\n id: number;\n iid: number;\n project_id: number;\n title: string;\n description?: string | null;\n state: 'opened' | 'closed';\n web_url: string;\n author?: GitLabUser | null;\n assignee?: GitLabUser | null;\n assignees?: GitLabUser[];\n labels?: string[];\n labelDetails?: GitLabLabelDetail[];\n weight?: number | null;\n user_notes_count?: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GitLabNote {\n id: number;\n body: string;\n type?: string | null;\n author?: GitLabUser | null;\n created_at: string;\n updated_at?: string;\n system?: boolean;\n}\n\nexport interface GitLabDiffRefs {\n base_sha: string;\n start_sha: string;\n head_sha: string;\n}\n\nexport interface GitLabMergeRequest {\n id: number;\n iid: number;\n project_id: number;\n title: string;\n description?: string | null;\n state: 'opened' | 'closed' | 'merged' | 'locked';\n web_url: string;\n author?: GitLabUser | null;\n assignees?: GitLabUser[];\n reviewers?: GitLabUser[];\n labels?: string[];\n source_branch: string;\n target_branch: string;\n sha: string;\n merge_commit_sha?: string | null;\n squash_commit_sha?: string | null;\n diff_refs?: GitLabDiffRefs | null;\n merge_status?: string;\n detailed_merge_status?: string;\n draft?: boolean;\n work_in_progress?: boolean;\n merged_at?: string | null;\n user_notes_count?: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GitLabMergeResult extends GitLabMergeRequest {\n message?: string;\n}\n\nexport interface GitLabDiscussionPosition {\n position_type: 'text';\n base_sha: string;\n start_sha: string;\n head_sha: string;\n old_path: string;\n new_path: string;\n old_line?: number | null;\n new_line?: number | null;\n line_range?: {\n start: GitLabDiscussionLine;\n end: GitLabDiscussionLine;\n };\n}\n\nexport interface GitLabDiscussionLine {\n line_code: string;\n type: 'old' | 'new';\n old_line?: number | null;\n new_line?: number | null;\n}\n\nexport interface GitLabDiscussionNote extends GitLabNote {\n position?: GitLabDiscussionPosition | null;\n resolvable?: boolean;\n resolved?: boolean;\n}\n\nexport interface GitLabDiscussion {\n id: string;\n individual_note?: boolean;\n notes: GitLabDiscussionNote[];\n}\n\nexport interface GitLabMergeRequestApprovals {\n approved: boolean;\n approvals_required?: number;\n approvals_left?: number;\n approved_by?: Array<{ user: GitLabUser }>;\n}\n\nexport interface GitLabMember {\n id: number;\n username: string;\n name?: string | null;\n state?: string;\n access_level?: number;\n}\n\nexport interface GitLabApiClientConfig {\n baseUrl: string;\n accessToken: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface PlatformGitLabApiClientConfig {\n client: PlatformApiClient;\n connectionId: string;\n}\n\nexport class GitLabApiClient {\n readonly #direct: { baseUrl: string; accessToken: string; fetch: typeof fetch } | null;\n readonly #platform: PlatformGitLabApiClientConfig | null;\n\n constructor(config: GitLabApiClientConfig | PlatformGitLabApiClientConfig) {\n if ('client' in config) {\n if (!config.connectionId.trim()) throw new Error('GitLabApiClient is missing required config: connectionId.');\n this.#direct = null;\n this.#platform = config;\n return;\n }\n\n const accessToken = config.accessToken.trim();\n if (!accessToken) throw new Error('GitLabApiClient is missing required config: accessToken.');\n let url: URL;\n try {\n url = new URL(config.baseUrl);\n } catch {\n throw new Error('GitLabApiClient baseUrl must be an absolute HTTP(S) URL.');\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('GitLabApiClient baseUrl must be an absolute HTTP(S) URL.');\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error('GitLabApiClient baseUrl must not include credentials, query, or fragment.');\n }\n const hostname = url.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n const isLoopback = hostname === 'localhost' || hostname === '::1' || /^127(?:\\.\\d{1,3}){3}$/.test(hostname);\n if (url.protocol === 'http:' && !isLoopback) {\n throw new Error('GitLabApiClient baseUrl must use HTTPS unless it targets a loopback host.');\n }\n this.#direct = {\n baseUrl: config.baseUrl.replace(/\\/+$/, ''),\n accessToken,\n fetch: config.fetchImpl ?? globalThis.fetch,\n };\n this.#platform = null;\n }\n\n async getCurrentUser(): Promise<GitLabUser> {\n return this.#request<GitLabUser>('GET', '/api/v4/user');\n }\n\n async getProject(projectId: string): Promise<GitLabProject> {\n return this.#request<GitLabProject>('GET', `/api/v4/projects/${encodeURIComponent(projectId)}`);\n }\n\n async listProjects(options: { page?: number } = {}): Promise<GitLabProject[]> {\n return this.#request<GitLabProject[]>('GET', '/api/v4/projects', {\n query: {\n membership: 'true',\n simple: 'true',\n with_issues_enabled: 'true',\n min_access_level: GITLAB_MIN_ACCESS_LEVEL,\n order_by: 'last_activity_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_PROJECTS_PAGE_SIZE,\n },\n });\n }\n\n async listIssues(projectId: string, options: { page?: number; labels?: string[] } = {}): Promise<GitLabIssue[]> {\n const issues = await this.#request<GitLabIssueResponse[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues`,\n {\n query: {\n state: 'opened',\n scope: 'all',\n order_by: 'updated_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_ISSUES_PAGE_SIZE,\n labels: options.labels?.length ? options.labels.join(',') : undefined,\n with_labels_details: 'true',\n },\n },\n );\n return issues.map(normalizeIssue);\n }\n\n async getIssue(projectId: string, issueIid: number): Promise<GitLabIssue> {\n // GitLab's single-issue endpoint returns label names even when\n // with_labels_details is requested. The IID-filtered list endpoint returns\n // the same issue with label colors, including for closed issues.\n const issues = await this.#request<GitLabIssueResponse[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues`,\n { query: { 'iids[]': issueIid, state: 'all', scope: 'all', with_labels_details: 'true' } },\n );\n const issue = issues.find(candidate => candidate.iid === issueIid);\n if (!issue) throw new GitLabApiError(`GitLab issue ${issueIid} was not found`, 404);\n return normalizeIssue(issue);\n }\n\n async listNotes(projectId: string, issueIid: number, options: { page?: number } = {}): Promise<GitLabNote[]> {\n return this.#request<GitLabNote[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/notes`,\n {\n query: { order_by: 'created_at', sort: 'asc', page: options.page ?? 1, per_page: GITLAB_NOTES_PAGE_SIZE },\n },\n );\n }\n\n async createNote(projectId: string, issueIid: number, body: string): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/notes`,\n { body: { body } },\n );\n }\n\n async updateIssueState(projectId: string, issueIid: number, stateEvent: 'close' | 'reopen'): Promise<GitLabIssue> {\n return this.#request<GitLabIssue>('PUT', `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`, {\n body: { state_event: stateEvent },\n });\n }\n\n async listMergeRequests(\n projectId: string,\n options: { page?: number; state?: 'opened' | 'closed' | 'merged' | 'all' } = {},\n ): Promise<GitLabMergeRequest[]> {\n return this.#request<GitLabMergeRequest[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests`,\n {\n query: {\n state: options.state ?? 'opened',\n order_by: 'updated_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_MERGE_REQUESTS_PAGE_SIZE,\n },\n },\n );\n }\n\n async getMergeRequest(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n );\n }\n\n async createMergeRequest(\n projectId: string,\n input: {\n sourceBranch: string;\n targetBranch: string;\n title: string;\n description?: string;\n removeSourceBranch?: boolean;\n squash?: boolean;\n },\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests`,\n {\n body: {\n source_branch: input.sourceBranch,\n target_branch: input.targetBranch,\n title: input.title,\n description: input.description,\n remove_source_branch: input.removeSourceBranch,\n squash: input.squash,\n },\n },\n );\n }\n\n async updateMergeRequest(\n projectId: string,\n mergeRequestIid: number,\n input: {\n title?: string;\n description?: string;\n targetBranch?: string;\n stateEvent?: 'close' | 'reopen';\n removeSourceBranch?: boolean;\n squash?: boolean;\n reviewerIds?: number[];\n },\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n {\n body: {\n title: input.title,\n description: input.description,\n target_branch: input.targetBranch,\n state_event: input.stateEvent,\n remove_source_branch: input.removeSourceBranch,\n squash: input.squash,\n reviewer_ids: input.reviewerIds,\n },\n },\n );\n }\n\n async mergeMergeRequest(\n projectId: string,\n mergeRequestIid: number,\n options: {\n squash?: boolean;\n mergeCommitMessage?: string;\n squashCommitMessage?: string;\n shouldRemoveSourceBranch?: boolean;\n } = {},\n ): Promise<GitLabMergeResult> {\n return this.#request<GitLabMergeResult>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/merge`,\n {\n body: {\n squash: options.squash,\n merge_commit_message: options.mergeCommitMessage,\n squash_commit_message: options.squashCommitMessage,\n should_remove_source_branch: options.shouldRemoveSourceBranch,\n },\n },\n );\n }\n\n async listMergeRequestNotes(\n projectId: string,\n mergeRequestIid: number,\n options: { page?: number } = {},\n ): Promise<GitLabNote[]> {\n return this.#request<GitLabNote[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes`,\n {\n query: {\n order_by: 'created_at',\n sort: 'asc',\n page: options.page ?? 1,\n per_page: GITLAB_NOTES_PAGE_SIZE,\n },\n },\n );\n }\n\n async createMergeRequestNote(projectId: string, mergeRequestIid: number, body: string): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes`,\n { body: { body } },\n );\n }\n\n async getMergeRequestNote(projectId: string, mergeRequestIid: number, noteId: number): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n );\n }\n\n async updateMergeRequestNote(\n projectId: string,\n mergeRequestIid: number,\n noteId: number,\n body: string,\n ): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n { body: { body } },\n );\n }\n\n async deleteMergeRequestNote(projectId: string, mergeRequestIid: number, noteId: number): Promise<void> {\n await this.#request<void>(\n 'DELETE',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n );\n }\n\n async listMergeRequestDiscussions(\n projectId: string,\n mergeRequestIid: number,\n options: { page?: number } = {},\n ): Promise<GitLabDiscussion[]> {\n return this.#request<GitLabDiscussion[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`,\n { query: { page: options.page ?? 1, per_page: GITLAB_DISCUSSIONS_PAGE_SIZE } },\n );\n }\n\n async getMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}`,\n );\n }\n\n async resolveMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n resolved: boolean,\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}`,\n { body: { resolved } },\n );\n }\n\n async createMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n input: { body: string; commitId?: string; position?: GitLabDiscussionPosition },\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`,\n { body: { body: input.body, commit_id: input.commitId, position: input.position } },\n );\n }\n\n async addMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n body: string,\n ): Promise<GitLabDiscussionNote> {\n return this.#request<GitLabDiscussionNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes`,\n { body: { body } },\n );\n }\n\n async updateMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n noteId: number,\n body: string,\n ): Promise<GitLabDiscussionNote> {\n return this.#request<GitLabDiscussionNote>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes/${noteId}`,\n { body: { body } },\n );\n }\n\n async deleteMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n noteId: number,\n ): Promise<void> {\n await this.#request<void>(\n 'DELETE',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes/${noteId}`,\n );\n }\n\n async getMergeRequestApprovals(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequestApprovals> {\n return this.#request<GitLabMergeRequestApprovals>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/approvals`,\n );\n }\n\n async approveMergeRequest(projectId: string, mergeRequestIid: number, sha?: string): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/approve`,\n sha ? { body: { sha } } : undefined,\n );\n }\n\n async unapproveMergeRequest(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/unapprove`,\n );\n }\n\n async setMergeRequestReviewers(\n projectId: string,\n mergeRequestIid: number,\n reviewerIds: number[],\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n { body: { reviewer_ids: reviewerIds } },\n );\n }\n\n async listProjectMembers(\n projectId: string,\n options: { query?: string; page?: number } = {},\n ): Promise<GitLabMember[]> {\n return this.#request<GitLabMember[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/members/all`,\n {\n query: {\n query: options.query,\n page: options.page ?? 1,\n per_page: GITLAB_DISCUSSIONS_PAGE_SIZE,\n },\n },\n );\n }\n\n async #request<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n options: { query?: Record<string, string | number | undefined>; body?: unknown } = {},\n ): Promise<T> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) query.set(key, String(value));\n }\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n // Repository targets carry both the immutable numeric ID for GitLab API\n // requests and the path for browser links. A Platform proxy decodes %2F,\n // so forwarding a path-based project locator would turn into a 404.\n const apiPath = path.replace(/^\\/api\\/v4\\/projects\\/([^/]+)/, (full, encoded: string) => {\n const target = decodeURIComponent(encoded);\n const match = /^(\\d+):(.+)$/.exec(target);\n return match ? `/api/v4/projects/${encodeURIComponent(match[1]!)}` : full;\n });\n\n if (this.#platform) {\n const proxyPath = `/v2/connections/${encodeURIComponent(this.#platform.connectionId)}/proxy${apiPath}${suffix}`;\n try {\n return await this.#platform.client.request<T>(method, proxyPath, options.body);\n } catch (error) {\n if (error instanceof PlatformApiError) throw new GitLabApiError(error.message, error.status);\n throw new GitLabApiError(error instanceof Error ? error.message : String(error), null);\n }\n }\n\n const direct = this.#direct!;\n const headers: Record<string, string> = {\n accept: 'application/json',\n 'private-token': direct.accessToken,\n };\n const init: RequestInit = { method, headers, signal: AbortSignal.timeout(15_000) };\n if (options.body !== undefined) {\n headers['content-type'] = 'application/json';\n init.body = JSON.stringify(options.body);\n }\n\n let response: Response;\n try {\n response = await direct.fetch(`${direct.baseUrl}${apiPath}${suffix}`, init);\n } catch (error) {\n const message = (error instanceof Error ? error.message : String(error))\n .split(direct.accessToken)\n .join('[REDACTED]');\n throw new GitLabApiError(message, null);\n }\n if (!response.ok) {\n const message = (await extractError(response)).split(direct.accessToken).join('[REDACTED]');\n throw new GitLabApiError(message, response.status);\n }\n if (response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n}\n\nasync function extractError(response: Response): Promise<string> {\n try {\n const data = (await response.clone().json()) as Record<string, unknown>;\n if (typeof data.message === 'string' && data.message) return data.message;\n if (typeof data.error === 'string' && data.error) return data.error;\n } catch {\n // Fall through to the status-based message.\n }\n return `GitLab API request failed (${response.status})`;\n}\n\nfunction normalizeIssue(response: GitLabIssueResponse): GitLabIssue {\n const { labels, ...issue } = response;\n const labelDetails = (labels ?? []).filter((label): label is GitLabLabelDetail => typeof label !== 'string');\n return {\n ...issue,\n labels: (labels ?? []).map(label => (typeof label === 'string' ? label : label.name)),\n ...(labelDetails.length > 0 ? { labelDetails } : {}),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.js","names":["#direct","#platform","#request"],"sources":["../../../src/integrations/gitlab/api.ts"],"sourcesContent":["import { PlatformApiClient, PlatformApiError } from '../platform/api-client.js';\n\nexport const GITLAB_PROJECTS_PAGE_SIZE = 100;\nexport const GITLAB_ISSUES_PAGE_SIZE = 30;\nexport const GITLAB_NOTES_PAGE_SIZE = 100;\nexport const GITLAB_MIN_ACCESS_LEVEL = 20;\nexport const GITLAB_MERGE_REQUESTS_PAGE_SIZE = 30;\nexport const GITLAB_DISCUSSIONS_PAGE_SIZE = 100;\n\nexport type GitLabApiErrorCode = 'gitlab_auth_failed' | 'gitlab_request_failed';\n\nexport class GitLabApiError extends Error {\n readonly status: number | null;\n readonly code: GitLabApiErrorCode;\n\n constructor(message: string, status: number | null) {\n super(message);\n this.name = 'GitLabApiError';\n this.status = status;\n this.code = status === 401 || status === 403 ? 'gitlab_auth_failed' : 'gitlab_request_failed';\n }\n}\n\nexport interface GitLabProject {\n id: number;\n name: string;\n path_with_namespace: string;\n web_url: string;\n default_branch?: string | null;\n}\n\nexport interface GitLabUser {\n id?: number;\n name?: string | null;\n username: string;\n}\n\nexport interface GitLabLabelDetail {\n name: string;\n color: string;\n text_color?: string;\n}\n\ntype GitLabIssueResponse = Omit<GitLabIssue, 'labels' | 'labelDetails'> & {\n labels?: Array<string | GitLabLabelDetail>;\n};\n\nexport interface GitLabIssue {\n id: number;\n iid: number;\n project_id: number;\n title: string;\n description?: string | null;\n state: 'opened' | 'closed';\n web_url: string;\n author?: GitLabUser | null;\n assignee?: GitLabUser | null;\n assignees?: GitLabUser[];\n labels?: string[];\n labelDetails?: GitLabLabelDetail[];\n weight?: number | null;\n user_notes_count?: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GitLabNote {\n id: number;\n body: string;\n type?: string | null;\n author?: GitLabUser | null;\n created_at: string;\n updated_at?: string;\n system?: boolean;\n}\n\nexport interface GitLabDiffRefs {\n base_sha: string;\n start_sha: string;\n head_sha: string;\n}\n\nexport interface GitLabMergeRequest {\n id: number;\n iid: number;\n project_id: number;\n title: string;\n description?: string | null;\n state: 'opened' | 'closed' | 'merged' | 'locked';\n web_url: string;\n author?: GitLabUser | null;\n assignees?: GitLabUser[];\n reviewers?: GitLabUser[];\n labels?: string[];\n source_branch: string;\n target_branch: string;\n sha: string;\n merge_commit_sha?: string | null;\n squash_commit_sha?: string | null;\n diff_refs?: GitLabDiffRefs | null;\n merge_status?: string;\n detailed_merge_status?: string;\n draft?: boolean;\n work_in_progress?: boolean;\n merged_at?: string | null;\n user_notes_count?: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GitLabMergeResult extends GitLabMergeRequest {\n message?: string;\n}\n\nexport interface GitLabDiscussionPosition {\n position_type: 'text';\n base_sha: string;\n start_sha: string;\n head_sha: string;\n old_path: string;\n new_path: string;\n old_line?: number | null;\n new_line?: number | null;\n line_range?: {\n start: GitLabDiscussionLine;\n end: GitLabDiscussionLine;\n };\n}\n\nexport interface GitLabDiscussionLine {\n line_code: string;\n type: 'old' | 'new';\n old_line?: number | null;\n new_line?: number | null;\n}\n\nexport interface GitLabDiscussionNote extends GitLabNote {\n position?: GitLabDiscussionPosition | null;\n resolvable?: boolean;\n resolved?: boolean;\n}\n\nexport interface GitLabDiscussion {\n id: string;\n individual_note?: boolean;\n notes: GitLabDiscussionNote[];\n}\n\nexport interface GitLabMergeRequestApprovals {\n approved: boolean;\n approvals_required?: number;\n approvals_left?: number;\n approved_by?: Array<{ user: GitLabUser }>;\n}\n\nexport interface GitLabMember {\n id: number;\n username: string;\n name?: string | null;\n state?: string;\n access_level?: number;\n}\n\nexport interface GitLabApiClientConfig {\n baseUrl: string;\n accessToken: string;\n fetchImpl?: typeof fetch;\n}\n\nexport interface PlatformGitLabApiClientConfig {\n client: PlatformApiClient;\n connectionId: string;\n}\n\nexport class GitLabApiClient {\n readonly #direct: { baseUrl: string; accessToken: string; fetch: typeof fetch } | null;\n readonly #platform: PlatformGitLabApiClientConfig | null;\n\n constructor(config: GitLabApiClientConfig | PlatformGitLabApiClientConfig) {\n if ('client' in config) {\n if (!config.connectionId.trim()) throw new Error('GitLabApiClient is missing required config: connectionId.');\n this.#direct = null;\n this.#platform = config;\n return;\n }\n\n const accessToken = config.accessToken.trim();\n if (!accessToken) throw new Error('GitLabApiClient is missing required config: accessToken.');\n let url: URL;\n try {\n url = new URL(config.baseUrl);\n } catch {\n throw new Error('GitLabApiClient baseUrl must be an absolute HTTP(S) URL.');\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('GitLabApiClient baseUrl must be an absolute HTTP(S) URL.');\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new Error('GitLabApiClient baseUrl must not include credentials, query, or fragment.');\n }\n const hostname = url.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n const isLoopback = hostname === 'localhost' || hostname === '::1' || /^127(?:\\.\\d{1,3}){3}$/.test(hostname);\n if (url.protocol === 'http:' && !isLoopback) {\n throw new Error('GitLabApiClient baseUrl must use HTTPS unless it targets a loopback host.');\n }\n this.#direct = {\n baseUrl: config.baseUrl.replace(/\\/+$/, ''),\n accessToken,\n fetch: config.fetchImpl ?? globalThis.fetch,\n };\n this.#platform = null;\n }\n\n async getCurrentUser(): Promise<GitLabUser> {\n return this.#request<GitLabUser>('GET', '/api/v4/user');\n }\n\n async getProject(projectId: string): Promise<GitLabProject> {\n return this.#request<GitLabProject>('GET', `/api/v4/projects/${encodeURIComponent(projectId)}`);\n }\n\n async listProjects(options: { page?: number } = {}): Promise<GitLabProject[]> {\n return this.#request<GitLabProject[]>('GET', '/api/v4/projects', {\n query: {\n membership: 'true',\n simple: 'true',\n with_issues_enabled: 'true',\n min_access_level: GITLAB_MIN_ACCESS_LEVEL,\n order_by: 'last_activity_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_PROJECTS_PAGE_SIZE,\n },\n });\n }\n\n async listIssues(projectId: string, options: { page?: number; labels?: string[] } = {}): Promise<GitLabIssue[]> {\n const issues = await this.#request<GitLabIssueResponse[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues`,\n {\n query: {\n state: 'opened',\n scope: 'all',\n order_by: 'updated_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_ISSUES_PAGE_SIZE,\n labels: options.labels?.length ? options.labels.join(',') : undefined,\n with_labels_details: 'true',\n },\n },\n );\n return issues.map(normalizeIssue);\n }\n\n async getIssue(projectId: string, issueIid: number): Promise<GitLabIssue> {\n // GitLab's single-issue endpoint returns label names even when\n // with_labels_details is requested. The IID-filtered list endpoint returns\n // the same issue with label colors, including for closed issues.\n const issues = await this.#request<GitLabIssueResponse[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues`,\n { query: { 'iids[]': issueIid, state: 'all', scope: 'all', with_labels_details: 'true' } },\n );\n const issue = issues.find(candidate => candidate.iid === issueIid);\n if (!issue) throw new GitLabApiError(`GitLab issue ${issueIid} was not found`, 404);\n return normalizeIssue(issue);\n }\n\n async listNotes(projectId: string, issueIid: number, options: { page?: number } = {}): Promise<GitLabNote[]> {\n return this.#request<GitLabNote[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/notes`,\n {\n query: { order_by: 'created_at', sort: 'asc', page: options.page ?? 1, per_page: GITLAB_NOTES_PAGE_SIZE },\n },\n );\n }\n\n async createNote(projectId: string, issueIid: number, body: string): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/notes`,\n { body: { body } },\n );\n }\n\n async updateIssueState(projectId: string, issueIid: number, stateEvent: 'close' | 'reopen'): Promise<GitLabIssue> {\n return this.#request<GitLabIssue>('PUT', `/api/v4/projects/${encodeURIComponent(projectId)}/issues/${issueIid}`, {\n body: { state_event: stateEvent },\n });\n }\n\n async listMergeRequests(\n projectId: string,\n options: { page?: number; state?: 'opened' | 'closed' | 'merged' | 'all' } = {},\n ): Promise<GitLabMergeRequest[]> {\n return this.#request<GitLabMergeRequest[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests`,\n {\n query: {\n state: options.state ?? 'opened',\n order_by: 'updated_at',\n sort: 'desc',\n page: options.page ?? 1,\n per_page: GITLAB_MERGE_REQUESTS_PAGE_SIZE,\n },\n },\n );\n }\n\n async getMergeRequest(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n );\n }\n\n async createMergeRequest(\n projectId: string,\n input: {\n sourceBranch: string;\n targetBranch: string;\n title: string;\n description?: string;\n removeSourceBranch?: boolean;\n squash?: boolean;\n },\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests`,\n {\n body: {\n source_branch: input.sourceBranch,\n target_branch: input.targetBranch,\n title: input.title,\n description: input.description,\n remove_source_branch: input.removeSourceBranch,\n squash: input.squash,\n },\n },\n );\n }\n\n async updateMergeRequest(\n projectId: string,\n mergeRequestIid: number,\n input: {\n title?: string;\n description?: string;\n targetBranch?: string;\n stateEvent?: 'close' | 'reopen';\n removeSourceBranch?: boolean;\n squash?: boolean;\n reviewerIds?: number[];\n },\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n {\n body: {\n title: input.title,\n description: input.description,\n target_branch: input.targetBranch,\n state_event: input.stateEvent,\n remove_source_branch: input.removeSourceBranch,\n squash: input.squash,\n reviewer_ids: input.reviewerIds,\n },\n },\n );\n }\n\n async mergeMergeRequest(\n projectId: string,\n mergeRequestIid: number,\n options: {\n squash?: boolean;\n mergeCommitMessage?: string;\n squashCommitMessage?: string;\n shouldRemoveSourceBranch?: boolean;\n } = {},\n ): Promise<GitLabMergeResult> {\n return this.#request<GitLabMergeResult>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/merge`,\n {\n body: {\n squash: options.squash,\n merge_commit_message: options.mergeCommitMessage,\n squash_commit_message: options.squashCommitMessage,\n should_remove_source_branch: options.shouldRemoveSourceBranch,\n },\n },\n );\n }\n\n async listMergeRequestNotes(\n projectId: string,\n mergeRequestIid: number,\n options: { page?: number } = {},\n ): Promise<GitLabNote[]> {\n return this.#request<GitLabNote[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes`,\n {\n query: {\n order_by: 'created_at',\n sort: 'asc',\n page: options.page ?? 1,\n per_page: GITLAB_NOTES_PAGE_SIZE,\n },\n },\n );\n }\n\n async createMergeRequestNote(projectId: string, mergeRequestIid: number, body: string): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes`,\n { body: { body } },\n );\n }\n\n async getMergeRequestNote(projectId: string, mergeRequestIid: number, noteId: number): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n );\n }\n\n async updateMergeRequestNote(\n projectId: string,\n mergeRequestIid: number,\n noteId: number,\n body: string,\n ): Promise<GitLabNote> {\n return this.#request<GitLabNote>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n { body: { body } },\n );\n }\n\n async deleteMergeRequestNote(projectId: string, mergeRequestIid: number, noteId: number): Promise<void> {\n await this.#request<void>(\n 'DELETE',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes/${noteId}`,\n );\n }\n\n async listMergeRequestDiscussions(\n projectId: string,\n mergeRequestIid: number,\n options: { page?: number } = {},\n ): Promise<GitLabDiscussion[]> {\n return this.#request<GitLabDiscussion[]>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`,\n { query: { page: options.page ?? 1, per_page: GITLAB_DISCUSSIONS_PAGE_SIZE } },\n );\n }\n\n async getMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}`,\n );\n }\n\n async resolveMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n resolved: boolean,\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}`,\n { body: { resolved } },\n );\n }\n\n async createMergeRequestDiscussion(\n projectId: string,\n mergeRequestIid: number,\n input: { body: string; commitId?: string; position?: GitLabDiscussionPosition },\n ): Promise<GitLabDiscussion> {\n return this.#request<GitLabDiscussion>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`,\n { body: { body: input.body, commit_id: input.commitId, position: input.position } },\n );\n }\n\n async addMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n body: string,\n ): Promise<GitLabDiscussionNote> {\n return this.#request<GitLabDiscussionNote>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes`,\n { body: { body } },\n );\n }\n\n async updateMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n noteId: number,\n body: string,\n ): Promise<GitLabDiscussionNote> {\n return this.#request<GitLabDiscussionNote>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes/${noteId}`,\n { body: { body } },\n );\n }\n\n async deleteMergeRequestDiscussionNote(\n projectId: string,\n mergeRequestIid: number,\n discussionId: string,\n noteId: number,\n ): Promise<void> {\n await this.#request<void>(\n 'DELETE',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions/${encodeURIComponent(discussionId)}/notes/${noteId}`,\n );\n }\n\n async getMergeRequestApprovals(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequestApprovals> {\n return this.#request<GitLabMergeRequestApprovals>(\n 'GET',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/approvals`,\n );\n }\n\n async approveMergeRequest(projectId: string, mergeRequestIid: number, sha?: string): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/approve`,\n sha ? { body: { sha } } : undefined,\n );\n }\n\n async unapproveMergeRequest(projectId: string, mergeRequestIid: number): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'POST',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/unapprove`,\n );\n }\n\n async setMergeRequestReviewers(\n projectId: string,\n mergeRequestIid: number,\n reviewerIds: number[],\n ): Promise<GitLabMergeRequest> {\n return this.#request<GitLabMergeRequest>(\n 'PUT',\n `/api/v4/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`,\n { body: { reviewer_ids: reviewerIds } },\n );\n }\n\n async listProjectMembers(\n projectId: string,\n options: { query?: string; page?: number } = {},\n ): Promise<GitLabMember[]> {\n return this.#request<GitLabMember[]>('GET', `/api/v4/projects/${encodeURIComponent(projectId)}/members/all`, {\n query: {\n query: options.query,\n page: options.page ?? 1,\n per_page: GITLAB_DISCUSSIONS_PAGE_SIZE,\n },\n });\n }\n\n async #request<T>(\n method: 'GET' | 'POST' | 'PUT' | 'DELETE',\n path: string,\n options: { query?: Record<string, string | number | undefined>; body?: unknown } = {},\n ): Promise<T> {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(options.query ?? {})) {\n if (value !== undefined) query.set(key, String(value));\n }\n const suffix = query.size > 0 ? `?${query.toString()}` : '';\n // Repository targets carry both the immutable numeric ID for GitLab API\n // requests and the path for browser links. A Platform proxy decodes %2F,\n // so forwarding a path-based project locator would turn into a 404.\n const apiPath = path.replace(/^\\/api\\/v4\\/projects\\/([^/]+)/, (full, encoded: string) => {\n const target = decodeURIComponent(encoded);\n const match = /^(\\d+):(.+)$/.exec(target);\n return match ? `/api/v4/projects/${encodeURIComponent(match[1]!)}` : full;\n });\n\n if (this.#platform) {\n const proxyPath = `/v2/connections/${encodeURIComponent(this.#platform.connectionId)}/proxy${apiPath}${suffix}`;\n try {\n return await this.#platform.client.request<T>(method, proxyPath, options.body);\n } catch (error) {\n if (error instanceof PlatformApiError) throw new GitLabApiError(error.message, error.status);\n throw new GitLabApiError(error instanceof Error ? error.message : String(error), null);\n }\n }\n\n const direct = this.#direct!;\n const headers: Record<string, string> = {\n accept: 'application/json',\n 'private-token': direct.accessToken,\n };\n const init: RequestInit = { method, headers, signal: AbortSignal.timeout(15_000) };\n if (options.body !== undefined) {\n headers['content-type'] = 'application/json';\n init.body = JSON.stringify(options.body);\n }\n\n let response: Response;\n try {\n response = await direct.fetch(`${direct.baseUrl}${apiPath}${suffix}`, init);\n } catch (error) {\n const message = (error instanceof Error ? error.message : String(error))\n .split(direct.accessToken)\n .join('[REDACTED]');\n throw new GitLabApiError(message, null);\n }\n if (!response.ok) {\n const message = (await extractError(response)).split(direct.accessToken).join('[REDACTED]');\n throw new GitLabApiError(message, response.status);\n }\n if (response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n}\n\nasync function extractError(response: Response): Promise<string> {\n try {\n const data = (await response.clone().json()) as Record<string, unknown>;\n if (typeof data.message === 'string' && data.message) return data.message;\n if (typeof data.error === 'string' && data.error) return data.error;\n } catch {\n // Fall through to the status-based message.\n }\n return `GitLab API request failed (${response.status})`;\n}\n\nfunction normalizeIssue(response: GitLabIssueResponse): GitLabIssue {\n const { labels, ...issue } = response;\n const labelDetails = (labels ?? []).filter((label): label is GitLabLabelDetail => typeof label !== 'string');\n return {\n ...issue,\n labels: (labels ?? []).map(label => (typeof label === 'string' ? label : label.name)),\n ...(labelDetails.length > 0 ? { labelDetails } : {}),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/default-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"default-rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/default-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEjH,MAAM,MAAM,mBAAmB,GAAG,OAAO,CACvC,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,wBAAwB,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAChG,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CACrC,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC,CACpF,CAAC;AAiBF,iBAAS,WAAW,CAAC,OAAO,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;;cA8BrD;AAED,iBAAS,aAAa,CAAC,OAAO,EAAE,wBAAwB;;;;;;cAWvD;AAED,iBAAS,WAAW,CAAC,OAAO,EAAE,wBAAwB;;;;;;;;cAYrD;AAED,iBAAS,uBAAuB,CAAC,OAAO,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCjE;AAED,iBAAS,mBAAmB,CAAC,OAAO,EAAE,wBAAwB;;;;;;cAc7D;AAED,iBAAS,qBAAqB,CAAC,OAAO,EAAE,wBAAwB;;;;;;cAc/D;AAED,iBAAS,kBAAkB,CAAC,OAAO,EAAE,wBAAwB;;;;;;;;;;;;;;;;cAsB5D;AAED,iBAAS,kBAAkB,CAAC,OAAO,EAAE,wBAAwB;;;;;;;;cAa5D;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;EAUF,CAAC;AAE9B,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,gBAAgB,CAgBpF"}
|
|
@@ -96,6 +96,7 @@ function mergeRequestUpdated(context) {
|
|
|
96
96
|
if (!context.item || context.item.source !== "gitlab-pr" || context.board !== "review") return;
|
|
97
97
|
if (!context.mergeRequest || context.mergeRequest.state !== "open" || context.mergeRequest.merged) return;
|
|
98
98
|
if (context.item.stages.some((stage) => stage === "intake")) return;
|
|
99
|
+
if (!trustedGitLabActor(context) && !context.mergeRequest.factoryAuthored) return;
|
|
99
100
|
const alreadyReviewing = context.item.stages.some((stage) => stage === "review");
|
|
100
101
|
return {
|
|
101
102
|
type: "transition",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-rules.js","names":[],"sources":["../../../src/integrations/gitlab/default-rules.ts"],"sourcesContent":["import type {\n FactoryGitLabEventName,\n FactoryGitLabRuleContext,\n FactoryRuleHandler,\n} from '../../rules/types.js';\n\nexport type GitLabRuleOverrides = Partial<\n Record<FactoryGitLabEventName, FactoryRuleHandler<FactoryGitLabRuleContext> | null | undefined>\n>;\nexport type GitLabEventRules = Readonly<\n Record<FactoryGitLabEventName, FactoryRuleHandler<FactoryGitLabRuleContext> | null>\n>;\n\n\nfunction actorUsername(context: Pick<FactoryGitLabRuleContext, 'actor'>): string | undefined {\n return context.actor.type === 'gitlab' ? context.actor.username : undefined;\n}\n\nfunction trustedGitLabActor(context: Pick<FactoryGitLabRuleContext, 'actor'>): boolean {\n return context.actor.type === 'gitlab' && context.actor.trusted;\n}\n\nfunction createdAfterFactory(createdAt: string | undefined, factoryCreatedAt: string): boolean {\n if (!createdAt) return false;\n const sourceCreatedAt = Date.parse(createdAt);\n const projectCreatedAt = Date.parse(factoryCreatedAt);\n return Number.isFinite(sourceCreatedAt) && Number.isFinite(projectCreatedAt) && sourceCreatedAt > projectCreatedAt;\n}\n\nfunction issueOpened(context: FactoryGitLabRuleContext) {\n if (!context.issue) return;\n return {\n type: 'upsertLinkedWorkItem',\n idempotencyKey: `${context.ingress.id}:issue-intake`,\n board: context.intake?.board ?? 'work',\n source: 'gitlab-issue',\n sourceKey: context.issue.sourceKey,\n title: context.issue.title,\n url: context.issue.url,\n stage: context.intake?.initialPhase ?? 'intake',\n metadata: {\n gitlabHost: context.repository.host,\n gitlabProjectId: context.repository.id,\n gitlabIssueIid: context.issue.number,\n identifier: `${context.repository.fullName}#${context.issue.number}`,\n ...(context.issue.createdAt ? { sourceCreatedAt: context.issue.createdAt } : {}),\n ...(context.issue.author ?? actorUsername(context)\n ? { author: context.issue.author ?? actorUsername(context) }\n : {}),\n authorTrusted: context.issue.authorTrusted,\n autoStartCandidate:\n trustedGitLabActor(context) &&\n context.issue.authorTrusted &&\n createdAfterFactory(context.issue.createdAt, context.factory.createdAt),\n assignees: context.issue.assignees ?? [],\n labels: context.issue.labels ?? [],\n labelColors: context.issue.labelColors ?? {},\n },\n } as const;\n}\n\nfunction retriageIssue(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-issue' || !context.item.url) return;\n if (context.actor.type === 'gitlab' && context.actor.factoryAuthored) return;\n const reason = context.event === 'issueCommented' ? 'a comment was added' : 'the issue changed';\n return {\n type: 'invokeSkill',\n idempotencyKey: `${context.ingress.id}:factory-triage`,\n role: 'triage',\n skillName: 'factory-triage',\n arguments: `Re-triage GitLab issue (${context.item.url}) after ${reason}.`,\n } as const;\n}\n\nfunction issueClosed(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-issue' || context.board !== 'work') return;\n if (context.item.stages.some(stage => stage === 'done' || stage === 'canceled')) return;\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:issue-closed`,\n board: 'work',\n stage: 'done',\n message: {\n text: `GitLab issue #${context.issue?.number ?? ''} was closed; this Work card was moved to Done.`,\n },\n } as const;\n}\n\nfunction materializeMergeRequest(context: FactoryGitLabRuleContext) {\n if (!context.mergeRequest) return;\n return {\n type: 'upsertLinkedWorkItem',\n idempotencyKey: `${context.ingress.id}:merge-request-intake`,\n board: 'review',\n source: 'gitlab-pr',\n sourceKey: context.mergeRequest.sourceKey,\n title: context.mergeRequest.title,\n url: context.mergeRequest.url,\n stage: 'intake',\n metadata: {\n gitlabHost: context.repository.host,\n gitlabProjectId: context.repository.id,\n gitlabMergeRequestIid: context.mergeRequest.number,\n ...(context.mergeRequest.createdAt ? { sourceCreatedAt: context.mergeRequest.createdAt } : {}),\n factoryAuthored: context.mergeRequest.factoryAuthored,\n authorTrusted: context.mergeRequest.authorTrusted,\n autoStartCandidate:\n ((trustedGitLabActor(context) && context.mergeRequest.authorTrusted) || context.mergeRequest.factoryAuthored) &&\n createdAfterFactory(context.mergeRequest.createdAt, context.factory.createdAt),\n state: context.mergeRequest.state,\n draft: context.mergeRequest.draft,\n merged: context.mergeRequest.merged,\n assignees: context.mergeRequest.assignees ?? [],\n requestedReviewers: context.mergeRequest.reviewers ?? [],\n labels: context.mergeRequest.labels ?? [],\n labelColors: context.mergeRequest.labelColors ?? {},\n headBranch: context.mergeRequest.headBranch,\n baseBranch: context.mergeRequest.baseBranch,\n ...(context.mergeRequest.author ? { author: context.mergeRequest.author } : {}),\n },\n } as const;\n}\n\nfunction mergeRequestUpdated(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-pr' || context.board !== 'review') return;\n if (!context.mergeRequest || context.mergeRequest.state !== 'open' || context.mergeRequest.merged) return;\n if (context.item.stages.some(stage => stage === 'intake')) return;\n const alreadyReviewing = context.item.stages.some(stage => stage === 'review');\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:re-review-updated`,\n board: 'review',\n stage: 'review',\n ...(alreadyReviewing ? { reenter: true } : {}),\n } as const;\n}\n\nfunction mergeRequestCommented(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest || !context.note || context.board !== 'work') return;\n if (context.mergeRequest.state !== 'open' || context.mergeRequest.merged) return;\n if (context.actor.type === 'gitlab' && context.actor.factoryAuthored) return;\n return {\n type: 'sendMessage',\n idempotencyKey: `${context.ingress.id}:address-merge-request-comment`,\n role: 'work',\n priority: 'high',\n message:\n `${context.note.author ?? 'Someone'} commented on GitLab merge request !${context.mergeRequest.number} ` +\n `(${context.note.url ?? context.mergeRequest.url}). Read the comment, address it if you agree, and push ` +\n 'the fixes to the merge-request branch. Reply in GitLab to anything you are deliberately not changing.',\n } as const;\n}\n\nfunction mergeRequestMerged(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest?.merged) return;\n if (context.board === 'review') {\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:merge-request-merged`,\n board: 'review',\n stage: 'done',\n message: {\n text: `GitLab merge request !${context.mergeRequest.number} merged; this Review card was moved to Done.`,\n },\n } as const;\n }\n if (context.board !== 'work') return;\n return {\n type: 'sendMessage',\n idempotencyKey: `${context.ingress.id}:assess-work-completion`,\n role: 'work',\n message:\n `GitLab merge request !${context.mergeRequest.number} merged. Assess whether the linked Work item is complete. ` +\n 'Do not mark it Done solely because this merge request merged.',\n } as const;\n}\n\nfunction mergeRequestClosed(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest || context.mergeRequest.merged || context.board !== 'review') return;\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:merge-request-closed`,\n board: 'review',\n stage: 'canceled',\n message: {\n text:\n `GitLab merge request !${context.mergeRequest.number} was closed without merging; ` +\n 'this Review card was moved to Canceled.',\n },\n } as const;\n}\n\nexport const defaultGitLabRules = Object.freeze({\n issueOpened,\n issueUpdated: retriageIssue,\n issueClosed,\n issueCommented: retriageIssue,\n mergeRequestOpened: materializeMergeRequest,\n mergeRequestUpdated,\n mergeRequestCommented,\n mergeRequestMerged,\n mergeRequestClosed,\n} satisfies GitLabEventRules);\n\nexport function resolveGitLabRules(overrides?: GitLabRuleOverrides): GitLabEventRules {\n if (overrides !== undefined && (overrides === null || typeof overrides !== 'object' || Array.isArray(overrides))) {\n throw new Error('GitLab rules must be an object.');\n }\n const rules: Record<string, FactoryRuleHandler<FactoryGitLabRuleContext> | null> = { ...defaultGitLabRules };\n for (const key of Reflect.ownKeys(overrides ?? {})) {\n if (typeof key !== 'string' || !Object.hasOwn(defaultGitLabRules, key)) {\n throw new Error(`Unknown GitLab rule event: ${String(key)}.`);\n }\n const handler = overrides?.[key as FactoryGitLabEventName];\n if (handler !== undefined && handler !== null && typeof handler !== 'function') {\n throw new Error(`GitLab rule ${key} must be a function, null, or undefined.`);\n }\n if (handler !== undefined) rules[key] = handler;\n }\n return Object.freeze(rules) as GitLabEventRules;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"default-rules.js","names":[],"sources":["../../../src/integrations/gitlab/default-rules.ts"],"sourcesContent":["import type { FactoryGitLabEventName, FactoryGitLabRuleContext, FactoryRuleHandler } from '../../rules/types.js';\n\nexport type GitLabRuleOverrides = Partial<\n Record<FactoryGitLabEventName, FactoryRuleHandler<FactoryGitLabRuleContext> | null | undefined>\n>;\nexport type GitLabEventRules = Readonly<\n Record<FactoryGitLabEventName, FactoryRuleHandler<FactoryGitLabRuleContext> | null>\n>;\n\nfunction actorUsername(context: Pick<FactoryGitLabRuleContext, 'actor'>): string | undefined {\n return context.actor.type === 'gitlab' ? context.actor.username : undefined;\n}\n\nfunction trustedGitLabActor(context: Pick<FactoryGitLabRuleContext, 'actor'>): boolean {\n return context.actor.type === 'gitlab' && context.actor.trusted;\n}\n\nfunction createdAfterFactory(createdAt: string | undefined, factoryCreatedAt: string): boolean {\n if (!createdAt) return false;\n const sourceCreatedAt = Date.parse(createdAt);\n const projectCreatedAt = Date.parse(factoryCreatedAt);\n return Number.isFinite(sourceCreatedAt) && Number.isFinite(projectCreatedAt) && sourceCreatedAt > projectCreatedAt;\n}\n\nfunction issueOpened(context: FactoryGitLabRuleContext) {\n if (!context.issue) return;\n return {\n type: 'upsertLinkedWorkItem',\n idempotencyKey: `${context.ingress.id}:issue-intake`,\n board: context.intake?.board ?? 'work',\n source: 'gitlab-issue',\n sourceKey: context.issue.sourceKey,\n title: context.issue.title,\n url: context.issue.url,\n stage: context.intake?.initialPhase ?? 'intake',\n metadata: {\n gitlabHost: context.repository.host,\n gitlabProjectId: context.repository.id,\n gitlabIssueIid: context.issue.number,\n identifier: `${context.repository.fullName}#${context.issue.number}`,\n ...(context.issue.createdAt ? { sourceCreatedAt: context.issue.createdAt } : {}),\n ...((context.issue.author ?? actorUsername(context))\n ? { author: context.issue.author ?? actorUsername(context) }\n : {}),\n authorTrusted: context.issue.authorTrusted,\n autoStartCandidate:\n trustedGitLabActor(context) &&\n context.issue.authorTrusted &&\n createdAfterFactory(context.issue.createdAt, context.factory.createdAt),\n assignees: context.issue.assignees ?? [],\n labels: context.issue.labels ?? [],\n labelColors: context.issue.labelColors ?? {},\n },\n } as const;\n}\n\nfunction retriageIssue(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-issue' || !context.item.url) return;\n if (context.actor.type === 'gitlab' && context.actor.factoryAuthored) return;\n const reason = context.event === 'issueCommented' ? 'a comment was added' : 'the issue changed';\n return {\n type: 'invokeSkill',\n idempotencyKey: `${context.ingress.id}:factory-triage`,\n role: 'triage',\n skillName: 'factory-triage',\n arguments: `Re-triage GitLab issue (${context.item.url}) after ${reason}.`,\n } as const;\n}\n\nfunction issueClosed(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-issue' || context.board !== 'work') return;\n if (context.item.stages.some(stage => stage === 'done' || stage === 'canceled')) return;\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:issue-closed`,\n board: 'work',\n stage: 'done',\n message: {\n text: `GitLab issue #${context.issue?.number ?? ''} was closed; this Work card was moved to Done.`,\n },\n } as const;\n}\n\nfunction materializeMergeRequest(context: FactoryGitLabRuleContext) {\n if (!context.mergeRequest) return;\n return {\n type: 'upsertLinkedWorkItem',\n idempotencyKey: `${context.ingress.id}:merge-request-intake`,\n board: 'review',\n source: 'gitlab-pr',\n sourceKey: context.mergeRequest.sourceKey,\n title: context.mergeRequest.title,\n url: context.mergeRequest.url,\n stage: 'intake',\n metadata: {\n gitlabHost: context.repository.host,\n gitlabProjectId: context.repository.id,\n gitlabMergeRequestIid: context.mergeRequest.number,\n ...(context.mergeRequest.createdAt ? { sourceCreatedAt: context.mergeRequest.createdAt } : {}),\n factoryAuthored: context.mergeRequest.factoryAuthored,\n authorTrusted: context.mergeRequest.authorTrusted,\n autoStartCandidate:\n ((trustedGitLabActor(context) && context.mergeRequest.authorTrusted) || context.mergeRequest.factoryAuthored) &&\n createdAfterFactory(context.mergeRequest.createdAt, context.factory.createdAt),\n state: context.mergeRequest.state,\n draft: context.mergeRequest.draft,\n merged: context.mergeRequest.merged,\n assignees: context.mergeRequest.assignees ?? [],\n requestedReviewers: context.mergeRequest.reviewers ?? [],\n labels: context.mergeRequest.labels ?? [],\n labelColors: context.mergeRequest.labelColors ?? {},\n headBranch: context.mergeRequest.headBranch,\n baseBranch: context.mergeRequest.baseBranch,\n ...(context.mergeRequest.author ? { author: context.mergeRequest.author } : {}),\n },\n } as const;\n}\n\nfunction mergeRequestUpdated(context: FactoryGitLabRuleContext) {\n if (!context.item || context.item.source !== 'gitlab-pr' || context.board !== 'review') return;\n if (!context.mergeRequest || context.mergeRequest.state !== 'open' || context.mergeRequest.merged) return;\n if (context.item.stages.some(stage => stage === 'intake')) return;\n // An untrusted push must not start review passes on demand.\n if (!trustedGitLabActor(context) && !context.mergeRequest.factoryAuthored) return;\n const alreadyReviewing = context.item.stages.some(stage => stage === 'review');\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:re-review-updated`,\n board: 'review',\n stage: 'review',\n ...(alreadyReviewing ? { reenter: true } : {}),\n } as const;\n}\n\nfunction mergeRequestCommented(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest || !context.note || context.board !== 'work') return;\n if (context.mergeRequest.state !== 'open' || context.mergeRequest.merged) return;\n if (context.actor.type === 'gitlab' && context.actor.factoryAuthored) return;\n return {\n type: 'sendMessage',\n idempotencyKey: `${context.ingress.id}:address-merge-request-comment`,\n role: 'work',\n priority: 'high',\n message:\n `${context.note.author ?? 'Someone'} commented on GitLab merge request !${context.mergeRequest.number} ` +\n `(${context.note.url ?? context.mergeRequest.url}). Read the comment, address it if you agree, and push ` +\n 'the fixes to the merge-request branch. Reply in GitLab to anything you are deliberately not changing.',\n } as const;\n}\n\nfunction mergeRequestMerged(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest?.merged) return;\n if (context.board === 'review') {\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:merge-request-merged`,\n board: 'review',\n stage: 'done',\n message: {\n text: `GitLab merge request !${context.mergeRequest.number} merged; this Review card was moved to Done.`,\n },\n } as const;\n }\n if (context.board !== 'work') return;\n return {\n type: 'sendMessage',\n idempotencyKey: `${context.ingress.id}:assess-work-completion`,\n role: 'work',\n message:\n `GitLab merge request !${context.mergeRequest.number} merged. Assess whether the linked Work item is complete. ` +\n 'Do not mark it Done solely because this merge request merged.',\n } as const;\n}\n\nfunction mergeRequestClosed(context: FactoryGitLabRuleContext) {\n if (!context.item || !context.mergeRequest || context.mergeRequest.merged || context.board !== 'review') return;\n return {\n type: 'transition',\n idempotencyKey: `${context.ingress.id}:merge-request-closed`,\n board: 'review',\n stage: 'canceled',\n message: {\n text:\n `GitLab merge request !${context.mergeRequest.number} was closed without merging; ` +\n 'this Review card was moved to Canceled.',\n },\n } as const;\n}\n\nexport const defaultGitLabRules = Object.freeze({\n issueOpened,\n issueUpdated: retriageIssue,\n issueClosed,\n issueCommented: retriageIssue,\n mergeRequestOpened: materializeMergeRequest,\n mergeRequestUpdated,\n mergeRequestCommented,\n mergeRequestMerged,\n mergeRequestClosed,\n} satisfies GitLabEventRules);\n\nexport function resolveGitLabRules(overrides?: GitLabRuleOverrides): GitLabEventRules {\n if (overrides !== undefined && (overrides === null || typeof overrides !== 'object' || Array.isArray(overrides))) {\n throw new Error('GitLab rules must be an object.');\n }\n const rules: Record<string, FactoryRuleHandler<FactoryGitLabRuleContext> | null> = { ...defaultGitLabRules };\n for (const key of Reflect.ownKeys(overrides ?? {})) {\n if (typeof key !== 'string' || !Object.hasOwn(defaultGitLabRules, key)) {\n throw new Error(`Unknown GitLab rule event: ${String(key)}.`);\n }\n const handler = overrides?.[key as FactoryGitLabEventName];\n if (handler !== undefined && handler !== null && typeof handler !== 'function') {\n throw new Error(`GitLab rule ${key} must be a function, null, or undefined.`);\n }\n if (handler !== undefined) rules[key] = handler;\n }\n return Object.freeze(rules) as GitLabEventRules;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciler.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/reconciler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,wBAAwB,CAAC;AACrF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAI9D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,eAAe,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"reconciler.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/reconciler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,wBAAwB,CAAC;AACrF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAI9D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,eAAe,GAAG,SAAS,CAqB7B"}
|