dsh-repo 0.0.0 → 0.1.0-beta.2

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/README.md CHANGED
@@ -98,7 +98,7 @@ if (repos?.version === 1) {
98
98
  }
99
99
  ```
100
100
 
101
- 接口覆盖仓库信息、分支、提交、目录、文件、多文件提交、issue 与 PR/MR 的读写和合并,完整定义见 [`src/contract.ts`](src/contract.ts)。所有预期内的失败都以 `name === 'RepoError'` 的错误拒绝,`code` 取值为 `invalid`、`not-allowed`、`unauthenticated`、`forbidden`、`not-found`、`conflict`、`rate-limited`、`too-large`、`unavailable`。
101
+ 接口覆盖仓库信息、分支、提交、目录、文件、多文件提交、issue 与 PR/MR 的读写和合并,完整定义见 [`src/contract.ts`](src/contract.ts)。多文件提交可以用 `baseSha` 从指定提交建新分支,`newBranch: true` 时分支已存在就以 `conflict` 失败,不会在已有分支上追加提交;`author` 指定提交作者(提交者始终是令牌对应的用户)。`getBranch` 读取单个分支,分支不存在时返回 `undefined`。所有预期内的失败都以 `name === 'RepoError'` 的错误拒绝,`code` 取值为 `invalid`、`not-allowed`、`unauthenticated`、`forbidden`、`not-found`、`conflict`、`rate-limited`、`too-large`、`unavailable`。
102
102
 
103
103
  ## GitHub 与 GitLab 的差异处理
104
104
 
package/lib/index.js CHANGED
@@ -393,6 +393,23 @@ var GithubProvider = class {
393
393
  ...nextPage(query, data.length)
394
394
  };
395
395
  }
396
+ async getBranch(ref, name, call) {
397
+ const [branch, info] = await Promise.all([this.octokit.rest.repos.getBranch({
398
+ ...split(ref.path),
399
+ branch: name,
400
+ request: { signal: call.signal }
401
+ }).catch((error) => {
402
+ if (error.status === 404) return void 0;
403
+ throw error;
404
+ }), this.repoInfo(ref, call)]);
405
+ if (branch === void 0 || branch.data.name !== name) return void 0;
406
+ return {
407
+ name,
408
+ commit: branch.data.commit.sha,
409
+ protected: branch.data.protected,
410
+ default: name === info.defaultBranch
411
+ };
412
+ }
396
413
  async listCommits(ref, query, call) {
397
414
  const { data } = await this.octokit.rest.repos.listCommits({
398
415
  ...split(ref.path),
@@ -474,8 +491,9 @@ var GithubProvider = class {
474
491
  if (error.status === 404) return void 0;
475
492
  throw error;
476
493
  });
494
+ if (existing !== void 0 && request.newBranch === true) throw new RepoError("conflict", `分支 ${request.branch} 已存在`);
477
495
  if (existing?.data.protected === true) throw new RepoError("forbidden", `分支 ${request.branch} 受保护,不能直接提交`);
478
- const parent = existing?.data.commit.sha ?? (await this.octokit.rest.repos.getBranch({
496
+ const parent = existing?.data.commit.sha ?? request.baseSha ?? (await this.octokit.rest.repos.getBranch({
479
497
  ...repo,
480
498
  branch: request.base ?? info.defaultBranch,
481
499
  request: { signal }
@@ -522,6 +540,7 @@ var GithubProvider = class {
522
540
  message: request.message,
523
541
  tree: tree.sha,
524
542
  parents: [parent],
543
+ ...request.author === void 0 ? {} : { author: request.author },
525
544
  request: { signal }
526
545
  });
527
546
  if (existing === void 0) await this.octokit.rest.git.createRef({
@@ -529,6 +548,9 @@ var GithubProvider = class {
529
548
  ref: `refs/heads/${request.branch}`,
530
549
  sha: commit.sha,
531
550
  request: { signal }
551
+ }).catch((error) => {
552
+ if (error.status === 422) throw new RepoError("conflict", `分支 ${request.branch} 已存在`);
553
+ throw error;
532
554
  });
533
555
  else await this.octokit.rest.git.updateRef({
534
556
  ...repo,
@@ -886,6 +908,19 @@ var GitlabProvider = class {
886
908
  ...nextPage(query, data.length)
887
909
  };
888
910
  }
911
+ async getBranch(ref, name, call) {
912
+ call.signal.throwIfAborted();
913
+ const branch = await this.api.Branches.show(ref.path, name).catch((error) => {
914
+ if (error.cause?.response?.status === 404) return void 0;
915
+ throw error;
916
+ });
917
+ return branch === void 0 ? void 0 : {
918
+ name: branch.name,
919
+ commit: String(branch.commit.id),
920
+ protected: branch.protected,
921
+ default: branch.default
922
+ };
923
+ }
889
924
  async listCommits(ref, query, call) {
890
925
  call.signal.throwIfAborted();
891
926
  const data = await this.api.Commits.all(ref.path, {
@@ -950,8 +985,9 @@ var GitlabProvider = class {
950
985
  if (error.cause?.response?.status === 404) return void 0;
951
986
  throw error;
952
987
  });
988
+ if (existing !== void 0 && request.newBranch === true) throw new RepoError("conflict", `分支 ${request.branch} 已存在`);
953
989
  if (existing?.protected === true) throw new RepoError("forbidden", `分支 ${request.branch} 受保护,不能直接提交`);
954
- const start = existing === void 0 ? request.base ?? info.defaultBranch : request.branch;
990
+ const start = existing === void 0 ? request.baseSha ?? request.base ?? info.defaultBranch : request.branch;
955
991
  const present = /* @__PURE__ */ new Set();
956
992
  for (const dir of new Set(request.files.filter((file) => file.action === "write").map((file) => dirname(file.path)))) {
957
993
  call.signal.throwIfAborted();
@@ -974,7 +1010,18 @@ var GitlabProvider = class {
974
1010
  content: file.content
975
1011
  });
976
1012
  call.signal.throwIfAborted();
977
- const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, existing === void 0 ? { startBranch: start } : {});
1013
+ const startOption = existing !== void 0 ? {} : request.baseSha === void 0 ? { startBranch: start } : { startSha: request.baseSha };
1014
+ const authorOption = request.author === void 0 ? {} : {
1015
+ authorName: request.author.name,
1016
+ authorEmail: request.author.email
1017
+ };
1018
+ const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, {
1019
+ ...startOption,
1020
+ ...authorOption
1021
+ }).catch((error) => {
1022
+ if (existing === void 0 && error.cause?.response?.status === 400 && error instanceof Error && /already exists/i.test(error.message)) throw new RepoError("conflict", `分支 ${request.branch} 已存在`);
1023
+ throw error;
1024
+ });
978
1025
  return {
979
1026
  sha: commit.id,
980
1027
  branch: request.branch,
@@ -1301,6 +1348,10 @@ var RepoService = class {
1301
1348
  };
1302
1349
  return await this.run(repo, options, "列出分支", (provider, ref, call) => provider.listBranches(ref, query, call));
1303
1350
  }
1351
+ async getBranch(repo, name, options = {}) {
1352
+ requireBranch(name, "分支名");
1353
+ return await this.run(repo, options, `读取分支 ${name}`, (provider, ref, call) => provider.getBranch(ref, name, call));
1354
+ }
1304
1355
  async listCommits(repo, options = {}) {
1305
1356
  if (options.path !== void 0) requireRepoPath(options.path, "路径");
1306
1357
  const query = {
@@ -1327,7 +1378,15 @@ var RepoService = class {
1327
1378
  async commitFiles(repo, request) {
1328
1379
  requireBranch(request.branch, "分支名");
1329
1380
  if (request.base !== void 0) requireBranch(request.base, "起点分支名");
1381
+ if (request.baseSha !== void 0) {
1382
+ if (request.base !== void 0) throw new RepoError("invalid", "base 和 baseSha 只能给一个");
1383
+ if (!/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(request.baseSha)) throw new RepoError("invalid", `起点提交必须是完整的十六进制提交 id:${request.baseSha}`);
1384
+ }
1330
1385
  requireText(request.message, "提交说明");
1386
+ if (request.author !== void 0) {
1387
+ if (!/^[^<>\n]+$/.test(request.author.name.trim())) throw new RepoError("invalid", "提交作者名不能为空,也不能包含 < > 或换行");
1388
+ if (!/^[^<>\s]+$/.test(request.author.email.trim())) throw new RepoError("invalid", "提交作者邮箱不能为空,也不能包含 < > 或空白");
1389
+ }
1331
1390
  if (request.files.length === 0) throw new RepoError("invalid", "提交至少要包含一个文件");
1332
1391
  if (request.files.length > this.config.limits.maxCommitFiles) throw new RepoError("too-large", `一次提交最多 ${this.config.limits.maxCommitFiles} 个文件`);
1333
1392
  const seen = /* @__PURE__ */ new Set();
@@ -1341,7 +1400,13 @@ var RepoService = class {
1341
1400
  branch: request.branch,
1342
1401
  message: request.message,
1343
1402
  files: request.files,
1344
- ...request.base === void 0 ? {} : { base: request.base }
1403
+ ...request.base === void 0 ? {} : { base: request.base },
1404
+ ...request.baseSha === void 0 ? {} : { baseSha: request.baseSha },
1405
+ ...request.newBranch === true ? { newBranch: true } : {},
1406
+ ...request.author === void 0 ? {} : { author: {
1407
+ name: request.author.name.trim(),
1408
+ email: request.author.email.trim()
1409
+ } }
1345
1410
  };
1346
1411
  return await this.run(repo, request, `提交到分支 ${request.branch}`, (provider, ref, call) => provider.commitFiles(ref, fields, call));
1347
1412
  }
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["user","labelNames","dirname","issue"],"sources":["../src/config.ts","../src/errors.ts","../src/providers/types.ts","../src/providers/github.ts","../src/providers/gitlab.ts","../src/target.ts","../src/service.ts","../src/tools.ts","../src/index.ts"],"sourcesContent":["/**\n * 插件配置:cordis.yml 中的 `config`,经 Standard Schema 在加载时校验。\n *\n * @module dsh-repo/config\n */\n\nimport { z } from 'zod'\nimport type { ForgeKind } from './contract.ts'\n\n/** Largest delay Node's `setTimeout` honors (2^31 − 1 ms). */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647\n\n/** Credential reference names: environment-variable style. */\nexport const TOKEN_REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/** Repository pattern: `host[:port]/seg/…`, the last segment may be `*` (one level) or `**` (any depth). */\nconst REPO_PATTERN = /^[a-z0-9.-]+(:\\d+)?(\\/[A-Za-z0-9._-]+)*(\\/(\\*|\\*\\*|[A-Za-z0-9._-]+))$/\n\n/**\n * Normalize a host address to `https://host[:port][/path]` with a lowercase\n * host and no trailing slash.\n * @param value - candidate address.\n * @returns the normalized address, or undefined when it is not an `https`/`http` URL without credentials, query, or fragment.\n */\nexport function normalizeHostUrl(value: string): string | undefined {\n let url: URL\n try {\n url = new URL(value)\n } catch {\n // Not a URL: refused.\n return undefined\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') return undefined\n if (url.host === '' || url.username !== '' || url.password !== '' || url.search !== '' || url.hash !== '') return undefined\n return `${url.protocol}//${url.host}${url.pathname.replace(/\\/+$/, '')}`\n}\n\nconst urlField = (label: string) => z.string().trim()\n .refine(value => normalizeHostUrl(value) !== undefined, `${label}不合法:填 https://主机[:端口][/路径],不含用户名、查询参数或片段`)\n .transform(value => normalizeHostUrl(value) as string)\n\nconst hostSchema = z.object({\n kind: z.enum(['github', 'gitlab']),\n url: urlField('主机地址'),\n apiUrl: urlField('接口地址').optional(),\n tokenRef: z.string().trim().regex(TOKEN_REF_PATTERN, '令牌名称只能包含字母、数字和下划线,且不能以数字开头(它是凭据库中的键名,不是令牌本身)'),\n alias: z.string().trim().max(64).optional(),\n}).strict().superRefine((host, issues) => {\n if (host.kind === 'gitlab' && host.apiUrl !== undefined) issues.addIssue({ code: 'custom', path: ['apiUrl'], message: 'apiUrl 只用于 GitHub;GitLab 的接口地址由 url 推出' })\n})\n\nconst limitsSchema = z.object({\n perPage: z.number().int().min(1).max(100).default(30),\n maxPerPage: z.number().int().min(1).max(100).default(100),\n maxFileBytes: z.number().int().min(1).max(64 * 1024 * 1024).default(1024 * 1024),\n maxDiffBytes: z.number().int().min(1).max(64 * 1024 * 1024).default(512 * 1024),\n maxTreeEntries: z.number().int().min(1).max(100_000).default(1000),\n maxCommitFiles: z.number().int().min(1).max(1000).default(100),\n maxComments: z.number().int().min(1).max(100).default(50),\n}).strict().superRefine((limits, issues) => {\n if (limits.perPage > limits.maxPerPage) issues.addIssue({ code: 'custom', path: ['perPage'], message: 'perPage 不能大于 maxPerPage' })\n})\n\nconst toolsSchema = z.object({\n enabled: z.boolean().default(true),\n /** `ask`: every write asks the user once; `allow`: writes run without asking; `off`: write tools are not registered. */\n writes: z.enum(['ask', 'allow', 'off']).default('ask'),\n /** Whether the merge tool is registered at all; it always follows `writes` for approval. */\n merge: z.boolean().default(false),\n /** Appended (after a blank line) to issue, change request, and comment bodies written through tools; empty = none. */\n signature: z.string().max(500).default(''),\n}).strict()\n\n/** Standard Schema of the `config` block. */\nexport const pluginConfigSchema = z.object({\n hosts: z.array(hostSchema).default([]).superRefine((hosts, issues) => {\n const seen = new Set<string>()\n for (const [index, host] of hosts.entries()) {\n if (seen.has(host.url)) issues.addIssue({ code: 'custom', path: [index, 'url'], message: `重复的主机地址:${host.url}` })\n seen.add(host.url)\n }\n }),\n /** Reachable repositories; omitted or empty = every repository on the configured hosts. */\n repos: z.array(z.string().trim().toLowerCase().regex(REPO_PATTERN, '仓库格式:主机/路径,末段可以是 *(一层)或 **(任意层),例如 github.com/modestoma/*')).default([]),\n timeoutMs: z.number().int().min(1000).max(MAX_TIMER_DELAY_MS).default(30_000),\n limits: limitsSchema.default({ perPage: 30, maxPerPage: 100, maxFileBytes: 1024 * 1024, maxDiffBytes: 512 * 1024, maxTreeEntries: 1000, maxCommitFiles: 100, maxComments: 50 }),\n tools: toolsSchema.default({ enabled: true, writes: 'ask', merge: false, signature: '' }),\n}).strict().default({\n hosts: [],\n repos: [],\n timeoutMs: 30_000,\n limits: { perPage: 30, maxPerPage: 100, maxFileBytes: 1024 * 1024, maxDiffBytes: 512 * 1024, maxTreeEntries: 1000, maxCommitFiles: 100, maxComments: 50 },\n tools: { enabled: true, writes: 'ask', merge: false, signature: '' },\n})\n\n/** Validated configuration. */\nexport type RepoConfig = z.output<typeof pluginConfigSchema>\n\n/** One configured host. */\nexport type HostSpec = RepoConfig['hosts'][number]\n\n/** Size and paging limits. */\nexport type RepoLimits = RepoConfig['limits']\n\n/**\n * Validate a raw `config` block.\n * @param config - loader input; undefined uses every default.\n * @returns the validated configuration.\n * @throws when the configuration is invalid, with every issue in the message.\n */\nexport function resolveConfig(config: unknown): RepoConfig {\n const parsed = pluginConfigSchema.safeParse(config)\n if (parsed.success) return parsed.data\n throw new Error(`dsh-repo 配置不合法:${parsed.error.issues.map(issue => `${issue.path.join('.') || '(根)'}:${issue.message}`).join(';')}`)\n}\n\n/**\n * The REST API base URL of a host.\n * @param host - configured host.\n * @returns `https://api.github.com` for github.com, `<url>/api/v3` for GitHub Enterprise Server, and the host URL itself for GitLab (GitBeaker appends `/api/v4`).\n */\nexport function apiBaseUrl(host: { readonly kind: ForgeKind; readonly url: string; readonly apiUrl?: string | undefined }): string {\n if (host.kind === 'gitlab') return host.url\n if (host.apiUrl !== undefined) return host.apiUrl\n return new URL(host.url).host === 'github.com' ? 'https://api.github.com' : `${host.url}/api/v3`\n}\n","/**\n * The service's single failure type and the mapping from Octokit and\n * GitBeaker errors to it.\n *\n * @module dsh-repo/errors\n */\n\nimport type { RepoErrorCode, RepoFailure } from './contract.ts'\n\n/** Expected failure of a `dshRepos` call. */\nexport class RepoError extends Error implements RepoFailure {\n override readonly name = 'RepoError'\n\n /**\n * @param code - failure class.\n * @param message - readable reason.\n */\n constructor(readonly code: RepoErrorCode, message: string) {\n super(message)\n }\n}\n\n/** Status and host message read off an SDK error, when it carries a response. */\ninterface HttpFailure {\n readonly status?: number\n readonly message: string\n readonly rateLimited: boolean\n}\n\nfunction httpFailureOf(error: unknown): HttpFailure | undefined {\n if (!(error instanceof Error)) return undefined\n // Octokit `RequestError`: `status` plus `response.headers`.\n const octokit = error as Error & { status?: unknown; response?: { headers?: Record<string, string | number | undefined> } }\n if (error.name === 'HttpError' && typeof octokit.status === 'number') {\n const remaining = octokit.response?.headers?.['x-ratelimit-remaining']\n return { status: octokit.status, message: error.message, rateLimited: octokit.status === 429 || (octokit.status === 403 && String(remaining) === '0') }\n }\n // GitBeaker `GitbeakerRequestError`: `cause.response`.\n const gitbeaker = error as Error & { cause?: { response?: { status?: unknown } } }\n if (error.name === 'GitbeakerRequestError' || gitbeaker.cause?.response !== undefined) {\n const status = gitbeaker.cause?.response?.status\n return { ...typeof status === 'number' ? { status } : {}, message: error.message, rateLimited: status === 429 }\n }\n if (error.name === 'GitbeakerRetryError') return { status: 429, message: error.message, rateLimited: true }\n return undefined\n}\n\n/**\n * Classify an error thrown while calling a host.\n * @param error - the thrown value.\n * @param what - what was being done, for the message (e.g. `读取 issue #3`).\n * @returns the error to rethrow; a {@link RepoError} passes through unchanged.\n */\nexport function toRepoError(error: unknown, what: string): RepoError {\n if (error instanceof RepoError) return error\n const http = httpFailureOf(error)\n if (http !== undefined) {\n const detail = http.message === '' ? '' : `:${http.message}`\n if (http.rateLimited) return new RepoError('rate-limited', `${what}失败,已达到接口限流${detail}`)\n switch (http.status) {\n case 401: return new RepoError('unauthenticated', `${what}失败,令牌无效或已过期${detail}`)\n case 403: return new RepoError('forbidden', `${what}失败,令牌没有权限${detail}`)\n case 404: return new RepoError('not-found', `${what}失败,目标不存在或令牌无权查看${detail}`)\n case 405:\n case 406:\n case 409:\n case 412: return new RepoError('conflict', `${what}失败,状态已变化或不满足条件${detail}`)\n case 400:\n case 422: return new RepoError('invalid', `${what}失败,参数被拒绝${detail}`)\n default: return new RepoError('unavailable', `${what}失败${http.status === undefined ? '' : `(HTTP ${http.status})`}${detail}`)\n }\n }\n if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError' || error.name === 'GitbeakerTimeoutError')) {\n return new RepoError('unavailable', `${what}超时或被取消`)\n }\n return new RepoError('unavailable', `${what}失败:${error instanceof Error ? error.message : String(error)}`)\n}\n","/**\n * The per-family provider interface the service delegates to after resolving\n * a target, normalizing paging, and attaching the call deadline.\n *\n * @module dsh-repo/providers/types\n */\n\nimport type {\n BranchInfo, ChangeDetail, ChangeDiff, ChangeInfo, ChangeState, ChangeStatus, CommentInfo, CommitInfo, CommitResult,\n FileChange, FileContent, IssueDetail, IssueInfo, IssueState, MergeMethod, MergeResult, Page, RepoInfo, RepoRef, TreeListing,\n} from '../contract.ts'\nimport type { RepoLimits } from '../config.ts'\n\n/** Per-call input every provider method receives. */\nexport interface Call {\n /** Combined caller cancellation and configured deadline. */\n readonly signal: AbortSignal\n readonly limits: RepoLimits\n}\n\n/** Normalized paging. */\nexport interface Paging {\n readonly page: number\n readonly perPage: number\n}\n\n/** One code host family. Methods throw SDK errors or {@link RepoError}; the service classifies them. */\nexport interface Provider {\n repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo>\n listBranches(ref: RepoRef, query: Paging & { readonly search?: string }, call: Call): Promise<Page<BranchInfo>>\n listCommits(ref: RepoRef, query: Paging & { readonly ref?: string; readonly path?: string }, call: Call): Promise<Page<CommitInfo>>\n listTree(ref: RepoRef, query: { readonly ref?: string; readonly path: string; readonly recursive: boolean }, call: Call): Promise<TreeListing>\n readFile(ref: RepoRef, path: string, at: string | undefined, call: Call): Promise<FileContent>\n commitFiles(ref: RepoRef, request: { readonly branch: string; readonly base?: string; readonly message: string; readonly files: readonly FileChange[] }, call: Call): Promise<CommitResult>\n\n listIssues(ref: RepoRef, query: Paging & { readonly state: IssueState | 'all'; readonly labels?: readonly string[]; readonly assignee?: string }, call: Call): Promise<Page<IssueInfo>>\n getIssue(ref: RepoRef, number: number, call: Call): Promise<IssueDetail>\n createIssue(ref: RepoRef, issue: IssueFields & { readonly title: string }, call: Call): Promise<IssueInfo>\n updateIssue(ref: RepoRef, number: number, update: IssueFields & { readonly state?: IssueState }, call: Call): Promise<IssueInfo>\n commentIssue(ref: RepoRef, number: number, body: string, call: Call): Promise<CommentInfo>\n\n listChanges(ref: RepoRef, query: Paging & { readonly state: ChangeState | 'all'; readonly sourceBranch?: string; readonly targetBranch?: string }, call: Call): Promise<Page<ChangeInfo>>\n getChange(ref: RepoRef, number: number, call: Call): Promise<ChangeDetail>\n changeDiff(ref: RepoRef, number: number, call: Call): Promise<ChangeDiff>\n changeStatus(ref: RepoRef, number: number, call: Call): Promise<ChangeStatus>\n createChange(ref: RepoRef, change: IssueFields & { readonly title: string; readonly sourceBranch: string; readonly targetBranch: string; readonly draft: boolean }, call: Call): Promise<ChangeInfo>\n updateChange(ref: RepoRef, number: number, update: IssueFields & { readonly state?: 'open' | 'closed'; readonly targetBranch?: string }, call: Call): Promise<ChangeInfo>\n commentChange(ref: RepoRef, number: number, body: string, call: Call): Promise<CommentInfo>\n mergeChange(ref: RepoRef, number: number, request: { readonly headSha: string; readonly method?: MergeMethod }, call: Call): Promise<MergeResult>\n}\n\n/** Editable fields shared by issues and change requests. */\nexport interface IssueFields {\n readonly title?: string\n readonly body?: string\n readonly labels?: readonly string[]\n readonly assignees?: readonly string[]\n}\n\n/** Resolves a host's token for each request. */\nexport type TokenSource = () => Promise<string>\n\n/**\n * The next page number after a page of `count` items.\n * @param paging - the requested page.\n * @param count - items returned.\n * @returns `page + 1` when the page was full.\n */\nexport function nextPage(paging: Paging, count: number): { nextPage?: number } {\n return count >= paging.perPage ? { nextPage: paging.page + 1 } : {}\n}\n\n/**\n * Cut text at a byte limit on a character boundary.\n * @param text - full text.\n * @param maxBytes - UTF-8 byte limit.\n * @returns the kept text and whether anything was cut.\n */\nexport function truncateBytes(text: string, maxBytes: number): { text: string; truncated: boolean } {\n const bytes = Buffer.from(text, 'utf8')\n if (bytes.length <= maxBytes) return { text, truncated: false }\n let end = maxBytes\n // Step back over UTF-8 continuation bytes so no character is split.\n while (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80) end -= 1\n return { text: bytes.subarray(0, end).toString('utf8'), truncated: true }\n}\n\n/**\n * The first line of a commit message.\n * @param message - full message.\n * @returns its first line.\n */\nexport function titleOf(message: string): string {\n return message.split('\\n', 1)[0] ?? ''\n}\n","/**\n * GitHub provider on the official `@octokit/rest` SDK: github.com and GitHub\n * Enterprise Server (`<url>/api/v3`). Pull requests are this module's change\n * requests.\n *\n * @module dsh-repo/providers/github\n */\n\nimport { Octokit } from '@octokit/rest'\nimport type {\n BranchInfo, ChangeInfo, ChangeState, CheckInfo, CheckState, CommentInfo, CommitInfo, IssueInfo, RepoInfo, RepoRef, RepoUser, TreeEntry,\n} from '../contract.ts'\nimport { RepoError } from '../errors.ts'\nimport { nextPage, titleOf, truncateBytes } from './types.ts'\nimport type { Call, Provider, TokenSource } from './types.ts'\n\n/** GitHub's largest page. */\nconst PAGE = 100\n\n/** Pages of check runs or statuses read before giving up on a complete status. */\nconst MAX_STATUS_PAGES = 10\n\ninterface GithubUser { readonly login: string; readonly html_url?: string }\ninterface GithubLabel { readonly name?: string }\n\nfunction user(value: GithubUser | null | undefined): RepoUser {\n return value === null || value === undefined ? { username: 'ghost' } : { username: value.login, ...value.html_url === undefined ? {} : { webUrl: value.html_url } }\n}\n\nfunction labelNames(labels: ReadonlyArray<string | GithubLabel>): string[] {\n return labels.map(label => typeof label === 'string' ? label : label.name ?? '').filter(name => name !== '')\n}\n\nfunction dirname(path: string): string {\n const slash = path.lastIndexOf('/')\n return slash < 0 ? '' : path.slice(0, slash)\n}\n\nfunction split(path: string): { owner: string; repo: string } {\n const [owner = '', repo = ''] = path.split('/')\n return { owner, repo }\n}\n\ninterface GithubIssue {\n readonly number: number\n readonly title: string\n readonly body?: string | null\n readonly state: string\n readonly user: GithubUser | null\n readonly labels: ReadonlyArray<string | GithubLabel>\n readonly assignees?: readonly GithubUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly html_url: string\n}\n\nfunction issue(value: GithubIssue): IssueInfo {\n return {\n number: value.number,\n title: value.title,\n body: value.body ?? '',\n state: value.state === 'closed' ? 'closed' : 'open',\n author: user(value.user),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.html_url,\n }\n}\n\ninterface GithubPull {\n readonly number: number\n readonly title: string\n readonly body: string | null\n readonly state: string\n readonly draft?: boolean\n readonly merged_at: string | null\n readonly head: { readonly ref: string; readonly sha: string }\n readonly base: { readonly ref: string }\n readonly user: GithubUser | null\n readonly labels: readonly GithubLabel[]\n readonly assignees?: readonly GithubUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly html_url: string\n}\n\nfunction pull(value: GithubPull): ChangeInfo {\n const state: ChangeState = value.merged_at !== null ? 'merged' : value.state === 'closed' ? 'closed' : 'open'\n return {\n number: value.number,\n title: value.title,\n body: value.body ?? '',\n state,\n draft: value.draft === true,\n sourceBranch: value.head.ref,\n targetBranch: value.base.ref,\n headSha: value.head.sha,\n author: user(value.user),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.html_url,\n }\n}\n\ninterface GithubComment {\n readonly id: number\n readonly user: GithubUser | null\n readonly body?: string\n readonly created_at: string\n readonly html_url: string\n}\n\nfunction comment(value: GithubComment): CommentInfo {\n return { id: String(value.id), author: user(value.user), body: value.body ?? '', createdAt: value.created_at, webUrl: value.html_url }\n}\n\nfunction overall(checks: readonly CheckInfo[]): CheckState {\n if (checks.length === 0) return 'none'\n if (checks.some(check => check.state === 'failure')) return 'failure'\n if (checks.some(check => check.state === 'pending')) return 'pending'\n return 'success'\n}\n\nfunction checkRunState(status: string, conclusion: string | null): CheckInfo['state'] {\n if (status !== 'completed') return 'pending'\n return conclusion === 'failure' || conclusion === 'timed_out' || conclusion === 'action_required' || conclusion === 'startup_failure' || conclusion === 'cancelled'\n ? 'failure'\n : 'success'\n}\n\n/** GitHub provider bound to one host. */\nexport class GithubProvider implements Provider {\n private readonly octokit: Octokit\n\n /**\n * @param baseUrl - REST base URL (`https://api.github.com` or `<url>/api/v3`).\n * @param token - resolves the host's token for every request.\n */\n constructor(baseUrl: string, token: TokenSource) {\n this.octokit = new Octokit({\n baseUrl,\n userAgent: 'dsh-repo',\n log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },\n })\n this.octokit.hook.before('request', async (options) => {\n options.headers.authorization = `token ${await token()}`\n })\n }\n\n async repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo> {\n const { data } = await this.octokit.rest.repos.get({ ...split(ref.path), request: { signal: call.signal } })\n return {\n ...ref,\n webUrl: data.html_url,\n defaultBranch: data.default_branch,\n ...data.description === null ? {} : { description: data.description },\n visibility: data.visibility === 'internal' ? 'internal' : data.private ? 'private' : 'public',\n archived: data.archived,\n cloneUrl: data.clone_url,\n }\n }\n\n async listBranches(ref: RepoRef, query: { page: number; perPage: number; search?: string }, call: Call) {\n const [{ data }, info] = await Promise.all([\n this.octokit.rest.repos.listBranches({ ...split(ref.path), page: query.page, per_page: query.perPage, request: { signal: call.signal } }),\n this.octokit.rest.repos.get({ ...split(ref.path), request: { signal: call.signal } }),\n ])\n const items: BranchInfo[] = data\n .filter(branch => query.search === undefined || branch.name.includes(query.search))\n .map(branch => ({ name: branch.name, commit: branch.commit.sha, protected: branch.protected, default: branch.name === info.data.default_branch }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listCommits(ref: RepoRef, query: { page: number; perPage: number; ref?: string; path?: string }, call: Call) {\n const { data } = await this.octokit.rest.repos.listCommits({\n ...split(ref.path),\n page: query.page,\n per_page: query.perPage,\n ...query.ref === undefined ? {} : { sha: query.ref },\n ...query.path === undefined ? {} : { path: query.path },\n request: { signal: call.signal },\n })\n const items: CommitInfo[] = data.map(entry => ({\n sha: entry.sha,\n title: titleOf(entry.commit.message),\n message: entry.commit.message,\n authorName: entry.commit.author?.name ?? entry.author?.login ?? '',\n ...entry.commit.author?.email === undefined ? {} : { authorEmail: entry.commit.author.email },\n ...entry.commit.author?.date === undefined ? {} : { authoredAt: entry.commit.author.date },\n webUrl: entry.html_url,\n }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listTree(ref: RepoRef, query: { ref?: string; path: string; recursive: boolean }, call: Call) {\n const at = query.ref ?? (await this.repoInfo(ref, call)).defaultBranch\n const max = call.limits.maxTreeEntries\n // The Trees API reports its own truncation; the Contents API silently stops at 1,000 entries.\n const treeish = query.path === '' ? at : `${at}:${query.path}`\n const { data } = await this.octokit.rest.git.getTree({\n ...split(ref.path),\n tree_sha: treeish,\n ...query.recursive ? { recursive: 'true' } : {},\n request: { signal: call.signal },\n })\n const prefix = query.path === '' ? '' : `${query.path}/`\n const entries: TreeEntry[] = data.tree.map(entry => ({\n path: `${prefix}${entry.path ?? ''}`,\n type: entry.type === 'tree' ? 'dir' : entry.type === 'commit' ? 'submodule' : entry.mode === '120000' ? 'symlink' : 'file',\n ...entry.size === undefined ? {} : { size: entry.size },\n }))\n return { ref: at, entries: entries.slice(0, max), truncated: data.truncated || entries.length > max }\n }\n\n async readFile(ref: RepoRef, path: string, at: string | undefined, call: Call) {\n const target = at ?? (await this.repoInfo(ref, call)).defaultBranch\n const response = await this.octokit.rest.repos.getContent({\n ...split(ref.path),\n path,\n ref: target,\n mediaType: { format: 'raw' },\n request: { signal: call.signal },\n })\n const raw: unknown = response.data\n if (typeof raw !== 'string') throw new RepoError('invalid', `${path} 不是文件`)\n if (raw.includes('\\0')) return { path, ref: target, text: '', binary: true, truncated: false }\n return { path, ref: target, binary: false, ...truncateBytes(raw, call.limits.maxFileBytes) }\n }\n\n async commitFiles(ref: RepoRef, request: { branch: string; base?: string; message: string; files: readonly ({ action: 'write'; path: string; content: string } | { action: 'delete'; path: string })[] }, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n const info = await this.repoInfo(ref, call)\n if (request.branch === info.defaultBranch) throw new RepoError('forbidden', `不允许直接提交到默认分支 ${request.branch};请提交到新分支后开 PR`)\n const existing = await this.octokit.rest.repos.getBranch({ ...repo, branch: request.branch, request: { signal } }).catch((error: unknown) => {\n if ((error as { status?: number }).status === 404) return undefined\n throw error\n })\n if (existing?.data.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)\n const parent = existing?.data.commit.sha\n ?? (await this.octokit.rest.repos.getBranch({ ...repo, branch: request.base ?? info.defaultBranch, request: { signal } })).data.commit.sha\n const { data: parentCommit } = await this.octokit.rest.git.getCommit({ ...repo, commit_sha: parent, request: { signal } })\n // Keep the executable bit of files that already exist; refuse to replace links and directories.\n const modes = new Map<string, string>()\n for (const dir of new Set(request.files.filter(file => file.action === 'write').map(file => dirname(file.path)))) {\n const listing = await this.octokit.rest.git.getTree({ ...repo, tree_sha: dir === '' ? parent : `${parent}:${dir}`, request: { signal } }).catch((error: unknown) => {\n // A directory that does not exist yet holds no files.\n if ((error as { status?: number }).status === 404) return undefined\n throw error\n })\n for (const entry of listing?.data.tree ?? []) modes.set(dir === '' ? entry.path ?? '' : `${dir}/${entry.path ?? ''}`, entry.mode ?? '')\n }\n for (const file of request.files) {\n const mode = modes.get(file.path)\n if (mode === '120000' || mode === '040000' || mode === '160000') throw new RepoError('invalid', `${file.path} 在仓库中不是普通文件,不能用文件内容覆盖`)\n }\n const { data: tree } = await this.octokit.rest.git.createTree({\n ...repo,\n base_tree: parentCommit.tree.sha,\n tree: request.files.map(file => file.action === 'write'\n ? { path: file.path, mode: modes.get(file.path) === '100755' ? '100755' as const : '100644' as const, type: 'blob' as const, content: file.content }\n : { path: file.path, mode: '100644' as const, type: 'blob' as const, sha: null }),\n request: { signal },\n })\n const { data: commit } = await this.octokit.rest.git.createCommit({ ...repo, message: request.message, tree: tree.sha, parents: [parent], request: { signal } })\n if (existing === undefined) {\n await this.octokit.rest.git.createRef({ ...repo, ref: `refs/heads/${request.branch}`, sha: commit.sha, request: { signal } })\n } else {\n await this.octokit.rest.git.updateRef({ ...repo, ref: `heads/${request.branch}`, sha: commit.sha, force: false, request: { signal } })\n }\n return { sha: commit.sha, branch: request.branch, createdBranch: existing === undefined, webUrl: commit.html_url }\n }\n\n async listIssues(ref: RepoRef, query: { page: number; perPage: number; state: 'open' | 'closed' | 'all'; labels?: readonly string[]; assignee?: string }, call: Call) {\n const { data } = await this.octokit.rest.issues.listForRepo({\n ...split(ref.path),\n state: query.state,\n page: query.page,\n per_page: query.perPage,\n ...query.labels === undefined || query.labels.length === 0 ? {} : { labels: query.labels.join(',') },\n ...query.assignee === undefined ? {} : { assignee: query.assignee },\n request: { signal: call.signal },\n })\n // The issues endpoint also lists pull requests; they are change requests here.\n return { items: data.filter(entry => entry.pull_request === undefined).map(issue), ...nextPage(query, data.length) }\n }\n\n async getIssue(ref: RepoRef, number: number, call: Call) {\n const repo = split(ref.path)\n const [{ data }, comments] = await Promise.all([\n this.octokit.rest.issues.get({ ...repo, issue_number: number, request: { signal: call.signal } }),\n this.comments(ref, number, call),\n ])\n if (data.pull_request !== undefined) throw new RepoError('not-found', `#${number} 是 PR,不是 issue;请用 PR/MR 相关接口`)\n return { ...issue(data), comments }\n }\n\n async createIssue(ref: RepoRef, fields: { title: string; body?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const { data } = await this.octokit.rest.issues.create({\n ...split(ref.path),\n title: fields.title,\n ...fields.body === undefined ? {} : { body: fields.body },\n ...fields.labels === undefined ? {} : { labels: [...fields.labels] },\n ...fields.assignees === undefined ? {} : { assignees: [...fields.assignees] },\n request: { signal: call.signal },\n })\n return issue(data)\n }\n\n async updateIssue(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const { data } = await this.octokit.rest.issues.update({\n ...split(ref.path),\n issue_number: number,\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { body: update.body },\n ...update.state === undefined ? {} : { state: update.state },\n ...update.labels === undefined ? {} : { labels: [...update.labels] },\n ...update.assignees === undefined ? {} : { assignees: [...update.assignees] },\n request: { signal: call.signal },\n })\n return issue(data)\n }\n\n async commentIssue(ref: RepoRef, number: number, body: string, call: Call) {\n const { data } = await this.octokit.rest.issues.createComment({ ...split(ref.path), issue_number: number, body, request: { signal: call.signal } })\n return comment(data)\n }\n\n async listChanges(ref: RepoRef, query: { page: number; perPage: number; state: ChangeState | 'all'; sourceBranch?: string; targetBranch?: string }, call: Call) {\n const repo = split(ref.path)\n const { data } = await this.octokit.rest.pulls.list({\n ...repo,\n state: query.state === 'merged' ? 'closed' : query.state,\n page: query.page,\n per_page: query.perPage,\n ...query.sourceBranch === undefined ? {} : { head: `${repo.owner}:${query.sourceBranch}` },\n ...query.targetBranch === undefined ? {} : { base: query.targetBranch },\n request: { signal: call.signal },\n })\n const items = data.map(pull).filter(change => query.state === 'all' || change.state === query.state)\n return { items, ...nextPage(query, data.length) }\n }\n\n async getChange(ref: RepoRef, number: number, call: Call) {\n const [{ data }, comments] = await Promise.all([\n this.octokit.rest.pulls.get({ ...split(ref.path), pull_number: number, request: { signal: call.signal } }),\n this.comments(ref, number, call),\n ])\n return { ...pull(data), comments }\n }\n\n async changeDiff(ref: RepoRef, number: number, call: Call) {\n const response = await this.octokit.rest.pulls.get({ ...split(ref.path), pull_number: number, mediaType: { format: 'diff' }, request: { signal: call.signal } })\n const raw: unknown = response.data\n const { text, truncated } = truncateBytes(typeof raw === 'string' ? raw : '', call.limits.maxDiffBytes)\n return { diff: text, truncated }\n }\n\n async changeStatus(ref: RepoRef, number: number, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n const { data: change } = await this.octokit.rest.pulls.get({ ...repo, pull_number: number, request: { signal } })\n const sha = change.head.sha\n const [runs, statuses] = await Promise.all([\n this.allPages(page => this.octokit.rest.checks.listForRef({ ...repo, ref: sha, per_page: PAGE, page, request: { signal } }).then(response => response.data.check_runs)),\n this.allPages(page => this.octokit.rest.repos.getCombinedStatusForRef({ ...repo, ref: sha, per_page: PAGE, page, request: { signal } }).then(response => response.data.statuses)),\n ])\n const checks: CheckInfo[] = [\n ...runs.map(run => ({ name: run.name, state: checkRunState(run.status, run.conclusion), ...run.html_url === null ? {} : { webUrl: run.html_url } })),\n ...statuses.map(status => ({\n name: status.context,\n state: status.state === 'success' ? 'success' as const : status.state === 'pending' ? 'pending' as const : 'failure' as const,\n ...status.target_url === null ? {} : { webUrl: status.target_url },\n })),\n ]\n return { headSha: sha, checks, overall: overall(checks), ...change.mergeable === null ? {} : { mergeable: change.mergeable } }\n }\n\n async createChange(ref: RepoRef, fields: { title: string; body?: string; sourceBranch: string; targetBranch: string; draft: boolean; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const repo = split(ref.path)\n const { data } = await this.octokit.rest.pulls.create({\n ...repo,\n title: fields.title,\n head: fields.sourceBranch,\n base: fields.targetBranch,\n draft: fields.draft,\n ...fields.body === undefined ? {} : { body: fields.body },\n request: { signal: call.signal },\n })\n if ((fields.labels?.length ?? 0) === 0 && (fields.assignees?.length ?? 0) === 0) return pull(data)\n // Labels and assignees live on the pull request's issue.\n await this.octokit.rest.issues.update({\n ...repo,\n issue_number: data.number,\n ...fields.labels === undefined ? {} : { labels: [...fields.labels] },\n ...fields.assignees === undefined ? {} : { assignees: [...fields.assignees] },\n request: { signal: call.signal },\n })\n return pull((await this.octokit.rest.pulls.get({ ...repo, pull_number: data.number, request: { signal: call.signal } })).data)\n }\n\n async updateChange(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; targetBranch?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n if (update.labels !== undefined || update.assignees !== undefined) {\n await this.octokit.rest.issues.update({\n ...repo,\n issue_number: number,\n ...update.labels === undefined ? {} : { labels: [...update.labels] },\n ...update.assignees === undefined ? {} : { assignees: [...update.assignees] },\n request: { signal },\n })\n }\n const { data } = await this.octokit.rest.pulls.update({\n ...repo,\n pull_number: number,\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { body: update.body },\n ...update.state === undefined ? {} : { state: update.state },\n ...update.targetBranch === undefined ? {} : { base: update.targetBranch },\n request: { signal },\n })\n return pull(data)\n }\n\n async commentChange(ref: RepoRef, number: number, body: string, call: Call) {\n return await this.commentIssue(ref, number, body, call)\n }\n\n async mergeChange(ref: RepoRef, number: number, request: { headSha: string; method?: 'merge' | 'squash' | 'rebase' }, call: Call) {\n const { data } = await this.octokit.rest.pulls.merge({\n ...split(ref.path),\n pull_number: number,\n sha: request.headSha,\n ...request.method === undefined ? {} : { merge_method: request.method },\n request: { signal: call.signal },\n })\n return { sha: data.sha }\n }\n\n /** Every page of a list endpoint, so an aggregate never rests on a partial list. */\n private async allPages<T>(read: (page: number) => Promise<readonly T[]>): Promise<T[]> {\n const items: T[] = []\n for (let page = 1; page <= MAX_STATUS_PAGES; page += 1) {\n const batch = await read(page)\n items.push(...batch)\n if (batch.length < PAGE) return items\n }\n throw new RepoError('too-large', `CI 检查超过 ${MAX_STATUS_PAGES * PAGE} 条,无法给出完整状态`)\n }\n\n private async comments(ref: RepoRef, number: number, call: Call): Promise<CommentInfo[]> {\n const { data } = await this.octokit.rest.issues.listComments({ ...split(ref.path), issue_number: number, per_page: call.limits.maxComments, request: { signal: call.signal } })\n return data.map(comment)\n }\n}\n","/**\n * GitLab provider on `@gitbeaker/rest`, the TypeScript SDK GitLab's\n * documentation lists: gitlab.com and self-managed instances, including ones\n * served under a path prefix. Merge requests are this module's change\n * requests; issue and merge request numbers are project-scoped IIDs.\n *\n * @module dsh-repo/providers/gitlab\n */\n\nimport { Gitlab } from '@gitbeaker/rest'\nimport type {\n BranchInfo, ChangeInfo, ChangeState, CheckInfo, CommentInfo, CommitInfo, FileChange, IssueInfo, RepoInfo, RepoRef, RepoUser, TreeEntry,\n} from '../contract.ts'\nimport { RepoError } from '../errors.ts'\nimport { nextPage, titleOf, truncateBytes } from './types.ts'\nimport type { Call, Paging, Provider, TokenSource } from './types.ts'\n\n/** GitLab's maximum page size. */\nconst MAX_PAGE = 100\n\n/** Prefix GitLab uses to mark a draft merge request in its title. */\nconst DRAFT_PREFIX = 'Draft: '\n\ninterface GitlabUser { readonly username: string; readonly web_url?: string }\n\nfunction user(value: GitlabUser | null | undefined): RepoUser {\n return value === null || value === undefined ? { username: 'ghost' } : { username: value.username, ...value.web_url === undefined ? {} : { webUrl: value.web_url } }\n}\n\nfunction labelNames(labels: unknown): string[] {\n if (!Array.isArray(labels)) return []\n return labels.map(label => typeof label === 'string' ? label : typeof label === 'object' && label !== null && 'name' in label ? String(label.name) : '').filter(name => name !== '')\n}\n\ninterface GitlabIssue {\n readonly iid: number\n readonly title: string\n readonly description?: string | null\n readonly state: string\n readonly author: GitlabUser\n readonly labels?: unknown\n readonly assignees?: readonly GitlabUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly web_url: string\n}\n\nfunction issue(value: GitlabIssue): IssueInfo {\n return {\n number: value.iid,\n title: value.title,\n body: value.description ?? '',\n state: value.state === 'closed' ? 'closed' : 'open',\n author: user(value.author),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.web_url,\n }\n}\n\ninterface GitlabMergeRequest extends GitlabIssue {\n readonly draft?: boolean\n readonly work_in_progress?: boolean\n readonly source_branch: string\n readonly target_branch: string\n readonly sha: string\n}\n\nfunction mergeRequest(value: GitlabMergeRequest): ChangeInfo {\n const state: ChangeState = value.state === 'merged' ? 'merged' : value.state === 'opened' ? 'open' : 'closed'\n return {\n ...issue(value),\n state,\n draft: value.draft === true || value.work_in_progress === true,\n sourceBranch: value.source_branch,\n targetBranch: value.target_branch,\n headSha: value.sha,\n }\n}\n\ninterface GitlabNote {\n readonly id: number\n readonly body: string\n readonly author: GitlabUser\n readonly created_at: string\n readonly system?: boolean\n}\n\nfunction note(value: GitlabNote): CommentInfo {\n return { id: String(value.id), author: user(value.author), body: value.body, createdAt: value.created_at }\n}\n\nfunction pipelineState(status: string): CheckInfo['state'] {\n if (status === 'success' || status === 'skipped') return 'success'\n if (status === 'failed' || status === 'canceled') return 'failure'\n return 'pending'\n}\n\n/** Detailed merge statuses GitLab reports while it is still computing mergeability. */\nconst COMPUTING = new Set(['checking', 'unchecked', 'preparing', 'approvals_syncing'])\n\nfunction paging(query: Paging): { page: number; perPage: number; maxPages: number } {\n return { page: query.page, perPage: query.perPage, maxPages: 1 }\n}\n\nfunction dirname(path: string): string {\n const slash = path.lastIndexOf('/')\n return slash < 0 ? '' : path.slice(0, slash)\n}\n\n/** GitLab provider bound to one host. */\nexport class GitlabProvider implements Provider {\n private readonly api: InstanceType<typeof Gitlab<false>>\n\n /**\n * @param host - instance URL, with its path prefix when it has one.\n * @param token - resolves the host's token for every request.\n * @param timeoutMs - per-request timeout; GitBeaker takes no per-call signal.\n */\n constructor(host: string, token: TokenSource, timeoutMs: number) {\n this.api = new Gitlab({ host, token, queryTimeout: timeoutMs })\n }\n\n async repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo> {\n call.signal.throwIfAborted()\n const data = await this.api.Projects.show(ref.path)\n return {\n ...ref,\n webUrl: data.web_url,\n defaultBranch: data.default_branch,\n ...typeof data.description === 'string' && data.description !== '' ? { description: data.description } : {},\n visibility: data.visibility === 'internal' ? 'internal' : data.visibility === 'private' ? 'private' : 'public',\n archived: data.archived,\n cloneUrl: data.http_url_to_repo,\n }\n }\n\n async listBranches(ref: RepoRef, query: Paging & { search?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Branches.all(ref.path, { ...paging(query), ...query.search === undefined ? {} : { search: query.search } })\n const items: BranchInfo[] = data.map(branch => ({ name: branch.name, commit: String(branch.commit.id), protected: branch.protected, default: branch.default }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listCommits(ref: RepoRef, query: Paging & { ref?: string; path?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Commits.all(ref.path, {\n ...paging(query),\n ...query.ref === undefined ? {} : { refName: query.ref },\n ...query.path === undefined ? {} : { path: query.path },\n })\n const items: CommitInfo[] = data.map(entry => ({\n sha: entry.id,\n title: entry.title ?? titleOf(entry.message),\n message: entry.message,\n authorName: entry.author_name,\n authorEmail: entry.author_email,\n authoredAt: entry.authored_date,\n webUrl: entry.web_url,\n }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listTree(ref: RepoRef, query: { ref?: string; path: string; recursive: boolean }, call: Call) {\n const at = query.ref ?? (await this.repoInfo(ref, call)).defaultBranch\n const max = call.limits.maxTreeEntries\n const data = await this.api.Repositories.allRepositoryTrees(ref.path, {\n ref: at,\n ...query.path === '' ? {} : { path: query.path },\n recursive: query.recursive,\n perPage: MAX_PAGE,\n maxPages: Math.floor(max / MAX_PAGE) + 1,\n })\n const entries: TreeEntry[] = data.map(entry => ({\n path: entry.path,\n type: entry.type === 'tree' ? 'dir' : entry.type === 'commit' ? 'submodule' : entry.mode === '120000' ? 'symlink' : 'file',\n }))\n return { ref: at, entries: entries.slice(0, max), truncated: entries.length > max }\n }\n\n async readFile(ref: RepoRef, path: string, at: string | undefined, call: Call) {\n const target = at ?? (await this.repoInfo(ref, call)).defaultBranch\n const raw = await this.api.RepositoryFiles.showRaw(ref.path, path, target)\n const text = typeof raw === 'string' ? raw : await raw.text()\n if (text.includes('\\0')) return { path, ref: target, text: '', binary: true, truncated: false }\n return { path, ref: target, binary: false, ...truncateBytes(text, call.limits.maxFileBytes) }\n }\n\n async commitFiles(ref: RepoRef, request: { branch: string; base?: string; message: string; files: readonly FileChange[] }, call: Call) {\n const info = await this.repoInfo(ref, call)\n if (request.branch === info.defaultBranch) throw new RepoError('forbidden', `不允许直接提交到默认分支 ${request.branch};请提交到新分支后开 MR`)\n const existing = await this.api.Branches.show(ref.path, request.branch).catch((error: unknown) => {\n if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return undefined\n throw error\n })\n if (existing?.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)\n const start = existing === undefined ? request.base ?? info.defaultBranch : request.branch\n // GitLab needs `create` or `update` per file, so list each touched directory at the start point.\n const present = new Set<string>()\n for (const dir of new Set(request.files.filter(file => file.action === 'write').map(file => dirname(file.path)))) {\n call.signal.throwIfAborted()\n const listing = await this.api.Repositories.allRepositoryTrees(ref.path, { ref: start, ...dir === '' ? {} : { path: dir }, perPage: MAX_PAGE }).catch((error: unknown) => {\n // A directory that does not exist yet holds no files.\n if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return []\n throw error\n })\n for (const entry of listing) if (entry.type === 'blob') present.add(entry.path)\n }\n const actions = request.files.map(file => file.action === 'delete'\n ? { action: 'delete' as const, filePath: file.path }\n : { action: present.has(file.path) ? 'update' as const : 'create' as const, filePath: file.path, content: file.content })\n call.signal.throwIfAborted()\n const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, existing === undefined ? { startBranch: start } : {})\n return { sha: commit.id, branch: request.branch, createdBranch: existing === undefined, webUrl: commit.web_url }\n }\n\n async listIssues(ref: RepoRef, query: Paging & { state: 'open' | 'closed' | 'all'; labels?: readonly string[]; assignee?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Issues.all({\n projectId: ref.path,\n ...paging(query),\n ...query.state === 'all' ? {} : { state: query.state === 'open' ? 'opened' as const : 'closed' as const },\n ...query.labels === undefined || query.labels.length === 0 ? {} : { labels: query.labels.join(',') },\n ...query.assignee === undefined ? {} : { assigneeUsername: [query.assignee] },\n })\n return { items: data.map(entry => issue(entry)), ...nextPage(query, data.length) }\n }\n\n async getIssue(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const [data, notes] = await Promise.all([\n this.api.Issues.show(number, { projectId: ref.path }),\n this.api.IssueNotes.all(ref.path, number, { sort: 'asc', perPage: call.limits.maxComments, maxPages: 1 }),\n ])\n return { ...issue(data), comments: notes.filter(entry => entry.system !== true).map(note) }\n }\n\n async createIssue(ref: RepoRef, fields: { title: string; body?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(fields.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.Issues.create(ref.path, fields.title, {\n ...fields.body === undefined ? {} : { description: fields.body },\n ...fields.labels === undefined ? {} : { labels: fields.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return issue(data)\n }\n\n async updateIssue(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(update.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.Issues.edit(ref.path, number, {\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { description: update.body },\n ...update.state === undefined ? {} : { stateEvent: update.state === 'closed' ? 'close' as const : 'reopen' as const },\n ...update.labels === undefined ? {} : { labels: update.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return issue(data)\n }\n\n async commentIssue(ref: RepoRef, number: number, body: string, call: Call) {\n call.signal.throwIfAborted()\n return note(await this.api.IssueNotes.create(ref.path, number, body))\n }\n\n async listChanges(ref: RepoRef, query: Paging & { state: ChangeState | 'all'; sourceBranch?: string; targetBranch?: string }, call: Call) {\n call.signal.throwIfAborted()\n const state = query.state === 'all' ? undefined : query.state === 'open' ? 'opened' as const : query.state\n const data = await this.api.MergeRequests.all({\n projectId: ref.path,\n ...paging(query),\n ...state === undefined ? {} : { state },\n ...query.sourceBranch === undefined ? {} : { sourceBranch: query.sourceBranch },\n ...query.targetBranch === undefined ? {} : { targetBranch: query.targetBranch },\n })\n return { items: data.map(entry => mergeRequest(entry)), ...nextPage(query, data.length) }\n }\n\n async getChange(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const [data, notes] = await Promise.all([\n this.api.MergeRequests.show(ref.path, number),\n this.api.MergeRequestNotes.all(ref.path, number, { sort: 'asc', perPage: call.limits.maxComments, maxPages: 1 }),\n ])\n return { ...mergeRequest(data), comments: notes.filter(entry => entry.system !== true).map(note) }\n }\n\n async changeDiff(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const files = await this.api.MergeRequests.allDiffs(ref.path, number, { perPage: MAX_PAGE })\n // GitLab leaves `diff` empty for collapsed or oversized files; say so instead of presenting a complete diff.\n let omitted = false\n const parts = files.map((file) => {\n const from = file.new_file ? '/dev/null' : `a/${file.old_path}`\n const to = file.deleted_file ? '/dev/null' : `b/${file.new_path}`\n const skipped = file.too_large === true || (file.collapsed === true && file.diff === '')\n if (skipped) omitted = true\n return `diff --git a/${file.old_path} b/${file.new_path}\\n--- ${from}\\n+++ ${to}\\n${skipped ? '# GitLab 未返回这个文件的 diff(文件过大或已折叠)\\n' : file.diff}`\n })\n const { text, truncated } = truncateBytes(parts.join(''), call.limits.maxDiffBytes)\n return { diff: text, truncated: truncated || omitted }\n }\n\n async changeStatus(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.show(ref.path, number)\n const pipeline = data.head_pipeline\n const checks: CheckInfo[] = pipeline === undefined || pipeline === null\n ? []\n : [{ name: `pipeline #${pipeline.id}`, state: pipelineState(pipeline.status), ...pipeline.web_url === undefined ? {} : { webUrl: pipeline.web_url } }]\n const detailed = data.detailed_merge_status\n return {\n headSha: data.sha,\n checks,\n overall: checks[0]?.state ?? 'none' as const,\n ...typeof detailed !== 'string' || COMPUTING.has(detailed) ? {} : { mergeable: detailed === 'mergeable' },\n }\n }\n\n async createChange(ref: RepoRef, fields: { title: string; body?: string; sourceBranch: string; targetBranch: string; draft: boolean; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(fields.assignees, call)\n call.signal.throwIfAborted()\n const title = fields.draft && !fields.title.startsWith(DRAFT_PREFIX) ? `${DRAFT_PREFIX}${fields.title}` : fields.title\n const data = await this.api.MergeRequests.create(ref.path, fields.sourceBranch, fields.targetBranch, title, {\n ...fields.body === undefined ? {} : { description: fields.body },\n ...fields.labels === undefined ? {} : { labels: fields.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return mergeRequest(data)\n }\n\n async updateChange(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; targetBranch?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(update.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.edit(ref.path, number, {\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { description: update.body },\n ...update.state === undefined ? {} : { stateEvent: update.state === 'closed' ? 'close' as const : 'reopen' as const },\n ...update.targetBranch === undefined ? {} : { targetBranch: update.targetBranch },\n ...update.labels === undefined ? {} : { labels: update.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return mergeRequest(data)\n }\n\n async commentChange(ref: RepoRef, number: number, body: string, call: Call) {\n call.signal.throwIfAborted()\n return note(await this.api.MergeRequestNotes.create(ref.path, number, body))\n }\n\n async mergeChange(ref: RepoRef, number: number, request: { headSha: string; method?: 'merge' | 'squash' | 'rebase' }, call: Call) {\n if (request.method === 'rebase') throw new RepoError('invalid', 'GitLab 的合并接口不支持 rebase 方式;可用 merge 或 squash')\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.merge(ref.path, number, {\n sha: request.headSha,\n ...request.method === undefined ? {} : { squash: request.method === 'squash' },\n })\n const sha = data.merge_commit_sha ?? data.squash_commit_sha\n return typeof sha === 'string' ? { sha } : {}\n }\n\n /** User ids for usernames; GitLab assigns by id. */\n private async userIds(usernames: readonly string[] | undefined, call: Call): Promise<number[] | undefined> {\n if (usernames === undefined) return undefined\n const ids: number[] = []\n for (const username of usernames) {\n call.signal.throwIfAborted()\n const [found] = await this.api.Users.all({ username, maxPages: 1 })\n if (found === undefined) throw new RepoError('invalid', `GitLab 上没有用户 ${username}`)\n ids.push(found.id)\n }\n return ids\n }\n}\n","/**\n * Repository targets: map a URL or `host/path` to a configured host and a\n * repository path, and apply the configured repository patterns.\n *\n * @module dsh-repo/target\n */\n\nimport type { RepoRef } from './contract.ts'\nimport type { HostSpec } from './config.ts'\nimport { RepoError } from './errors.ts'\n\nconst SEGMENT = /^[A-Za-z0-9._-]+$/\nconst SCP_LIKE = /^[A-Za-z0-9._-]+@([A-Za-z0-9.-]+):(.+)$/\n\n/** A target resolved to its host. */\nexport interface ResolvedTarget extends RepoRef {\n readonly spec: HostSpec\n}\n\ninterface ParsedTarget {\n /** Lowercase host, with port only for HTTP(S) addresses. */\n readonly host: string\n /** Whether the address was HTTP(S) or bare, so the host's port and path prefix apply. */\n readonly web: boolean\n readonly pathname: string\n}\n\nfunction parse(input: string): ParsedTarget | undefined {\n const value = input.trim()\n if (value === '' || /\\s/.test(value)) return undefined\n const scp = SCP_LIKE.exec(value)\n if (scp !== null) return { host: (scp[1] ?? '').toLowerCase(), web: false, pathname: `/${scp[2] ?? ''}` }\n let url: URL\n try {\n url = new URL(/^[a-z][a-z0-9+.-]*:\\/\\//i.test(value) ? value : `https://${value}`)\n } catch {\n // Neither a URL nor host/path.\n return undefined\n }\n if (url.protocol === 'https:' || url.protocol === 'http:') return { host: url.host.toLowerCase(), web: true, pathname: decodeURIComponent(url.pathname) }\n if (url.protocol === 'ssh:' || url.protocol === 'git:') return { host: url.hostname.toLowerCase(), web: false, pathname: decodeURIComponent(url.pathname) }\n return undefined\n}\n\nfunction repoPath(kind: HostSpec['kind'], rest: string): string | undefined {\n let segments = rest.replace(/\\.git$/, '').split('/').filter(segment => segment !== '')\n if (kind === 'github') {\n segments = segments.slice(0, 2)\n if (segments.length !== 2) return undefined\n } else {\n const marker = segments.indexOf('-')\n if (marker >= 0) segments = segments.slice(0, marker)\n if (segments.length < 2) return undefined\n }\n if (segments.at(-1)?.endsWith('.git') === true) segments[segments.length - 1] = segments.at(-1)!.slice(0, -4)\n return segments.every(segment => SEGMENT.test(segment) && segment !== '.' && segment !== '..') ? segments.join('/') : undefined\n}\n\n/**\n * Whether a repository key matches one configured pattern.\n * @param key - lowercase `host/path`.\n * @param pattern - lowercase pattern; a final `*` matches one segment, `**` one or more.\n * @returns whether it matches.\n */\nexport function matchesPattern(key: string, pattern: string): boolean {\n const keySegments = key.split('/')\n const patternSegments = pattern.split('/')\n const last = patternSegments.at(-1)\n if (last === '**') {\n const prefix = patternSegments.slice(0, -1)\n return keySegments.length > prefix.length && prefix.every((segment, index) => segment === keySegments[index])\n }\n if (keySegments.length !== patternSegments.length) return false\n return patternSegments.every((segment, index) => segment === '*' ? index === patternSegments.length - 1 : segment === keySegments[index])\n}\n\n/**\n * Resolve a repository target.\n * @param input - URL or `host/path`.\n * @param hosts - configured hosts.\n * @param patterns - configured repository patterns; empty allows every repository on the hosts.\n * @returns the host and repository path.\n * @throws {RepoError} `invalid` for an unreadable target, `not-allowed` when no host or pattern admits it.\n */\nexport function resolveTarget(input: string, hosts: readonly HostSpec[], patterns: readonly string[]): ResolvedTarget {\n const parsed = parse(input)\n if (parsed === undefined) throw new RepoError('invalid', `无法识别的仓库:${input}(填仓库网址、git 地址或 主机/路径)`)\n let best: { spec: HostSpec; rest: string; prefix: number } | undefined\n for (const spec of hosts) {\n const url = new URL(spec.url)\n const prefix = url.pathname.replace(/\\/+$/, '')\n if (parsed.web) {\n if (url.host !== parsed.host) continue\n if (prefix !== '' && parsed.pathname !== prefix && !parsed.pathname.startsWith(`${prefix}/`)) continue\n if (best === undefined || prefix.length > best.prefix) best = { spec, rest: parsed.pathname.slice(prefix.length), prefix: prefix.length }\n } else if (url.hostname === parsed.host && best === undefined) {\n best = { spec, rest: parsed.pathname, prefix: 0 }\n }\n }\n if (best === undefined) throw new RepoError('not-allowed', `没有为 ${parsed.host} 配置主机,dsh-repo 不能访问 ${input}`)\n const path = repoPath(best.spec.kind, best.rest)\n if (path === undefined) {\n throw new RepoError('invalid', best.spec.kind === 'github' ? `GitHub 仓库路径应为 owner/name:${input}` : `GitLab 仓库路径应为 group/project(可有多级 group):${input}`)\n }\n const host = new URL(best.spec.url).host\n const key = `${host}/${path}`.toLowerCase()\n if (patterns.length > 0 && !patterns.some(pattern => matchesPattern(key, pattern))) {\n throw new RepoError('not-allowed', `${host}/${path} 不在 dsh-repo 配置的仓库范围内`)\n }\n return { spec: best.spec, kind: best.spec.kind, host, path, webUrl: `${best.spec.url}/${path}` }\n}\n","/**\n * The `dshRepos` service: resolves each target against the configured hosts\n * and repositories, validates arguments, attaches the call deadline, delegates\n * to the host family's provider, and turns every failure into a\n * {@link RepoError}.\n *\n * Tokens are read through `ctx.credentials` on every request, so a rotated\n * token takes effect without a reload.\n *\n * @module dsh-repo/service\n */\n\nimport type {\n CallOptions, ChangeCreate, ChangeListOptions, ChangeUpdate, CommitRequest, DshRepoService, IssueCreate, IssueListOptions, IssueUpdate,\n MergeOptions, PageOptions, RepoRef, RepoTarget,\n} from './contract.ts'\nimport { apiBaseUrl } from './config.ts'\nimport type { HostSpec, RepoConfig } from './config.ts'\nimport { RepoError, toRepoError } from './errors.ts'\nimport type { HostCredentials } from './host.ts'\nimport { GithubProvider } from './providers/github.ts'\nimport { GitlabProvider } from './providers/gitlab.ts'\nimport type { Call, Paging, Provider } from './providers/types.ts'\nimport { resolveTarget } from './target.ts'\nimport type { ResolvedTarget } from './target.ts'\n\n/** Name the service is provided under. */\nexport const DSH_REPOS_SERVICE = 'dshRepos'\n\n/** Builds the provider of one host; tests substitute it. */\nexport type ProviderFactory = (spec: HostSpec, token: () => Promise<string>, timeoutMs: number) => Provider\n\n/** Default factory: Octokit for GitHub, GitBeaker for GitLab. */\nexport const defaultProviderFactory: ProviderFactory = (spec, token, timeoutMs) => spec.kind === 'github'\n ? new GithubProvider(apiBaseUrl(spec), token)\n : new GitlabProvider(apiBaseUrl(spec), token, timeoutMs)\n\nconst BRANCH = /^(?!-)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*\\.lock$)(?!.*\\/$)[^\\s~^:?*[\\\\\\u0000-\\u001f\\u007f]+$/\n\nfunction requireBranch(value: string, label: string): void {\n if (!BRANCH.test(value) || value.startsWith('/') || value === '@') throw new RepoError('invalid', `${label}不合法:${value}`)\n}\n\nfunction requireRepoPath(value: string, label: string): void {\n const segments = value.split('/')\n if (value === '' || value.startsWith('/') || segments.some(segment => segment === '' || segment === '.' || segment === '..') || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n throw new RepoError('invalid', `${label}不合法:${value}(用仓库根目录下的相对路径,例如 src/index.ts)`)\n }\n}\n\nfunction requireNumber(value: number): void {\n if (!Number.isSafeInteger(value) || value < 1) throw new RepoError('invalid', `编号必须是正整数:${value}`)\n}\n\nfunction requireText(value: string, label: string): void {\n if (value.trim() === '') throw new RepoError('invalid', `${label}不能为空`)\n}\n\n/** The service implementation. */\nexport class RepoService implements DshRepoService {\n readonly version = 1 as const\n private readonly providers = new Map<string, Provider>()\n\n /**\n * @param config - validated configuration.\n * @param credentials - DSH credential store; tokens are resolved per request.\n * @param factory - provider factory.\n */\n constructor(\n private readonly config: RepoConfig,\n private readonly credentials: HostCredentials,\n private readonly factory: ProviderFactory = defaultProviderFactory,\n ) {}\n\n /** Whether any host is configured. */\n get configured(): boolean {\n return this.config.hosts.length > 0\n }\n\n resolve(repo: RepoTarget): RepoRef {\n const { spec: _spec, ...ref } = this.target(repo)\n return ref\n }\n\n async repoInfo(repo: RepoTarget, options: CallOptions = {}) {\n return await this.run(repo, options, '读取仓库信息', (provider, ref, call) => provider.repoInfo(ref, call))\n }\n\n async listBranches(repo: RepoTarget, options: PageOptions & { readonly search?: string } = {}) {\n const query = { ...this.paging(options), ...options.search === undefined ? {} : { search: options.search } }\n return await this.run(repo, options, '列出分支', (provider, ref, call) => provider.listBranches(ref, query, call))\n }\n\n async listCommits(repo: RepoTarget, options: PageOptions & { readonly ref?: string; readonly path?: string } = {}) {\n if (options.path !== undefined) requireRepoPath(options.path, '路径')\n const query = { ...this.paging(options), ...options.ref === undefined ? {} : { ref: options.ref }, ...options.path === undefined ? {} : { path: options.path } }\n return await this.run(repo, options, '列出提交', (provider, ref, call) => provider.listCommits(ref, query, call))\n }\n\n async listTree(repo: RepoTarget, options: CallOptions & { readonly ref?: string; readonly path?: string; readonly recursive?: boolean } = {}) {\n const path = (options.path ?? '').replace(/^\\/+|\\/+$/g, '')\n if (path !== '') requireRepoPath(path, '目录')\n const query = { path, recursive: options.recursive === true, ...options.ref === undefined ? {} : { ref: options.ref } }\n return await this.run(repo, options, '列出目录', (provider, ref, call) => provider.listTree(ref, query, call))\n }\n\n async readFile(repo: RepoTarget, path: string, options: CallOptions & { readonly ref?: string } = {}) {\n requireRepoPath(path, '文件路径')\n return await this.run(repo, options, `读取文件 ${path}`, (provider, ref, call) => provider.readFile(ref, path, options.ref, call))\n }\n\n async commitFiles(repo: RepoTarget, request: CommitRequest) {\n requireBranch(request.branch, '分支名')\n if (request.base !== undefined) requireBranch(request.base, '起点分支名')\n requireText(request.message, '提交说明')\n if (request.files.length === 0) throw new RepoError('invalid', '提交至少要包含一个文件')\n if (request.files.length > this.config.limits.maxCommitFiles) throw new RepoError('too-large', `一次提交最多 ${this.config.limits.maxCommitFiles} 个文件`)\n const seen = new Set<string>()\n for (const file of request.files) {\n requireRepoPath(file.path, '文件路径')\n if (seen.has(file.path)) throw new RepoError('invalid', `文件重复:${file.path}`)\n seen.add(file.path)\n if (file.action === 'write' && Buffer.byteLength(file.content, 'utf8') > this.config.limits.maxFileBytes) {\n throw new RepoError('too-large', `${file.path} 超过单文件上限 ${this.config.limits.maxFileBytes} 字节`)\n }\n }\n const fields = { branch: request.branch, message: request.message, files: request.files, ...request.base === undefined ? {} : { base: request.base } }\n return await this.run(repo, request, `提交到分支 ${request.branch}`, (provider, ref, call) => provider.commitFiles(ref, fields, call))\n }\n\n async listIssues(repo: RepoTarget, options: IssueListOptions = {}) {\n const query = {\n ...this.paging(options),\n state: options.state ?? 'open',\n ...options.labels === undefined ? {} : { labels: options.labels },\n ...options.assignee === undefined ? {} : { assignee: options.assignee },\n }\n return await this.run(repo, options, '列出 issue', (provider, ref, call) => provider.listIssues(ref, query, call))\n }\n\n async getIssue(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 issue #${number}`, (provider, ref, call) => provider.getIssue(ref, number, call))\n }\n\n async createIssue(repo: RepoTarget, fields: IssueCreate) {\n requireText(fields.title, '标题')\n return await this.run(repo, fields, '创建 issue', (provider, ref, call) => provider.createIssue(ref, fields, call))\n }\n\n async updateIssue(repo: RepoTarget, number: number, update: IssueUpdate) {\n requireNumber(number)\n if (update.title !== undefined) requireText(update.title, '标题')\n return await this.run(repo, update, `更新 issue #${number}`, (provider, ref, call) => provider.updateIssue(ref, number, update, call))\n }\n\n async commentIssue(repo: RepoTarget, number: number, body: string, options: CallOptions = {}) {\n requireNumber(number)\n requireText(body, '评论内容')\n return await this.run(repo, options, `评论 issue #${number}`, (provider, ref, call) => provider.commentIssue(ref, number, body, call))\n }\n\n async listChanges(repo: RepoTarget, options: ChangeListOptions = {}) {\n const query = {\n ...this.paging(options),\n state: options.state ?? 'open',\n ...options.sourceBranch === undefined ? {} : { sourceBranch: options.sourceBranch },\n ...options.targetBranch === undefined ? {} : { targetBranch: options.targetBranch },\n }\n return await this.run(repo, options, '列出 PR/MR', (provider, ref, call) => provider.listChanges(ref, query, call))\n }\n\n async getChange(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number}`, (provider, ref, call) => provider.getChange(ref, number, call))\n }\n\n async changeDiff(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number} 的 diff`, (provider, ref, call) => provider.changeDiff(ref, number, call))\n }\n\n async changeStatus(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number} 的状态`, (provider, ref, call) => provider.changeStatus(ref, number, call))\n }\n\n async createChange(repo: RepoTarget, change: ChangeCreate) {\n requireText(change.title, '标题')\n requireBranch(change.sourceBranch, '源分支名')\n if (change.targetBranch !== undefined) requireBranch(change.targetBranch, '目标分支名')\n return await this.run(repo, change, '创建 PR/MR', async (provider, ref, call) => {\n const targetBranch = change.targetBranch ?? (await provider.repoInfo(ref, call)).defaultBranch\n if (targetBranch === change.sourceBranch) throw new RepoError('invalid', '源分支和目标分支不能相同')\n const { signal: _signal, ...fields } = change\n return await provider.createChange(ref, { ...fields, targetBranch, draft: change.draft === true }, call)\n })\n }\n\n async updateChange(repo: RepoTarget, number: number, update: ChangeUpdate) {\n requireNumber(number)\n if (update.title !== undefined) requireText(update.title, '标题')\n if (update.targetBranch !== undefined) requireBranch(update.targetBranch, '目标分支名')\n return await this.run(repo, update, `更新 PR/MR #${number}`, (provider, ref, call) => provider.updateChange(ref, number, update, call))\n }\n\n async commentChange(repo: RepoTarget, number: number, body: string, options: CallOptions = {}) {\n requireNumber(number)\n requireText(body, '评论内容')\n return await this.run(repo, options, `评论 PR/MR #${number}`, (provider, ref, call) => provider.commentChange(ref, number, body, call))\n }\n\n async mergeChange(repo: RepoTarget, number: number, options: MergeOptions) {\n requireNumber(number)\n if (!/^[0-9a-f]{40}([0-9a-f]{24})?$/i.test(options.headSha)) throw new RepoError('invalid', `headSha 必须是完整的提交号:${options.headSha}`)\n const request = { headSha: options.headSha, ...options.method === undefined ? {} : { method: options.method } }\n return await this.run(repo, options, `合并 PR/MR #${number}`, (provider, ref, call) => provider.mergeChange(ref, number, request, call))\n }\n\n private target(repo: RepoTarget): ResolvedTarget {\n return resolveTarget(repo, this.config.hosts, this.config.repos)\n }\n\n private paging(options: PageOptions): Paging {\n const page = options.page ?? 1\n const perPage = options.perPage ?? this.config.limits.perPage\n if (!Number.isSafeInteger(page) || page < 1) throw new RepoError('invalid', `page 必须是正整数:${page}`)\n if (!Number.isSafeInteger(perPage) || perPage < 1 || perPage > this.config.limits.maxPerPage) {\n throw new RepoError('invalid', `perPage 必须在 1 到 ${this.config.limits.maxPerPage} 之间:${perPage}`)\n }\n return { page, perPage }\n }\n\n private provider(spec: HostSpec): Provider {\n const existing = this.providers.get(spec.url)\n if (existing !== undefined) return existing\n const token = async (): Promise<string> => {\n const resolved = await this.credentials.resolve(spec.tokenRef)\n if (resolved === undefined || resolved.value === '') throw new RepoError('unauthenticated', `${spec.url} 的令牌 ${spec.tokenRef} 未设置(在 DSH 凭据库或同名环境变量中设置)`)\n return resolved.value\n }\n const created = this.factory(spec, token, this.config.timeoutMs)\n this.providers.set(spec.url, created)\n return created\n }\n\n private async run<T>(repo: RepoTarget, options: CallOptions, what: string, body: (provider: Provider, ref: RepoRef, call: Call) => Promise<T>): Promise<T> {\n const { spec, ...ref } = this.target(repo)\n const deadline = AbortSignal.timeout(this.config.timeoutMs)\n const signal = options.signal === undefined ? deadline : AbortSignal.any([options.signal, deadline])\n try {\n return await body(this.provider(spec), ref, { signal, limits: this.config.limits })\n } catch (error) {\n throw toRepoError(error, `${what}(${ref.host}/${ref.path})`)\n }\n }\n}\n","/**\n * Model tools over the `dshRepos` service: read code, history, issues, and\n * pull/merge requests, and, after the user approves each call, write them.\n *\n * - Every tool takes `repo` (URL or `host/path`); only configured hosts and\n * repositories are reachable.\n * - Write tools ask once per call through `ctx.approval` when\n * `tools.writes` is `ask`; without an approval service they refuse. With\n * `off` they are not registered. The merge tool is registered only when\n * `tools.merge` is true.\n * - A declined approval returns `{ status: 'declined' }`; a service failure\n * throws with the failure code in brackets, e.g. `[not-found] …`.\n *\n * @module dsh-repo/tools\n */\n\nimport { z } from 'zod'\nimport type { DshRepoService } from './contract.ts'\nimport type { RepoConfig } from './config.ts'\nimport { RepoError } from './errors.ts'\nimport type { ContentBlock, HostApproval, ToolDefinition, ToolRunContext } from './host.ts'\n\n/** Outcome of a write the user did not approve. */\nexport interface Declined {\n readonly status: 'declined'\n /** `rejected`, `cancelled`, or `unavailable` (no answerer). */\n readonly outcome: string\n}\n\n/** Collaborators of the tool set. */\nexport interface ToolDeps {\n readonly service: DshRepoService\n readonly config: RepoConfig\n /** DSH's approval service, looked up per call. */\n readonly approval: () => HostApproval | undefined\n}\n\nconst repo = z.string().min(1).describe('Repository: web or clone URL (https://github.com/owner/name, git@gitlab.example.com:group/project.git) or host/path')\nconst number = z.number().int().min(1).describe('Issue or PR/MR number as shown in the web UI (GitLab IID)')\nconst page = z.number().int().min(1).optional().describe('1-based page, default 1')\nconst perPage = z.number().int().min(1).max(100).optional().describe('Items per page')\nconst labels = z.array(z.string().min(1)).optional()\nconst assignees = z.array(z.string().min(1)).optional().describe('Usernames')\n\ninterface Spec<S extends z.ZodType, V> {\n readonly name: string\n readonly description: string\n readonly schema: S\n /** Present on write tools: what the approval prompt says will happen. */\n readonly describe?: (args: z.output<S>) => { readonly zh: string; readonly en: string }\n readonly run: (args: z.output<S>, signal: AbortSignal) => Promise<V>\n}\n\nfunction render(value: unknown): ContentBlock[] {\n return [{ type: 'text', text: JSON.stringify(value, null, 2) }]\n}\n\nfunction withSignature(body: string | undefined, signature: string): string | undefined {\n if (body === undefined || signature === '') return body\n return `${body}\\n\\n${signature}`\n}\n\n/**\n * Build the tool definitions the configuration enables.\n * @param deps - service, configuration, and approval lookup.\n * @returns the definitions to register.\n */\nexport function createTools(deps: ToolDeps): ToolDefinition[] {\n const { service, config } = deps\n const sign = (body: string | undefined) => withSignature(body, config.tools.signature)\n const signRequired = (body: string) => withSignature(body, config.tools.signature) ?? body\n\n const reads: ToolDefinition[] = [\n define(deps, {\n name: 'repo_info',\n description: 'Show a repository\\'s default branch, visibility, description, and clone URL on GitHub or GitLab.',\n schema: z.object({ repo }).strict(),\n run: (args, signal) => service.repoInfo(args.repo, { signal }),\n }),\n define(deps, {\n name: 'repo_list_branches',\n description: 'List branches with their head commit and protection.',\n schema: z.object({ repo, search: z.string().optional().describe('Substring of the branch name'), page, perPage }).strict(),\n run: (args, signal) => service.listBranches(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_list_commits',\n description: 'List commits newest first, optionally on a branch/tag/SHA and touching a path.',\n schema: z.object({ repo, ref: z.string().optional(), path: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listCommits(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_list_tree',\n description: 'List files and directories under a path at a ref (default: repository root on the default branch).',\n schema: z.object({ repo, path: z.string().optional(), ref: z.string().optional(), recursive: z.boolean().optional() }).strict(),\n run: (args, signal) => service.listTree(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_read_file',\n description: 'Read one text file at a ref (default: the default branch). Long files are cut at the configured size limit.',\n schema: z.object({ repo, path: z.string().min(1), ref: z.string().optional() }).strict(),\n run: (args, signal) => service.readFile(args.repo, args.path, { ...args.ref === undefined ? {} : { ref: args.ref }, signal }),\n }),\n define(deps, {\n name: 'repo_issue_list',\n description: 'List issues (pull/merge requests excluded).',\n schema: z.object({ repo, state: z.enum(['open', 'closed', 'all']).optional(), labels, assignee: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listIssues(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_get',\n description: 'Read one issue with its comments.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.getIssue(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_list',\n description: 'List pull requests (GitHub) or merge requests (GitLab).',\n schema: z.object({ repo, state: z.enum(['open', 'closed', 'merged', 'all']).optional(), sourceBranch: z.string().optional(), targetBranch: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listChanges(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_mr_get',\n description: 'Read one pull/merge request with its conversation comments.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.getChange(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_diff',\n description: 'Read the unified diff of a pull/merge request. Long diffs are cut at the configured size limit.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.changeDiff(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_status',\n description: 'Read CI checks/pipeline and mergeability of a pull/merge request, with its head SHA.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.changeStatus(args.repo, args.number, { signal }),\n }),\n ]\n if (config.tools.writes === 'off') return reads\n\n const writes: ToolDefinition[] = [\n define(deps, {\n name: 'repo_commit_files',\n description: 'Commit file writes and deletions to a branch in one commit. A missing branch is created from `base` (default: the default branch). Never commits to the default or a protected branch; open a PR/MR afterwards. Requires user approval.',\n schema: z.object({\n repo,\n branch: z.string().min(1),\n base: z.string().optional(),\n message: z.string().min(1),\n files: z.array(z.discriminatedUnion('action', [\n z.object({ action: z.literal('write'), path: z.string().min(1), content: z.string() }).strict(),\n z.object({ action: z.literal('delete'), path: z.string().min(1) }).strict(),\n ])).min(1),\n }).strict(),\n describe: args => ({\n zh: `向 ${args.repo} 的分支 ${args.branch} 提交 ${args.files.length} 个文件(${args.files.map(file => `${file.action === 'delete' ? '删除' : '写入'} ${file.path}`).join(',')}):${args.message.split('\\n', 1)[0]}`,\n en: `Commit ${args.files.length} file(s) to ${args.repo} branch ${args.branch}: ${args.message.split('\\n', 1)[0]}`,\n }),\n run: (args, signal) => service.commitFiles(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_create',\n description: 'Create an issue. Requires user approval.',\n schema: z.object({ repo, title: z.string().min(1), body: z.string().optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `在 ${args.repo} 创建 issue:${args.title}`, en: `Create an issue in ${args.repo}: ${args.title}` }),\n run: (args, signal) => service.createIssue(args.repo, { ...args, ...args.body === undefined ? {} : { body: sign(args.body) }, signal }),\n }),\n define(deps, {\n name: 'repo_issue_update',\n description: 'Change an issue\\'s title, body, labels, or assignees, or close/reopen it. Labels and assignees replace the current ones. Requires user approval.',\n schema: z.object({ repo, number, title: z.string().min(1).optional(), body: z.string().optional(), state: z.enum(['open', 'closed']).optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `修改 ${args.repo} 的 issue #${args.number}${args.state === 'closed' ? '(关闭)' : args.state === 'open' ? '(重新打开)' : ''}`, en: `Update issue #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.updateIssue(args.repo, args.number, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_comment',\n description: 'Comment on an issue. Requires user approval.',\n schema: z.object({ repo, number, body: z.string().min(1) }).strict(),\n describe: args => ({ zh: `评论 ${args.repo} 的 issue #${args.number}`, en: `Comment on issue #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.commentIssue(args.repo, args.number, signRequired(args.body), { signal }),\n }),\n define(deps, {\n name: 'repo_mr_create',\n description: 'Open a pull request (GitHub) or merge request (GitLab) from a pushed branch. Requires user approval.',\n schema: z.object({ repo, title: z.string().min(1), body: z.string().optional(), sourceBranch: z.string().min(1), targetBranch: z.string().optional(), draft: z.boolean().optional(), labels, assignees }).strict(),\n describe: args => ({\n zh: `在 ${args.repo} 创建${args.draft === true ? '草稿 ' : ''}PR/MR:${args.sourceBranch} → ${args.targetBranch ?? '默认分支'},标题「${args.title}」`,\n en: `Open a ${args.draft === true ? 'draft ' : ''}PR/MR in ${args.repo}: ${args.sourceBranch} → ${args.targetBranch ?? 'default branch'}, \"${args.title}\"`,\n }),\n run: (args, signal) => service.createChange(args.repo, { ...args, ...args.body === undefined ? {} : { body: sign(args.body) }, signal }),\n }),\n define(deps, {\n name: 'repo_mr_update',\n description: 'Change a pull/merge request\\'s title, body, target branch, labels, or assignees, or close/reopen it. Requires user approval.',\n schema: z.object({ repo, number, title: z.string().min(1).optional(), body: z.string().optional(), state: z.enum(['open', 'closed']).optional(), targetBranch: z.string().optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `修改 ${args.repo} 的 PR/MR #${args.number}${args.state === 'closed' ? '(关闭)' : args.state === 'open' ? '(重新打开)' : ''}`, en: `Update PR/MR #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.updateChange(args.repo, args.number, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_mr_comment',\n description: 'Comment on a pull/merge request conversation. Requires user approval.',\n schema: z.object({ repo, number, body: z.string().min(1) }).strict(),\n describe: args => ({ zh: `评论 ${args.repo} 的 PR/MR #${args.number}`, en: `Comment on PR/MR #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.commentChange(args.repo, args.number, signRequired(args.body), { signal }),\n }),\n ]\n if (config.tools.merge) {\n writes.push(define(deps, {\n name: 'repo_mr_merge',\n description: 'Merge a pull/merge request, only while its head is still `headSha` (read it with repo_mr_status first). Requires user approval.',\n schema: z.object({ repo, number, headSha: z.string().min(40), method: z.enum(['merge', 'squash', 'rebase']).optional() }).strict(),\n describe: args => ({ zh: `合并 ${args.repo} 的 PR/MR #${args.number}(head ${args.headSha.slice(0, 12)}${args.method === undefined ? '' : `,方式 ${args.method}`})`, en: `Merge PR/MR #${args.number} in ${args.repo} at ${args.headSha.slice(0, 12)}` }),\n run: (args, signal) => service.mergeChange(args.repo, args.number, { headSha: args.headSha, ...args.method === undefined ? {} : { method: args.method }, signal }),\n }))\n }\n return [...reads, ...writes]\n}\n\nfunction define<S extends z.ZodType, V>(deps: ToolDeps, spec: Spec<S, V>): ToolDefinition<V | Declined> {\n const parameters = z.toJSONSchema(spec.schema, { target: 'draft-2020-12' }) as Record<string, unknown>\n delete parameters.$schema\n return {\n name: spec.name,\n description: spec.description,\n parameters,\n output: { schema: { type: 'object' }, render: (_args, value) => render(value) },\n isConcurrencySafe: () => spec.describe === undefined,\n execute: async (raw: unknown, exec: ToolRunContext): Promise<V | Declined> => {\n const parsed = spec.schema.safeParse(raw)\n if (!parsed.success) throw new Error(`[invalid] ${spec.name} 参数不合法:${parsed.error.issues.map(issue => `${issue.path.join('.') || '(根)'}:${issue.message}`).join(';')}`)\n const args = parsed.data\n if (spec.describe !== undefined && deps.config.tools.writes === 'ask') {\n const outcome = await approve(deps, spec.name, spec.describe(args), exec)\n if (outcome !== 'allowed-once') return { status: 'declined', outcome }\n }\n try {\n return await spec.run(args, exec.signal)\n } catch (error) {\n if (error instanceof RepoError) throw new Error(`[${error.code}] ${error.message}`)\n throw error\n }\n },\n }\n}\n\nasync function approve(deps: ToolDeps, toolName: string, text: { readonly zh: string; readonly en: string }, exec: ToolRunContext): Promise<string> {\n const approval = deps.approval()\n if (approval === undefined) throw new Error(`[forbidden] 当前 DSH 组合没有审批服务(@deepseek-ai/dsh-user-approval),dsh-repo 不会在未经授权时执行 ${toolName};或把 tools.writes 设为 allow`)\n if (exec.agent === undefined) throw new Error(`[forbidden] ${toolName} 需要由 Agent 调用`)\n const outcome = await approval.request({\n agent: exec.agent,\n toolName,\n ...exec.callId === undefined ? {} : { callId: exec.callId },\n reason: text.zh,\n displayReason: { en: text.en, zh: text.zh },\n signal: exec.signal,\n })\n if (outcome === 'cancelled') exec.signal.throwIfAborted()\n return outcome\n}\n","/**\n * dsh-repo —— DeepSeek Harness 代码仓库插件。\n *\n * 用 GitHub 官方 SDK(Octokit)和 GitLab 文档推荐的 GitBeaker 抹平\n * GitHub(含 GitHub Enterprise Server)与 GitLab(含自建实例)的差异:\n * 对其他插件提供 `dshRepos` 服务(类型见 `dsh-repo/contract`),\n * 对模型提供代码、issue、PR/MR 工具,写操作逐次经用户审批。\n *\n * @module dsh-repo\n */\n\nimport { resolveConfig } from './config.ts'\nimport type { HostApproval, HostContext } from './host.ts'\nimport { DSH_REPOS_SERVICE, RepoService } from './service.ts'\nimport type { ProviderFactory } from './service.ts'\nimport { createTools } from './tools.ts'\n\nexport type * from './contract.ts'\nexport type { HostSpec, RepoConfig, RepoLimits } from './config.ts'\nexport { apiBaseUrl, normalizeHostUrl, pluginConfigSchema, resolveConfig } from './config.ts'\nexport { RepoError, toRepoError } from './errors.ts'\nexport { DSH_REPOS_SERVICE, RepoService, defaultProviderFactory } from './service.ts'\nexport type { ProviderFactory } from './service.ts'\nexport { GithubProvider } from './providers/github.ts'\nexport { GitlabProvider } from './providers/gitlab.ts'\nexport type { Provider } from './providers/types.ts'\nexport { matchesPattern, resolveTarget } from './target.ts'\nexport { createTools } from './tools.ts'\nexport type { Declined, ToolDeps } from './tools.ts'\n\n/** Cordis plugin name. */\nexport const name = 'dsh-repo'\n\n/** Host services the plugin needs before `apply()`. */\nexport const inject = ['tools', 'credentials'] as const\n\n/** Standard Schema the loader validates `config` with before `apply()`. */\nexport { pluginConfigSchema as Config } from './config.ts'\n\n/** Direct-invocation options (tests and embedding hosts). */\nexport interface RepoPluginOptions {\n /** Substitute the per-host providers. */\n readonly providerFactory?: ProviderFactory\n}\n\n/**\n * Provide the `dshRepos` service and register the model tools.\n * @param ctx - plugin context.\n * @param config - loader-validated configuration.\n * @param options - test seams.\n */\nexport function apply(ctx: HostContext, config?: unknown, options: RepoPluginOptions = {}): void {\n const resolved = resolveConfig(config)\n const service = new RepoService(resolved, ctx.credentials, options.providerFactory)\n ctx.provide?.(DSH_REPOS_SERVICE, service)\n if (!resolved.tools.enabled) return\n if (!service.configured) {\n ctx.logger?.warn?.('dsh-repo: 没有配置 hosts,代码仓库工具未注册')\n return\n }\n for (const definition of createTools({ service, config: resolved, approval: () => ctx.get?.('approval') as HostApproval | undefined })) {\n ctx.effect(() => ctx.tools.register(definition), `dsh-repo: ${definition.name}`)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["user","labelNames","dirname","issue"],"sources":["../src/config.ts","../src/errors.ts","../src/providers/types.ts","../src/providers/github.ts","../src/providers/gitlab.ts","../src/target.ts","../src/service.ts","../src/tools.ts","../src/index.ts"],"sourcesContent":["/**\n * 插件配置:cordis.yml 中的 `config`,经 Standard Schema 在加载时校验。\n *\n * @module dsh-repo/config\n */\n\nimport { z } from 'zod'\nimport type { ForgeKind } from './contract.ts'\n\n/** Largest delay Node's `setTimeout` honors (2^31 − 1 ms). */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647\n\n/** Credential reference names: environment-variable style. */\nexport const TOKEN_REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/** Repository pattern: `host[:port]/seg/…`, the last segment may be `*` (one level) or `**` (any depth). */\nconst REPO_PATTERN = /^[a-z0-9.-]+(:\\d+)?(\\/[A-Za-z0-9._-]+)*(\\/(\\*|\\*\\*|[A-Za-z0-9._-]+))$/\n\n/**\n * Normalize a host address to `https://host[:port][/path]` with a lowercase\n * host and no trailing slash.\n * @param value - candidate address.\n * @returns the normalized address, or undefined when it is not an `https`/`http` URL without credentials, query, or fragment.\n */\nexport function normalizeHostUrl(value: string): string | undefined {\n let url: URL\n try {\n url = new URL(value)\n } catch {\n // Not a URL: refused.\n return undefined\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') return undefined\n if (url.host === '' || url.username !== '' || url.password !== '' || url.search !== '' || url.hash !== '') return undefined\n return `${url.protocol}//${url.host}${url.pathname.replace(/\\/+$/, '')}`\n}\n\nconst urlField = (label: string) => z.string().trim()\n .refine(value => normalizeHostUrl(value) !== undefined, `${label}不合法:填 https://主机[:端口][/路径],不含用户名、查询参数或片段`)\n .transform(value => normalizeHostUrl(value) as string)\n\nconst hostSchema = z.object({\n kind: z.enum(['github', 'gitlab']),\n url: urlField('主机地址'),\n apiUrl: urlField('接口地址').optional(),\n tokenRef: z.string().trim().regex(TOKEN_REF_PATTERN, '令牌名称只能包含字母、数字和下划线,且不能以数字开头(它是凭据库中的键名,不是令牌本身)'),\n alias: z.string().trim().max(64).optional(),\n}).strict().superRefine((host, issues) => {\n if (host.kind === 'gitlab' && host.apiUrl !== undefined) issues.addIssue({ code: 'custom', path: ['apiUrl'], message: 'apiUrl 只用于 GitHub;GitLab 的接口地址由 url 推出' })\n})\n\nconst limitsSchema = z.object({\n perPage: z.number().int().min(1).max(100).default(30),\n maxPerPage: z.number().int().min(1).max(100).default(100),\n maxFileBytes: z.number().int().min(1).max(64 * 1024 * 1024).default(1024 * 1024),\n maxDiffBytes: z.number().int().min(1).max(64 * 1024 * 1024).default(512 * 1024),\n maxTreeEntries: z.number().int().min(1).max(100_000).default(1000),\n maxCommitFiles: z.number().int().min(1).max(1000).default(100),\n maxComments: z.number().int().min(1).max(100).default(50),\n}).strict().superRefine((limits, issues) => {\n if (limits.perPage > limits.maxPerPage) issues.addIssue({ code: 'custom', path: ['perPage'], message: 'perPage 不能大于 maxPerPage' })\n})\n\nconst toolsSchema = z.object({\n enabled: z.boolean().default(true),\n /** `ask`: every write asks the user once; `allow`: writes run without asking; `off`: write tools are not registered. */\n writes: z.enum(['ask', 'allow', 'off']).default('ask'),\n /** Whether the merge tool is registered at all; it always follows `writes` for approval. */\n merge: z.boolean().default(false),\n /** Appended (after a blank line) to issue, change request, and comment bodies written through tools; empty = none. */\n signature: z.string().max(500).default(''),\n}).strict()\n\n/** Standard Schema of the `config` block. */\nexport const pluginConfigSchema = z.object({\n hosts: z.array(hostSchema).default([]).superRefine((hosts, issues) => {\n const seen = new Set<string>()\n for (const [index, host] of hosts.entries()) {\n if (seen.has(host.url)) issues.addIssue({ code: 'custom', path: [index, 'url'], message: `重复的主机地址:${host.url}` })\n seen.add(host.url)\n }\n }),\n /** Reachable repositories; omitted or empty = every repository on the configured hosts. */\n repos: z.array(z.string().trim().toLowerCase().regex(REPO_PATTERN, '仓库格式:主机/路径,末段可以是 *(一层)或 **(任意层),例如 github.com/modestoma/*')).default([]),\n timeoutMs: z.number().int().min(1000).max(MAX_TIMER_DELAY_MS).default(30_000),\n limits: limitsSchema.default({ perPage: 30, maxPerPage: 100, maxFileBytes: 1024 * 1024, maxDiffBytes: 512 * 1024, maxTreeEntries: 1000, maxCommitFiles: 100, maxComments: 50 }),\n tools: toolsSchema.default({ enabled: true, writes: 'ask', merge: false, signature: '' }),\n}).strict().default({\n hosts: [],\n repos: [],\n timeoutMs: 30_000,\n limits: { perPage: 30, maxPerPage: 100, maxFileBytes: 1024 * 1024, maxDiffBytes: 512 * 1024, maxTreeEntries: 1000, maxCommitFiles: 100, maxComments: 50 },\n tools: { enabled: true, writes: 'ask', merge: false, signature: '' },\n})\n\n/** Validated configuration. */\nexport type RepoConfig = z.output<typeof pluginConfigSchema>\n\n/** One configured host. */\nexport type HostSpec = RepoConfig['hosts'][number]\n\n/** Size and paging limits. */\nexport type RepoLimits = RepoConfig['limits']\n\n/**\n * Validate a raw `config` block.\n * @param config - loader input; undefined uses every default.\n * @returns the validated configuration.\n * @throws when the configuration is invalid, with every issue in the message.\n */\nexport function resolveConfig(config: unknown): RepoConfig {\n const parsed = pluginConfigSchema.safeParse(config)\n if (parsed.success) return parsed.data\n throw new Error(`dsh-repo 配置不合法:${parsed.error.issues.map(issue => `${issue.path.join('.') || '(根)'}:${issue.message}`).join(';')}`)\n}\n\n/**\n * The REST API base URL of a host.\n * @param host - configured host.\n * @returns `https://api.github.com` for github.com, `<url>/api/v3` for GitHub Enterprise Server, and the host URL itself for GitLab (GitBeaker appends `/api/v4`).\n */\nexport function apiBaseUrl(host: { readonly kind: ForgeKind; readonly url: string; readonly apiUrl?: string | undefined }): string {\n if (host.kind === 'gitlab') return host.url\n if (host.apiUrl !== undefined) return host.apiUrl\n return new URL(host.url).host === 'github.com' ? 'https://api.github.com' : `${host.url}/api/v3`\n}\n","/**\n * The service's single failure type and the mapping from Octokit and\n * GitBeaker errors to it.\n *\n * @module dsh-repo/errors\n */\n\nimport type { RepoErrorCode, RepoFailure } from './contract.ts'\n\n/** Expected failure of a `dshRepos` call. */\nexport class RepoError extends Error implements RepoFailure {\n override readonly name = 'RepoError'\n\n /**\n * @param code - failure class.\n * @param message - readable reason.\n */\n constructor(readonly code: RepoErrorCode, message: string) {\n super(message)\n }\n}\n\n/** Status and host message read off an SDK error, when it carries a response. */\ninterface HttpFailure {\n readonly status?: number\n readonly message: string\n readonly rateLimited: boolean\n}\n\nfunction httpFailureOf(error: unknown): HttpFailure | undefined {\n if (!(error instanceof Error)) return undefined\n // Octokit `RequestError`: `status` plus `response.headers`.\n const octokit = error as Error & { status?: unknown; response?: { headers?: Record<string, string | number | undefined> } }\n if (error.name === 'HttpError' && typeof octokit.status === 'number') {\n const remaining = octokit.response?.headers?.['x-ratelimit-remaining']\n return { status: octokit.status, message: error.message, rateLimited: octokit.status === 429 || (octokit.status === 403 && String(remaining) === '0') }\n }\n // GitBeaker `GitbeakerRequestError`: `cause.response`.\n const gitbeaker = error as Error & { cause?: { response?: { status?: unknown } } }\n if (error.name === 'GitbeakerRequestError' || gitbeaker.cause?.response !== undefined) {\n const status = gitbeaker.cause?.response?.status\n return { ...typeof status === 'number' ? { status } : {}, message: error.message, rateLimited: status === 429 }\n }\n if (error.name === 'GitbeakerRetryError') return { status: 429, message: error.message, rateLimited: true }\n return undefined\n}\n\n/**\n * Classify an error thrown while calling a host.\n * @param error - the thrown value.\n * @param what - what was being done, for the message (e.g. `读取 issue #3`).\n * @returns the error to rethrow; a {@link RepoError} passes through unchanged.\n */\nexport function toRepoError(error: unknown, what: string): RepoError {\n if (error instanceof RepoError) return error\n const http = httpFailureOf(error)\n if (http !== undefined) {\n const detail = http.message === '' ? '' : `:${http.message}`\n if (http.rateLimited) return new RepoError('rate-limited', `${what}失败,已达到接口限流${detail}`)\n switch (http.status) {\n case 401: return new RepoError('unauthenticated', `${what}失败,令牌无效或已过期${detail}`)\n case 403: return new RepoError('forbidden', `${what}失败,令牌没有权限${detail}`)\n case 404: return new RepoError('not-found', `${what}失败,目标不存在或令牌无权查看${detail}`)\n case 405:\n case 406:\n case 409:\n case 412: return new RepoError('conflict', `${what}失败,状态已变化或不满足条件${detail}`)\n case 400:\n case 422: return new RepoError('invalid', `${what}失败,参数被拒绝${detail}`)\n default: return new RepoError('unavailable', `${what}失败${http.status === undefined ? '' : `(HTTP ${http.status})`}${detail}`)\n }\n }\n if (error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError' || error.name === 'GitbeakerTimeoutError')) {\n return new RepoError('unavailable', `${what}超时或被取消`)\n }\n return new RepoError('unavailable', `${what}失败:${error instanceof Error ? error.message : String(error)}`)\n}\n","/**\n * The per-family provider interface the service delegates to after resolving\n * a target, normalizing paging, and attaching the call deadline.\n *\n * @module dsh-repo/providers/types\n */\n\nimport type {\n BranchInfo, ChangeDetail, ChangeDiff, ChangeInfo, ChangeState, ChangeStatus, CommentInfo, CommitAuthor, CommitInfo, CommitResult,\n FileChange, FileContent, IssueDetail, IssueInfo, IssueState, MergeMethod, MergeResult, Page, RepoInfo, RepoRef, TreeListing,\n} from '../contract.ts'\nimport type { RepoLimits } from '../config.ts'\n\n/** Per-call input every provider method receives. */\nexport interface Call {\n /** Combined caller cancellation and configured deadline. */\n readonly signal: AbortSignal\n readonly limits: RepoLimits\n}\n\n/** Normalized paging. */\nexport interface Paging {\n readonly page: number\n readonly perPage: number\n}\n\n/** One code host family. Methods throw SDK errors or {@link RepoError}; the service classifies them. */\nexport interface Provider {\n repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo>\n getBranch(ref: RepoRef, name: string, call: Call): Promise<BranchInfo | undefined>\n listBranches(ref: RepoRef, query: Paging & { readonly search?: string }, call: Call): Promise<Page<BranchInfo>>\n listCommits(ref: RepoRef, query: Paging & { readonly ref?: string; readonly path?: string }, call: Call): Promise<Page<CommitInfo>>\n listTree(ref: RepoRef, query: { readonly ref?: string; readonly path: string; readonly recursive: boolean }, call: Call): Promise<TreeListing>\n readFile(ref: RepoRef, path: string, at: string | undefined, call: Call): Promise<FileContent>\n commitFiles(ref: RepoRef, request: { readonly branch: string; readonly base?: string; readonly baseSha?: string; readonly newBranch?: boolean; readonly author?: CommitAuthor; readonly message: string; readonly files: readonly FileChange[] }, call: Call): Promise<CommitResult>\n\n listIssues(ref: RepoRef, query: Paging & { readonly state: IssueState | 'all'; readonly labels?: readonly string[]; readonly assignee?: string }, call: Call): Promise<Page<IssueInfo>>\n getIssue(ref: RepoRef, number: number, call: Call): Promise<IssueDetail>\n createIssue(ref: RepoRef, issue: IssueFields & { readonly title: string }, call: Call): Promise<IssueInfo>\n updateIssue(ref: RepoRef, number: number, update: IssueFields & { readonly state?: IssueState }, call: Call): Promise<IssueInfo>\n commentIssue(ref: RepoRef, number: number, body: string, call: Call): Promise<CommentInfo>\n\n listChanges(ref: RepoRef, query: Paging & { readonly state: ChangeState | 'all'; readonly sourceBranch?: string; readonly targetBranch?: string }, call: Call): Promise<Page<ChangeInfo>>\n getChange(ref: RepoRef, number: number, call: Call): Promise<ChangeDetail>\n changeDiff(ref: RepoRef, number: number, call: Call): Promise<ChangeDiff>\n changeStatus(ref: RepoRef, number: number, call: Call): Promise<ChangeStatus>\n createChange(ref: RepoRef, change: IssueFields & { readonly title: string; readonly sourceBranch: string; readonly targetBranch: string; readonly draft: boolean }, call: Call): Promise<ChangeInfo>\n updateChange(ref: RepoRef, number: number, update: IssueFields & { readonly state?: 'open' | 'closed'; readonly targetBranch?: string }, call: Call): Promise<ChangeInfo>\n commentChange(ref: RepoRef, number: number, body: string, call: Call): Promise<CommentInfo>\n mergeChange(ref: RepoRef, number: number, request: { readonly headSha: string; readonly method?: MergeMethod }, call: Call): Promise<MergeResult>\n}\n\n/** Editable fields shared by issues and change requests. */\nexport interface IssueFields {\n readonly title?: string\n readonly body?: string\n readonly labels?: readonly string[]\n readonly assignees?: readonly string[]\n}\n\n/** Resolves a host's token for each request. */\nexport type TokenSource = () => Promise<string>\n\n/**\n * The next page number after a page of `count` items.\n * @param paging - the requested page.\n * @param count - items returned.\n * @returns `page + 1` when the page was full.\n */\nexport function nextPage(paging: Paging, count: number): { nextPage?: number } {\n return count >= paging.perPage ? { nextPage: paging.page + 1 } : {}\n}\n\n/**\n * Cut text at a byte limit on a character boundary.\n * @param text - full text.\n * @param maxBytes - UTF-8 byte limit.\n * @returns the kept text and whether anything was cut.\n */\nexport function truncateBytes(text: string, maxBytes: number): { text: string; truncated: boolean } {\n const bytes = Buffer.from(text, 'utf8')\n if (bytes.length <= maxBytes) return { text, truncated: false }\n let end = maxBytes\n // Step back over UTF-8 continuation bytes so no character is split.\n while (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80) end -= 1\n return { text: bytes.subarray(0, end).toString('utf8'), truncated: true }\n}\n\n/**\n * The first line of a commit message.\n * @param message - full message.\n * @returns its first line.\n */\nexport function titleOf(message: string): string {\n return message.split('\\n', 1)[0] ?? ''\n}\n","/**\n * GitHub provider on the official `@octokit/rest` SDK: github.com and GitHub\n * Enterprise Server (`<url>/api/v3`). Pull requests are this module's change\n * requests.\n *\n * @module dsh-repo/providers/github\n */\n\nimport { Octokit } from '@octokit/rest'\nimport type {\n BranchInfo, ChangeInfo, ChangeState, CheckInfo, CheckState, CommentInfo, CommitInfo, IssueInfo, RepoInfo, RepoRef, RepoUser, TreeEntry,\n} from '../contract.ts'\nimport { RepoError } from '../errors.ts'\nimport { nextPage, titleOf, truncateBytes } from './types.ts'\nimport type { Call, Provider, TokenSource } from './types.ts'\n\n/** GitHub's largest page. */\nconst PAGE = 100\n\n/** Pages of check runs or statuses read before giving up on a complete status. */\nconst MAX_STATUS_PAGES = 10\n\ninterface GithubUser { readonly login: string; readonly html_url?: string }\ninterface GithubLabel { readonly name?: string }\n\nfunction user(value: GithubUser | null | undefined): RepoUser {\n return value === null || value === undefined ? { username: 'ghost' } : { username: value.login, ...value.html_url === undefined ? {} : { webUrl: value.html_url } }\n}\n\nfunction labelNames(labels: ReadonlyArray<string | GithubLabel>): string[] {\n return labels.map(label => typeof label === 'string' ? label : label.name ?? '').filter(name => name !== '')\n}\n\nfunction dirname(path: string): string {\n const slash = path.lastIndexOf('/')\n return slash < 0 ? '' : path.slice(0, slash)\n}\n\nfunction split(path: string): { owner: string; repo: string } {\n const [owner = '', repo = ''] = path.split('/')\n return { owner, repo }\n}\n\ninterface GithubIssue {\n readonly number: number\n readonly title: string\n readonly body?: string | null\n readonly state: string\n readonly user: GithubUser | null\n readonly labels: ReadonlyArray<string | GithubLabel>\n readonly assignees?: readonly GithubUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly html_url: string\n}\n\nfunction issue(value: GithubIssue): IssueInfo {\n return {\n number: value.number,\n title: value.title,\n body: value.body ?? '',\n state: value.state === 'closed' ? 'closed' : 'open',\n author: user(value.user),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.html_url,\n }\n}\n\ninterface GithubPull {\n readonly number: number\n readonly title: string\n readonly body: string | null\n readonly state: string\n readonly draft?: boolean\n readonly merged_at: string | null\n readonly head: { readonly ref: string; readonly sha: string }\n readonly base: { readonly ref: string }\n readonly user: GithubUser | null\n readonly labels: readonly GithubLabel[]\n readonly assignees?: readonly GithubUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly html_url: string\n}\n\nfunction pull(value: GithubPull): ChangeInfo {\n const state: ChangeState = value.merged_at !== null ? 'merged' : value.state === 'closed' ? 'closed' : 'open'\n return {\n number: value.number,\n title: value.title,\n body: value.body ?? '',\n state,\n draft: value.draft === true,\n sourceBranch: value.head.ref,\n targetBranch: value.base.ref,\n headSha: value.head.sha,\n author: user(value.user),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.html_url,\n }\n}\n\ninterface GithubComment {\n readonly id: number\n readonly user: GithubUser | null\n readonly body?: string\n readonly created_at: string\n readonly html_url: string\n}\n\nfunction comment(value: GithubComment): CommentInfo {\n return { id: String(value.id), author: user(value.user), body: value.body ?? '', createdAt: value.created_at, webUrl: value.html_url }\n}\n\nfunction overall(checks: readonly CheckInfo[]): CheckState {\n if (checks.length === 0) return 'none'\n if (checks.some(check => check.state === 'failure')) return 'failure'\n if (checks.some(check => check.state === 'pending')) return 'pending'\n return 'success'\n}\n\nfunction checkRunState(status: string, conclusion: string | null): CheckInfo['state'] {\n if (status !== 'completed') return 'pending'\n return conclusion === 'failure' || conclusion === 'timed_out' || conclusion === 'action_required' || conclusion === 'startup_failure' || conclusion === 'cancelled'\n ? 'failure'\n : 'success'\n}\n\n/** GitHub provider bound to one host. */\nexport class GithubProvider implements Provider {\n private readonly octokit: Octokit\n\n /**\n * @param baseUrl - REST base URL (`https://api.github.com` or `<url>/api/v3`).\n * @param token - resolves the host's token for every request.\n */\n constructor(baseUrl: string, token: TokenSource) {\n this.octokit = new Octokit({\n baseUrl,\n userAgent: 'dsh-repo',\n log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },\n })\n this.octokit.hook.before('request', async (options) => {\n options.headers.authorization = `token ${await token()}`\n })\n }\n\n async repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo> {\n const { data } = await this.octokit.rest.repos.get({ ...split(ref.path), request: { signal: call.signal } })\n return {\n ...ref,\n webUrl: data.html_url,\n defaultBranch: data.default_branch,\n ...data.description === null ? {} : { description: data.description },\n visibility: data.visibility === 'internal' ? 'internal' : data.private ? 'private' : 'public',\n archived: data.archived,\n cloneUrl: data.clone_url,\n }\n }\n\n async listBranches(ref: RepoRef, query: { page: number; perPage: number; search?: string }, call: Call) {\n const [{ data }, info] = await Promise.all([\n this.octokit.rest.repos.listBranches({ ...split(ref.path), page: query.page, per_page: query.perPage, request: { signal: call.signal } }),\n this.octokit.rest.repos.get({ ...split(ref.path), request: { signal: call.signal } }),\n ])\n const items: BranchInfo[] = data\n .filter(branch => query.search === undefined || branch.name.includes(query.search))\n .map(branch => ({ name: branch.name, commit: branch.commit.sha, protected: branch.protected, default: branch.name === info.data.default_branch }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async getBranch(ref: RepoRef, name: string, call: Call) {\n const [branch, info] = await Promise.all([\n this.octokit.rest.repos.getBranch({ ...split(ref.path), branch: name, request: { signal: call.signal } }).catch((error: unknown) => {\n if ((error as { status?: number }).status === 404) return undefined\n throw error\n }),\n this.repoInfo(ref, call),\n ])\n // GitHub answers a renamed branch with the branch it was renamed to.\n if (branch === undefined || branch.data.name !== name) return undefined\n return { name, commit: branch.data.commit.sha, protected: branch.data.protected, default: name === info.defaultBranch }\n }\n\n async listCommits(ref: RepoRef, query: { page: number; perPage: number; ref?: string; path?: string }, call: Call) {\n const { data } = await this.octokit.rest.repos.listCommits({\n ...split(ref.path),\n page: query.page,\n per_page: query.perPage,\n ...query.ref === undefined ? {} : { sha: query.ref },\n ...query.path === undefined ? {} : { path: query.path },\n request: { signal: call.signal },\n })\n const items: CommitInfo[] = data.map(entry => ({\n sha: entry.sha,\n title: titleOf(entry.commit.message),\n message: entry.commit.message,\n authorName: entry.commit.author?.name ?? entry.author?.login ?? '',\n ...entry.commit.author?.email === undefined ? {} : { authorEmail: entry.commit.author.email },\n ...entry.commit.author?.date === undefined ? {} : { authoredAt: entry.commit.author.date },\n webUrl: entry.html_url,\n }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listTree(ref: RepoRef, query: { ref?: string; path: string; recursive: boolean }, call: Call) {\n const at = query.ref ?? (await this.repoInfo(ref, call)).defaultBranch\n const max = call.limits.maxTreeEntries\n // The Trees API reports its own truncation; the Contents API silently stops at 1,000 entries.\n const treeish = query.path === '' ? at : `${at}:${query.path}`\n const { data } = await this.octokit.rest.git.getTree({\n ...split(ref.path),\n tree_sha: treeish,\n ...query.recursive ? { recursive: 'true' } : {},\n request: { signal: call.signal },\n })\n const prefix = query.path === '' ? '' : `${query.path}/`\n const entries: TreeEntry[] = data.tree.map(entry => ({\n path: `${prefix}${entry.path ?? ''}`,\n type: entry.type === 'tree' ? 'dir' : entry.type === 'commit' ? 'submodule' : entry.mode === '120000' ? 'symlink' : 'file',\n ...entry.size === undefined ? {} : { size: entry.size },\n }))\n return { ref: at, entries: entries.slice(0, max), truncated: data.truncated || entries.length > max }\n }\n\n async readFile(ref: RepoRef, path: string, at: string | undefined, call: Call) {\n const target = at ?? (await this.repoInfo(ref, call)).defaultBranch\n const response = await this.octokit.rest.repos.getContent({\n ...split(ref.path),\n path,\n ref: target,\n mediaType: { format: 'raw' },\n request: { signal: call.signal },\n })\n const raw: unknown = response.data\n if (typeof raw !== 'string') throw new RepoError('invalid', `${path} 不是文件`)\n if (raw.includes('\\0')) return { path, ref: target, text: '', binary: true, truncated: false }\n return { path, ref: target, binary: false, ...truncateBytes(raw, call.limits.maxFileBytes) }\n }\n\n async commitFiles(ref: RepoRef, request: { branch: string; base?: string; baseSha?: string; newBranch?: boolean; author?: { name: string; email: string }; message: string; files: readonly ({ action: 'write'; path: string; content: string } | { action: 'delete'; path: string })[] }, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n const info = await this.repoInfo(ref, call)\n if (request.branch === info.defaultBranch) throw new RepoError('forbidden', `不允许直接提交到默认分支 ${request.branch};请提交到新分支后开 PR`)\n const existing = await this.octokit.rest.repos.getBranch({ ...repo, branch: request.branch, request: { signal } }).catch((error: unknown) => {\n if ((error as { status?: number }).status === 404) return undefined\n throw error\n })\n if (existing !== undefined && request.newBranch === true) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)\n if (existing?.data.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)\n const parent = existing?.data.commit.sha\n ?? request.baseSha\n ?? (await this.octokit.rest.repos.getBranch({ ...repo, branch: request.base ?? info.defaultBranch, request: { signal } })).data.commit.sha\n const { data: parentCommit } = await this.octokit.rest.git.getCommit({ ...repo, commit_sha: parent, request: { signal } })\n // Keep the executable bit of files that already exist; refuse to replace links and directories.\n const modes = new Map<string, string>()\n for (const dir of new Set(request.files.filter(file => file.action === 'write').map(file => dirname(file.path)))) {\n const listing = await this.octokit.rest.git.getTree({ ...repo, tree_sha: dir === '' ? parent : `${parent}:${dir}`, request: { signal } }).catch((error: unknown) => {\n // A directory that does not exist yet holds no files.\n if ((error as { status?: number }).status === 404) return undefined\n throw error\n })\n for (const entry of listing?.data.tree ?? []) modes.set(dir === '' ? entry.path ?? '' : `${dir}/${entry.path ?? ''}`, entry.mode ?? '')\n }\n for (const file of request.files) {\n const mode = modes.get(file.path)\n if (mode === '120000' || mode === '040000' || mode === '160000') throw new RepoError('invalid', `${file.path} 在仓库中不是普通文件,不能用文件内容覆盖`)\n }\n const { data: tree } = await this.octokit.rest.git.createTree({\n ...repo,\n base_tree: parentCommit.tree.sha,\n tree: request.files.map(file => file.action === 'write'\n ? { path: file.path, mode: modes.get(file.path) === '100755' ? '100755' as const : '100644' as const, type: 'blob' as const, content: file.content }\n : { path: file.path, mode: '100644' as const, type: 'blob' as const, sha: null }),\n request: { signal },\n })\n const { data: commit } = await this.octokit.rest.git.createCommit({ ...repo, message: request.message, tree: tree.sha, parents: [parent], ...request.author === undefined ? {} : { author: request.author }, request: { signal } })\n if (existing === undefined) {\n await this.octokit.rest.git.createRef({ ...repo, ref: `refs/heads/${request.branch}`, sha: commit.sha, request: { signal } }).catch((error: unknown) => {\n // Another writer created the branch after the lookup above.\n if ((error as { status?: number }).status === 422) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)\n throw error\n })\n } else {\n await this.octokit.rest.git.updateRef({ ...repo, ref: `heads/${request.branch}`, sha: commit.sha, force: false, request: { signal } })\n }\n return { sha: commit.sha, branch: request.branch, createdBranch: existing === undefined, webUrl: commit.html_url }\n }\n\n async listIssues(ref: RepoRef, query: { page: number; perPage: number; state: 'open' | 'closed' | 'all'; labels?: readonly string[]; assignee?: string }, call: Call) {\n const { data } = await this.octokit.rest.issues.listForRepo({\n ...split(ref.path),\n state: query.state,\n page: query.page,\n per_page: query.perPage,\n ...query.labels === undefined || query.labels.length === 0 ? {} : { labels: query.labels.join(',') },\n ...query.assignee === undefined ? {} : { assignee: query.assignee },\n request: { signal: call.signal },\n })\n // The issues endpoint also lists pull requests; they are change requests here.\n return { items: data.filter(entry => entry.pull_request === undefined).map(issue), ...nextPage(query, data.length) }\n }\n\n async getIssue(ref: RepoRef, number: number, call: Call) {\n const repo = split(ref.path)\n const [{ data }, comments] = await Promise.all([\n this.octokit.rest.issues.get({ ...repo, issue_number: number, request: { signal: call.signal } }),\n this.comments(ref, number, call),\n ])\n if (data.pull_request !== undefined) throw new RepoError('not-found', `#${number} 是 PR,不是 issue;请用 PR/MR 相关接口`)\n return { ...issue(data), comments }\n }\n\n async createIssue(ref: RepoRef, fields: { title: string; body?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const { data } = await this.octokit.rest.issues.create({\n ...split(ref.path),\n title: fields.title,\n ...fields.body === undefined ? {} : { body: fields.body },\n ...fields.labels === undefined ? {} : { labels: [...fields.labels] },\n ...fields.assignees === undefined ? {} : { assignees: [...fields.assignees] },\n request: { signal: call.signal },\n })\n return issue(data)\n }\n\n async updateIssue(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const { data } = await this.octokit.rest.issues.update({\n ...split(ref.path),\n issue_number: number,\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { body: update.body },\n ...update.state === undefined ? {} : { state: update.state },\n ...update.labels === undefined ? {} : { labels: [...update.labels] },\n ...update.assignees === undefined ? {} : { assignees: [...update.assignees] },\n request: { signal: call.signal },\n })\n return issue(data)\n }\n\n async commentIssue(ref: RepoRef, number: number, body: string, call: Call) {\n const { data } = await this.octokit.rest.issues.createComment({ ...split(ref.path), issue_number: number, body, request: { signal: call.signal } })\n return comment(data)\n }\n\n async listChanges(ref: RepoRef, query: { page: number; perPage: number; state: ChangeState | 'all'; sourceBranch?: string; targetBranch?: string }, call: Call) {\n const repo = split(ref.path)\n const { data } = await this.octokit.rest.pulls.list({\n ...repo,\n state: query.state === 'merged' ? 'closed' : query.state,\n page: query.page,\n per_page: query.perPage,\n ...query.sourceBranch === undefined ? {} : { head: `${repo.owner}:${query.sourceBranch}` },\n ...query.targetBranch === undefined ? {} : { base: query.targetBranch },\n request: { signal: call.signal },\n })\n const items = data.map(pull).filter(change => query.state === 'all' || change.state === query.state)\n return { items, ...nextPage(query, data.length) }\n }\n\n async getChange(ref: RepoRef, number: number, call: Call) {\n const [{ data }, comments] = await Promise.all([\n this.octokit.rest.pulls.get({ ...split(ref.path), pull_number: number, request: { signal: call.signal } }),\n this.comments(ref, number, call),\n ])\n return { ...pull(data), comments }\n }\n\n async changeDiff(ref: RepoRef, number: number, call: Call) {\n const response = await this.octokit.rest.pulls.get({ ...split(ref.path), pull_number: number, mediaType: { format: 'diff' }, request: { signal: call.signal } })\n const raw: unknown = response.data\n const { text, truncated } = truncateBytes(typeof raw === 'string' ? raw : '', call.limits.maxDiffBytes)\n return { diff: text, truncated }\n }\n\n async changeStatus(ref: RepoRef, number: number, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n const { data: change } = await this.octokit.rest.pulls.get({ ...repo, pull_number: number, request: { signal } })\n const sha = change.head.sha\n const [runs, statuses] = await Promise.all([\n this.allPages(page => this.octokit.rest.checks.listForRef({ ...repo, ref: sha, per_page: PAGE, page, request: { signal } }).then(response => response.data.check_runs)),\n this.allPages(page => this.octokit.rest.repos.getCombinedStatusForRef({ ...repo, ref: sha, per_page: PAGE, page, request: { signal } }).then(response => response.data.statuses)),\n ])\n const checks: CheckInfo[] = [\n ...runs.map(run => ({ name: run.name, state: checkRunState(run.status, run.conclusion), ...run.html_url === null ? {} : { webUrl: run.html_url } })),\n ...statuses.map(status => ({\n name: status.context,\n state: status.state === 'success' ? 'success' as const : status.state === 'pending' ? 'pending' as const : 'failure' as const,\n ...status.target_url === null ? {} : { webUrl: status.target_url },\n })),\n ]\n return { headSha: sha, checks, overall: overall(checks), ...change.mergeable === null ? {} : { mergeable: change.mergeable } }\n }\n\n async createChange(ref: RepoRef, fields: { title: string; body?: string; sourceBranch: string; targetBranch: string; draft: boolean; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const repo = split(ref.path)\n const { data } = await this.octokit.rest.pulls.create({\n ...repo,\n title: fields.title,\n head: fields.sourceBranch,\n base: fields.targetBranch,\n draft: fields.draft,\n ...fields.body === undefined ? {} : { body: fields.body },\n request: { signal: call.signal },\n })\n if ((fields.labels?.length ?? 0) === 0 && (fields.assignees?.length ?? 0) === 0) return pull(data)\n // Labels and assignees live on the pull request's issue.\n await this.octokit.rest.issues.update({\n ...repo,\n issue_number: data.number,\n ...fields.labels === undefined ? {} : { labels: [...fields.labels] },\n ...fields.assignees === undefined ? {} : { assignees: [...fields.assignees] },\n request: { signal: call.signal },\n })\n return pull((await this.octokit.rest.pulls.get({ ...repo, pull_number: data.number, request: { signal: call.signal } })).data)\n }\n\n async updateChange(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; targetBranch?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const repo = split(ref.path)\n const signal = call.signal\n if (update.labels !== undefined || update.assignees !== undefined) {\n await this.octokit.rest.issues.update({\n ...repo,\n issue_number: number,\n ...update.labels === undefined ? {} : { labels: [...update.labels] },\n ...update.assignees === undefined ? {} : { assignees: [...update.assignees] },\n request: { signal },\n })\n }\n const { data } = await this.octokit.rest.pulls.update({\n ...repo,\n pull_number: number,\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { body: update.body },\n ...update.state === undefined ? {} : { state: update.state },\n ...update.targetBranch === undefined ? {} : { base: update.targetBranch },\n request: { signal },\n })\n return pull(data)\n }\n\n async commentChange(ref: RepoRef, number: number, body: string, call: Call) {\n return await this.commentIssue(ref, number, body, call)\n }\n\n async mergeChange(ref: RepoRef, number: number, request: { headSha: string; method?: 'merge' | 'squash' | 'rebase' }, call: Call) {\n const { data } = await this.octokit.rest.pulls.merge({\n ...split(ref.path),\n pull_number: number,\n sha: request.headSha,\n ...request.method === undefined ? {} : { merge_method: request.method },\n request: { signal: call.signal },\n })\n return { sha: data.sha }\n }\n\n /** Every page of a list endpoint, so an aggregate never rests on a partial list. */\n private async allPages<T>(read: (page: number) => Promise<readonly T[]>): Promise<T[]> {\n const items: T[] = []\n for (let page = 1; page <= MAX_STATUS_PAGES; page += 1) {\n const batch = await read(page)\n items.push(...batch)\n if (batch.length < PAGE) return items\n }\n throw new RepoError('too-large', `CI 检查超过 ${MAX_STATUS_PAGES * PAGE} 条,无法给出完整状态`)\n }\n\n private async comments(ref: RepoRef, number: number, call: Call): Promise<CommentInfo[]> {\n const { data } = await this.octokit.rest.issues.listComments({ ...split(ref.path), issue_number: number, per_page: call.limits.maxComments, request: { signal: call.signal } })\n return data.map(comment)\n }\n}\n","/**\n * GitLab provider on `@gitbeaker/rest`, the TypeScript SDK GitLab's\n * documentation lists: gitlab.com and self-managed instances, including ones\n * served under a path prefix. Merge requests are this module's change\n * requests; issue and merge request numbers are project-scoped IIDs.\n *\n * @module dsh-repo/providers/gitlab\n */\n\nimport { Gitlab } from '@gitbeaker/rest'\nimport type {\n BranchInfo, ChangeInfo, ChangeState, CheckInfo, CommentInfo, CommitInfo, FileChange, IssueInfo, RepoInfo, RepoRef, RepoUser, TreeEntry,\n} from '../contract.ts'\nimport { RepoError } from '../errors.ts'\nimport { nextPage, titleOf, truncateBytes } from './types.ts'\nimport type { Call, Paging, Provider, TokenSource } from './types.ts'\n\n/** GitLab's maximum page size. */\nconst MAX_PAGE = 100\n\n/** Prefix GitLab uses to mark a draft merge request in its title. */\nconst DRAFT_PREFIX = 'Draft: '\n\ninterface GitlabUser { readonly username: string; readonly web_url?: string }\n\nfunction user(value: GitlabUser | null | undefined): RepoUser {\n return value === null || value === undefined ? { username: 'ghost' } : { username: value.username, ...value.web_url === undefined ? {} : { webUrl: value.web_url } }\n}\n\nfunction labelNames(labels: unknown): string[] {\n if (!Array.isArray(labels)) return []\n return labels.map(label => typeof label === 'string' ? label : typeof label === 'object' && label !== null && 'name' in label ? String(label.name) : '').filter(name => name !== '')\n}\n\ninterface GitlabIssue {\n readonly iid: number\n readonly title: string\n readonly description?: string | null\n readonly state: string\n readonly author: GitlabUser\n readonly labels?: unknown\n readonly assignees?: readonly GitlabUser[] | null\n readonly created_at: string\n readonly updated_at: string\n readonly web_url: string\n}\n\nfunction issue(value: GitlabIssue): IssueInfo {\n return {\n number: value.iid,\n title: value.title,\n body: value.description ?? '',\n state: value.state === 'closed' ? 'closed' : 'open',\n author: user(value.author),\n labels: labelNames(value.labels),\n assignees: (value.assignees ?? []).map(user),\n createdAt: value.created_at,\n updatedAt: value.updated_at,\n webUrl: value.web_url,\n }\n}\n\ninterface GitlabMergeRequest extends GitlabIssue {\n readonly draft?: boolean\n readonly work_in_progress?: boolean\n readonly source_branch: string\n readonly target_branch: string\n readonly sha: string\n}\n\nfunction mergeRequest(value: GitlabMergeRequest): ChangeInfo {\n const state: ChangeState = value.state === 'merged' ? 'merged' : value.state === 'opened' ? 'open' : 'closed'\n return {\n ...issue(value),\n state,\n draft: value.draft === true || value.work_in_progress === true,\n sourceBranch: value.source_branch,\n targetBranch: value.target_branch,\n headSha: value.sha,\n }\n}\n\ninterface GitlabNote {\n readonly id: number\n readonly body: string\n readonly author: GitlabUser\n readonly created_at: string\n readonly system?: boolean\n}\n\nfunction note(value: GitlabNote): CommentInfo {\n return { id: String(value.id), author: user(value.author), body: value.body, createdAt: value.created_at }\n}\n\nfunction pipelineState(status: string): CheckInfo['state'] {\n if (status === 'success' || status === 'skipped') return 'success'\n if (status === 'failed' || status === 'canceled') return 'failure'\n return 'pending'\n}\n\n/** Detailed merge statuses GitLab reports while it is still computing mergeability. */\nconst COMPUTING = new Set(['checking', 'unchecked', 'preparing', 'approvals_syncing'])\n\nfunction paging(query: Paging): { page: number; perPage: number; maxPages: number } {\n return { page: query.page, perPage: query.perPage, maxPages: 1 }\n}\n\nfunction dirname(path: string): string {\n const slash = path.lastIndexOf('/')\n return slash < 0 ? '' : path.slice(0, slash)\n}\n\n/** GitLab provider bound to one host. */\nexport class GitlabProvider implements Provider {\n private readonly api: InstanceType<typeof Gitlab<false>>\n\n /**\n * @param host - instance URL, with its path prefix when it has one.\n * @param token - resolves the host's token for every request.\n * @param timeoutMs - per-request timeout; GitBeaker takes no per-call signal.\n */\n constructor(host: string, token: TokenSource, timeoutMs: number) {\n this.api = new Gitlab({ host, token, queryTimeout: timeoutMs })\n }\n\n async repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo> {\n call.signal.throwIfAborted()\n const data = await this.api.Projects.show(ref.path)\n return {\n ...ref,\n webUrl: data.web_url,\n defaultBranch: data.default_branch,\n ...typeof data.description === 'string' && data.description !== '' ? { description: data.description } : {},\n visibility: data.visibility === 'internal' ? 'internal' : data.visibility === 'private' ? 'private' : 'public',\n archived: data.archived,\n cloneUrl: data.http_url_to_repo,\n }\n }\n\n async listBranches(ref: RepoRef, query: Paging & { search?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Branches.all(ref.path, { ...paging(query), ...query.search === undefined ? {} : { search: query.search } })\n const items: BranchInfo[] = data.map(branch => ({ name: branch.name, commit: String(branch.commit.id), protected: branch.protected, default: branch.default }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async getBranch(ref: RepoRef, name: string, call: Call) {\n call.signal.throwIfAborted()\n const branch = await this.api.Branches.show(ref.path, name).catch((error: unknown) => {\n if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return undefined\n throw error\n })\n return branch === undefined ? undefined : { name: branch.name, commit: String(branch.commit.id), protected: branch.protected, default: branch.default }\n }\n\n async listCommits(ref: RepoRef, query: Paging & { ref?: string; path?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Commits.all(ref.path, {\n ...paging(query),\n ...query.ref === undefined ? {} : { refName: query.ref },\n ...query.path === undefined ? {} : { path: query.path },\n })\n const items: CommitInfo[] = data.map(entry => ({\n sha: entry.id,\n title: entry.title ?? titleOf(entry.message),\n message: entry.message,\n authorName: entry.author_name,\n authorEmail: entry.author_email,\n authoredAt: entry.authored_date,\n webUrl: entry.web_url,\n }))\n return { items, ...nextPage(query, data.length) }\n }\n\n async listTree(ref: RepoRef, query: { ref?: string; path: string; recursive: boolean }, call: Call) {\n const at = query.ref ?? (await this.repoInfo(ref, call)).defaultBranch\n const max = call.limits.maxTreeEntries\n const data = await this.api.Repositories.allRepositoryTrees(ref.path, {\n ref: at,\n ...query.path === '' ? {} : { path: query.path },\n recursive: query.recursive,\n perPage: MAX_PAGE,\n maxPages: Math.floor(max / MAX_PAGE) + 1,\n })\n const entries: TreeEntry[] = data.map(entry => ({\n path: entry.path,\n type: entry.type === 'tree' ? 'dir' : entry.type === 'commit' ? 'submodule' : entry.mode === '120000' ? 'symlink' : 'file',\n }))\n return { ref: at, entries: entries.slice(0, max), truncated: entries.length > max }\n }\n\n async readFile(ref: RepoRef, path: string, at: string | undefined, call: Call) {\n const target = at ?? (await this.repoInfo(ref, call)).defaultBranch\n const raw = await this.api.RepositoryFiles.showRaw(ref.path, path, target)\n const text = typeof raw === 'string' ? raw : await raw.text()\n if (text.includes('\\0')) return { path, ref: target, text: '', binary: true, truncated: false }\n return { path, ref: target, binary: false, ...truncateBytes(text, call.limits.maxFileBytes) }\n }\n\n async commitFiles(ref: RepoRef, request: { branch: string; base?: string; baseSha?: string; newBranch?: boolean; author?: { name: string; email: string }; message: string; files: readonly FileChange[] }, call: Call) {\n const info = await this.repoInfo(ref, call)\n if (request.branch === info.defaultBranch) throw new RepoError('forbidden', `不允许直接提交到默认分支 ${request.branch};请提交到新分支后开 MR`)\n const existing = await this.api.Branches.show(ref.path, request.branch).catch((error: unknown) => {\n if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return undefined\n throw error\n })\n if (existing !== undefined && request.newBranch === true) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)\n if (existing?.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)\n const start = existing === undefined ? request.baseSha ?? request.base ?? info.defaultBranch : request.branch\n // GitLab needs `create` or `update` per file, so list each touched directory at the start point.\n const present = new Set<string>()\n for (const dir of new Set(request.files.filter(file => file.action === 'write').map(file => dirname(file.path)))) {\n call.signal.throwIfAborted()\n const listing = await this.api.Repositories.allRepositoryTrees(ref.path, { ref: start, ...dir === '' ? {} : { path: dir }, perPage: MAX_PAGE }).catch((error: unknown) => {\n // A directory that does not exist yet holds no files.\n if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return []\n throw error\n })\n for (const entry of listing) if (entry.type === 'blob') present.add(entry.path)\n }\n const actions = request.files.map(file => file.action === 'delete'\n ? { action: 'delete' as const, filePath: file.path }\n : { action: present.has(file.path) ? 'update' as const : 'create' as const, filePath: file.path, content: file.content })\n call.signal.throwIfAborted()\n const startOption = existing !== undefined ? {} : request.baseSha === undefined ? { startBranch: start } : { startSha: request.baseSha }\n const authorOption = request.author === undefined ? {} : { authorName: request.author.name, authorEmail: request.author.email }\n const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, { ...startOption, ...authorOption }).catch((error: unknown) => {\n // GitLab answers 400 when another writer created the branch after the lookup above.\n if (existing === undefined && (error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 400 && error instanceof Error && /already exists/i.test(error.message)) {\n throw new RepoError('conflict', `分支 ${request.branch} 已存在`)\n }\n throw error\n })\n return { sha: commit.id, branch: request.branch, createdBranch: existing === undefined, webUrl: commit.web_url }\n }\n\n async listIssues(ref: RepoRef, query: Paging & { state: 'open' | 'closed' | 'all'; labels?: readonly string[]; assignee?: string }, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.Issues.all({\n projectId: ref.path,\n ...paging(query),\n ...query.state === 'all' ? {} : { state: query.state === 'open' ? 'opened' as const : 'closed' as const },\n ...query.labels === undefined || query.labels.length === 0 ? {} : { labels: query.labels.join(',') },\n ...query.assignee === undefined ? {} : { assigneeUsername: [query.assignee] },\n })\n return { items: data.map(entry => issue(entry)), ...nextPage(query, data.length) }\n }\n\n async getIssue(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const [data, notes] = await Promise.all([\n this.api.Issues.show(number, { projectId: ref.path }),\n this.api.IssueNotes.all(ref.path, number, { sort: 'asc', perPage: call.limits.maxComments, maxPages: 1 }),\n ])\n return { ...issue(data), comments: notes.filter(entry => entry.system !== true).map(note) }\n }\n\n async createIssue(ref: RepoRef, fields: { title: string; body?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(fields.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.Issues.create(ref.path, fields.title, {\n ...fields.body === undefined ? {} : { description: fields.body },\n ...fields.labels === undefined ? {} : { labels: fields.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return issue(data)\n }\n\n async updateIssue(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(update.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.Issues.edit(ref.path, number, {\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { description: update.body },\n ...update.state === undefined ? {} : { stateEvent: update.state === 'closed' ? 'close' as const : 'reopen' as const },\n ...update.labels === undefined ? {} : { labels: update.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return issue(data)\n }\n\n async commentIssue(ref: RepoRef, number: number, body: string, call: Call) {\n call.signal.throwIfAborted()\n return note(await this.api.IssueNotes.create(ref.path, number, body))\n }\n\n async listChanges(ref: RepoRef, query: Paging & { state: ChangeState | 'all'; sourceBranch?: string; targetBranch?: string }, call: Call) {\n call.signal.throwIfAborted()\n const state = query.state === 'all' ? undefined : query.state === 'open' ? 'opened' as const : query.state\n const data = await this.api.MergeRequests.all({\n projectId: ref.path,\n ...paging(query),\n ...state === undefined ? {} : { state },\n ...query.sourceBranch === undefined ? {} : { sourceBranch: query.sourceBranch },\n ...query.targetBranch === undefined ? {} : { targetBranch: query.targetBranch },\n })\n return { items: data.map(entry => mergeRequest(entry)), ...nextPage(query, data.length) }\n }\n\n async getChange(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const [data, notes] = await Promise.all([\n this.api.MergeRequests.show(ref.path, number),\n this.api.MergeRequestNotes.all(ref.path, number, { sort: 'asc', perPage: call.limits.maxComments, maxPages: 1 }),\n ])\n return { ...mergeRequest(data), comments: notes.filter(entry => entry.system !== true).map(note) }\n }\n\n async changeDiff(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const files = await this.api.MergeRequests.allDiffs(ref.path, number, { perPage: MAX_PAGE })\n // GitLab leaves `diff` empty for collapsed or oversized files; say so instead of presenting a complete diff.\n let omitted = false\n const parts = files.map((file) => {\n const from = file.new_file ? '/dev/null' : `a/${file.old_path}`\n const to = file.deleted_file ? '/dev/null' : `b/${file.new_path}`\n const skipped = file.too_large === true || (file.collapsed === true && file.diff === '')\n if (skipped) omitted = true\n return `diff --git a/${file.old_path} b/${file.new_path}\\n--- ${from}\\n+++ ${to}\\n${skipped ? '# GitLab 未返回这个文件的 diff(文件过大或已折叠)\\n' : file.diff}`\n })\n const { text, truncated } = truncateBytes(parts.join(''), call.limits.maxDiffBytes)\n return { diff: text, truncated: truncated || omitted }\n }\n\n async changeStatus(ref: RepoRef, number: number, call: Call) {\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.show(ref.path, number)\n const pipeline = data.head_pipeline\n const checks: CheckInfo[] = pipeline === undefined || pipeline === null\n ? []\n : [{ name: `pipeline #${pipeline.id}`, state: pipelineState(pipeline.status), ...pipeline.web_url === undefined ? {} : { webUrl: pipeline.web_url } }]\n const detailed = data.detailed_merge_status\n return {\n headSha: data.sha,\n checks,\n overall: checks[0]?.state ?? 'none' as const,\n ...typeof detailed !== 'string' || COMPUTING.has(detailed) ? {} : { mergeable: detailed === 'mergeable' },\n }\n }\n\n async createChange(ref: RepoRef, fields: { title: string; body?: string; sourceBranch: string; targetBranch: string; draft: boolean; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(fields.assignees, call)\n call.signal.throwIfAborted()\n const title = fields.draft && !fields.title.startsWith(DRAFT_PREFIX) ? `${DRAFT_PREFIX}${fields.title}` : fields.title\n const data = await this.api.MergeRequests.create(ref.path, fields.sourceBranch, fields.targetBranch, title, {\n ...fields.body === undefined ? {} : { description: fields.body },\n ...fields.labels === undefined ? {} : { labels: fields.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return mergeRequest(data)\n }\n\n async updateChange(ref: RepoRef, number: number, update: { title?: string; body?: string; state?: 'open' | 'closed'; targetBranch?: string; labels?: readonly string[]; assignees?: readonly string[] }, call: Call) {\n const assigneeIds = await this.userIds(update.assignees, call)\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.edit(ref.path, number, {\n ...update.title === undefined ? {} : { title: update.title },\n ...update.body === undefined ? {} : { description: update.body },\n ...update.state === undefined ? {} : { stateEvent: update.state === 'closed' ? 'close' as const : 'reopen' as const },\n ...update.targetBranch === undefined ? {} : { targetBranch: update.targetBranch },\n ...update.labels === undefined ? {} : { labels: update.labels.join(',') },\n ...assigneeIds === undefined ? {} : { assigneeIds },\n })\n return mergeRequest(data)\n }\n\n async commentChange(ref: RepoRef, number: number, body: string, call: Call) {\n call.signal.throwIfAborted()\n return note(await this.api.MergeRequestNotes.create(ref.path, number, body))\n }\n\n async mergeChange(ref: RepoRef, number: number, request: { headSha: string; method?: 'merge' | 'squash' | 'rebase' }, call: Call) {\n if (request.method === 'rebase') throw new RepoError('invalid', 'GitLab 的合并接口不支持 rebase 方式;可用 merge 或 squash')\n call.signal.throwIfAborted()\n const data = await this.api.MergeRequests.merge(ref.path, number, {\n sha: request.headSha,\n ...request.method === undefined ? {} : { squash: request.method === 'squash' },\n })\n const sha = data.merge_commit_sha ?? data.squash_commit_sha\n return typeof sha === 'string' ? { sha } : {}\n }\n\n /** User ids for usernames; GitLab assigns by id. */\n private async userIds(usernames: readonly string[] | undefined, call: Call): Promise<number[] | undefined> {\n if (usernames === undefined) return undefined\n const ids: number[] = []\n for (const username of usernames) {\n call.signal.throwIfAborted()\n const [found] = await this.api.Users.all({ username, maxPages: 1 })\n if (found === undefined) throw new RepoError('invalid', `GitLab 上没有用户 ${username}`)\n ids.push(found.id)\n }\n return ids\n }\n}\n","/**\n * Repository targets: map a URL or `host/path` to a configured host and a\n * repository path, and apply the configured repository patterns.\n *\n * @module dsh-repo/target\n */\n\nimport type { RepoRef } from './contract.ts'\nimport type { HostSpec } from './config.ts'\nimport { RepoError } from './errors.ts'\n\nconst SEGMENT = /^[A-Za-z0-9._-]+$/\nconst SCP_LIKE = /^[A-Za-z0-9._-]+@([A-Za-z0-9.-]+):(.+)$/\n\n/** A target resolved to its host. */\nexport interface ResolvedTarget extends RepoRef {\n readonly spec: HostSpec\n}\n\ninterface ParsedTarget {\n /** Lowercase host, with port only for HTTP(S) addresses. */\n readonly host: string\n /** Whether the address was HTTP(S) or bare, so the host's port and path prefix apply. */\n readonly web: boolean\n readonly pathname: string\n}\n\nfunction parse(input: string): ParsedTarget | undefined {\n const value = input.trim()\n if (value === '' || /\\s/.test(value)) return undefined\n const scp = SCP_LIKE.exec(value)\n if (scp !== null) return { host: (scp[1] ?? '').toLowerCase(), web: false, pathname: `/${scp[2] ?? ''}` }\n let url: URL\n try {\n url = new URL(/^[a-z][a-z0-9+.-]*:\\/\\//i.test(value) ? value : `https://${value}`)\n } catch {\n // Neither a URL nor host/path.\n return undefined\n }\n if (url.protocol === 'https:' || url.protocol === 'http:') return { host: url.host.toLowerCase(), web: true, pathname: decodeURIComponent(url.pathname) }\n if (url.protocol === 'ssh:' || url.protocol === 'git:') return { host: url.hostname.toLowerCase(), web: false, pathname: decodeURIComponent(url.pathname) }\n return undefined\n}\n\nfunction repoPath(kind: HostSpec['kind'], rest: string): string | undefined {\n let segments = rest.replace(/\\.git$/, '').split('/').filter(segment => segment !== '')\n if (kind === 'github') {\n segments = segments.slice(0, 2)\n if (segments.length !== 2) return undefined\n } else {\n const marker = segments.indexOf('-')\n if (marker >= 0) segments = segments.slice(0, marker)\n if (segments.length < 2) return undefined\n }\n if (segments.at(-1)?.endsWith('.git') === true) segments[segments.length - 1] = segments.at(-1)!.slice(0, -4)\n return segments.every(segment => SEGMENT.test(segment) && segment !== '.' && segment !== '..') ? segments.join('/') : undefined\n}\n\n/**\n * Whether a repository key matches one configured pattern.\n * @param key - lowercase `host/path`.\n * @param pattern - lowercase pattern; a final `*` matches one segment, `**` one or more.\n * @returns whether it matches.\n */\nexport function matchesPattern(key: string, pattern: string): boolean {\n const keySegments = key.split('/')\n const patternSegments = pattern.split('/')\n const last = patternSegments.at(-1)\n if (last === '**') {\n const prefix = patternSegments.slice(0, -1)\n return keySegments.length > prefix.length && prefix.every((segment, index) => segment === keySegments[index])\n }\n if (keySegments.length !== patternSegments.length) return false\n return patternSegments.every((segment, index) => segment === '*' ? index === patternSegments.length - 1 : segment === keySegments[index])\n}\n\n/**\n * Resolve a repository target.\n * @param input - URL or `host/path`.\n * @param hosts - configured hosts.\n * @param patterns - configured repository patterns; empty allows every repository on the hosts.\n * @returns the host and repository path.\n * @throws {RepoError} `invalid` for an unreadable target, `not-allowed` when no host or pattern admits it.\n */\nexport function resolveTarget(input: string, hosts: readonly HostSpec[], patterns: readonly string[]): ResolvedTarget {\n const parsed = parse(input)\n if (parsed === undefined) throw new RepoError('invalid', `无法识别的仓库:${input}(填仓库网址、git 地址或 主机/路径)`)\n let best: { spec: HostSpec; rest: string; prefix: number } | undefined\n for (const spec of hosts) {\n const url = new URL(spec.url)\n const prefix = url.pathname.replace(/\\/+$/, '')\n if (parsed.web) {\n if (url.host !== parsed.host) continue\n if (prefix !== '' && parsed.pathname !== prefix && !parsed.pathname.startsWith(`${prefix}/`)) continue\n if (best === undefined || prefix.length > best.prefix) best = { spec, rest: parsed.pathname.slice(prefix.length), prefix: prefix.length }\n } else if (url.hostname === parsed.host && best === undefined) {\n best = { spec, rest: parsed.pathname, prefix: 0 }\n }\n }\n if (best === undefined) throw new RepoError('not-allowed', `没有为 ${parsed.host} 配置主机,dsh-repo 不能访问 ${input}`)\n const path = repoPath(best.spec.kind, best.rest)\n if (path === undefined) {\n throw new RepoError('invalid', best.spec.kind === 'github' ? `GitHub 仓库路径应为 owner/name:${input}` : `GitLab 仓库路径应为 group/project(可有多级 group):${input}`)\n }\n const host = new URL(best.spec.url).host\n const key = `${host}/${path}`.toLowerCase()\n if (patterns.length > 0 && !patterns.some(pattern => matchesPattern(key, pattern))) {\n throw new RepoError('not-allowed', `${host}/${path} 不在 dsh-repo 配置的仓库范围内`)\n }\n return { spec: best.spec, kind: best.spec.kind, host, path, webUrl: `${best.spec.url}/${path}` }\n}\n","/**\n * The `dshRepos` service: resolves each target against the configured hosts\n * and repositories, validates arguments, attaches the call deadline, delegates\n * to the host family's provider, and turns every failure into a\n * {@link RepoError}.\n *\n * Tokens are read through `ctx.credentials` on every request, so a rotated\n * token takes effect without a reload.\n *\n * @module dsh-repo/service\n */\n\nimport type {\n CallOptions, ChangeCreate, ChangeListOptions, ChangeUpdate, CommitRequest, DshRepoService, IssueCreate, IssueListOptions, IssueUpdate,\n MergeOptions, PageOptions, RepoRef, RepoTarget,\n} from './contract.ts'\nimport { apiBaseUrl } from './config.ts'\nimport type { HostSpec, RepoConfig } from './config.ts'\nimport { RepoError, toRepoError } from './errors.ts'\nimport type { HostCredentials } from './host.ts'\nimport { GithubProvider } from './providers/github.ts'\nimport { GitlabProvider } from './providers/gitlab.ts'\nimport type { Call, Paging, Provider } from './providers/types.ts'\nimport { resolveTarget } from './target.ts'\nimport type { ResolvedTarget } from './target.ts'\n\n/** Name the service is provided under. */\nexport const DSH_REPOS_SERVICE = 'dshRepos'\n\n/** Builds the provider of one host; tests substitute it. */\nexport type ProviderFactory = (spec: HostSpec, token: () => Promise<string>, timeoutMs: number) => Provider\n\n/** Default factory: Octokit for GitHub, GitBeaker for GitLab. */\nexport const defaultProviderFactory: ProviderFactory = (spec, token, timeoutMs) => spec.kind === 'github'\n ? new GithubProvider(apiBaseUrl(spec), token)\n : new GitlabProvider(apiBaseUrl(spec), token, timeoutMs)\n\nconst BRANCH = /^(?!-)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*\\.lock$)(?!.*\\/$)[^\\s~^:?*[\\\\\\u0000-\\u001f\\u007f]+$/\n\nfunction requireBranch(value: string, label: string): void {\n if (!BRANCH.test(value) || value.startsWith('/') || value === '@') throw new RepoError('invalid', `${label}不合法:${value}`)\n}\n\nfunction requireRepoPath(value: string, label: string): void {\n const segments = value.split('/')\n if (value === '' || value.startsWith('/') || segments.some(segment => segment === '' || segment === '.' || segment === '..') || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n throw new RepoError('invalid', `${label}不合法:${value}(用仓库根目录下的相对路径,例如 src/index.ts)`)\n }\n}\n\nfunction requireNumber(value: number): void {\n if (!Number.isSafeInteger(value) || value < 1) throw new RepoError('invalid', `编号必须是正整数:${value}`)\n}\n\nfunction requireText(value: string, label: string): void {\n if (value.trim() === '') throw new RepoError('invalid', `${label}不能为空`)\n}\n\n/** The service implementation. */\nexport class RepoService implements DshRepoService {\n readonly version = 1 as const\n private readonly providers = new Map<string, Provider>()\n\n /**\n * @param config - validated configuration.\n * @param credentials - DSH credential store; tokens are resolved per request.\n * @param factory - provider factory.\n */\n constructor(\n private readonly config: RepoConfig,\n private readonly credentials: HostCredentials,\n private readonly factory: ProviderFactory = defaultProviderFactory,\n ) {}\n\n /** Whether any host is configured. */\n get configured(): boolean {\n return this.config.hosts.length > 0\n }\n\n resolve(repo: RepoTarget): RepoRef {\n const { spec: _spec, ...ref } = this.target(repo)\n return ref\n }\n\n async repoInfo(repo: RepoTarget, options: CallOptions = {}) {\n return await this.run(repo, options, '读取仓库信息', (provider, ref, call) => provider.repoInfo(ref, call))\n }\n\n async listBranches(repo: RepoTarget, options: PageOptions & { readonly search?: string } = {}) {\n const query = { ...this.paging(options), ...options.search === undefined ? {} : { search: options.search } }\n return await this.run(repo, options, '列出分支', (provider, ref, call) => provider.listBranches(ref, query, call))\n }\n\n async getBranch(repo: RepoTarget, name: string, options: CallOptions = {}) {\n requireBranch(name, '分支名')\n return await this.run(repo, options, `读取分支 ${name}`, (provider, ref, call) => provider.getBranch(ref, name, call))\n }\n\n async listCommits(repo: RepoTarget, options: PageOptions & { readonly ref?: string; readonly path?: string } = {}) {\n if (options.path !== undefined) requireRepoPath(options.path, '路径')\n const query = { ...this.paging(options), ...options.ref === undefined ? {} : { ref: options.ref }, ...options.path === undefined ? {} : { path: options.path } }\n return await this.run(repo, options, '列出提交', (provider, ref, call) => provider.listCommits(ref, query, call))\n }\n\n async listTree(repo: RepoTarget, options: CallOptions & { readonly ref?: string; readonly path?: string; readonly recursive?: boolean } = {}) {\n const path = (options.path ?? '').replace(/^\\/+|\\/+$/g, '')\n if (path !== '') requireRepoPath(path, '目录')\n const query = { path, recursive: options.recursive === true, ...options.ref === undefined ? {} : { ref: options.ref } }\n return await this.run(repo, options, '列出目录', (provider, ref, call) => provider.listTree(ref, query, call))\n }\n\n async readFile(repo: RepoTarget, path: string, options: CallOptions & { readonly ref?: string } = {}) {\n requireRepoPath(path, '文件路径')\n return await this.run(repo, options, `读取文件 ${path}`, (provider, ref, call) => provider.readFile(ref, path, options.ref, call))\n }\n\n async commitFiles(repo: RepoTarget, request: CommitRequest) {\n requireBranch(request.branch, '分支名')\n if (request.base !== undefined) requireBranch(request.base, '起点分支名')\n if (request.baseSha !== undefined) {\n if (request.base !== undefined) throw new RepoError('invalid', 'base 和 baseSha 只能给一个')\n if (!/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(request.baseSha)) throw new RepoError('invalid', `起点提交必须是完整的十六进制提交 id:${request.baseSha}`)\n }\n requireText(request.message, '提交说明')\n if (request.author !== undefined) {\n if (!/^[^<>\\n]+$/.test(request.author.name.trim())) throw new RepoError('invalid', '提交作者名不能为空,也不能包含 < > 或换行')\n if (!/^[^<>\\s]+$/.test(request.author.email.trim())) throw new RepoError('invalid', '提交作者邮箱不能为空,也不能包含 < > 或空白')\n }\n if (request.files.length === 0) throw new RepoError('invalid', '提交至少要包含一个文件')\n if (request.files.length > this.config.limits.maxCommitFiles) throw new RepoError('too-large', `一次提交最多 ${this.config.limits.maxCommitFiles} 个文件`)\n const seen = new Set<string>()\n for (const file of request.files) {\n requireRepoPath(file.path, '文件路径')\n if (seen.has(file.path)) throw new RepoError('invalid', `文件重复:${file.path}`)\n seen.add(file.path)\n if (file.action === 'write' && Buffer.byteLength(file.content, 'utf8') > this.config.limits.maxFileBytes) {\n throw new RepoError('too-large', `${file.path} 超过单文件上限 ${this.config.limits.maxFileBytes} 字节`)\n }\n }\n const fields = {\n branch: request.branch,\n message: request.message,\n files: request.files,\n ...request.base === undefined ? {} : { base: request.base },\n ...request.baseSha === undefined ? {} : { baseSha: request.baseSha },\n ...request.newBranch === true ? { newBranch: true } : {},\n ...request.author === undefined ? {} : { author: { name: request.author.name.trim(), email: request.author.email.trim() } },\n }\n return await this.run(repo, request, `提交到分支 ${request.branch}`, (provider, ref, call) => provider.commitFiles(ref, fields, call))\n }\n\n async listIssues(repo: RepoTarget, options: IssueListOptions = {}) {\n const query = {\n ...this.paging(options),\n state: options.state ?? 'open',\n ...options.labels === undefined ? {} : { labels: options.labels },\n ...options.assignee === undefined ? {} : { assignee: options.assignee },\n }\n return await this.run(repo, options, '列出 issue', (provider, ref, call) => provider.listIssues(ref, query, call))\n }\n\n async getIssue(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 issue #${number}`, (provider, ref, call) => provider.getIssue(ref, number, call))\n }\n\n async createIssue(repo: RepoTarget, fields: IssueCreate) {\n requireText(fields.title, '标题')\n return await this.run(repo, fields, '创建 issue', (provider, ref, call) => provider.createIssue(ref, fields, call))\n }\n\n async updateIssue(repo: RepoTarget, number: number, update: IssueUpdate) {\n requireNumber(number)\n if (update.title !== undefined) requireText(update.title, '标题')\n return await this.run(repo, update, `更新 issue #${number}`, (provider, ref, call) => provider.updateIssue(ref, number, update, call))\n }\n\n async commentIssue(repo: RepoTarget, number: number, body: string, options: CallOptions = {}) {\n requireNumber(number)\n requireText(body, '评论内容')\n return await this.run(repo, options, `评论 issue #${number}`, (provider, ref, call) => provider.commentIssue(ref, number, body, call))\n }\n\n async listChanges(repo: RepoTarget, options: ChangeListOptions = {}) {\n const query = {\n ...this.paging(options),\n state: options.state ?? 'open',\n ...options.sourceBranch === undefined ? {} : { sourceBranch: options.sourceBranch },\n ...options.targetBranch === undefined ? {} : { targetBranch: options.targetBranch },\n }\n return await this.run(repo, options, '列出 PR/MR', (provider, ref, call) => provider.listChanges(ref, query, call))\n }\n\n async getChange(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number}`, (provider, ref, call) => provider.getChange(ref, number, call))\n }\n\n async changeDiff(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number} 的 diff`, (provider, ref, call) => provider.changeDiff(ref, number, call))\n }\n\n async changeStatus(repo: RepoTarget, number: number, options: CallOptions = {}) {\n requireNumber(number)\n return await this.run(repo, options, `读取 PR/MR #${number} 的状态`, (provider, ref, call) => provider.changeStatus(ref, number, call))\n }\n\n async createChange(repo: RepoTarget, change: ChangeCreate) {\n requireText(change.title, '标题')\n requireBranch(change.sourceBranch, '源分支名')\n if (change.targetBranch !== undefined) requireBranch(change.targetBranch, '目标分支名')\n return await this.run(repo, change, '创建 PR/MR', async (provider, ref, call) => {\n const targetBranch = change.targetBranch ?? (await provider.repoInfo(ref, call)).defaultBranch\n if (targetBranch === change.sourceBranch) throw new RepoError('invalid', '源分支和目标分支不能相同')\n const { signal: _signal, ...fields } = change\n return await provider.createChange(ref, { ...fields, targetBranch, draft: change.draft === true }, call)\n })\n }\n\n async updateChange(repo: RepoTarget, number: number, update: ChangeUpdate) {\n requireNumber(number)\n if (update.title !== undefined) requireText(update.title, '标题')\n if (update.targetBranch !== undefined) requireBranch(update.targetBranch, '目标分支名')\n return await this.run(repo, update, `更新 PR/MR #${number}`, (provider, ref, call) => provider.updateChange(ref, number, update, call))\n }\n\n async commentChange(repo: RepoTarget, number: number, body: string, options: CallOptions = {}) {\n requireNumber(number)\n requireText(body, '评论内容')\n return await this.run(repo, options, `评论 PR/MR #${number}`, (provider, ref, call) => provider.commentChange(ref, number, body, call))\n }\n\n async mergeChange(repo: RepoTarget, number: number, options: MergeOptions) {\n requireNumber(number)\n if (!/^[0-9a-f]{40}([0-9a-f]{24})?$/i.test(options.headSha)) throw new RepoError('invalid', `headSha 必须是完整的提交号:${options.headSha}`)\n const request = { headSha: options.headSha, ...options.method === undefined ? {} : { method: options.method } }\n return await this.run(repo, options, `合并 PR/MR #${number}`, (provider, ref, call) => provider.mergeChange(ref, number, request, call))\n }\n\n private target(repo: RepoTarget): ResolvedTarget {\n return resolveTarget(repo, this.config.hosts, this.config.repos)\n }\n\n private paging(options: PageOptions): Paging {\n const page = options.page ?? 1\n const perPage = options.perPage ?? this.config.limits.perPage\n if (!Number.isSafeInteger(page) || page < 1) throw new RepoError('invalid', `page 必须是正整数:${page}`)\n if (!Number.isSafeInteger(perPage) || perPage < 1 || perPage > this.config.limits.maxPerPage) {\n throw new RepoError('invalid', `perPage 必须在 1 到 ${this.config.limits.maxPerPage} 之间:${perPage}`)\n }\n return { page, perPage }\n }\n\n private provider(spec: HostSpec): Provider {\n const existing = this.providers.get(spec.url)\n if (existing !== undefined) return existing\n const token = async (): Promise<string> => {\n const resolved = await this.credentials.resolve(spec.tokenRef)\n if (resolved === undefined || resolved.value === '') throw new RepoError('unauthenticated', `${spec.url} 的令牌 ${spec.tokenRef} 未设置(在 DSH 凭据库或同名环境变量中设置)`)\n return resolved.value\n }\n const created = this.factory(spec, token, this.config.timeoutMs)\n this.providers.set(spec.url, created)\n return created\n }\n\n private async run<T>(repo: RepoTarget, options: CallOptions, what: string, body: (provider: Provider, ref: RepoRef, call: Call) => Promise<T>): Promise<T> {\n const { spec, ...ref } = this.target(repo)\n const deadline = AbortSignal.timeout(this.config.timeoutMs)\n const signal = options.signal === undefined ? deadline : AbortSignal.any([options.signal, deadline])\n try {\n return await body(this.provider(spec), ref, { signal, limits: this.config.limits })\n } catch (error) {\n throw toRepoError(error, `${what}(${ref.host}/${ref.path})`)\n }\n }\n}\n","/**\n * Model tools over the `dshRepos` service: read code, history, issues, and\n * pull/merge requests, and, after the user approves each call, write them.\n *\n * - Every tool takes `repo` (URL or `host/path`); only configured hosts and\n * repositories are reachable.\n * - Write tools ask once per call through `ctx.approval` when\n * `tools.writes` is `ask`; without an approval service they refuse. With\n * `off` they are not registered. The merge tool is registered only when\n * `tools.merge` is true.\n * - A declined approval returns `{ status: 'declined' }`; a service failure\n * throws with the failure code in brackets, e.g. `[not-found] …`.\n *\n * @module dsh-repo/tools\n */\n\nimport { z } from 'zod'\nimport type { DshRepoService } from './contract.ts'\nimport type { RepoConfig } from './config.ts'\nimport { RepoError } from './errors.ts'\nimport type { ContentBlock, HostApproval, ToolDefinition, ToolRunContext } from './host.ts'\n\n/** Outcome of a write the user did not approve. */\nexport interface Declined {\n readonly status: 'declined'\n /** `rejected`, `cancelled`, or `unavailable` (no answerer). */\n readonly outcome: string\n}\n\n/** Collaborators of the tool set. */\nexport interface ToolDeps {\n readonly service: DshRepoService\n readonly config: RepoConfig\n /** DSH's approval service, looked up per call. */\n readonly approval: () => HostApproval | undefined\n}\n\nconst repo = z.string().min(1).describe('Repository: web or clone URL (https://github.com/owner/name, git@gitlab.example.com:group/project.git) or host/path')\nconst number = z.number().int().min(1).describe('Issue or PR/MR number as shown in the web UI (GitLab IID)')\nconst page = z.number().int().min(1).optional().describe('1-based page, default 1')\nconst perPage = z.number().int().min(1).max(100).optional().describe('Items per page')\nconst labels = z.array(z.string().min(1)).optional()\nconst assignees = z.array(z.string().min(1)).optional().describe('Usernames')\n\ninterface Spec<S extends z.ZodType, V> {\n readonly name: string\n readonly description: string\n readonly schema: S\n /** Present on write tools: what the approval prompt says will happen. */\n readonly describe?: (args: z.output<S>) => { readonly zh: string; readonly en: string }\n readonly run: (args: z.output<S>, signal: AbortSignal) => Promise<V>\n}\n\nfunction render(value: unknown): ContentBlock[] {\n return [{ type: 'text', text: JSON.stringify(value, null, 2) }]\n}\n\nfunction withSignature(body: string | undefined, signature: string): string | undefined {\n if (body === undefined || signature === '') return body\n return `${body}\\n\\n${signature}`\n}\n\n/**\n * Build the tool definitions the configuration enables.\n * @param deps - service, configuration, and approval lookup.\n * @returns the definitions to register.\n */\nexport function createTools(deps: ToolDeps): ToolDefinition[] {\n const { service, config } = deps\n const sign = (body: string | undefined) => withSignature(body, config.tools.signature)\n const signRequired = (body: string) => withSignature(body, config.tools.signature) ?? body\n\n const reads: ToolDefinition[] = [\n define(deps, {\n name: 'repo_info',\n description: 'Show a repository\\'s default branch, visibility, description, and clone URL on GitHub or GitLab.',\n schema: z.object({ repo }).strict(),\n run: (args, signal) => service.repoInfo(args.repo, { signal }),\n }),\n define(deps, {\n name: 'repo_list_branches',\n description: 'List branches with their head commit and protection.',\n schema: z.object({ repo, search: z.string().optional().describe('Substring of the branch name'), page, perPage }).strict(),\n run: (args, signal) => service.listBranches(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_list_commits',\n description: 'List commits newest first, optionally on a branch/tag/SHA and touching a path.',\n schema: z.object({ repo, ref: z.string().optional(), path: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listCommits(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_list_tree',\n description: 'List files and directories under a path at a ref (default: repository root on the default branch).',\n schema: z.object({ repo, path: z.string().optional(), ref: z.string().optional(), recursive: z.boolean().optional() }).strict(),\n run: (args, signal) => service.listTree(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_read_file',\n description: 'Read one text file at a ref (default: the default branch). Long files are cut at the configured size limit.',\n schema: z.object({ repo, path: z.string().min(1), ref: z.string().optional() }).strict(),\n run: (args, signal) => service.readFile(args.repo, args.path, { ...args.ref === undefined ? {} : { ref: args.ref }, signal }),\n }),\n define(deps, {\n name: 'repo_issue_list',\n description: 'List issues (pull/merge requests excluded).',\n schema: z.object({ repo, state: z.enum(['open', 'closed', 'all']).optional(), labels, assignee: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listIssues(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_get',\n description: 'Read one issue with its comments.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.getIssue(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_list',\n description: 'List pull requests (GitHub) or merge requests (GitLab).',\n schema: z.object({ repo, state: z.enum(['open', 'closed', 'merged', 'all']).optional(), sourceBranch: z.string().optional(), targetBranch: z.string().optional(), page, perPage }).strict(),\n run: (args, signal) => service.listChanges(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_mr_get',\n description: 'Read one pull/merge request with its conversation comments.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.getChange(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_diff',\n description: 'Read the unified diff of a pull/merge request. Long diffs are cut at the configured size limit.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.changeDiff(args.repo, args.number, { signal }),\n }),\n define(deps, {\n name: 'repo_mr_status',\n description: 'Read CI checks/pipeline and mergeability of a pull/merge request, with its head SHA.',\n schema: z.object({ repo, number }).strict(),\n run: (args, signal) => service.changeStatus(args.repo, args.number, { signal }),\n }),\n ]\n if (config.tools.writes === 'off') return reads\n\n const writes: ToolDefinition[] = [\n define(deps, {\n name: 'repo_commit_files',\n description: 'Commit file writes and deletions to a branch in one commit. A missing branch is created from `base` (default: the default branch). Never commits to the default or a protected branch; open a PR/MR afterwards. Requires user approval.',\n schema: z.object({\n repo,\n branch: z.string().min(1),\n base: z.string().optional(),\n message: z.string().min(1),\n files: z.array(z.discriminatedUnion('action', [\n z.object({ action: z.literal('write'), path: z.string().min(1), content: z.string() }).strict(),\n z.object({ action: z.literal('delete'), path: z.string().min(1) }).strict(),\n ])).min(1),\n }).strict(),\n describe: args => ({\n zh: `向 ${args.repo} 的分支 ${args.branch} 提交 ${args.files.length} 个文件(${args.files.map(file => `${file.action === 'delete' ? '删除' : '写入'} ${file.path}`).join(',')}):${args.message.split('\\n', 1)[0]}`,\n en: `Commit ${args.files.length} file(s) to ${args.repo} branch ${args.branch}: ${args.message.split('\\n', 1)[0]}`,\n }),\n run: (args, signal) => service.commitFiles(args.repo, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_create',\n description: 'Create an issue. Requires user approval.',\n schema: z.object({ repo, title: z.string().min(1), body: z.string().optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `在 ${args.repo} 创建 issue:${args.title}`, en: `Create an issue in ${args.repo}: ${args.title}` }),\n run: (args, signal) => service.createIssue(args.repo, { ...args, ...args.body === undefined ? {} : { body: sign(args.body) }, signal }),\n }),\n define(deps, {\n name: 'repo_issue_update',\n description: 'Change an issue\\'s title, body, labels, or assignees, or close/reopen it. Labels and assignees replace the current ones. Requires user approval.',\n schema: z.object({ repo, number, title: z.string().min(1).optional(), body: z.string().optional(), state: z.enum(['open', 'closed']).optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `修改 ${args.repo} 的 issue #${args.number}${args.state === 'closed' ? '(关闭)' : args.state === 'open' ? '(重新打开)' : ''}`, en: `Update issue #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.updateIssue(args.repo, args.number, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_issue_comment',\n description: 'Comment on an issue. Requires user approval.',\n schema: z.object({ repo, number, body: z.string().min(1) }).strict(),\n describe: args => ({ zh: `评论 ${args.repo} 的 issue #${args.number}`, en: `Comment on issue #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.commentIssue(args.repo, args.number, signRequired(args.body), { signal }),\n }),\n define(deps, {\n name: 'repo_mr_create',\n description: 'Open a pull request (GitHub) or merge request (GitLab) from a pushed branch. Requires user approval.',\n schema: z.object({ repo, title: z.string().min(1), body: z.string().optional(), sourceBranch: z.string().min(1), targetBranch: z.string().optional(), draft: z.boolean().optional(), labels, assignees }).strict(),\n describe: args => ({\n zh: `在 ${args.repo} 创建${args.draft === true ? '草稿 ' : ''}PR/MR:${args.sourceBranch} → ${args.targetBranch ?? '默认分支'},标题「${args.title}」`,\n en: `Open a ${args.draft === true ? 'draft ' : ''}PR/MR in ${args.repo}: ${args.sourceBranch} → ${args.targetBranch ?? 'default branch'}, \"${args.title}\"`,\n }),\n run: (args, signal) => service.createChange(args.repo, { ...args, ...args.body === undefined ? {} : { body: sign(args.body) }, signal }),\n }),\n define(deps, {\n name: 'repo_mr_update',\n description: 'Change a pull/merge request\\'s title, body, target branch, labels, or assignees, or close/reopen it. Requires user approval.',\n schema: z.object({ repo, number, title: z.string().min(1).optional(), body: z.string().optional(), state: z.enum(['open', 'closed']).optional(), targetBranch: z.string().optional(), labels, assignees }).strict(),\n describe: args => ({ zh: `修改 ${args.repo} 的 PR/MR #${args.number}${args.state === 'closed' ? '(关闭)' : args.state === 'open' ? '(重新打开)' : ''}`, en: `Update PR/MR #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.updateChange(args.repo, args.number, { ...args, signal }),\n }),\n define(deps, {\n name: 'repo_mr_comment',\n description: 'Comment on a pull/merge request conversation. Requires user approval.',\n schema: z.object({ repo, number, body: z.string().min(1) }).strict(),\n describe: args => ({ zh: `评论 ${args.repo} 的 PR/MR #${args.number}`, en: `Comment on PR/MR #${args.number} in ${args.repo}` }),\n run: (args, signal) => service.commentChange(args.repo, args.number, signRequired(args.body), { signal }),\n }),\n ]\n if (config.tools.merge) {\n writes.push(define(deps, {\n name: 'repo_mr_merge',\n description: 'Merge a pull/merge request, only while its head is still `headSha` (read it with repo_mr_status first). Requires user approval.',\n schema: z.object({ repo, number, headSha: z.string().min(40), method: z.enum(['merge', 'squash', 'rebase']).optional() }).strict(),\n describe: args => ({ zh: `合并 ${args.repo} 的 PR/MR #${args.number}(head ${args.headSha.slice(0, 12)}${args.method === undefined ? '' : `,方式 ${args.method}`})`, en: `Merge PR/MR #${args.number} in ${args.repo} at ${args.headSha.slice(0, 12)}` }),\n run: (args, signal) => service.mergeChange(args.repo, args.number, { headSha: args.headSha, ...args.method === undefined ? {} : { method: args.method }, signal }),\n }))\n }\n return [...reads, ...writes]\n}\n\nfunction define<S extends z.ZodType, V>(deps: ToolDeps, spec: Spec<S, V>): ToolDefinition<V | Declined> {\n const parameters = z.toJSONSchema(spec.schema, { target: 'draft-2020-12' }) as Record<string, unknown>\n delete parameters.$schema\n return {\n name: spec.name,\n description: spec.description,\n parameters,\n output: { schema: { type: 'object' }, render: (_args, value) => render(value) },\n isConcurrencySafe: () => spec.describe === undefined,\n execute: async (raw: unknown, exec: ToolRunContext): Promise<V | Declined> => {\n const parsed = spec.schema.safeParse(raw)\n if (!parsed.success) throw new Error(`[invalid] ${spec.name} 参数不合法:${parsed.error.issues.map(issue => `${issue.path.join('.') || '(根)'}:${issue.message}`).join(';')}`)\n const args = parsed.data\n if (spec.describe !== undefined && deps.config.tools.writes === 'ask') {\n const outcome = await approve(deps, spec.name, spec.describe(args), exec)\n if (outcome !== 'allowed-once') return { status: 'declined', outcome }\n }\n try {\n return await spec.run(args, exec.signal)\n } catch (error) {\n if (error instanceof RepoError) throw new Error(`[${error.code}] ${error.message}`)\n throw error\n }\n },\n }\n}\n\nasync function approve(deps: ToolDeps, toolName: string, text: { readonly zh: string; readonly en: string }, exec: ToolRunContext): Promise<string> {\n const approval = deps.approval()\n if (approval === undefined) throw new Error(`[forbidden] 当前 DSH 组合没有审批服务(@deepseek-ai/dsh-user-approval),dsh-repo 不会在未经授权时执行 ${toolName};或把 tools.writes 设为 allow`)\n if (exec.agent === undefined) throw new Error(`[forbidden] ${toolName} 需要由 Agent 调用`)\n const outcome = await approval.request({\n agent: exec.agent,\n toolName,\n ...exec.callId === undefined ? {} : { callId: exec.callId },\n reason: text.zh,\n displayReason: { en: text.en, zh: text.zh },\n signal: exec.signal,\n })\n if (outcome === 'cancelled') exec.signal.throwIfAborted()\n return outcome\n}\n","/**\n * dsh-repo —— DeepSeek Harness 代码仓库插件。\n *\n * 用 GitHub 官方 SDK(Octokit)和 GitLab 文档推荐的 GitBeaker 抹平\n * GitHub(含 GitHub Enterprise Server)与 GitLab(含自建实例)的差异:\n * 对其他插件提供 `dshRepos` 服务(类型见 `dsh-repo/contract`),\n * 对模型提供代码、issue、PR/MR 工具,写操作逐次经用户审批。\n *\n * @module dsh-repo\n */\n\nimport { resolveConfig } from './config.ts'\nimport type { HostApproval, HostContext } from './host.ts'\nimport { DSH_REPOS_SERVICE, RepoService } from './service.ts'\nimport type { ProviderFactory } from './service.ts'\nimport { createTools } from './tools.ts'\n\nexport type * from './contract.ts'\nexport type { HostSpec, RepoConfig, RepoLimits } from './config.ts'\nexport { apiBaseUrl, normalizeHostUrl, pluginConfigSchema, resolveConfig } from './config.ts'\nexport { RepoError, toRepoError } from './errors.ts'\nexport { DSH_REPOS_SERVICE, RepoService, defaultProviderFactory } from './service.ts'\nexport type { ProviderFactory } from './service.ts'\nexport { GithubProvider } from './providers/github.ts'\nexport { GitlabProvider } from './providers/gitlab.ts'\nexport type { Provider } from './providers/types.ts'\nexport { matchesPattern, resolveTarget } from './target.ts'\nexport { createTools } from './tools.ts'\nexport type { Declined, ToolDeps } from './tools.ts'\n\n/** Cordis plugin name. */\nexport const name = 'dsh-repo'\n\n/** Host services the plugin needs before `apply()`. */\nexport const inject = ['tools', 'credentials'] as const\n\n/** Standard Schema the loader validates `config` with before `apply()`. */\nexport { pluginConfigSchema as Config } from './config.ts'\n\n/** Direct-invocation options (tests and embedding hosts). */\nexport interface RepoPluginOptions {\n /** Substitute the per-host providers. */\n readonly providerFactory?: ProviderFactory\n}\n\n/**\n * Provide the `dshRepos` service and register the model tools.\n * @param ctx - plugin context.\n * @param config - loader-validated configuration.\n * @param options - test seams.\n */\nexport function apply(ctx: HostContext, config?: unknown, options: RepoPluginOptions = {}): void {\n const resolved = resolveConfig(config)\n const service = new RepoService(resolved, ctx.credentials, options.providerFactory)\n ctx.provide?.(DSH_REPOS_SERVICE, service)\n if (!resolved.tools.enabled) return\n if (!service.configured) {\n ctx.logger?.warn?.('dsh-repo: 没有配置 hosts,代码仓库工具未注册')\n return\n }\n for (const definition of createTools({ service, config: resolved, approval: () => ctx.get?.('approval') as HostApproval | undefined })) {\n ctx.effect(() => ctx.tools.register(definition), `dsh-repo: ${definition.name}`)\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "dsh-repo",
3
- "version": "0.0.0",
3
+ "version": "0.1.0-beta.2",
4
4
  "description": "DeepSeek Harness (DSH) 代码仓库插件:用 GitHub 官方 Octokit 和 GitBeaker 抹平 GitHub / GitLab(含 GitHub Enterprise 与自建 GitLab)差异,对外提供 dshRepos 服务,并为模型提供代码、issue、PR/MR 工具",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/modestoma/dsh-repo.git"
