@contentrain/mcp 3.0.3 → 3.1.0

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.
Files changed (162) hide show
  1. package/README.md +6 -3
  2. package/dist/{annotations-C-tQVmot.mjs → annotations-CXHPnS-M.mjs} +8 -1
  3. package/dist/annotations-CXHPnS-M.mjs.map +1 -0
  4. package/dist/{apply-manager-BybvnUVC.mjs → apply-manager-DsNq7Zhm.mjs} +7 -7
  5. package/dist/{apply-manager-BybvnUVC.mjs.map → apply-manager-DsNq7Zhm.mjs.map} +1 -1
  6. package/dist/{astro-parser-Cb9uuBpW.mjs → astro-parser-dhFgc2wA.mjs} +3 -3
  7. package/dist/{astro-parser-Cb9uuBpW.mjs.map → astro-parser-dhFgc2wA.mjs.map} +1 -1
  8. package/dist/{availability-Dgcmvv99.mjs → availability-DYHNoP0_.mjs} +5 -1
  9. package/dist/availability-DYHNoP0_.mjs.map +1 -0
  10. package/dist/{branch-lifecycle-DhzHfzs3.d.mts → branch-lifecycle-DGlgjnC7.d.mts} +32 -2
  11. package/dist/branch-lifecycle-DGlgjnC7.d.mts.map +1 -0
  12. package/dist/{branch-lifecycle-B6PXZ2N7.mjs → branch-lifecycle-DUOoyNWn.mjs} +32 -4
  13. package/dist/branch-lifecycle-DUOoyNWn.mjs.map +1 -0
  14. package/dist/{compiler-B6hNQeCC.mjs → compiler-CR9F0wZZ.mjs} +2 -2
  15. package/dist/{compiler-B6hNQeCC.mjs.map → compiler-CR9F0wZZ.mjs.map} +1 -1
  16. package/dist/{compiler-sfc.cjs-8yY7b5bx.mjs → compiler-sfc.cjs-Cpexs92i.mjs} +2 -2
  17. package/dist/{compiler-sfc.cjs-8yY7b5bx.mjs.map → compiler-sfc.cjs-Cpexs92i.mjs.map} +1 -1
  18. package/dist/{config-VlRKRwAS.mjs → config-B8a4JBT1.mjs} +2 -2
  19. package/dist/{config-VlRKRwAS.mjs.map → config-B8a4JBT1.mjs.map} +1 -1
  20. package/dist/{content-manager-Dn4tqDw1.d.mts → content-manager-Bx94DXSF.d.mts} +2 -2
  21. package/dist/{content-manager-Dn4tqDw1.d.mts.map → content-manager-Bx94DXSF.d.mts.map} +1 -1
  22. package/dist/{context-C3x6I3cE.mjs → context-CxpTATh4.mjs} +7 -7
  23. package/dist/context-CxpTATh4.mjs.map +1 -0
  24. package/dist/core/apply-manager.mjs +10 -11
  25. package/dist/core/config.d.mts +1 -1
  26. package/dist/core/config.mjs +2 -2
  27. package/dist/core/content-manager.d.mts +1 -1
  28. package/dist/core/content-manager.mjs +3 -3
  29. package/dist/core/context.d.mts +1 -1
  30. package/dist/core/context.mjs +5 -6
  31. package/dist/core/contracts/index.d.mts +1 -1
  32. package/dist/core/doctor.mjs +8 -8
  33. package/dist/core/graph-builder.mjs +3 -3
  34. package/dist/core/meta-manager.mjs +2 -2
  35. package/dist/core/model-manager.d.mts +1 -1
  36. package/dist/core/model-manager.mjs +3 -3
  37. package/dist/core/ops/index.d.mts +17 -29
  38. package/dist/core/ops/index.d.mts.map +1 -1
  39. package/dist/core/ops/index.mjs +9 -6
  40. package/dist/core/overlay-reader.d.mts +1 -1
  41. package/dist/core/overlay-reader.mjs +1 -1
  42. package/dist/core/scan-config.mjs +2 -2
  43. package/dist/core/scanner.mjs +4 -4
  44. package/dist/core/validator/index.d.mts +1 -1
  45. package/dist/core/validator/index.mjs +5 -5
  46. package/dist/{detect-B0oXbQaP.mjs → detect-CI32ynpq.mjs} +2 -2
  47. package/dist/{detect-B0oXbQaP.mjs.map → detect-CI32ynpq.mjs.map} +1 -1
  48. package/dist/{doctor-DNPuGgcg.mjs → doctor-B7G0oFxO.mjs} +7 -7
  49. package/dist/{doctor-DNPuGgcg.mjs.map → doctor-B7G0oFxO.mjs.map} +1 -1
  50. package/dist/errors-BmLE-JSC.mjs +55 -0
  51. package/dist/errors-BmLE-JSC.mjs.map +1 -0
  52. package/dist/{errors-CvBS12e7.mjs → errors-DLkAWnzQ.mjs} +1 -1
  53. package/dist/{errors-CvBS12e7.mjs.map → errors-DLkAWnzQ.mjs.map} +1 -1
  54. package/dist/{fs-DLbVB-Ek.mjs → fs-DJv5G8uL.mjs} +1 -1
  55. package/dist/{fs-DLbVB-Ek.mjs.map → fs-DJv5G8uL.mjs.map} +1 -1
  56. package/dist/git/branch-lifecycle.d.mts +2 -2
  57. package/dist/git/branch-lifecycle.mjs +5 -5
  58. package/dist/git/errors.d.mts +30 -0
  59. package/dist/git/errors.d.mts.map +1 -0
  60. package/dist/git/errors.mjs +2 -0
  61. package/dist/git/identity.mjs +1 -1
  62. package/dist/git/reconcile.d.mts +49 -0
  63. package/dist/git/reconcile.d.mts.map +1 -0
  64. package/dist/git/reconcile.mjs +13 -0
  65. package/dist/git/transaction.d.mts +60 -15
  66. package/dist/git/transaction.d.mts.map +1 -1
  67. package/dist/git/transaction.mjs +10 -11
  68. package/dist/{graph-builder-BEocwW13.mjs → graph-builder-C9NS7y-a.mjs} +3 -3
  69. package/dist/{graph-builder-BEocwW13.mjs.map → graph-builder-C9NS7y-a.mjs.map} +1 -1
  70. package/dist/{id-BjhaIxTL.mjs → id-CjGMPP1k.mjs} +2 -2
  71. package/dist/{id-BjhaIxTL.mjs.map → id-CjGMPP1k.mjs.map} +1 -1
  72. package/dist/{identity-D8QoGxhT.mjs → identity-CxAB9Qb8.mjs} +1 -1
  73. package/dist/{identity-D8QoGxhT.mjs.map → identity-CxAB9Qb8.mjs.map} +1 -1
  74. package/dist/index-_HJVkDJa.d.mts +85 -0
  75. package/dist/index-_HJVkDJa.d.mts.map +1 -0
  76. package/dist/index.mjs +24 -22
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/{local-Db5X9mjZ.mjs → local-bnn6yrG7.mjs} +83 -8
  79. package/dist/local-bnn6yrG7.mjs.map +1 -0
  80. package/dist/{meta-manager-B_Se183X.mjs → meta-manager-g3shoZES.mjs} +2 -2
  81. package/dist/{meta-manager-B_Se183X.mjs.map → meta-manager-g3shoZES.mjs.map} +1 -1
  82. package/dist/{model-manager-DgyKMjLN.mjs → model-manager-DqwL8ptm.mjs} +66 -5
  83. package/dist/model-manager-DqwL8ptm.mjs.map +1 -0
  84. package/dist/{node-DUGiIkv1.mjs → node-CpLm3qr6.mjs} +1 -1
  85. package/dist/{node-DUGiIkv1.mjs.map → node-CpLm3qr6.mjs.map} +1 -1
  86. package/dist/{ops-BzbThweu.mjs → ops-BfrdZ6GK.mjs} +24 -34
  87. package/dist/ops-BfrdZ6GK.mjs.map +1 -0
  88. package/dist/{overlay-reader-CkU_pGXZ.mjs → overlay-reader-Bx1YxGXq.mjs} +1 -1
  89. package/dist/{overlay-reader-CkU_pGXZ.mjs.map → overlay-reader-Bx1YxGXq.mjs.map} +1 -1
  90. package/dist/{paths-CdPPWpbG.mjs → paths-C6_C1gLp.mjs} +1 -1
  91. package/dist/{paths-CdPPWpbG.mjs.map → paths-C6_C1gLp.mjs.map} +1 -1
  92. package/dist/providers/github/index.d.mts +10 -1
  93. package/dist/providers/github/index.d.mts.map +1 -1
  94. package/dist/providers/github/index.mjs +104 -4
  95. package/dist/providers/github/index.mjs.map +1 -1
  96. package/dist/providers/gitlab/index.d.mts +8 -1
  97. package/dist/providers/gitlab/index.d.mts.map +1 -1
  98. package/dist/providers/gitlab/index.mjs +15 -2
  99. package/dist/providers/gitlab/index.mjs.map +1 -1
  100. package/dist/providers/local/index.d.mts +26 -2
  101. package/dist/providers/local/index.d.mts.map +1 -1
  102. package/dist/providers/local/index.mjs +13 -12
  103. package/dist/reconcile-D5FTVW5z.mjs +1704 -0
  104. package/dist/reconcile-D5FTVW5z.mjs.map +1 -0
  105. package/dist/reconcile-M7KBZtdn.mjs +249 -0
  106. package/dist/reconcile-M7KBZtdn.mjs.map +1 -0
  107. package/dist/{scan-config-Dx49nCqk.mjs → scan-config-C5zzygeH.mjs} +2 -2
  108. package/dist/{scan-config-Dx49nCqk.mjs.map → scan-config-C5zzygeH.mjs.map} +1 -1
  109. package/dist/{scanner-BSvXjfkp.mjs → scanner-CEiT8Tgx.mjs} +7 -7
  110. package/dist/{scanner-BSvXjfkp.mjs.map → scanner-CEiT8Tgx.mjs.map} +1 -1
  111. package/dist/server/http/index.d.mts +1 -1
  112. package/dist/server/http/index.mjs +24 -22
  113. package/dist/server/http/index.mjs.map +1 -1
  114. package/dist/{server-B7QA0Q1M.mjs → server-BtzVY7yp.mjs} +343 -227
  115. package/dist/server-BtzVY7yp.mjs.map +1 -0
  116. package/dist/{server-CLPNnhYL.d.mts → server-SDsD0XGM.d.mts} +2 -2
  117. package/dist/{server-CLPNnhYL.d.mts.map → server-SDsD0XGM.d.mts.map} +1 -1
  118. package/dist/server.d.mts +1 -1
  119. package/dist/server.mjs +24 -22
  120. package/dist/{source-map-generator-DhjiQdV3.mjs → source-map-generator-Clb2Eqse.mjs} +1 -1
  121. package/dist/{source-map-generator-DhjiQdV3.mjs.map → source-map-generator-Clb2Eqse.mjs.map} +1 -1
  122. package/dist/{svelte-parser-CwySu9yn.mjs → svelte-parser-CBN7Jxb7.mjs} +3 -3
  123. package/dist/{svelte-parser-CwySu9yn.mjs.map → svelte-parser-CBN7Jxb7.mjs.map} +1 -1
  124. package/dist/templates/index.mjs +1 -1
  125. package/dist/{templates-CAkTIRkE.mjs → templates-BZbohJc8.mjs} +1 -1
  126. package/dist/{templates-CAkTIRkE.mjs.map → templates-BZbohJc8.mjs.map} +1 -1
  127. package/dist/testing/memory-provider.d.mts +26 -1
  128. package/dist/testing/memory-provider.d.mts.map +1 -1
  129. package/dist/testing/memory-provider.mjs +62 -2
  130. package/dist/testing/memory-provider.mjs.map +1 -1
  131. package/dist/tools/annotations.d.mts.map +1 -1
  132. package/dist/tools/annotations.mjs +1 -1
  133. package/dist/tools/availability.d.mts.map +1 -1
  134. package/dist/tools/availability.mjs +1 -1
  135. package/dist/{transaction-BW9ektWu.mjs → transaction-BxDiiakv.mjs} +128 -64
  136. package/dist/transaction-BxDiiakv.mjs.map +1 -0
  137. package/dist/tsx-parser-DOQpJVgK.mjs +2 -0
  138. package/dist/{tsx-parser-BvsK6lyG.mjs → tsx-parser-go5V9zoc.mjs} +1 -1
  139. package/dist/{tsx-parser-BvsK6lyG.mjs.map → tsx-parser-go5V9zoc.mjs.map} +1 -1
  140. package/dist/util/detect.mjs +2 -2
  141. package/dist/util/fs.mjs +1 -1
  142. package/dist/util/id.mjs +1 -1
  143. package/dist/{validator-0sJ9vh1j.mjs → validator-B2GhPM3L.mjs} +5 -6
  144. package/dist/{validator-0sJ9vh1j.mjs.map → validator-B2GhPM3L.mjs.map} +1 -1
  145. package/dist/{vue-parser-auedZiJG.mjs → vue-parser-5Mp8w-mb.mjs} +3 -3
  146. package/dist/{vue-parser-auedZiJG.mjs.map → vue-parser-5Mp8w-mb.mjs.map} +1 -1
  147. package/package.json +13 -5
  148. package/dist/annotations-C-tQVmot.mjs.map +0 -1
  149. package/dist/availability-Dgcmvv99.mjs.map +0 -1
  150. package/dist/branch-lifecycle-B6PXZ2N7.mjs.map +0 -1
  151. package/dist/branch-lifecycle-DhzHfzs3.d.mts.map +0 -1
  152. package/dist/context-C3x6I3cE.mjs.map +0 -1
  153. package/dist/local-Db5X9mjZ.mjs.map +0 -1
  154. package/dist/model-manager-DgyKMjLN.mjs.map +0 -1
  155. package/dist/ops-BzbThweu.mjs.map +0 -1
  156. package/dist/paths-CmVw5Cw2.mjs +0 -65
  157. package/dist/paths-CmVw5Cw2.mjs.map +0 -1
  158. package/dist/serialization-tmgfFBOh.mjs +0 -2
  159. package/dist/server-B7QA0Q1M.mjs.map +0 -1
  160. package/dist/transaction-BW9ektWu.mjs.map +0 -1
  161. package/dist/tsx-parser-Byc7HlJ8.mjs +0 -2
  162. /package/dist/{index-BWbTJlXm.d.mts → index-ByrVsRJE.d.mts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["listBranchesOp","getDefaultBranchOp","createBranchOp","deleteBranchOp","getBranchDiffOp","mergeBranchOp","isMergedOp"],"sources":["../../../src/providers/gitlab/capabilities.ts","../../../src/providers/gitlab/apply-plan.ts","../../../src/providers/gitlab/branch-ops.ts","../../../src/providers/gitlab/reader.ts","../../../src/providers/gitlab/provider.ts","../../../src/providers/gitlab/factory.ts","../../../src/providers/gitlab/types.ts"],"sourcesContent":["import type { ProviderCapabilities } from '../../core/contracts/index.js'\n\n/**\n * Capability set for GitLabProvider.\n *\n * GitLab over REST has no working tree, so local worktree features,\n * source-file access and AST scans are unavailable. Push, merge and\n * branch-protection detection all work over the API. GitLab enforces\n * merges through merge requests, so `pullRequestFallback` is `true` —\n * `mergeBranch` opens an MR and auto-accepts it to match GitHub's\n * `repos.merge` semantics while still leaving an audit trail.\n */\nexport const GITLAB_CAPABILITIES: ProviderCapabilities = {\n localWorktree: false,\n sourceRead: false,\n sourceWrite: false,\n pushRemote: true,\n branchProtection: true,\n pullRequestFallback: true,\n astScan: false,\n}\n","import { CONTENTRAIN_BRANCH } from '@contentrain/types'\nimport type { ApplyPlanInput, Commit, FileChange } from '../../core/contracts/index.js'\nimport { isNotFoundError, resolveRepoPath } from '../shared/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\ntype CommitActionType = 'create' | 'update' | 'delete'\n\ninterface CommitAction {\n action: CommitActionType\n filePath: string\n content?: string\n encoding?: 'text' | 'base64'\n}\n\n/**\n * Apply a plan to a GitLab repository as a single atomic commit via the\n * Commits API. High-level flow:\n *\n * 1. Check whether the target branch exists. If it does not, GitLab's\n * `startBranch` option forks a new branch from `input.base` (or the\n * project's default branch) as part of the same commit.\n * 2. For each `FileChange`, figure out the right GitLab action verb\n * (`create` vs `update` vs `delete`) by probing the path against the\n * resolved ref. GitLab validates this server-side and returns a 400\n * for mismatches — we avoid the round trip by getting it right up\n * front.\n * 3. POST `/repository/commits` once with the full action set. No\n * working tree, no multi-call tree-assembly dance — GitLab exposes\n * a richer primitive than the GitHub Git Data API for this case.\n *\n * The commit is durable as soon as the call returns; GitLab's ref\n * update happens inside the same request.\n */\nexport async function applyPlanToGitLab(\n client: GitLabClient,\n project: ProjectRef,\n input: ApplyPlanInput,\n): Promise<Commit> {\n const branchExists = await branchHasRef(client, project, input.branch)\n // Invariant: fork from the Contentrain content-tracking branch, not\n // the repo's default branch. See ApplyPlanInput.base docstring in\n // @contentrain/types.\n const baseBranch = input.base ?? CONTENTRAIN_BRANCH\n\n // Actions are computed against the HEAD of the feature branch when it\n // exists, otherwise against the fork point (baseBranch). GitLab\n // treats `create` / `update` / `delete` as a strict check against the\n // path's existence at that ref.\n const refForActionResolution = branchExists ? input.branch : baseBranch\n const rawActions = await Promise.all(\n input.changes.map(change => resolveAction(client, project, refForActionResolution, change)),\n )\n const actions = rawActions.filter((a): a is CommitAction => a !== null)\n\n if (actions.length === 0) {\n // Nothing to apply. Callers don't generally build empty plans, but\n // if they do we short-circuit before touching the API.\n throw new Error('applyPlanToGitLab: plan contained no applicable actions')\n }\n\n const options: Record<string, unknown> = {\n authorName: input.author.name,\n authorEmail: input.author.email,\n }\n if (!branchExists) {\n options.startBranch = baseBranch\n }\n\n const response = await client.Commits.create(\n project.projectId,\n input.branch,\n input.message,\n actions,\n options,\n )\n\n // Gitbeaker's generic-heavy response type widens string fields to\n // `string | Camelize<…>` — at runtime they are always strings under\n // the default (non-camelize) response mode we use. Cast narrows the\n // shape we actually touch.\n const commit = response as {\n id: string\n message?: string\n author_name?: string\n author_email?: string\n created_at?: string\n }\n const commitTimestamp = toIsoTimestamp(commit.created_at) ?? new Date().toISOString()\n return {\n sha: commit.id,\n message: commit.message ?? input.message,\n author: {\n name: commit.author_name ?? input.author.name,\n email: commit.author_email ?? input.author.email,\n },\n timestamp: commitTimestamp,\n }\n}\n\nasync function resolveAction(\n client: GitLabClient,\n project: ProjectRef,\n ref: string,\n change: FileChange,\n): Promise<CommitAction | null> {\n const filePath = resolveRepoPath(project.contentRoot, change.path)\n const exists = await fileExistsAtRef(client, project, filePath, ref)\n\n if (change.content === null) {\n // Filter out deletes against non-existent files — GitLab returns\n // 400 otherwise. The plan author asked us to \"make this file not\n // exist\", which is already satisfied.\n if (!exists) return null\n return { action: 'delete', filePath }\n }\n\n return {\n action: exists ? 'update' : 'create',\n filePath,\n content: change.content,\n encoding: 'text',\n }\n}\n\nasync function branchHasRef(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n): Promise<boolean> {\n try {\n await client.Branches.show(project.projectId, branch)\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n}\n\nasync function fileExistsAtRef(\n client: GitLabClient,\n project: ProjectRef,\n filePath: string,\n ref: string,\n): Promise<boolean> {\n try {\n await client.RepositoryFiles.show(project.projectId, filePath, ref)\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n}\n\n\nfunction toIsoTimestamp(raw: unknown): string | null {\n if (typeof raw !== 'string') return null\n const date = new Date(raw)\n if (Number.isNaN(date.getTime())) return null\n return date.toISOString()\n}\n\n","import { CONTENTRAIN_BRANCH } from '@contentrain/types'\nimport type { Branch, FileDiff, MergeResult } from '../../core/contracts/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * Branch / merge / diff helpers backed by the GitLab REST API.\n *\n * Pure functions so they can be composed into `GitLabProvider` or used\n * standalone. 404s collapse to empty-ish results where that matches\n * the `RepoProvider` contract (missing branch prefix → `[]`).\n *\n * Merge semantics: GitLab does not expose a direct branch-to-branch\n * merge endpoint. Every merge flows through a merge request, so\n * `mergeBranch` opens an MR and immediately accepts it. The resulting\n * `MergeResult` mirrors GitHub's `repos.merge` return shape — callers\n * see the same `{ merged, sha, pullRequestUrl }` envelope either way,\n * with the MR URL available for audit.\n */\n\nexport async function getDefaultBranch(\n client: GitLabClient,\n project: ProjectRef,\n): Promise<string> {\n const p = await client.Projects.show(project.projectId) as { default_branch?: string }\n return p.default_branch ?? 'main'\n}\n\nexport async function listBranches(\n client: GitLabClient,\n project: ProjectRef,\n prefix?: string,\n): Promise<Branch[]> {\n // Gitbeaker's `all` supports a `search` string (substring match). For\n // Contentrain's `cr/*` naming the substring case is equivalent to a\n // prefix because the slug never appears anywhere except at the start.\n // Server-side filter + client-side prefix enforcement keeps us\n // correct even if the substring coincidence breaks someday.\n const options: Record<string, unknown> = {\n perPage: 100,\n maxPages: 10,\n }\n if (prefix) options.search = prefix\n\n const rawBranches = await client.Branches.all(project.projectId, options)\n const branches = Array.isArray(rawBranches) ? rawBranches : []\n\n return branches\n .filter((b: { name: string }) => !prefix || b.name.startsWith(prefix))\n .map((b: { name: string, commit: { id: string }, protected?: boolean }) => ({\n name: b.name,\n sha: b.commit.id,\n protected: b.protected ?? false,\n }))\n}\n\nexport async function createBranch(\n client: GitLabClient,\n project: ProjectRef,\n name: string,\n fromRef: string,\n): Promise<void> {\n await client.Branches.create(project.projectId, name, fromRef)\n}\n\nexport async function deleteBranch(\n client: GitLabClient,\n project: ProjectRef,\n name: string,\n): Promise<void> {\n await client.Branches.remove(project.projectId, name)\n}\n\nexport async function getBranchDiff(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n base: string,\n): Promise<FileDiff[]> {\n const response = await client.Repositories.compare(\n project.projectId,\n base,\n branch,\n { straight: false },\n )\n const diffs = Array.isArray(response.diffs) ? response.diffs : []\n return diffs.map((d: { new_path: string, old_path: string, new_file?: boolean, deleted_file?: boolean }) => ({\n path: d.new_file ? d.new_path : d.old_path,\n status: d.deleted_file ? 'removed' : d.new_file ? 'added' : 'modified',\n before: null,\n after: null,\n }))\n}\n\nexport async function mergeBranch(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n opts?: { removeSourceBranch?: boolean },\n): Promise<MergeResult> {\n // 1. Open MR — GitLab rejects create when source === target or when\n // an MR is already open for this pair. Let the error propagate in\n // those cases; the caller retries or surfaces the message.\n const mr = await client.MergeRequests.create(\n project.projectId,\n branch,\n into,\n `[contentrain] merge ${branch} → ${into}`,\n { removeSourceBranch: false },\n )\n\n // 2. Accept the MR immediately. `shouldRemoveSourceBranch: false` keeps\n // GitLab's async server-side deletion out of the accept call — the\n // explicit cleanup below owns it, so the outcome is deterministic and\n // reported via `MergeResult.remote`.\n const accepted = await client.MergeRequests.accept(\n project.projectId,\n (mr as { iid: number }).iid,\n { shouldRemoveSourceBranch: false, squash: false },\n )\n\n const mergeSha = (accepted as { merge_commit_sha?: string | null, sha?: string | null }).merge_commit_sha\n ?? (accepted as { sha?: string | null }).sha\n ?? null\n const webUrl = (mr as { web_url?: string }).web_url ?? null\n const merged = mergeSha !== null\n\n // 3. Source-branch cleanup — OPT-IN (`removeSourceBranch: true`). Like git\n // and GitLab's own merge, `mergeBranch` leaves the source alone by\n // default. Even when opted in, a long-lived branch is NEVER deleted:\n // not the merge target (`into`), not the `contentrain` content branch,\n // not the project's default branch. Mirrors the LocalProvider guard;\n // defends against head/base confusion and contentrain↔default flows.\n // Never throws — the merge itself already succeeded.\n const remote = merged ? await cleanupSourceBranch(client, project, branch, into, opts) : undefined\n\n return { merged, sha: mergeSha, pullRequestUrl: webUrl, ...(remote ? { remote } : {}) }\n}\n\n/**\n * Opt-in ({@link mergeBranch} `removeSourceBranch: true`) deletion of the\n * merged source branch, with the same guard as the GitHub provider and the\n * LocalProvider: never delete the merge target, the `contentrain` content\n * branch, or the project default branch — even when opted in. Fail-safe\n * skips the delete if the default branch cannot be resolved. Never throws.\n */\nasync function cleanupSourceBranch(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n opts?: { removeSourceBranch?: boolean },\n): Promise<MergeResult['remote'] | undefined> {\n if (opts?.removeSourceBranch !== true) return undefined\n\n if (branch === into || branch === CONTENTRAIN_BRANCH) {\n return { deleted: false, skipped: 'protected' }\n }\n try {\n if (branch === await getDefaultBranch(client, project)) {\n return { deleted: false, skipped: 'protected' }\n }\n } catch {\n return { deleted: false, skipped: 'protected' }\n }\n\n try {\n await deleteBranch(client, project, branch)\n return { deleted: true }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return /404|not found/i.test(message)\n ? { deleted: false, skipped: 'not-found' }\n : { deleted: false, warning: `Could not delete \"${branch}\": ${message}` }\n }\n}\n\nexport async function isMerged(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n): Promise<boolean> {\n // compare(from=into, to=branch) — commits list is empty when branch\n // is fully contained in into (i.e. already merged).\n const response = await client.Repositories.compare(\n project.projectId,\n into,\n branch,\n { straight: false },\n )\n const commits = Array.isArray(response.commits) ? response.commits : []\n return commits.length === 0\n}\n","import type { RepoReader } from '../../core/contracts/index.js'\nimport { isNotFoundError, resolveRepoPath } from '../shared/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * GitLabReader — `RepoReader` backed by the GitLab REST API.\n *\n * File reads go through `RepositoryFiles.showRaw`, which returns the\n * file content as UTF-8 text (or a `Blob` on browser/edge runtimes we\n * decode with `.text()`). Directory listings go through\n * `Repositories.allRepositoryTrees`. `fileExists` tries the file\n * endpoint first and falls back to a tree listing so directories\n * resolve to `true` as well — matching LocalReader / GitHubReader.\n *\n * `ref` is forwarded verbatim and may be a branch name, tag name or\n * commit SHA. Callers should always pass the explicit `contentrain`\n * tracking branch; GitLab's default resolution is the project's\n * default branch, which is usually wrong for Contentrain flows.\n */\nexport class GitLabReader implements RepoReader {\n constructor(\n private readonly client: GitLabClient,\n private readonly project: ProjectRef,\n ) {}\n\n async readFile(path: string, ref?: string): Promise<string> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n const raw = await this.client.RepositoryFiles.showRaw(\n this.project.projectId,\n repoPath,\n resolvedRef,\n )\n if (typeof raw === 'string') return raw\n // Browser / edge runtimes return a Blob; decode as UTF-8.\n return (raw as Blob).text()\n }\n\n async listDirectory(path: string, ref?: string): Promise<string[]> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n try {\n const entries = await this.client.Repositories.allRepositoryTrees(\n this.project.projectId,\n {\n path: repoPath,\n ref: resolvedRef,\n perPage: 100,\n recursive: false,\n },\n )\n return Array.isArray(entries) ? entries.map(e => e.name) : []\n } catch (error) {\n if (isNotFoundError(error)) return []\n throw error\n }\n }\n\n async fileExists(path: string, ref?: string): Promise<boolean> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n\n // 1. Try as a file — cheap and most common case for Contentrain.\n try {\n await this.client.RepositoryFiles.show(\n this.project.projectId,\n repoPath,\n resolvedRef,\n )\n return true\n } catch (error) {\n if (!isNotFoundError(error)) throw error\n }\n\n // 2. Fall back to a tree listing — directories and empty dirs show\n // up here. Any non-404 result means the path resolves.\n try {\n const entries = await this.client.Repositories.allRepositoryTrees(\n this.project.projectId,\n { path: repoPath, ref: resolvedRef, perPage: 1 },\n )\n return Array.isArray(entries) && entries.length > 0\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n }\n\n private async resolveDefaultRef(): Promise<string> {\n const project = await this.client.Projects.show(this.project.projectId) as { default_branch?: string }\n return project.default_branch ?? 'main'\n }\n}\n\n","import type {\n ApplyPlanInput,\n Branch,\n Commit,\n FileDiff,\n MergeResult,\n ProviderCapabilities,\n RepoProvider,\n} from '../../core/contracts/index.js'\nimport { applyPlanToGitLab } from './apply-plan.js'\nimport {\n createBranch as createBranchOp,\n deleteBranch as deleteBranchOp,\n getBranchDiff as getBranchDiffOp,\n getDefaultBranch as getDefaultBranchOp,\n isMerged as isMergedOp,\n listBranches as listBranchesOp,\n mergeBranch as mergeBranchOp,\n} from './branch-ops.js'\nimport { GITLAB_CAPABILITIES } from './capabilities.js'\nimport type { GitLabClient } from './client.js'\nimport { GitLabReader } from './reader.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * GitLabProvider — `RepoProvider` backed by the gitbeaker-driven GitLab\n * REST API.\n *\n * Transport-agnostic: the provider only talks to a `GitLabClient`\n * (a `@gitbeaker/rest` `Gitlab` instance). `createGitLabProvider` in\n * `factory.ts` wraps the dynamic import so consumers never touch\n * `@gitbeaker/rest` directly unless they want to.\n *\n * Capability gaps versus `GitHubProvider`: none — both providers\n * expose the same set. GitLab's merge flow routes through an MR under\n * the hood, but `mergeBranch` presents the same `MergeResult` shape.\n */\nexport class GitLabProvider implements RepoProvider {\n readonly capabilities: ProviderCapabilities = GITLAB_CAPABILITIES\n private readonly reader: GitLabReader\n\n constructor(\n private readonly client: GitLabClient,\n public readonly project: ProjectRef,\n ) {\n this.reader = new GitLabReader(client, project)\n }\n\n readFile(path: string, ref?: string): Promise<string> {\n return this.reader.readFile(path, ref)\n }\n listDirectory(path: string, ref?: string): Promise<string[]> {\n return this.reader.listDirectory(path, ref)\n }\n fileExists(path: string, ref?: string): Promise<boolean> {\n return this.reader.fileExists(path, ref)\n }\n\n applyPlan(input: ApplyPlanInput): Promise<Commit> {\n return applyPlanToGitLab(this.client, this.project, input)\n }\n\n listBranches(prefix?: string): Promise<Branch[]> {\n return listBranchesOp(this.client, this.project, prefix)\n }\n async createBranch(name: string, fromRef?: string): Promise<void> {\n const resolved = fromRef ?? await getDefaultBranchOp(this.client, this.project)\n await createBranchOp(this.client, this.project, name, resolved)\n }\n deleteBranch(name: string): Promise<void> {\n return deleteBranchOp(this.client, this.project, name)\n }\n async getBranchDiff(branch: string, base?: string): Promise<FileDiff[]> {\n const resolved = base ?? await getDefaultBranchOp(this.client, this.project)\n return getBranchDiffOp(this.client, this.project, branch, resolved)\n }\n mergeBranch(branch: string, into: string, opts?: { removeSourceBranch?: boolean }): Promise<MergeResult> {\n return mergeBranchOp(this.client, this.project, branch, into, opts)\n }\n async isMerged(branch: string, into?: string): Promise<boolean> {\n const resolved = into ?? await getDefaultBranchOp(this.client, this.project)\n return isMergedOp(this.client, this.project, branch, resolved)\n }\n getDefaultBranch(): Promise<string> {\n return getDefaultBranchOp(this.client, this.project)\n }\n}\n","import type { GitLabClient } from './client.js'\nimport { GitLabProvider } from './provider.js'\nimport type { GitLabAuth, ProjectRef } from './types.js'\n\n/**\n * Create a gitbeaker-backed `GitLabClient` from an auth configuration.\n *\n * The `@gitbeaker/rest` module is imported dynamically so it stays a\n * pure optional peer dependency — self-hosted MCP on stdio runs fine\n * without it. If the module is not installed, the import throws with\n * a helpful hint pointing the operator at the peer dependency.\n *\n * Supported auth types: `pat`, `oauth`, `job`. All three are thin\n * wrappers over gitbeaker's `token`, `oauthToken`, and `jobToken`\n * constructor options.\n */\nexport async function createGitLabClient(\n auth: GitLabAuth,\n host?: string,\n): Promise<GitLabClient> {\n let GitlabCtor: typeof import('@gitbeaker/rest').Gitlab\n try {\n ({ Gitlab: GitlabCtor } = await import('@gitbeaker/rest'))\n } catch (error) {\n throw new Error(\n '@gitbeaker/rest is required for the GitLabProvider but could not be loaded. '\n + 'Install it as a peer dependency: pnpm add @gitbeaker/rest.',\n { cause: error },\n )\n }\n\n const config: Record<string, unknown> = host ? { host } : {}\n switch (auth.type) {\n case 'pat':\n config.token = auth.token\n break\n case 'oauth':\n config.oauthToken = auth.oauthToken\n break\n case 'job':\n config.jobToken = auth.jobToken\n break\n default: {\n const { type } = auth as { type: string }\n throw new Error(`Unsupported GitLab auth type: \"${type}\"`)\n }\n }\n\n return new GitlabCtor(config) as GitLabClient\n}\n\n/**\n * Factory for the full provider — instantiates a gitbeaker client and\n * wraps it in a `GitLabProvider`. Consumers who already hold a\n * gitbeaker instance (HTTP server injecting shared clients, tests,\n * etc.) should instantiate `GitLabProvider` directly instead.\n */\nexport async function createGitLabProvider(\n opts: { auth: GitLabAuth, project: ProjectRef },\n): Promise<GitLabProvider> {\n const client = await createGitLabClient(opts.auth, opts.project.host)\n return new GitLabProvider(client, opts.project)\n}\n","import type { CommitAuthor } from '../../core/contracts/index.js'\n\n/**\n * A reference to a GitLab project.\n *\n * `projectId` accepts the numeric project ID or a URL-encoded path\n * (`namespace/project`). Gitbeaker URL-encodes string paths internally,\n * so either form is fine.\n *\n * `contentRoot` is the repo-relative directory prefix where Contentrain\n * content lives. For a flat content repo it stays `''`; for a monorepo\n * where Contentrain sits under `apps/web/.contentrain/` it holds that\n * prefix. All reader/writer paths are joined against it.\n *\n * `host` points at a self-hosted GitLab instance. Leave undefined to\n * use `https://gitlab.com` (gitbeaker's default).\n */\nexport interface ProjectRef {\n projectId: string | number\n contentRoot?: string\n host?: string\n}\n\n/**\n * Authentication options for the GitLab provider.\n *\n * - `pat` — personal access token with the `api` scope. Simplest for\n * self-hosted MCP or CI runners.\n * - `oauth` — OAuth2 token. Used when the runner is driven by a GitLab\n * OAuth flow.\n * - `job` — CI job token (`CI_JOB_TOKEN`). Scoped to the running\n * pipeline; useful for pipeline-driven content updates.\n */\nexport type GitLabAuth =\n | { type: 'pat', token: string }\n | { type: 'oauth', oauthToken: string }\n | { type: 'job', jobToken: string }\n\n/** Default author used when a call does not provide one. */\nexport const DEFAULT_GITLAB_AUTHOR: CommitAuthor = {\n name: 'Contentrain',\n email: 'ai@contentrain.io',\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,MAAa,sBAA4C;CACvD,eAAe;CACf,YAAY;CACZ,aAAa;CACb,YAAY;CACZ,kBAAkB;CAClB,qBAAqB;CACrB,SAAS;CACV;;;;;;;;;;;;;;;;;;;;;;ACcD,eAAsB,kBACpB,QACA,SACA,OACiB;CACjB,MAAM,eAAe,MAAM,aAAa,QAAQ,SAAS,MAAM,OAAO;CAItE,MAAM,aAAa,MAAM,QAAQ;CAMjC,MAAM,yBAAyB,eAAe,MAAM,SAAS;CAI7D,MAAM,WAHa,MAAM,QAAQ,IAC/B,MAAM,QAAQ,KAAI,WAAU,cAAc,QAAQ,SAAS,wBAAwB,OAAO,CAAC,CAC5F,EAC0B,QAAQ,MAAyB,MAAM,KAAK;AAEvE,KAAI,QAAQ,WAAW,EAGrB,OAAM,IAAI,MAAM,0DAA0D;CAG5E,MAAM,UAAmC;EACvC,YAAY,MAAM,OAAO;EACzB,aAAa,MAAM,OAAO;EAC3B;AACD,KAAI,CAAC,aACH,SAAQ,cAAc;CAexB,MAAM,SAZW,MAAM,OAAO,QAAQ,OACpC,QAAQ,WACR,MAAM,QACN,MAAM,SACN,SACA,QACD;CAaD,MAAM,kBAAkB,eAAe,OAAO,WAAW,qBAAI,IAAI,MAAM,EAAC,aAAa;AACrF,QAAO;EACL,KAAK,OAAO;EACZ,SAAS,OAAO,WAAW,MAAM;EACjC,QAAQ;GACN,MAAM,OAAO,eAAe,MAAM,OAAO;GACzC,OAAO,OAAO,gBAAgB,MAAM,OAAO;GAC5C;EACD,WAAW;EACZ;;AAGH,eAAe,cACb,QACA,SACA,KACA,QAC8B;CAC9B,MAAM,WAAW,gBAAgB,QAAQ,aAAa,OAAO,KAAK;CAClE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,SAAS,UAAU,IAAI;AAEpE,KAAI,OAAO,YAAY,MAAM;AAI3B,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO;GAAE,QAAQ;GAAU;GAAU;;AAGvC,QAAO;EACL,QAAQ,SAAS,WAAW;EAC5B;EACA,SAAS,OAAO;EAChB,UAAU;EACX;;AAGH,eAAe,aACb,QACA,SACA,QACkB;AAClB,KAAI;AACF,QAAM,OAAO,SAAS,KAAK,QAAQ,WAAW,OAAO;AACrD,SAAO;UACA,OAAO;AACd,MAAI,gBAAgB,MAAM,CAAE,QAAO;AACnC,QAAM;;;AAIV,eAAe,gBACb,QACA,SACA,UACA,KACkB;AAClB,KAAI;AACF,QAAM,OAAO,gBAAgB,KAAK,QAAQ,WAAW,UAAU,IAAI;AACnE,SAAO;UACA,OAAO;AACd,MAAI,gBAAgB,MAAM,CAAE,QAAO;AACnC,QAAM;;;AAKV,SAAS,eAAe,KAA6B;AACnD,KAAI,OAAO,QAAQ,SAAU,QAAO;CACpC,MAAM,OAAO,IAAI,KAAK,IAAI;AAC1B,KAAI,OAAO,MAAM,KAAK,SAAS,CAAC,CAAE,QAAO;AACzC,QAAO,KAAK,aAAa;;;;;;;;;;;;;;;;;;AC3I3B,eAAsB,iBACpB,QACA,SACiB;AAEjB,SADU,MAAM,OAAO,SAAS,KAAK,QAAQ,UAAU,EAC9C,kBAAkB;;AAG7B,eAAsB,aACpB,QACA,SACA,QACmB;CAMnB,MAAM,UAAmC;EACvC,SAAS;EACT,UAAU;EACX;AACD,KAAI,OAAQ,SAAQ,SAAS;CAE7B,MAAM,cAAc,MAAM,OAAO,SAAS,IAAI,QAAQ,WAAW,QAAQ;AAGzE,SAFiB,MAAM,QAAQ,YAAY,GAAG,cAAc,EAAE,EAG3D,QAAQ,MAAwB,CAAC,UAAU,EAAE,KAAK,WAAW,OAAO,CAAC,CACrE,KAAK,OAAsE;EAC1E,MAAM,EAAE;EACR,KAAK,EAAE,OAAO;EACd,WAAW,EAAE,aAAa;EAC3B,EAAE;;AAGP,eAAsB,aACpB,QACA,SACA,MACA,SACe;AACf,OAAM,OAAO,SAAS,OAAO,QAAQ,WAAW,MAAM,QAAQ;;AAGhE,eAAsB,aACpB,QACA,SACA,MACe;AACf,OAAM,OAAO,SAAS,OAAO,QAAQ,WAAW,KAAK;;AAGvD,eAAsB,cACpB,QACA,SACA,QACA,MACqB;CACrB,MAAM,WAAW,MAAM,OAAO,aAAa,QACzC,QAAQ,WACR,MACA,QACA,EAAE,UAAU,OAAO,CACpB;AAED,SADc,MAAM,QAAQ,SAAS,MAAM,GAAG,SAAS,QAAQ,EAAE,EACpD,KAAK,OAA2F;EAC3G,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE;EAClC,QAAQ,EAAE,eAAe,YAAY,EAAE,WAAW,UAAU;EAC5D,QAAQ;EACR,OAAO;EACR,EAAE;;AAGL,eAAsB,YACpB,QACA,SACA,QACA,MACA,MACsB;CAItB,MAAM,KAAK,MAAM,OAAO,cAAc,OACpC,QAAQ,WACR,QACA,MACA,uBAAuB,OAAO,KAAK,QACnC,EAAE,oBAAoB,OAAO,CAC9B;CAMD,MAAM,WAAW,MAAM,OAAO,cAAc,OAC1C,QAAQ,WACP,GAAuB,KACxB;EAAE,0BAA0B;EAAO,QAAQ;EAAO,CACnD;CAED,MAAM,WAAY,SAAuE,oBACnF,SAAqC,OACtC;CACL,MAAM,SAAU,GAA4B,WAAW;CACvD,MAAM,SAAS,aAAa;CAS5B,MAAM,SAAS,SAAS,MAAM,oBAAoB,QAAQ,SAAS,QAAQ,MAAM,KAAK,GAAG,KAAA;AAEzF,QAAO;EAAE;EAAQ,KAAK;EAAU,gBAAgB;EAAQ,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;EAAG;;;;;;;;;AAUzF,eAAe,oBACb,QACA,SACA,QACA,MACA,MAC4C;AAC5C,KAAI,MAAM,uBAAuB,KAAM,QAAO,KAAA;AAE9C,KAAI,WAAW,QAAQ,WAAW,mBAChC,QAAO;EAAE,SAAS;EAAO,SAAS;EAAa;AAEjD,KAAI;AACF,MAAI,WAAW,MAAM,iBAAiB,QAAQ,QAAQ,CACpD,QAAO;GAAE,SAAS;GAAO,SAAS;GAAa;SAE3C;AACN,SAAO;GAAE,SAAS;GAAO,SAAS;GAAa;;AAGjD,KAAI;AACF,QAAM,aAAa,QAAQ,SAAS,OAAO;AAC3C,SAAO,EAAE,SAAS,MAAM;UACjB,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,SAAO,iBAAiB,KAAK,QAAQ,GACjC;GAAE,SAAS;GAAO,SAAS;GAAa,GACxC;GAAE,SAAS;GAAO,SAAS,qBAAqB,OAAO,KAAK;GAAW;;;AAI/E,eAAsB,SACpB,QACA,SACA,QACA,MACkB;CAGlB,MAAM,WAAW,MAAM,OAAO,aAAa,QACzC,QAAQ,WACR,MACA,QACA,EAAE,UAAU,OAAO,CACpB;AAED,SADgB,MAAM,QAAQ,SAAS,QAAQ,GAAG,SAAS,UAAU,EAAE,EACxD,WAAW;;;;;;;;;;;;;;;;;;;AC7K5B,IAAa,eAAb,MAAgD;CAC9C,YACE,QACA,SACA;AAFiB,OAAA,SAAA;AACA,OAAA,UAAA;;CAGnB,MAAM,SAAS,MAAc,KAA+B;EAC1D,MAAM,WAAW,gBAAgB,KAAK,QAAQ,aAAa,KAAK;EAChE,MAAM,cAAc,OAAO,MAAM,KAAK,mBAAmB;EACzD,MAAM,MAAM,MAAM,KAAK,OAAO,gBAAgB,QAC5C,KAAK,QAAQ,WACb,UACA,YACD;AACD,MAAI,OAAO,QAAQ,SAAU,QAAO;AAEpC,SAAQ,IAAa,MAAM;;CAG7B,MAAM,cAAc,MAAc,KAAiC;EACjE,MAAM,WAAW,gBAAgB,KAAK,QAAQ,aAAa,KAAK;EAChE,MAAM,cAAc,OAAO,MAAM,KAAK,mBAAmB;AACzD,MAAI;GACF,MAAM,UAAU,MAAM,KAAK,OAAO,aAAa,mBAC7C,KAAK,QAAQ,WACb;IACE,MAAM;IACN,KAAK;IACL,SAAS;IACT,WAAW;IACZ,CACF;AACD,UAAO,MAAM,QAAQ,QAAQ,GAAG,QAAQ,KAAI,MAAK,EAAE,KAAK,GAAG,EAAE;WACtD,OAAO;AACd,OAAI,gBAAgB,MAAM,CAAE,QAAO,EAAE;AACrC,SAAM;;;CAIV,MAAM,WAAW,MAAc,KAAgC;EAC7D,MAAM,WAAW,gBAAgB,KAAK,QAAQ,aAAa,KAAK;EAChE,MAAM,cAAc,OAAO,MAAM,KAAK,mBAAmB;AAGzD,MAAI;AACF,SAAM,KAAK,OAAO,gBAAgB,KAChC,KAAK,QAAQ,WACb,UACA,YACD;AACD,UAAO;WACA,OAAO;AACd,OAAI,CAAC,gBAAgB,MAAM,CAAE,OAAM;;AAKrC,MAAI;GACF,MAAM,UAAU,MAAM,KAAK,OAAO,aAAa,mBAC7C,KAAK,QAAQ,WACb;IAAE,MAAM;IAAU,KAAK;IAAa,SAAS;IAAG,CACjD;AACD,UAAO,MAAM,QAAQ,QAAQ,IAAI,QAAQ,SAAS;WAC3C,OAAO;AACd,OAAI,gBAAgB,MAAM,CAAE,QAAO;AACnC,SAAM;;;CAIV,MAAc,oBAAqC;AAEjD,UADgB,MAAM,KAAK,OAAO,SAAS,KAAK,KAAK,QAAQ,UAAU,EACxD,kBAAkB;;;;;;;;;;;;;;;;;;ACtDrC,IAAa,iBAAb,MAAoD;CAClD,eAA8C;CAC9C;CAEA,YACE,QACA,SACA;AAFiB,OAAA,SAAA;AACD,OAAA,UAAA;AAEhB,OAAK,SAAS,IAAI,aAAa,QAAQ,QAAQ;;CAGjD,SAAS,MAAc,KAA+B;AACpD,SAAO,KAAK,OAAO,SAAS,MAAM,IAAI;;CAExC,cAAc,MAAc,KAAiC;AAC3D,SAAO,KAAK,OAAO,cAAc,MAAM,IAAI;;CAE7C,WAAW,MAAc,KAAgC;AACvD,SAAO,KAAK,OAAO,WAAW,MAAM,IAAI;;CAG1C,UAAU,OAAwC;AAChD,SAAO,kBAAkB,KAAK,QAAQ,KAAK,SAAS,MAAM;;CAG5D,aAAa,QAAoC;AAC/C,SAAOA,aAAe,KAAK,QAAQ,KAAK,SAAS,OAAO;;CAE1D,MAAM,aAAa,MAAc,SAAiC;EAChE,MAAM,WAAW,WAAW,MAAMC,iBAAmB,KAAK,QAAQ,KAAK,QAAQ;AAC/E,QAAMC,aAAe,KAAK,QAAQ,KAAK,SAAS,MAAM,SAAS;;CAEjE,aAAa,MAA6B;AACxC,SAAOC,aAAe,KAAK,QAAQ,KAAK,SAAS,KAAK;;CAExD,MAAM,cAAc,QAAgB,MAAoC;EACtE,MAAM,WAAW,QAAQ,MAAMF,iBAAmB,KAAK,QAAQ,KAAK,QAAQ;AAC5E,SAAOG,cAAgB,KAAK,QAAQ,KAAK,SAAS,QAAQ,SAAS;;CAErE,YAAY,QAAgB,MAAc,MAA+D;AACvG,SAAOC,YAAc,KAAK,QAAQ,KAAK,SAAS,QAAQ,MAAM,KAAK;;CAErE,MAAM,SAAS,QAAgB,MAAiC;EAC9D,MAAM,WAAW,QAAQ,MAAMJ,iBAAmB,KAAK,QAAQ,KAAK,QAAQ;AAC5E,SAAOK,SAAW,KAAK,QAAQ,KAAK,SAAS,QAAQ,SAAS;;CAEhE,mBAAoC;AAClC,SAAOL,iBAAmB,KAAK,QAAQ,KAAK,QAAQ;;;;;;;;;;;;;;;;;ACpExD,eAAsB,mBACpB,MACA,MACuB;CACvB,IAAI;AACJ,KAAI;AACF,GAAC,CAAE,QAAQ,cAAe,MAAM,OAAO;UAChC,OAAO;AACd,QAAM,IAAI,MACR,0IAEA,EAAE,OAAO,OAAO,CACjB;;CAGH,MAAM,SAAkC,OAAO,EAAE,MAAM,GAAG,EAAE;AAC5D,SAAQ,KAAK,MAAb;EACE,KAAK;AACH,UAAO,QAAQ,KAAK;AACpB;EACF,KAAK;AACH,UAAO,aAAa,KAAK;AACzB;EACF,KAAK;AACH,UAAO,WAAW,KAAK;AACvB;EACF,SAAS;GACP,MAAM,EAAE,SAAS;AACjB,SAAM,IAAI,MAAM,kCAAkC,KAAK,GAAG;;;AAI9D,QAAO,IAAI,WAAW,OAAO;;;;;;;;AAS/B,eAAsB,qBACpB,MACyB;AAEzB,QAAO,IAAI,eADI,MAAM,mBAAmB,KAAK,MAAM,KAAK,QAAQ,KAAK,EACnC,KAAK,QAAQ;;;;;ACtBjD,MAAa,wBAAsC;CACjD,MAAM;CACN,OAAO;CACR"}
1
+ {"version":3,"file":"index.mjs","names":["listBranchesOp","getDefaultBranchOp","createBranchOp","deleteBranchOp","getBranchDiffOp","mergeBranchOp","isMergedOp"],"sources":["../../../src/providers/gitlab/capabilities.ts","../../../src/providers/gitlab/apply-plan.ts","../../../src/providers/gitlab/branch-ops.ts","../../../src/providers/gitlab/reader.ts","../../../src/providers/gitlab/provider.ts","../../../src/providers/gitlab/factory.ts","../../../src/providers/gitlab/types.ts"],"sourcesContent":["import type { ProviderCapabilities } from '../../core/contracts/index.js'\n\n/**\n * Capability set for GitLabProvider.\n *\n * GitLab over REST has no working tree, so local worktree features,\n * source-file access and AST scans are unavailable. Push, merge and\n * branch-protection detection all work over the API. GitLab enforces\n * merges through merge requests, so `pullRequestFallback` is `true` —\n * `mergeBranch` opens an MR and auto-accepts it to match GitHub's\n * `repos.merge` semantics while still leaving an audit trail.\n */\nexport const GITLAB_CAPABILITIES: ProviderCapabilities = {\n localWorktree: false,\n sourceRead: false,\n sourceWrite: false,\n pushRemote: true,\n branchProtection: true,\n pullRequestFallback: true,\n astScan: false,\n}\n","import { CONTENTRAIN_BRANCH } from '@contentrain/types'\nimport type { ApplyPlanInput, Commit, FileChange } from '../../core/contracts/index.js'\nimport { isNotFoundError, resolveRepoPath } from '../shared/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\ntype CommitActionType = 'create' | 'update' | 'delete'\n\ninterface CommitAction {\n action: CommitActionType\n filePath: string\n content?: string\n encoding?: 'text' | 'base64'\n}\n\n/**\n * Apply a plan to a GitLab repository as a single atomic commit via the\n * Commits API. High-level flow:\n *\n * 1. Check whether the target branch exists. If it does not, GitLab's\n * `startBranch` option forks a new branch from `input.base` (or the\n * project's default branch) as part of the same commit.\n * 2. For each `FileChange`, figure out the right GitLab action verb\n * (`create` vs `update` vs `delete`) by probing the path against the\n * resolved ref. GitLab validates this server-side and returns a 400\n * for mismatches — we avoid the round trip by getting it right up\n * front.\n * 3. POST `/repository/commits` once with the full action set. No\n * working tree, no multi-call tree-assembly dance — GitLab exposes\n * a richer primitive than the GitHub Git Data API for this case.\n *\n * The commit is durable as soon as the call returns; GitLab's ref\n * update happens inside the same request.\n */\nexport async function applyPlanToGitLab(\n client: GitLabClient,\n project: ProjectRef,\n input: ApplyPlanInput,\n): Promise<Commit> {\n const branchExists = await branchHasRef(client, project, input.branch)\n // Invariant: fork from the Contentrain content-tracking branch, not\n // the repo's default branch. See ApplyPlanInput.base docstring in\n // @contentrain/types.\n const baseBranch = input.base ?? CONTENTRAIN_BRANCH\n\n // Actions are computed against the HEAD of the feature branch when it\n // exists, otherwise against the fork point (baseBranch). GitLab\n // treats `create` / `update` / `delete` as a strict check against the\n // path's existence at that ref.\n const refForActionResolution = branchExists ? input.branch : baseBranch\n const rawActions = await Promise.all(\n input.changes.map(change => resolveAction(client, project, refForActionResolution, change)),\n )\n const actions = rawActions.filter((a): a is CommitAction => a !== null)\n\n if (actions.length === 0) {\n // Nothing to apply. Callers don't generally build empty plans, but\n // if they do we short-circuit before touching the API.\n throw new Error('applyPlanToGitLab: plan contained no applicable actions')\n }\n\n const options: Record<string, unknown> = {\n authorName: input.author.name,\n authorEmail: input.author.email,\n }\n if (!branchExists) {\n options.startBranch = baseBranch\n }\n\n const response = await client.Commits.create(\n project.projectId,\n input.branch,\n input.message,\n actions,\n options,\n )\n\n // Gitbeaker's generic-heavy response type widens string fields to\n // `string | Camelize<…>` — at runtime they are always strings under\n // the default (non-camelize) response mode we use. Cast narrows the\n // shape we actually touch.\n const commit = response as {\n id: string\n message?: string\n author_name?: string\n author_email?: string\n created_at?: string\n }\n const commitTimestamp = toIsoTimestamp(commit.created_at) ?? new Date().toISOString()\n return {\n sha: commit.id,\n message: commit.message ?? input.message,\n author: {\n name: commit.author_name ?? input.author.name,\n email: commit.author_email ?? input.author.email,\n },\n timestamp: commitTimestamp,\n }\n}\n\nasync function resolveAction(\n client: GitLabClient,\n project: ProjectRef,\n ref: string,\n change: FileChange,\n): Promise<CommitAction | null> {\n const filePath = resolveRepoPath(project.contentRoot, change.path)\n const exists = await fileExistsAtRef(client, project, filePath, ref)\n\n if (change.content === null) {\n // Filter out deletes against non-existent files — GitLab returns\n // 400 otherwise. The plan author asked us to \"make this file not\n // exist\", which is already satisfied.\n if (!exists) return null\n return { action: 'delete', filePath }\n }\n\n return {\n action: exists ? 'update' : 'create',\n filePath,\n content: change.content,\n encoding: 'text',\n }\n}\n\nasync function branchHasRef(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n): Promise<boolean> {\n try {\n await client.Branches.show(project.projectId, branch)\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n}\n\nasync function fileExistsAtRef(\n client: GitLabClient,\n project: ProjectRef,\n filePath: string,\n ref: string,\n): Promise<boolean> {\n try {\n await client.RepositoryFiles.show(project.projectId, filePath, ref)\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n}\n\n\nfunction toIsoTimestamp(raw: unknown): string | null {\n if (typeof raw !== 'string') return null\n const date = new Date(raw)\n if (Number.isNaN(date.getTime())) return null\n return date.toISOString()\n}\n\n","import { CONTENTRAIN_BRANCH } from '@contentrain/types'\nimport type { Branch, FileDiff, MergeResult } from '../../core/contracts/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * Branch / merge / diff helpers backed by the GitLab REST API.\n *\n * Pure functions so they can be composed into `GitLabProvider` or used\n * standalone. 404s collapse to empty-ish results where that matches\n * the `RepoProvider` contract (missing branch prefix → `[]`).\n *\n * Merge semantics: GitLab does not expose a direct branch-to-branch\n * merge endpoint. Every merge flows through a merge request, so\n * `mergeBranch` opens an MR and immediately accepts it. The resulting\n * `MergeResult` mirrors GitHub's `repos.merge` return shape — callers\n * see the same `{ merged, sha, pullRequestUrl }` envelope either way,\n * with the MR URL available for audit.\n */\n\nexport async function getDefaultBranch(\n client: GitLabClient,\n project: ProjectRef,\n): Promise<string> {\n const p = await client.Projects.show(project.projectId) as { default_branch?: string }\n return p.default_branch ?? 'main'\n}\n\nexport async function listBranches(\n client: GitLabClient,\n project: ProjectRef,\n prefix?: string,\n): Promise<Branch[]> {\n // Gitbeaker's `all` supports a `search` string (substring match). For\n // Contentrain's `cr/*` naming the substring case is equivalent to a\n // prefix because the slug never appears anywhere except at the start.\n // Server-side filter + client-side prefix enforcement keeps us\n // correct even if the substring coincidence breaks someday.\n const options: Record<string, unknown> = {\n perPage: 100,\n maxPages: 10,\n }\n if (prefix) options.search = prefix\n\n const rawBranches = await client.Branches.all(project.projectId, options)\n const branches = Array.isArray(rawBranches) ? rawBranches : []\n\n return branches\n .filter((b: { name: string }) => !prefix || b.name.startsWith(prefix))\n .map((b: { name: string, commit: { id: string }, protected?: boolean }) => ({\n name: b.name,\n sha: b.commit.id,\n protected: b.protected ?? false,\n }))\n}\n\nexport async function createBranch(\n client: GitLabClient,\n project: ProjectRef,\n name: string,\n fromRef: string,\n): Promise<void> {\n await client.Branches.create(project.projectId, name, fromRef)\n}\n\nexport async function deleteBranch(\n client: GitLabClient,\n project: ProjectRef,\n name: string,\n): Promise<void> {\n await client.Branches.remove(project.projectId, name)\n}\n\nexport async function getBranchDiff(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n base: string,\n): Promise<FileDiff[]> {\n const response = await client.Repositories.compare(\n project.projectId,\n base,\n branch,\n { straight: false },\n )\n const diffs = Array.isArray(response.diffs) ? response.diffs : []\n return diffs.map((d: { new_path: string, old_path: string, new_file?: boolean, deleted_file?: boolean }) => ({\n path: d.new_file ? d.new_path : d.old_path,\n status: d.deleted_file ? 'removed' : d.new_file ? 'added' : 'modified',\n before: null,\n after: null,\n }))\n}\n\nexport async function mergeBranch(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n opts?: { removeSourceBranch?: boolean },\n): Promise<MergeResult> {\n // 1. Open MR — GitLab rejects create when source === target or when\n // an MR is already open for this pair. Let the error propagate in\n // those cases; the caller retries or surfaces the message.\n const mr = await client.MergeRequests.create(\n project.projectId,\n branch,\n into,\n `[contentrain] merge ${branch} → ${into}`,\n { removeSourceBranch: false },\n )\n\n // 2. Accept the MR immediately. `shouldRemoveSourceBranch: false` keeps\n // GitLab's async server-side deletion out of the accept call — the\n // explicit cleanup below owns it, so the outcome is deterministic and\n // reported via `MergeResult.remote`.\n const accepted = await client.MergeRequests.accept(\n project.projectId,\n (mr as { iid: number }).iid,\n { shouldRemoveSourceBranch: false, squash: false },\n )\n\n const mergeSha = (accepted as { merge_commit_sha?: string | null, sha?: string | null }).merge_commit_sha\n ?? (accepted as { sha?: string | null }).sha\n ?? null\n const webUrl = (mr as { web_url?: string }).web_url ?? null\n const merged = mergeSha !== null\n\n // 3. Source-branch cleanup — OPT-IN (`removeSourceBranch: true`). Like git\n // and GitLab's own merge, `mergeBranch` leaves the source alone by\n // default. Even when opted in, a long-lived branch is NEVER deleted:\n // not the merge target (`into`), not the `contentrain` content branch,\n // not the project's default branch. Mirrors the LocalProvider guard;\n // defends against head/base confusion and contentrain↔default flows.\n // Never throws — the merge itself already succeeded.\n const remote = merged ? await cleanupSourceBranch(client, project, branch, into, opts) : undefined\n\n return { merged, sha: mergeSha, pullRequestUrl: webUrl, ...(remote ? { remote } : {}) }\n}\n\n/**\n * Opt-in ({@link mergeBranch} `removeSourceBranch: true`) deletion of the\n * merged source branch, with the same guard as the GitHub provider and the\n * LocalProvider: never delete the merge target, the `contentrain` content\n * branch, or the project default branch — even when opted in. Fail-safe\n * skips the delete if the default branch cannot be resolved. Never throws.\n */\nasync function cleanupSourceBranch(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n opts?: { removeSourceBranch?: boolean },\n): Promise<MergeResult['remote'] | undefined> {\n if (opts?.removeSourceBranch !== true) return undefined\n\n if (branch === into || branch === CONTENTRAIN_BRANCH) {\n return { deleted: false, skipped: 'protected' }\n }\n try {\n if (branch === await getDefaultBranch(client, project)) {\n return { deleted: false, skipped: 'protected' }\n }\n } catch {\n return { deleted: false, skipped: 'protected' }\n }\n\n try {\n await deleteBranch(client, project, branch)\n return { deleted: true }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return /404|not found/i.test(message)\n ? { deleted: false, skipped: 'not-found' }\n : { deleted: false, warning: `Could not delete \"${branch}\": ${message}` }\n }\n}\n\nexport async function isMerged(\n client: GitLabClient,\n project: ProjectRef,\n branch: string,\n into: string,\n): Promise<boolean> {\n // compare(from=into, to=branch) — commits list is empty when branch\n // is fully contained in into (i.e. already merged).\n const response = await client.Repositories.compare(\n project.projectId,\n into,\n branch,\n { straight: false },\n )\n const commits = Array.isArray(response.commits) ? response.commits : []\n return commits.length === 0\n}\n","import type { RepoReader } from '../../core/contracts/index.js'\nimport { isNotFoundError, resolveRepoPath } from '../shared/index.js'\nimport type { GitLabClient } from './client.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * GitLabReader — `RepoReader` backed by the GitLab REST API.\n *\n * File reads go through `RepositoryFiles.showRaw`, which returns the\n * file content as UTF-8 text (or a `Blob` on browser/edge runtimes we\n * decode with `.text()`). Directory listings go through\n * `Repositories.allRepositoryTrees`. `fileExists` tries the file\n * endpoint first and falls back to a tree listing so directories\n * resolve to `true` as well — matching LocalReader / GitHubReader.\n *\n * `ref` is forwarded verbatim and may be a branch name, tag name or\n * commit SHA. Callers should always pass the explicit `contentrain`\n * tracking branch; GitLab's default resolution is the project's\n * default branch, which is usually wrong for Contentrain flows.\n */\nexport class GitLabReader implements RepoReader {\n constructor(\n private readonly client: GitLabClient,\n private readonly project: ProjectRef,\n ) {}\n\n async readFile(path: string, ref?: string): Promise<string> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n const raw = await this.client.RepositoryFiles.showRaw(\n this.project.projectId,\n repoPath,\n resolvedRef,\n )\n if (typeof raw === 'string') return raw\n // Browser / edge runtimes return a Blob; decode as UTF-8.\n return (raw as Blob).text()\n }\n\n async listDirectory(path: string, ref?: string): Promise<string[]> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n try {\n const entries = await this.client.Repositories.allRepositoryTrees(\n this.project.projectId,\n {\n path: repoPath,\n ref: resolvedRef,\n perPage: 100,\n recursive: false,\n },\n )\n return Array.isArray(entries) ? entries.map(e => e.name) : []\n } catch (error) {\n if (isNotFoundError(error)) return []\n throw error\n }\n }\n\n async fileExists(path: string, ref?: string): Promise<boolean> {\n const repoPath = resolveRepoPath(this.project.contentRoot, path)\n const resolvedRef = ref ?? await this.resolveDefaultRef()\n\n // 1. Try as a file — cheap and most common case for Contentrain.\n try {\n await this.client.RepositoryFiles.show(\n this.project.projectId,\n repoPath,\n resolvedRef,\n )\n return true\n } catch (error) {\n if (!isNotFoundError(error)) throw error\n }\n\n // 2. Fall back to a tree listing — directories and empty dirs show\n // up here. Any non-404 result means the path resolves.\n try {\n const entries = await this.client.Repositories.allRepositoryTrees(\n this.project.projectId,\n { path: repoPath, ref: resolvedRef, perPage: 1 },\n )\n return Array.isArray(entries) && entries.length > 0\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n }\n\n private async resolveDefaultRef(): Promise<string> {\n const project = await this.client.Projects.show(this.project.projectId) as { default_branch?: string }\n return project.default_branch ?? 'main'\n }\n}\n\n","import type {\n ApplyPlanInput,\n Branch,\n Commit,\n FileDiff,\n MergeResult,\n ProviderCapabilities,\n RepoProvider,\n} from '../../core/contracts/index.js'\nimport { applyPlanToGitLab } from './apply-plan.js'\nimport {\n createBranch as createBranchOp,\n deleteBranch as deleteBranchOp,\n getBranchDiff as getBranchDiffOp,\n getDefaultBranch as getDefaultBranchOp,\n isMerged as isMergedOp,\n listBranches as listBranchesOp,\n mergeBranch as mergeBranchOp,\n} from './branch-ops.js'\nimport { GITLAB_CAPABILITIES } from './capabilities.js'\nimport type { GitLabClient } from './client.js'\nimport { GitLabReader } from './reader.js'\nimport type { ProjectRef } from './types.js'\n\n/**\n * GitLabProvider — `RepoProvider` backed by the gitbeaker-driven GitLab\n * REST API.\n *\n * Transport-agnostic: the provider only talks to a `GitLabClient`\n * (a `@gitbeaker/rest` `Gitlab` instance). `createGitLabProvider` in\n * `factory.ts` wraps the dynamic import so consumers never touch\n * `@gitbeaker/rest` directly unless they want to.\n *\n * Capability gaps versus `GitHubProvider`: none — both providers\n * expose the same set. GitLab's merge flow routes through an MR under\n * the hood, but `mergeBranch` presents the same `MergeResult` shape.\n */\nexport class GitLabProvider implements RepoProvider {\n readonly capabilities: ProviderCapabilities = GITLAB_CAPABILITIES\n private readonly reader: GitLabReader\n\n constructor(\n private readonly client: GitLabClient,\n public readonly project: ProjectRef,\n ) {\n this.reader = new GitLabReader(client, project)\n }\n\n readFile(path: string, ref?: string): Promise<string> {\n return this.reader.readFile(path, ref)\n }\n listDirectory(path: string, ref?: string): Promise<string[]> {\n return this.reader.listDirectory(path, ref)\n }\n fileExists(path: string, ref?: string): Promise<boolean> {\n return this.reader.fileExists(path, ref)\n }\n\n applyPlan(input: ApplyPlanInput): Promise<Commit> {\n return applyPlanToGitLab(this.client, this.project, input)\n }\n\n listBranches(prefix?: string): Promise<Branch[]> {\n return listBranchesOp(this.client, this.project, prefix)\n }\n async createBranch(name: string, fromRef?: string): Promise<void> {\n const resolved = fromRef ?? await getDefaultBranchOp(this.client, this.project)\n await createBranchOp(this.client, this.project, name, resolved)\n }\n deleteBranch(name: string): Promise<void> {\n return deleteBranchOp(this.client, this.project, name)\n }\n async getBranchDiff(branch: string, base?: string): Promise<FileDiff[]> {\n const resolved = base ?? await getDefaultBranchOp(this.client, this.project)\n return getBranchDiffOp(this.client, this.project, branch, resolved)\n }\n mergeBranch(branch: string, into: string, opts?: { removeSourceBranch?: boolean }): Promise<MergeResult> {\n return mergeBranchOp(this.client, this.project, branch, into, opts)\n }\n async isMerged(branch: string, into?: string): Promise<boolean> {\n const resolved = into ?? await getDefaultBranchOp(this.client, this.project)\n return isMergedOp(this.client, this.project, branch, resolved)\n }\n getDefaultBranch(): Promise<string> {\n return getDefaultBranchOp(this.client, this.project)\n }\n\n /**\n * Merge-base via GitLab's dedicated endpoint. `createMergeCommit` is\n * deliberately ABSENT (and `capabilities.mergeCommit` unset): the GitLab\n * Commits API cannot express a two-parent commit, so a reconcile against\n * GitLab falls back to a merge-request flow driven by the caller.\n */\n async getMergeBase(refA: string, refB: string): Promise<string | null> {\n try {\n const commit = await this.client.Repositories.mergeBase(this.project.projectId, [refA, refB])\n return commit.id ?? null\n } catch {\n return null\n }\n }\n}\n","import type { GitLabClient } from './client.js'\nimport { GitLabProvider } from './provider.js'\nimport type { GitLabAuth, ProjectRef } from './types.js'\n\n/**\n * Create a gitbeaker-backed `GitLabClient` from an auth configuration.\n *\n * The `@gitbeaker/rest` module is imported dynamically so it stays a\n * pure optional peer dependency — self-hosted MCP on stdio runs fine\n * without it. If the module is not installed, the import throws with\n * a helpful hint pointing the operator at the peer dependency.\n *\n * Supported auth types: `pat`, `oauth`, `job`. All three are thin\n * wrappers over gitbeaker's `token`, `oauthToken`, and `jobToken`\n * constructor options.\n */\nexport async function createGitLabClient(\n auth: GitLabAuth,\n host?: string,\n): Promise<GitLabClient> {\n let GitlabCtor: typeof import('@gitbeaker/rest').Gitlab\n try {\n ({ Gitlab: GitlabCtor } = await import('@gitbeaker/rest'))\n } catch (error) {\n throw new Error(\n '@gitbeaker/rest is required for the GitLabProvider but could not be loaded. '\n + 'Install it as a peer dependency: pnpm add @gitbeaker/rest.',\n { cause: error },\n )\n }\n\n const config: Record<string, unknown> = host ? { host } : {}\n switch (auth.type) {\n case 'pat':\n config.token = auth.token\n break\n case 'oauth':\n config.oauthToken = auth.oauthToken\n break\n case 'job':\n config.jobToken = auth.jobToken\n break\n default: {\n const { type } = auth as { type: string }\n throw new Error(`Unsupported GitLab auth type: \"${type}\"`)\n }\n }\n\n return new GitlabCtor(config) as GitLabClient\n}\n\n/**\n * Factory for the full provider — instantiates a gitbeaker client and\n * wraps it in a `GitLabProvider`. Consumers who already hold a\n * gitbeaker instance (HTTP server injecting shared clients, tests,\n * etc.) should instantiate `GitLabProvider` directly instead.\n */\nexport async function createGitLabProvider(\n opts: { auth: GitLabAuth, project: ProjectRef },\n): Promise<GitLabProvider> {\n const client = await createGitLabClient(opts.auth, opts.project.host)\n return new GitLabProvider(client, opts.project)\n}\n","import type { CommitAuthor } from '../../core/contracts/index.js'\n\n/**\n * A reference to a GitLab project.\n *\n * `projectId` accepts the numeric project ID or a URL-encoded path\n * (`namespace/project`). Gitbeaker URL-encodes string paths internally,\n * so either form is fine.\n *\n * `contentRoot` is the repo-relative directory prefix where Contentrain\n * content lives. For a flat content repo it stays `''`; for a monorepo\n * where Contentrain sits under `apps/web/.contentrain/` it holds that\n * prefix. All reader/writer paths are joined against it.\n *\n * `host` points at a self-hosted GitLab instance. Leave undefined to\n * use `https://gitlab.com` (gitbeaker's default).\n */\nexport interface ProjectRef {\n projectId: string | number\n contentRoot?: string\n host?: string\n}\n\n/**\n * Authentication options for the GitLab provider.\n *\n * - `pat` — personal access token with the `api` scope. Simplest for\n * self-hosted MCP or CI runners.\n * - `oauth` — OAuth2 token. Used when the runner is driven by a GitLab\n * OAuth flow.\n * - `job` — CI job token (`CI_JOB_TOKEN`). Scoped to the running\n * pipeline; useful for pipeline-driven content updates.\n */\nexport type GitLabAuth =\n | { type: 'pat', token: string }\n | { type: 'oauth', oauthToken: string }\n | { type: 'job', jobToken: string }\n\n/** Default author used when a call does not provide one. */\nexport const DEFAULT_GITLAB_AUTHOR: CommitAuthor = {\n name: 'Contentrain',\n email: 'ai@contentrain.io',\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { _ as RepoReader, a as FileChange, g as RepoProvider, h as ProviderCapabilities$1, i as CommitAuthor, m as MergeResult, n as Branch, o as FileDiff, r as Commit, y as WriteReadiness } from "../../index-BWbTJlXm.mjs";
2
- import { SyncResult, WorkflowMode } from "@contentrain/types";
1
+ import { _ as RepoReader, a as FileChange, g as RepoProvider, h as ProviderCapabilities$1, i as CommitAuthor, m as MergeResult, n as Branch, o as FileDiff, r as Commit, y as WriteReadiness } from "../../index-ByrVsRJE.mjs";
2
+ import { BaseAdvance, RemotePush, SyncResult, WorkflowMode } from "@contentrain/types";
3
3
 
4
4
  //#region src/providers/local/types.d.ts
5
5
  /** Optional payload written to `.contentrain/context.json` after changes apply. */
@@ -46,6 +46,14 @@ interface LocalApplyResult extends Commit {
46
46
  sync?: SyncResult;
47
47
  /** Non-fatal warning bubbled up from the transaction layer (e.g. partial sync). */
48
48
  warning?: string;
49
+ /**
50
+ * Present on `auto-merged`: whether the base branch advanced to the
51
+ * contentrain tip. `blocked_diverged` is a partial success — the content is
52
+ * on the contentrain branch; only the base fast-forward is pending.
53
+ */
54
+ base_advance?: BaseAdvance;
55
+ /** Present on `auto-merged`: outcome of pushing the contentrain branch. */
56
+ remote_push?: RemotePush;
49
57
  }
50
58
  //#endregion
51
59
  //#region src/providers/local/provider.d.ts
@@ -86,6 +94,22 @@ declare class LocalProvider implements RepoProvider {
86
94
  mergeBranch(branch: string, into: string): Promise<MergeResult>;
87
95
  isMerged(branch: string, into?: string): Promise<boolean>;
88
96
  getDefaultBranch(): Promise<string>;
97
+ getMergeBase(refA: string, refB: string): Promise<string | null>;
98
+ /**
99
+ * Two-parent merge commit in a temp worktree. The real `git merge`
100
+ * resolves everything outside the plan; the plan's changes then
101
+ * overwrite every content-owned path (planner output is authoritative,
102
+ * never git's textual auto-merge). Leftover unmerged paths abort — they
103
+ * are outside the content planner's scope by construction.
104
+ */
105
+ createMergeCommit(input: {
106
+ branch: string;
107
+ ours: string;
108
+ theirs: string;
109
+ changes: FileChange[];
110
+ message: string;
111
+ author: CommitAuthor;
112
+ }): Promise<Commit>;
89
113
  }
90
114
  //#endregion
91
115
  //#region src/providers/local/reader.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/providers/local/types.ts","../../../src/providers/local/provider.ts","../../../src/providers/local/reader.ts"],"mappings":";;;;;UAIiB,kBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;EACA,OAAA;AAAA;;;;;;AAYF;;;;UAAiB,mBAAA;EAYL;EAVV,MAAA;EAY+B;EAV/B,OAAA,EAAS,UAAA;EAFT;EAIA,OAAA;EAFS;EAIT,MAAA,GAAS,YAAA;EAAT;EAEA,IAAA;EAAA;EAEA,OAAA,GAAU,kBAAA;EAAA;EAEV,gBAAA,GAAmB,YAAA;AAAA;AAAA,UAGJ,gBAAA,SAAyB,MAAA;EAHT;AAGjC;;;;;EAOE,cAAA;EAEA;EAAA,IAAA,GAAO,UAAA;EAEP;EAAA,OAAA;AAAA;;;;;AA5CF;;;;;;;;;;AAgBA;;;cCuBa,aAAA,YAAyB,YAAA;EAAA,SAIR,WAAA;EAAA,SAHnB,YAAA,EAAc,sBAAA;EAAA,iBACN,MAAA;cAEW,WAAA;EAI5B,QAAA,CAAS,IAAA,UAAc,GAAA,YAAe,OAAA;EAItC,aAAA,CAAc,IAAA,UAAc,GAAA,YAAe,OAAA;EAI3C,UAAA,CAAW,IAAA,UAAc,GAAA,YAAe,OAAA;EDnC/B;;;;;EC4CH,mBAAA,CAAA,GAAuB,OAAA,CAAQ,cAAA;EAO/B,SAAA,CAAU,KAAA,EAAO,mBAAA,GAAsB,OAAA,CAAQ,gBAAA;EA2BrD,YAAA,CAAa,MAAA,YAAkB,OAAA,CAAQ,MAAA;EAIjC,YAAA,CAAa,IAAA,UAAc,OAAA,YAAmB,OAAA;EAKpD,YAAA,CAAa,IAAA,WAAe,OAAA;EAI5B,aAAA,CAAc,MAAA,UAAgB,IAAA,YAAgB,OAAA,CAAQ,QAAA;EAKtD,WAAA,CAAY,MAAA,UAAgB,IAAA,WAAe,OAAA,CAAQ,WAAA;EAInD,QAAA,CAAS,MAAA,UAAgB,IAAA,YAAgB,OAAA;EAKzC,gBAAA,CAAA,GAAoB,OAAA;AAAA;;;;;;AD7HtB;;;;;;;;cEWa,WAAA,YAAuB,UAAA;EAAA,SACN,WAAA;cAAA,WAAA;EAEtB,QAAA,CAAS,IAAA,UAAc,IAAA,YAAgB,OAAA;EAIvC,aAAA,CAAc,IAAA,UAAc,IAAA,YAAgB,OAAA;EAQ5C,UAAA,CAAW,IAAA,UAAc,IAAA,YAAgB,OAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/providers/local/types.ts","../../../src/providers/local/provider.ts","../../../src/providers/local/reader.ts"],"mappings":";;;;;UAIiB,kBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;EACA,OAAA;AAAA;;;;;;AAYF;;;;UAAiB,mBAAA;EAYL;EAVV,MAAA;EAY+B;EAV/B,OAAA,EAAS,UAAA;EAFT;EAIA,OAAA;EAFS;EAIT,MAAA,GAAS,YAAA;EAAT;EAEA,IAAA;EAAA;EAEA,OAAA,GAAU,kBAAA;EAAA;EAEV,gBAAA,GAAmB,YAAA;AAAA;AAAA,UAGJ,gBAAA,SAAyB,MAAA;EAHT;AAGjC;;;;;EAOE,cAAA;EAPwC;EASxC,IAAA,GAAO,UAAA;EATuC;EAW9C,OAAA;EAJA;;;;;EAUA,YAAA,GAAe,WAAA;EAEf;EAAA,WAAA,GAAc,UAAA;AAAA;;;;;AApDhB;;;;;;;;;;AAgBA;;;cC8Ba,aAAA,YAAyB,YAAA;EAAA,SAIR,WAAA;EAAA,SAHnB,YAAA,EAAc,sBAAA;EAAA,iBACN,MAAA;cAEW,WAAA;EAI5B,QAAA,CAAS,IAAA,UAAc,GAAA,YAAe,OAAA;EAItC,aAAA,CAAc,IAAA,UAAc,GAAA,YAAe,OAAA;EAI3C,UAAA,CAAW,IAAA,UAAc,GAAA,YAAe,OAAA;ED1C/B;;;;;ECmDH,mBAAA,CAAA,GAAuB,OAAA,CAAQ,cAAA;EAO/B,SAAA,CAAU,KAAA,EAAO,mBAAA,GAAsB,OAAA,CAAQ,gBAAA;EA6BrD,YAAA,CAAa,MAAA,YAAkB,OAAA,CAAQ,MAAA;EAIjC,YAAA,CAAa,IAAA,UAAc,OAAA,YAAmB,OAAA;EAKpD,YAAA,CAAa,IAAA,WAAe,OAAA;EAI5B,aAAA,CAAc,MAAA,UAAgB,IAAA,YAAgB,OAAA,CAAQ,QAAA;EAKtD,WAAA,CAAY,MAAA,UAAgB,IAAA,WAAe,OAAA,CAAQ,WAAA;EAInD,QAAA,CAAS,MAAA,UAAgB,IAAA,YAAgB,OAAA;EAKzC,gBAAA,CAAA,GAAoB,OAAA;EAId,YAAA,CAAa,IAAA,UAAc,IAAA,WAAe,OAAA;EDxFjC;;;;;;;ECwGT,iBAAA,CAAkB,KAAA;IACtB,MAAA;IACA,IAAA;IACA,MAAA;IACA,OAAA,EAAS,UAAA;IACT,OAAA;IACA,MAAA,EAAQ,YAAA;EAAA,IACN,OAAA,CAAQ,MAAA;AAAA;;;;;;ADjKd;;;;;;;;cEWa,WAAA,YAAuB,UAAA;EAAA,SACN,WAAA;cAAA,WAAA;EAEtB,QAAA,CAAS,IAAA,UAAc,IAAA,YAAgB,OAAA;EAIvC,aAAA,CAAc,IAAA,UAAc,IAAA,YAAgB,OAAA;EAQ5C,UAAA,CAAW,IAAA,UAAc,IAAA,YAAgB,OAAA;AAAA"}
@@ -1,14 +1,15 @@
1
1
  import "../../contracts-DfL0BfrD.mjs";
2
- import "../../ops-BzbThweu.mjs";
3
- import "../../serialization-tmgfFBOh.mjs";
4
- import "../../fs-DLbVB-Ek.mjs";
5
- import "../../meta-manager-B_Se183X.mjs";
6
- import "../../identity-D8QoGxhT.mjs";
7
- import "../../config-VlRKRwAS.mjs";
8
- import "../../branch-lifecycle-B6PXZ2N7.mjs";
9
- import { E as LocalReader } from "../../model-manager-DgyKMjLN.mjs";
10
- import "../../context-C3x6I3cE.mjs";
11
- import "../../id-BjhaIxTL.mjs";
12
- import "../../transaction-BW9ektWu.mjs";
13
- import { t as LocalProvider } from "../../local-Db5X9mjZ.mjs";
2
+ import "../../reconcile-D5FTVW5z.mjs";
3
+ import "../../context-CxpTATh4.mjs";
4
+ import { E as LocalReader } from "../../model-manager-DqwL8ptm.mjs";
5
+ import "../../ops-BfrdZ6GK.mjs";
6
+ import "../../fs-DJv5G8uL.mjs";
7
+ import "../../meta-manager-g3shoZES.mjs";
8
+ import "../../config-B8a4JBT1.mjs";
9
+ import "../../validator-B2GhPM3L.mjs";
10
+ import "../../identity-CxAB9Qb8.mjs";
11
+ import "../../branch-lifecycle-DUOoyNWn.mjs";
12
+ import "../../id-CjGMPP1k.mjs";
13
+ import "../../transaction-BxDiiakv.mjs";
14
+ import { t as LocalProvider } from "../../local-bnn6yrG7.mjs";
14
15
  export { LocalProvider, LocalReader };