8
8
  },
9
+ "packageManager": "pnpm@12.15.0",
9
10
  "type": "module",
10
11
  "main": "lib/index.js",
11
12
  "types": "src/index.ts",
@@ -30,6 +31,15 @@
30
31
  "patch": "./cordis.patch.yml"
31
32
  }
32
33
  },
34
+ "scripts": {
35
+ "typecheck": "tsc --noEmit -p tsconfig.json",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "build": "tsdown --config tsdown.config.ts",
39
+ "verify:host": "node scripts/verify-host-loader.mjs",
40
+ "prepack": "pnpm build",
41
+ "check": "pnpm typecheck && pnpm test && pnpm build && pnpm verify:host"
42
+ },
33
43
  "keywords": [
34
44
  "deepseek-harness",
35
45
  "dsh",
@@ -71,13 +81,5 @@
71
81
  "@deepseek-ai/cordis": {
72
82
  "optional": false
73
83
  }
74
- },
75
- "scripts": {
76
- "typecheck": "tsc --noEmit -p tsconfig.json",
77
- "test": "vitest run",
78
- "test:watch": "vitest",
79
- "build": "tsdown --config tsdown.config.ts",
80
- "verify:host": "node scripts/verify-host-loader.mjs",
81
- "check": "pnpm typecheck && pnpm test && pnpm build && pnpm verify:host"
82
84
  }
83
- }
85
+ }
package/src/contract.ts CHANGED
@@ -167,12 +167,24 @@ export type FileChange =
167
167
  | { readonly action: 'write'; readonly path: string; readonly content: string }
168
168
  | { readonly action: 'delete'; readonly path: string }
169
169
 
170
+ /** Name and email recorded as a commit's author. */
171
+ export interface CommitAuthor {
172
+ readonly name: string
173
+ readonly email: string
174
+ }
175
+
170
176
  /** A multi-file commit. */
171
177
  export interface CommitRequest extends CallOptions {
172
178
  /** Target branch; created from {@link base} when it does not exist. Never the default or a protected branch. */
173
179
  readonly branch: string
174
- /** Start point of a new branch; default: the repository's default branch. Ignored when the branch exists. */
180
+ /** Start branch of a new branch; default: the repository's default branch. Ignored when the branch exists. Not with {@link baseSha}. */
175
181
  readonly base?: string
182
+ /** Start commit of a new branch, as a full hexadecimal object id. Ignored when the branch exists. Not with {@link base}. */
183
+ readonly baseSha?: string
184
+ /** When true, the call fails with `conflict` instead of committing on top of a branch that already exists. */
185
+ readonly newBranch?: boolean
186
+ /** Commit author; default: the token's user. The committer is always the token's user. */
187
+ readonly author?: CommitAuthor
176
188
  readonly message: string
177
189
  readonly files: readonly FileChange[]
178
190
  }
@@ -365,6 +377,8 @@ export interface DshRepoService {
365
377
  repoInfo(repo: RepoTarget, options?: CallOptions): Promise<RepoInfo>
366
378
  /** @returns one page of branches. */
367
379
  listBranches(repo: RepoTarget, options?: PageOptions & { readonly search?: string }): Promise<Page<BranchInfo>>
380
+ /** @returns the branch, or undefined when the repository has no branch of that name. */
381
+ getBranch(repo: RepoTarget, name: string, options?: CallOptions): Promise<BranchInfo | undefined>
368
382
  /** @returns one page of commits, newest first. */
369
383
  listCommits(repo: RepoTarget, options?: PageOptions & { readonly ref?: string; readonly path?: string }): Promise<Page<CommitInfo>>
370
384
  /** @returns entries below `path` (default: root) at `ref` (default: the default branch). */
@@ -175,6 +175,19 @@ export class GithubProvider implements Provider {
175
175
  return { items, ...nextPage(query, data.length) }
176
176
  }
177
177
 
178
+ async getBranch(ref: RepoRef, name: string, call: Call) {
179
+ const [branch, info] = await Promise.all([
180
+ this.octokit.rest.repos.getBranch({ ...split(ref.path), branch: name, request: { signal: call.signal } }).catch((error: unknown) => {
181
+ if ((error as { status?: number }).status === 404) return undefined
182
+ throw error
183
+ }),
184
+ this.repoInfo(ref, call),
185
+ ])
186
+ // GitHub answers a renamed branch with the branch it was renamed to.
187
+ if (branch === undefined || branch.data.name !== name) return undefined
188
+ return { name, commit: branch.data.commit.sha, protected: branch.data.protected, default: name === info.defaultBranch }
189
+ }
190
+
178
191
  async listCommits(ref: RepoRef, query: { page: number; perPage: number; ref?: string; path?: string }, call: Call) {
179
192
  const { data } = await this.octokit.rest.repos.listCommits({
180
193
  ...split(ref.path),
@@ -231,7 +244,7 @@ export class GithubProvider implements Provider {
231
244
  return { path, ref: target, binary: false, ...truncateBytes(raw, call.limits.maxFileBytes) }
232
245
  }
233
246
 
234
- async commitFiles(ref: RepoRef, request: { branch: string; base?: string; message: string; files: readonly ({ action: 'write'; path: string; content: string } | { action: 'delete'; path: string })[] }, call: Call) {
247
+ async commitFiles(ref: RepoRef, request: { branch: string; base?: string; baseSha?: string; newBranch?: boolean; author?: { name: string; email: string }; message: string; files: readonly ({ action: 'write'; path: string; content: string } | { action: 'delete'; path: string })[] }, call: Call) {
235
248
  const repo = split(ref.path)
236
249
  const signal = call.signal
237
250
  const info = await this.repoInfo(ref, call)
@@ -240,8 +253,10 @@ export class GithubProvider implements Provider {
240
253
  if ((error as { status?: number }).status === 404) return undefined
241
254
  throw error
242
255
  })
256
+ if (existing !== undefined && request.newBranch === true) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)
243
257
  if (existing?.data.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)
244
258
  const parent = existing?.data.commit.sha
259
+ ?? request.baseSha
245
260
  ?? (await this.octokit.rest.repos.getBranch({ ...repo, branch: request.base ?? info.defaultBranch, request: { signal } })).data.commit.sha
246
261
  const { data: parentCommit } = await this.octokit.rest.git.getCommit({ ...repo, commit_sha: parent, request: { signal } })
247
262
  // Keep the executable bit of files that already exist; refuse to replace links and directories.
@@ -266,9 +281,13 @@ export class GithubProvider implements Provider {
266
281
  : { path: file.path, mode: '100644' as const, type: 'blob' as const, sha: null }),
267
282
  request: { signal },
268
283
  })
269
- const { data: commit } = await this.octokit.rest.git.createCommit({ ...repo, message: request.message, tree: tree.sha, parents: [parent], request: { signal } })
284
+ const { data: commit } = await this.octokit.rest.git.createCommit({ ...repo, message: request.message, tree: tree.sha, parents: [parent], ...request.author === undefined ? {} : { author: request.author }, request: { signal } })
270
285
  if (existing === undefined) {
271
- await this.octokit.rest.git.createRef({ ...repo, ref: `refs/heads/${request.branch}`, sha: commit.sha, request: { signal } })
286
+ await this.octokit.rest.git.createRef({ ...repo, ref: `refs/heads/${request.branch}`, sha: commit.sha, request: { signal } }).catch((error: unknown) => {
287
+ // Another writer created the branch after the lookup above.
288
+ if ((error as { status?: number }).status === 422) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)
289
+ throw error
290
+ })
272
291
  } else {
273
292
  await this.octokit.rest.git.updateRef({ ...repo, ref: `heads/${request.branch}`, sha: commit.sha, force: false, request: { signal } })
274
293
  }
@@ -144,6 +144,15 @@ export class GitlabProvider implements Provider {
144
144
  return { items, ...nextPage(query, data.length) }
145
145
  }
146
146
 
147
+ async getBranch(ref: RepoRef, name: string, call: Call) {
148
+ call.signal.throwIfAborted()
149
+ const branch = await this.api.Branches.show(ref.path, name).catch((error: unknown) => {
150
+ if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return undefined
151
+ throw error
152
+ })
153
+ return branch === undefined ? undefined : { name: branch.name, commit: String(branch.commit.id), protected: branch.protected, default: branch.default }
154
+ }
155
+
147
156
  async listCommits(ref: RepoRef, query: Paging & { ref?: string; path?: string }, call: Call) {
148
157
  call.signal.throwIfAborted()
149
158
  const data = await this.api.Commits.all(ref.path, {
@@ -188,15 +197,16 @@ export class GitlabProvider implements Provider {
188
197
  return { path, ref: target, binary: false, ...truncateBytes(text, call.limits.maxFileBytes) }
189
198
  }
190
199
 
191
- async commitFiles(ref: RepoRef, request: { branch: string; base?: string; message: string; files: readonly FileChange[] }, call: Call) {
200
+ async commitFiles(ref: RepoRef, request: { branch: string; base?: string; baseSha?: string; newBranch?: boolean; author?: { name: string; email: string }; message: string; files: readonly FileChange[] }, call: Call) {
192
201
  const info = await this.repoInfo(ref, call)
193
202
  if (request.branch === info.defaultBranch) throw new RepoError('forbidden', `不允许直接提交到默认分支 ${request.branch};请提交到新分支后开 MR`)
194
203
  const existing = await this.api.Branches.show(ref.path, request.branch).catch((error: unknown) => {
195
204
  if ((error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 404) return undefined
196
205
  throw error
197
206
  })
207
+ if (existing !== undefined && request.newBranch === true) throw new RepoError('conflict', `分支 ${request.branch} 已存在`)
198
208
  if (existing?.protected === true) throw new RepoError('forbidden', `分支 ${request.branch} 受保护,不能直接提交`)
199
- const start = existing === undefined ? request.base ?? info.defaultBranch : request.branch
209
+ const start = existing === undefined ? request.baseSha ?? request.base ?? info.defaultBranch : request.branch
200
210
  // GitLab needs `create` or `update` per file, so list each touched directory at the start point.
201
211
  const present = new Set<string>()
202
212
  for (const dir of new Set(request.files.filter(file => file.action === 'write').map(file => dirname(file.path)))) {
@@ -212,7 +222,15 @@ export class GitlabProvider implements Provider {
212
222
  ? { action: 'delete' as const, filePath: file.path }
213
223
  : { action: present.has(file.path) ? 'update' as const : 'create' as const, filePath: file.path, content: file.content })
214
224
  call.signal.throwIfAborted()
215
- const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, existing === undefined ? { startBranch: start } : {})
225
+ const startOption = existing !== undefined ? {} : request.baseSha === undefined ? { startBranch: start } : { startSha: request.baseSha }
226
+ const authorOption = request.author === undefined ? {} : { authorName: request.author.name, authorEmail: request.author.email }
227
+ const commit = await this.api.Commits.create(ref.path, request.branch, request.message, actions, { ...startOption, ...authorOption }).catch((error: unknown) => {
228
+ // GitLab answers 400 when another writer created the branch after the lookup above.
229
+ if (existing === undefined && (error as { cause?: { response?: { status?: number } } }).cause?.response?.status === 400 && error instanceof Error && /already exists/i.test(error.message)) {
230
+ throw new RepoError('conflict', `分支 ${request.branch} 已存在`)
231
+ }
232
+ throw error
233
+ })
216
234
  return { sha: commit.id, branch: request.branch, createdBranch: existing === undefined, webUrl: commit.web_url }
217
235
  }
218
236
 
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import type {
9
- BranchInfo, ChangeDetail, ChangeDiff, ChangeInfo, ChangeState, ChangeStatus, CommentInfo, CommitInfo, CommitResult,
9
+ BranchInfo, ChangeDetail, ChangeDiff, ChangeInfo, ChangeState, ChangeStatus, CommentInfo, CommitAuthor, CommitInfo, CommitResult,
10
10
  FileChange, FileContent, IssueDetail, IssueInfo, IssueState, MergeMethod, MergeResult, Page, RepoInfo, RepoRef, TreeListing,
11
11
  } from '../contract.ts'
12
12
  import type { RepoLimits } from '../config.ts'
@@ -27,11 +27,12 @@ export interface Paging {
27
27
  /** One code host family. Methods throw SDK errors or {@link RepoError}; the service classifies them. */
28
28
  export interface Provider {
29
29
  repoInfo(ref: RepoRef, call: Call): Promise<RepoInfo>
30
+ getBranch(ref: RepoRef, name: string, call: Call): Promise<BranchInfo | undefined>
30
31
  listBranches(ref: RepoRef, query: Paging & { readonly search?: string }, call: Call): Promise<Page<BranchInfo>>
31
32
  listCommits(ref: RepoRef, query: Paging & { readonly ref?: string; readonly path?: string }, call: Call): Promise<Page<CommitInfo>>
32
33
  listTree(ref: RepoRef, query: { readonly ref?: string; readonly path: string; readonly recursive: boolean }, call: Call): Promise<TreeListing>
33
34
  readFile(ref: RepoRef, path: string, at: string | undefined, call: Call): Promise<FileContent>
34
- commitFiles(ref: RepoRef, request: { readonly branch: string; readonly base?: string; readonly message: string; readonly files: readonly FileChange[] }, call: Call): Promise<CommitResult>
35
+ commitFiles(ref: RepoRef, request: { readonly branch: string; readonly base?: string; readonly baseSha?: string; readonly newBranch?: boolean; readonly author?: CommitAuthor; readonly message: string; readonly files: readonly FileChange[] }, call: Call): Promise<CommitResult>
35
36
 
36
37
  listIssues(ref: RepoRef, query: Paging & { readonly state: IssueState | 'all'; readonly labels?: readonly string[]; readonly assignee?: string }, call: Call): Promise<Page<IssueInfo>>
37
38
  getIssue(ref: RepoRef, number: number, call: Call): Promise<IssueDetail>
package/src/service.ts CHANGED
@@ -91,6 +91,11 @@ export class RepoService implements DshRepoService {
91
91
  return await this.run(repo, options, '列出分支', (provider, ref, call) => provider.listBranches(ref, query, call))
92
92
  }
93
93
 
94
+ async getBranch(repo: RepoTarget, name: string, options: CallOptions = {}) {
95
+ requireBranch(name, '分支名')
96
+ return await this.run(repo, options, `读取分支 ${name}`, (provider, ref, call) => provider.getBranch(ref, name, call))
97
+ }
98
+
94
99
  async listCommits(repo: RepoTarget, options: PageOptions & { readonly ref?: string; readonly path?: string } = {}) {
95
100
  if (options.path !== undefined) requireRepoPath(options.path, '路径')
96
101
  const query = { ...this.paging(options), ...options.ref === undefined ? {} : { ref: options.ref }, ...options.path === undefined ? {} : { path: options.path } }
@@ -112,7 +117,15 @@ export class RepoService implements DshRepoService {
112
117
  async commitFiles(repo: RepoTarget, request: CommitRequest) {
113
118
  requireBranch(request.branch, '分支名')
114
119
  if (request.base !== undefined) requireBranch(request.base, '起点分支名')
120
+ if (request.baseSha !== undefined) {
121
+ if (request.base !== undefined) throw new RepoError('invalid', 'base 和 baseSha 只能给一个')
122
+ if (!/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(request.baseSha)) throw new RepoError('invalid', `起点提交必须是完整的十六进制提交 id:${request.baseSha}`)
123
+ }
115
124
  requireText(request.message, '提交说明')
125
+ if (request.author !== undefined) {
126
+ if (!/^[^<>\n]+$/.test(request.author.name.trim())) throw new RepoError('invalid', '提交作者名不能为空,也不能包含 < > 或换行')
127
+ if (!/^[^<>\s]+$/.test(request.author.email.trim())) throw new RepoError('invalid', '提交作者邮箱不能为空,也不能包含 < > 或空白')
128
+ }
116
129
  if (request.files.length === 0) throw new RepoError('invalid', '提交至少要包含一个文件')
117
130
  if (request.files.length > this.config.limits.maxCommitFiles) throw new RepoError('too-large', `一次提交最多 ${this.config.limits.maxCommitFiles} 个文件`)
118
131
  const seen = new Set<string>()
@@ -124,7 +137,15 @@ export class RepoService implements DshRepoService {
124
137
  throw new RepoError('too-large', `${file.path} 超过单文件上限 ${this.config.limits.maxFileBytes} 字节`)
125
138
  }
126
139
  }
127
- const fields = { branch: request.branch, message: request.message, files: request.files, ...request.base === undefined ? {} : { base: request.base } }
140
+ const fields = {
141
+ branch: request.branch,
142
+ message: request.message,
143
+ files: request.files,
144
+ ...request.base === undefined ? {} : { base: request.base },
145
+ ...request.baseSha === undefined ? {} : { baseSha: request.baseSha },
146
+ ...request.newBranch === true ? { newBranch: true } : {},
147
+ ...request.author === undefined ? {} : { author: { name: request.author.name.trim(), email: request.author.email.trim() } },
148
+ }
128
149
  return await this.run(repo, request, `提交到分支 ${request.branch}`, (provider, ref, call) => provider.commitFiles(ref, fields, call))
129
150
  }
130
151