@vercel/factory 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/github.mjs CHANGED
@@ -19,6 +19,41 @@ const reviewCommentSchema = z.object({
19
19
  user: z.object({ login: z.string().min(1) }),
20
20
  in_reply_to_id: z.number().int().positive().nullish()
21
21
  });
22
+ const submittedReviewSchema = z.object({
23
+ id: z.number().int().positive(),
24
+ html_url: z.url(),
25
+ state: z.string().min(1)
26
+ });
27
+ const checkRunSchema = z.object({
28
+ id: z.number().int().positive(),
29
+ name: z.string().min(1),
30
+ head_sha: z.string().regex(/^[0-9a-f]{40}$/),
31
+ status: z.enum([
32
+ "queued",
33
+ "in_progress",
34
+ "completed",
35
+ "waiting",
36
+ "requested",
37
+ "pending"
38
+ ]),
39
+ conclusion: z.enum([
40
+ "action_required",
41
+ "cancelled",
42
+ "failure",
43
+ "neutral",
44
+ "skipped",
45
+ "success",
46
+ "timed_out",
47
+ "stale",
48
+ "startup_failure"
49
+ ]).nullable(),
50
+ html_url: z.url().nullable(),
51
+ details_url: z.url().nullable(),
52
+ external_id: z.string().nullable(),
53
+ started_at: z.string().nullable(),
54
+ completed_at: z.string().nullable()
55
+ });
56
+ const checkRunsSchema = z.object({ check_runs: z.array(checkRunSchema) });
22
57
  const labelsSchema = z.array(z.object({ name: z.string().min(1) }));
23
58
  const pullRequestCandidateSchema = z.object({
24
59
  number: z.number().int().positive(),
@@ -77,6 +112,36 @@ async function createPullRequest(input) {
77
112
  prUrl: pull.html_url
78
113
  };
79
114
  }
115
+ /** Create a check run for one commit. Requires a GitHub App token with checks:write. */
116
+ async function createCheckRun(input) {
117
+ if (input.status === "completed" && input.conclusion === void 0) throw new Error("completed check runs require a conclusion");
118
+ if (input.status !== "completed" && input.conclusion !== void 0) throw new Error("creating a check run with a conclusion requires completed status");
119
+ return parseCheckRun(await gitHubRequest(input, "/check-runs", {
120
+ method: "POST",
121
+ body: JSON.stringify({
122
+ name: input.name,
123
+ head_sha: commitSha(input.headSha),
124
+ ...checkRunFields(input)
125
+ })
126
+ }));
127
+ }
128
+ /** Update a check run previously created by the authenticated GitHub App. */
129
+ async function updateCheckRun(input) {
130
+ if (input.status !== void 0 && input.status !== "completed" && input.conclusion !== void 0) throw new Error("a check run conclusion conflicts with an incomplete status");
131
+ return parseCheckRun(await gitHubRequest(input, `/check-runs/${positiveInteger(input.checkRunId, "checkRunId")}`, {
132
+ method: "PATCH",
133
+ body: JSON.stringify({
134
+ ...input.name === void 0 ? {} : { name: input.name },
135
+ ...checkRunFields(input)
136
+ })
137
+ }));
138
+ }
139
+ /** List check runs reported for a commit, branch, or tag. */
140
+ async function listCheckRunsForRef(input) {
141
+ const query = new URLSearchParams({ per_page: "100" });
142
+ if (input.checkName !== void 0) query.set("check_name", input.checkName);
143
+ return checkRunsSchema.parse(await gitHubRequest(input, `/commits/${encodeURIComponent(input.ref)}/check-runs?${query.toString()}`)).check_runs.map(parseCheckRun);
144
+ }
80
145
  /** Read one inline review comment after applying the author policy, which requires write access by default. */
81
146
  async function readReviewComment(input) {
82
147
  const comment = parseReviewComment(await gitHubRequest(input, `/pulls/comments/${positiveInteger(input.commentId, "commentId")}`));
@@ -91,6 +156,31 @@ async function answerReviewComment(input) {
91
156
  body: JSON.stringify({ body: input.body })
92
157
  }));
93
158
  }
159
+ /** Submit a summary and optional inline comments against a reviewed pull request commit. */
160
+ async function submitPullRequestReview(input) {
161
+ const commitId = z.string().regex(/^[0-9a-f]{40}$/).parse(input.commitId);
162
+ const head = await readPullRequestHead(input);
163
+ if (head.sha !== commitId) throw new Error(`pull request changed after review: expected ${commitId}, found ${head.sha}`);
164
+ const review = submittedReviewSchema.parse(await gitHubRequest(input, `/pulls/${positiveInteger(input.pullRequestNumber, "pullRequestNumber")}/reviews`, {
165
+ method: "POST",
166
+ body: JSON.stringify({
167
+ commit_id: commitId,
168
+ event: input.event,
169
+ body: input.body,
170
+ comments: (input.comments ?? []).map((comment) => ({
171
+ path: comment.path,
172
+ line: positiveInteger(comment.line, "comment line"),
173
+ side: "RIGHT",
174
+ body: comment.body
175
+ }))
176
+ })
177
+ }));
178
+ return {
179
+ id: review.id,
180
+ url: review.html_url,
181
+ state: review.state
182
+ };
183
+ }
94
184
  /** Read the current head branch and commit of a pull request. */
95
185
  async function readPullRequestHead(input) {
96
186
  const pull = pullRequestHeadSchema.parse(await gitHubRequest(input, `/pulls/${positiveInteger(input.pullRequestNumber, "pullRequestNumber")}`));
@@ -160,6 +250,50 @@ function parseReviewComment(value) {
160
250
  function parseLabels(value) {
161
251
  return labelsSchema.parse(value).map(({ name }) => name);
162
252
  }
253
+ function parseCheckRun(value) {
254
+ const checkRun = checkRunSchema.parse(value);
255
+ return {
256
+ id: checkRun.id,
257
+ name: checkRun.name,
258
+ headSha: checkRun.head_sha,
259
+ status: checkRun.status,
260
+ conclusion: checkRun.conclusion,
261
+ url: checkRun.html_url,
262
+ detailsUrl: checkRun.details_url,
263
+ externalId: checkRun.external_id,
264
+ startedAt: checkRun.started_at,
265
+ completedAt: checkRun.completed_at
266
+ };
267
+ }
268
+ function checkRunFields(input) {
269
+ return {
270
+ ...input.status === void 0 ? {} : { status: input.status },
271
+ ...input.conclusion === void 0 ? {} : { conclusion: input.conclusion },
272
+ ...input.detailsUrl === void 0 ? {} : { details_url: input.detailsUrl },
273
+ ...input.externalId === void 0 ? {} : { external_id: input.externalId },
274
+ ...input.startedAt === void 0 ? {} : { started_at: input.startedAt },
275
+ ...input.completedAt === void 0 ? {} : { completed_at: input.completedAt },
276
+ ...input.output === void 0 ? {} : { output: checkRunOutput(input.output) }
277
+ };
278
+ }
279
+ function checkRunOutput(output) {
280
+ return {
281
+ title: output.title,
282
+ summary: output.summary,
283
+ ...output.text === void 0 ? {} : { text: output.text },
284
+ ...output.annotations === void 0 ? {} : { annotations: output.annotations.map((annotation) => ({
285
+ path: annotation.path,
286
+ start_line: positiveInteger(annotation.startLine, "annotation startLine"),
287
+ end_line: positiveInteger(annotation.endLine ?? annotation.startLine, "annotation endLine"),
288
+ ...annotation.startColumn === void 0 ? {} : { start_column: positiveInteger(annotation.startColumn, "annotation startColumn") },
289
+ ...annotation.endColumn === void 0 ? {} : { end_column: positiveInteger(annotation.endColumn, "annotation endColumn") },
290
+ annotation_level: annotation.annotationLevel,
291
+ message: annotation.message,
292
+ ...annotation.title === void 0 ? {} : { title: annotation.title },
293
+ ...annotation.rawDetails === void 0 ? {} : { raw_details: annotation.rawDetails }
294
+ })) }
295
+ };
296
+ }
163
297
  async function assertReviewCommentAuthor(input, author) {
164
298
  if (input.authorPolicy === "any") return;
165
299
  const { permission } = collaboratorPermissionSchema.parse(await gitHubRequest(input, `/collaborators/${encodeURIComponent(author)}/permission`));
@@ -169,6 +303,9 @@ function positiveInteger(value, name) {
169
303
  if (!Number.isInteger(value) || value < 1) throw new Error(`${name} must be a positive integer`);
170
304
  return value;
171
305
  }
306
+ function commitSha(value) {
307
+ return z.string().regex(/^[0-9a-f]{40}$/).parse(value);
308
+ }
172
309
  /**
173
310
  * Verify a GitHub webhook HMAC signature (the x-hub-signature-256 header)
174
311
  * against the raw request body. Returns false for missing or malformed
@@ -201,6 +338,63 @@ function normalizeGitHubDefaultBranchPush(options) {
201
338
  defaultBranch: parsed.data.repository.default_branch
202
339
  };
203
340
  }
341
+ const pullRequestEventSchema = z.looseObject({
342
+ action: z.string(),
343
+ number: z.number().int().positive(),
344
+ pull_request: z.looseObject({
345
+ html_url: z.url(),
346
+ draft: z.boolean(),
347
+ user: z.looseObject({ login: z.string().min(1) }),
348
+ head: z.looseObject({
349
+ sha: z.string().regex(/^[0-9a-f]{40}$/),
350
+ ref: z.string().min(1),
351
+ repo: z.looseObject({ full_name: z.string().min(1) })
352
+ }),
353
+ base: z.looseObject({
354
+ sha: z.string().regex(/^[0-9a-f]{40}$/),
355
+ ref: z.string().min(1)
356
+ })
357
+ }),
358
+ repository: z.looseObject({ full_name: z.string().min(1) }),
359
+ sender: z.looseObject({ login: z.string().min(1) })
360
+ });
361
+ const reviewablePullRequestActions = /* @__PURE__ */ new Set([
362
+ "opened",
363
+ "reopened",
364
+ "ready_for_review",
365
+ "synchronize"
366
+ ]);
367
+ /** Normalize a newly reviewable or updated pull request into a factory signal. */
368
+ function normalizeGitHubPullRequest(options) {
369
+ if (options.event !== "pull_request") return null;
370
+ const parsed = pullRequestEventSchema.safeParse(options.payload);
371
+ if (!parsed.success || !reviewablePullRequestActions.has(parsed.data.action)) return null;
372
+ if (parsed.data.pull_request.draft && parsed.data.action !== "ready_for_review") return null;
373
+ const slug = parsed.data.repository.full_name.toLowerCase();
374
+ const pull = parsed.data.pull_request;
375
+ return {
376
+ source: "github_pr",
377
+ deliveryId: options.deliveryId,
378
+ repositorySlug: slug,
379
+ replyTo: {
380
+ channel: "github",
381
+ address: `${slug}/pull/${parsed.data.number}`
382
+ },
383
+ pullRequest: {
384
+ number: parsed.data.number,
385
+ url: pull.html_url,
386
+ author: pull.user.login,
387
+ draft: pull.draft,
388
+ headSha: pull.head.sha,
389
+ headBranch: pull.head.ref,
390
+ headRepositorySlug: pull.head.repo.full_name.toLowerCase(),
391
+ baseSha: pull.base.sha,
392
+ baseBranch: pull.base.ref,
393
+ sender: parsed.data.sender.login
394
+ },
395
+ payload: options.payload
396
+ };
397
+ }
204
398
  const issueEventSchema = z.looseObject({
205
399
  action: z.string(),
206
400
  issue: z.looseObject({
@@ -329,6 +523,6 @@ function normalizeGitHubWorkflowRunFailure(options) {
329
523
  };
330
524
  }
331
525
  //#endregion
332
- export { GitHubReviewCommentAuthorError, addLabel, answerReviewComment, createPullRequest, listConflictedPullRequests, normalizeGitHubDefaultBranchPush, normalizeGitHubIssueOpened, normalizeGitHubPullRequestClosed, normalizeGitHubWorkflowRunFailure, readPullRequestHead, readReviewComment, removeLabel, verifyGitHubSignature };
526
+ export { GitHubReviewCommentAuthorError, addLabel, answerReviewComment, createCheckRun, createPullRequest, listCheckRunsForRef, listConflictedPullRequests, normalizeGitHubDefaultBranchPush, normalizeGitHubIssueOpened, normalizeGitHubPullRequest, normalizeGitHubPullRequestClosed, normalizeGitHubWorkflowRunFailure, readPullRequestHead, readReviewComment, removeLabel, submitPullRequestReview, updateCheckRun, verifyGitHubSignature };
333
527
 
334
528
  //# sourceMappingURL=github.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"github.mjs","names":[],"sources":["../src/github.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { NormalizedSignal, WebhookEvent } from \"./connectors/index\";\n\nconst gitHubApiUrl = \"https://api.github.com\";\nconst repositorySlugPattern = /^[^/\\s]+\\/[^/\\s]+$/;\n\nexport interface GitHubRepositoryRequest {\n repository: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface CreatePullRequestInput extends GitHubRepositoryRequest {\n title: string;\n head: string;\n base: string;\n body?: string;\n draft?: boolean;\n}\n\nexport interface CreatedPullRequest {\n prNumber: number;\n prUrl: string;\n}\n\nexport type ReviewCommentAuthorPolicy = \"write\" | \"any\";\n\ninterface ReviewCommentTrustInput {\n /** Defaults to `write`. Use `any` only when untrusted review text is handled as data. */\n authorPolicy?: ReviewCommentAuthorPolicy;\n}\n\nexport interface ReadReviewCommentInput extends GitHubRepositoryRequest, ReviewCommentTrustInput {\n commentId: number;\n}\n\nexport interface GitHubReviewComment {\n id: number;\n body: string;\n url: string;\n author: string;\n inReplyToId: number | null;\n}\n\nexport interface AnswerReviewCommentInput\n extends GitHubRepositoryRequest,\n ReviewCommentTrustInput {\n pullRequestNumber: number;\n commentId: number;\n body: string;\n}\n\nexport interface ReadPullRequestHeadInput extends GitHubRepositoryRequest {\n pullRequestNumber: number;\n}\n\nexport interface GitHubPullRequestHead {\n branch: string;\n sha: string;\n repository: string;\n}\n\nexport interface PullRequestLabelInput extends GitHubRepositoryRequest {\n pullRequestNumber: number;\n label: string;\n}\n\nexport interface ConflictedPullRequest {\n prNumber: number;\n prUrl: string;\n headBranch: string;\n headSha: string;\n baseBranch: string;\n baseSha: string;\n}\n\nexport type ListConflictedPullRequestsInput = GitHubRepositoryRequest;\n\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n});\n\nconst pullRequestHeadSchema = z.object({\n head: z.object({\n ref: z\n .string()\n .regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/)\n .refine((value) => !value.includes(\"..\")),\n sha: z.string().regex(/^[0-9a-f]{40}$/),\n repo: z.object({ full_name: z.string().min(1) }),\n }),\n});\n\nconst reviewCommentSchema = z.object({\n id: z.number().int().positive(),\n body: z.string(),\n html_url: z.url(),\n user: z.object({ login: z.string().min(1) }),\n in_reply_to_id: z.number().int().positive().nullish(),\n});\n\nconst labelsSchema = z.array(z.object({ name: z.string().min(1) }));\nconst pullRequestCandidateSchema = z.object({\n number: z.number().int().positive(),\n user: z.object({ type: z.string().min(1) }),\n head: z.object({ ref: z.string().min(1), repo: z.object({ full_name: z.string().min(1) }) }),\n});\nconst openPullRequestsSchema = z.array(pullRequestCandidateSchema);\nconst pullRequestDetailSchema = pullRequestCandidateSchema.extend({\n html_url: z.url(),\n mergeable: z.boolean().nullable(),\n mergeable_state: z.string().min(1),\n head: pullRequestCandidateSchema.shape.head.extend({ sha: z.string().min(1) }),\n base: z.object({ ref: z.string().min(1), sha: z.string().min(1) }),\n});\nconst collaboratorPermissionSchema = z.object({\n permission: z.enum([\"admin\", \"maintain\", \"write\", \"triage\", \"read\", \"none\"]),\n});\nconst writePermissions = new Set([\"admin\", \"maintain\", \"write\"]);\n\nexport class GitHubReviewCommentAuthorError extends Error {\n readonly author: string;\n\n constructor(author: string) {\n super(`GitHub user ${author} does not have write access to the repository`);\n this.name = \"GitHubReviewCommentAuthorError\";\n this.author = author;\n }\n}\n\n/** Create a pull request from an existing head branch. */\nexport async function createPullRequest(input: CreatePullRequestInput): Promise<CreatedPullRequest> {\n const pull = pullRequestSchema.parse(\n await gitHubRequest(input, \"/pulls\", {\n method: \"POST\",\n body: JSON.stringify({\n title: input.title,\n head: input.head,\n base: input.base,\n ...(input.body === undefined ? {} : { body: input.body }),\n ...(input.draft === undefined ? {} : { draft: input.draft }),\n }),\n }),\n );\n return { prNumber: pull.number, prUrl: pull.html_url };\n}\n\n/** Read one inline review comment after applying the author policy, which requires write access by default. */\nexport async function readReviewComment(\n input: ReadReviewCommentInput,\n): Promise<GitHubReviewComment> {\n const comment = parseReviewComment(\n await gitHubRequest(input, `/pulls/comments/${positiveInteger(input.commentId, \"commentId\")}`),\n );\n await assertReviewCommentAuthor(input, comment.author);\n return comment;\n}\n\n/** Reply to an inline review comment after applying the author policy, which requires write access by default. */\nexport async function answerReviewComment(\n input: AnswerReviewCommentInput,\n): Promise<GitHubReviewComment> {\n await readReviewComment(input);\n return parseReviewComment(\n await gitHubRequest(\n input,\n `/pulls/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/comments/${positiveInteger(input.commentId, \"commentId\")}/replies`,\n { method: \"POST\", body: JSON.stringify({ body: input.body }) },\n ),\n );\n}\n\n/** Read the current head branch and commit of a pull request. */\nexport async function readPullRequestHead(\n input: ReadPullRequestHeadInput,\n): Promise<GitHubPullRequestHead> {\n const pull = pullRequestHeadSchema.parse(\n await gitHubRequest(input, `/pulls/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}`),\n );\n return {\n branch: pull.head.ref,\n sha: pull.head.sha,\n repository: pull.head.repo.full_name.toLowerCase(),\n };\n}\n\n/** List open, same-repository pull requests by one author that GitHub reports as conflicting. */\nexport async function listConflictedPullRequests(\n input: ListConflictedPullRequestsInput,\n): Promise<ConflictedPullRequest[]> {\n const pulls = openPullRequestsSchema.parse(\n await gitHubRequest(input, `/pulls?state=open&per_page=100`),\n );\n const candidates = pulls.filter(\n (pull) =>\n pull.user.type === \"Bot\" &&\n pull.head.ref.startsWith(\"factory/\") &&\n pull.head.repo.full_name.toLowerCase() === input.repository.toLowerCase(),\n );\n const conflicted: ConflictedPullRequest[] = [];\n for (const candidate of candidates) {\n const pull = pullRequestDetailSchema.parse(\n await gitHubRequest(input, `/pulls/${candidate.number}`),\n );\n if (pull.mergeable === false || pull.mergeable_state === \"dirty\") {\n conflicted.push({\n prNumber: pull.number,\n prUrl: pull.html_url,\n headBranch: pull.head.ref,\n headSha: pull.head.sha,\n baseBranch: pull.base.ref,\n baseSha: pull.base.sha,\n });\n }\n }\n return conflicted;\n}\n\n/** Add one label to a pull request. */\nexport async function addLabel(input: PullRequestLabelInput): Promise<string[]> {\n return parseLabels(\n await gitHubRequest(\n input,\n `/issues/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/labels`,\n { method: \"POST\", body: JSON.stringify({ labels: [input.label] }) },\n ),\n );\n}\n\n/** Remove one label from a pull request. */\nexport async function removeLabel(input: PullRequestLabelInput): Promise<string[]> {\n return parseLabels(\n await gitHubRequest(\n input,\n `/issues/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/labels/${encodeURIComponent(input.label)}`,\n { method: \"DELETE\" },\n ),\n );\n}\n\nasync function gitHubRequest(\n input: GitHubRepositoryRequest,\n path: string,\n init: RequestInit = {},\n): Promise<unknown> {\n if (!repositorySlugPattern.test(input.repository)) {\n throw new Error(`invalid GitHub repository slug: ${input.repository}`);\n }\n const response = await (input.fetch ?? globalThis.fetch)(\n `${gitHubApiUrl}/repos/${input.repository}${path}`,\n {\n ...init,\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${input.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...init.headers,\n },\n },\n );\n const body: unknown = await response.json();\n if (!response.ok) {\n const message = z.object({ message: z.string() }).safeParse(body);\n throw new Error(\n `GitHub API request failed (${response.status}): ${message.success ? message.data.message : response.statusText}`,\n );\n }\n return body;\n}\n\nfunction parseReviewComment(value: unknown): GitHubReviewComment {\n const comment = reviewCommentSchema.parse(value);\n return {\n id: comment.id,\n body: comment.body,\n url: comment.html_url,\n author: comment.user.login,\n inReplyToId: comment.in_reply_to_id ?? null,\n };\n}\n\nfunction parseLabels(value: unknown): string[] {\n return labelsSchema.parse(value).map(({ name }) => name);\n}\n\nasync function assertReviewCommentAuthor(\n input: GitHubRepositoryRequest & ReviewCommentTrustInput,\n author: string,\n): Promise<void> {\n if (input.authorPolicy === \"any\") {\n return;\n }\n const { permission } = collaboratorPermissionSchema.parse(\n await gitHubRequest(input, `/collaborators/${encodeURIComponent(author)}/permission`),\n );\n if (!writePermissions.has(permission)) {\n throw new GitHubReviewCommentAuthorError(author);\n }\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`${name} must be a positive integer`);\n }\n return value;\n}\n\n/**\n * Verify a GitHub webhook HMAC signature (the x-hub-signature-256 header)\n * against the raw request body. Returns false for missing or malformed\n * signatures instead of throwing.\n */\nexport function verifyGitHubSignature(options: {\n secret: string;\n payload: string;\n signature: string | null;\n}): boolean {\n const { secret, payload, signature } = options;\n if (signature === null || !signature.startsWith(\"sha256=\")) {\n return false;\n }\n const expected = createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n const provided = signature.slice(\"sha256=\".length);\n if (provided.length !== expected.length) {\n return false;\n }\n return timingSafeEqual(Buffer.from(provided, \"hex\"), Buffer.from(expected, \"hex\"));\n}\n\nconst pushEventSchema = z.looseObject({\n ref: z.string().min(1),\n repository: z.looseObject({\n default_branch: z.string().min(1),\n full_name: z.string().min(1),\n }),\n});\n\nexport interface GitHubDefaultBranchPush {\n source: \"github_default_branch_push\";\n deliveryId: string;\n repositorySlug: string;\n defaultBranch: string;\n}\n\n/** Normalize a push to a repository's default branch for deterministic reconciliation. */\nexport function normalizeGitHubDefaultBranchPush(options: {\n deliveryId: string;\n event: string;\n payload: unknown;\n}): GitHubDefaultBranchPush | null {\n if (options.event !== \"push\") return null;\n const parsed = pushEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.ref !== `refs/heads/${parsed.data.repository.default_branch}`) {\n return null;\n }\n return {\n source: \"github_default_branch_push\",\n deliveryId: options.deliveryId,\n repositorySlug: parsed.data.repository.full_name.toLowerCase(),\n defaultBranch: parsed.data.repository.default_branch,\n };\n}\n\nconst issueEventSchema = z.looseObject({\n action: z.string(),\n issue: z.looseObject({\n number: z.number().int().min(1),\n title: z.string(),\n body: z.string().nullable(),\n }),\n repository: z.looseObject({\n full_name: z.string().min(1),\n }),\n});\n\nexport interface GitHubIssueSignal extends NormalizedSignal<\"github_issue\"> {\n repositorySlug: string;\n issue: { number: number; title: string; body: string | null };\n}\n\nconst failedWorkflowConclusions = new Set([\n \"action_required\",\n \"failure\",\n \"stale\",\n \"startup_failure\",\n \"timed_out\",\n]);\n\nconst workflowRunEventSchema = z.looseObject({\n action: z.string(),\n repository: z.looseObject({\n default_branch: z.string().min(1),\n full_name: z.string().min(1),\n }),\n workflow_run: z.looseObject({\n id: z.number().int().min(1),\n name: z.string().min(1),\n event: z.string().min(1),\n head_branch: z.string().min(1).nullable(),\n head_repository: z\n .looseObject({\n full_name: z.string().min(1),\n })\n .nullable(),\n head_sha: z.string().min(1),\n html_url: z.url(),\n conclusion: z.string().nullable(),\n run_attempt: z.number().int().min(1),\n }),\n});\n\nexport interface GitHubCIFailureSignal extends NormalizedSignal<\"github_ci_failure\"> {\n repositoryDefaultBranch: string;\n repositorySlug: string;\n workflowRun: {\n id: number;\n name: string;\n trigger: string;\n branch: string | null;\n headRepositorySlug: string | null;\n headSha: string;\n url: string;\n conclusion: string;\n attempt: number;\n };\n}\n\n/**\n * Normalize a GitHub issues webhook into the factory's signal shape. Returns\n * null for payloads that are not an opened issue. The caller supplies the\n * repository id; the payload stays untrusted data.\n */\nexport function normalizeGitHubIssueOpened(options: WebhookEvent): GitHubIssueSignal | null {\n if (options.event !== \"issues\") {\n return null;\n }\n const parsed = issueEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"opened\") {\n return null;\n }\n const slug = parsed.data.repository.full_name.toLowerCase();\n const { number, title, body } = parsed.data.issue;\n return {\n source: \"github_issue\",\n deliveryId: options.deliveryId,\n repositorySlug: slug,\n replyTo: { channel: \"github\", address: `${slug}#${number}` },\n issue: { number, title, body },\n payload: options.payload,\n };\n}\n\nconst pullRequestClosedSchema = z.looseObject({\n action: z.string(),\n pull_request: z.looseObject({\n number: z.number().int().min(1),\n html_url: z.url(),\n merged: z.boolean(),\n merged_by: z.looseObject({ login: z.string().min(1) }).nullable().optional(),\n merge_commit_sha: z\n .string()\n .regex(/^[0-9a-f]{40}$/)\n .nullable()\n .optional(),\n }),\n repository: z.looseObject({\n full_name: z.string().min(1),\n }),\n sender: z.looseObject({ login: z.string().min(1) }),\n});\n\nexport interface GitHubPullRequestClosed {\n source: \"github_pull_request_closed\";\n deliveryId: string;\n repositorySlug: string;\n prNumber: number;\n prUrl: string;\n merged: boolean;\n /** The merge commit on the base branch; null when closed without merging. */\n mergeCommitSha: string | null;\n /** The GitHub login that merged the pull request, or closed it without merging. */\n decidedBy: string;\n}\n\n/**\n * Normalize a closed pull_request webhook so the factory can observe what\n * happened to its change: merged records merged_by (the sender when GitHub\n * omits it), a close without merge records the sender.\n */\nexport function normalizeGitHubPullRequestClosed(\n options: WebhookEvent,\n): GitHubPullRequestClosed | null {\n if (options.event !== \"pull_request\") {\n return null;\n }\n const parsed = pullRequestClosedSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"closed\") {\n return null;\n }\n const pr = parsed.data.pull_request;\n const sender = parsed.data.sender.login;\n return {\n source: \"github_pull_request_closed\",\n deliveryId: options.deliveryId,\n repositorySlug: parsed.data.repository.full_name.toLowerCase(),\n prNumber: pr.number,\n prUrl: pr.html_url,\n merged: pr.merged,\n mergeCommitSha: pr.merged ? (pr.merge_commit_sha ?? null) : null,\n decidedBy: pr.merged ? (pr.merged_by?.login ?? sender) : sender,\n };\n}\n\n/** Normalize a completed, unsuccessful GitHub Actions run into a CI failure signal. */\nexport function normalizeGitHubWorkflowRunFailure(\n options: WebhookEvent,\n): GitHubCIFailureSignal | null {\n if (options.event !== \"workflow_run\") {\n return null;\n }\n const parsed = workflowRunEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"completed\") {\n return null;\n }\n\n const run = parsed.data.workflow_run;\n const conclusion = run.conclusion;\n if (conclusion === null || !failedWorkflowConclusions.has(conclusion)) {\n return null;\n }\n const slug = parsed.data.repository.full_name.toLowerCase();\n return {\n source: \"github_ci_failure\",\n deliveryId: options.deliveryId,\n repositoryDefaultBranch: parsed.data.repository.default_branch,\n repositorySlug: slug,\n replyTo: { channel: \"github\", address: `${slug}/actions/runs/${run.id}` },\n workflowRun: {\n id: run.id,\n name: run.name,\n trigger: run.event,\n branch: run.head_branch,\n headRepositorySlug: run.head_repository?.full_name.toLowerCase() ?? null,\n headSha: run.head_sha,\n url: run.html_url,\n conclusion,\n attempt: run.run_attempt,\n },\n payload: options.payload,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"github.mjs","names":[],"sources":["../src/github.ts"],"sourcesContent":["import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { NormalizedSignal, WebhookEvent } from \"./connectors/index\";\n\nconst gitHubApiUrl = \"https://api.github.com\";\nconst repositorySlugPattern = /^[^/\\s]+\\/[^/\\s]+$/;\n\nexport interface GitHubRepositoryRequest {\n repository: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface CreatePullRequestInput extends GitHubRepositoryRequest {\n title: string;\n head: string;\n base: string;\n body?: string;\n draft?: boolean;\n}\n\nexport interface CreatedPullRequest {\n prNumber: number;\n prUrl: string;\n}\n\nexport type ReviewCommentAuthorPolicy = \"write\" | \"any\";\n\ninterface ReviewCommentTrustInput {\n /** Defaults to `write`. Use `any` only when untrusted review text is handled as data. */\n authorPolicy?: ReviewCommentAuthorPolicy;\n}\n\nexport interface ReadReviewCommentInput extends GitHubRepositoryRequest, ReviewCommentTrustInput {\n commentId: number;\n}\n\nexport interface GitHubReviewComment {\n id: number;\n body: string;\n url: string;\n author: string;\n inReplyToId: number | null;\n}\n\nexport interface AnswerReviewCommentInput\n extends GitHubRepositoryRequest,\n ReviewCommentTrustInput {\n pullRequestNumber: number;\n commentId: number;\n body: string;\n}\n\nexport interface ReadPullRequestHeadInput extends GitHubRepositoryRequest {\n pullRequestNumber: number;\n}\n\nexport interface GitHubPullRequestHead {\n branch: string;\n sha: string;\n repository: string;\n}\n\nexport type PullRequestReviewEvent = \"APPROVE\" | \"REQUEST_CHANGES\" | \"COMMENT\";\n\nexport interface PullRequestReviewComment {\n path: string;\n line: number;\n body: string;\n}\n\nexport interface SubmitPullRequestReviewInput extends GitHubRepositoryRequest {\n pullRequestNumber: number;\n commitId: string;\n event: PullRequestReviewEvent;\n body: string;\n comments?: readonly PullRequestReviewComment[];\n}\n\nexport interface SubmittedPullRequestReview {\n id: number;\n url: string;\n state: string;\n}\n\nexport interface PullRequestLabelInput extends GitHubRepositoryRequest {\n pullRequestNumber: number;\n label: string;\n}\n\nexport interface ConflictedPullRequest {\n prNumber: number;\n prUrl: string;\n headBranch: string;\n headSha: string;\n baseBranch: string;\n baseSha: string;\n}\n\nexport type ListConflictedPullRequestsInput = GitHubRepositoryRequest;\n\nexport type CheckRunStatus = \"queued\" | \"in_progress\" | \"completed\";\nexport type GitHubCheckRunStatus = CheckRunStatus | \"waiting\" | \"requested\" | \"pending\";\nexport type CheckRunConclusion =\n | \"action_required\"\n | \"cancelled\"\n | \"failure\"\n | \"neutral\"\n | \"skipped\"\n | \"success\"\n | \"timed_out\";\nexport type CheckRunAnnotationLevel = \"notice\" | \"warning\" | \"failure\";\n\nexport interface CheckRunAnnotation {\n path: string;\n startLine: number;\n endLine?: number;\n startColumn?: number;\n endColumn?: number;\n annotationLevel: CheckRunAnnotationLevel;\n message: string;\n title?: string;\n rawDetails?: string;\n}\n\nexport interface CheckRunOutput {\n title: string;\n summary: string;\n text?: string;\n annotations?: readonly CheckRunAnnotation[];\n}\n\ninterface CheckRunFields {\n status?: CheckRunStatus;\n conclusion?: CheckRunConclusion;\n detailsUrl?: string;\n externalId?: string;\n startedAt?: string;\n completedAt?: string;\n output?: CheckRunOutput;\n}\n\nexport interface CreateCheckRunInput extends GitHubRepositoryRequest, CheckRunFields {\n name: string;\n headSha: string;\n}\n\nexport interface UpdateCheckRunInput extends GitHubRepositoryRequest, CheckRunFields {\n checkRunId: number;\n name?: string;\n}\n\nexport interface ListCheckRunsForRefInput extends GitHubRepositoryRequest {\n ref: string;\n checkName?: string;\n}\n\nexport interface GitHubCheckRun {\n id: number;\n name: string;\n headSha: string;\n status: GitHubCheckRunStatus;\n conclusion: CheckRunConclusion | \"stale\" | \"startup_failure\" | null;\n url: string | null;\n detailsUrl: string | null;\n externalId: string | null;\n startedAt: string | null;\n completedAt: string | null;\n}\n\nconst pullRequestSchema = z.object({\n number: z.number().int().positive(),\n html_url: z.url(),\n});\n\nconst pullRequestHeadSchema = z.object({\n head: z.object({\n ref: z\n .string()\n .regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/)\n .refine((value) => !value.includes(\"..\")),\n sha: z.string().regex(/^[0-9a-f]{40}$/),\n repo: z.object({ full_name: z.string().min(1) }),\n }),\n});\n\nconst reviewCommentSchema = z.object({\n id: z.number().int().positive(),\n body: z.string(),\n html_url: z.url(),\n user: z.object({ login: z.string().min(1) }),\n in_reply_to_id: z.number().int().positive().nullish(),\n});\n\nconst submittedReviewSchema = z.object({\n id: z.number().int().positive(),\n html_url: z.url(),\n state: z.string().min(1),\n});\n\nconst checkRunSchema = z.object({\n id: z.number().int().positive(),\n name: z.string().min(1),\n head_sha: z.string().regex(/^[0-9a-f]{40}$/),\n status: z.enum([\"queued\", \"in_progress\", \"completed\", \"waiting\", \"requested\", \"pending\"]),\n conclusion: z\n .enum([\n \"action_required\",\n \"cancelled\",\n \"failure\",\n \"neutral\",\n \"skipped\",\n \"success\",\n \"timed_out\",\n \"stale\",\n \"startup_failure\",\n ])\n .nullable(),\n html_url: z.url().nullable(),\n details_url: z.url().nullable(),\n external_id: z.string().nullable(),\n started_at: z.string().nullable(),\n completed_at: z.string().nullable(),\n});\n\nconst checkRunsSchema = z.object({ check_runs: z.array(checkRunSchema) });\nconst labelsSchema = z.array(z.object({ name: z.string().min(1) }));\nconst pullRequestCandidateSchema = z.object({\n number: z.number().int().positive(),\n user: z.object({ type: z.string().min(1) }),\n head: z.object({ ref: z.string().min(1), repo: z.object({ full_name: z.string().min(1) }) }),\n});\nconst openPullRequestsSchema = z.array(pullRequestCandidateSchema);\nconst pullRequestDetailSchema = pullRequestCandidateSchema.extend({\n html_url: z.url(),\n mergeable: z.boolean().nullable(),\n mergeable_state: z.string().min(1),\n head: pullRequestCandidateSchema.shape.head.extend({ sha: z.string().min(1) }),\n base: z.object({ ref: z.string().min(1), sha: z.string().min(1) }),\n});\nconst collaboratorPermissionSchema = z.object({\n permission: z.enum([\"admin\", \"maintain\", \"write\", \"triage\", \"read\", \"none\"]),\n});\nconst writePermissions = new Set([\"admin\", \"maintain\", \"write\"]);\n\nexport class GitHubReviewCommentAuthorError extends Error {\n readonly author: string;\n\n constructor(author: string) {\n super(`GitHub user ${author} does not have write access to the repository`);\n this.name = \"GitHubReviewCommentAuthorError\";\n this.author = author;\n }\n}\n\n/** Create a pull request from an existing head branch. */\nexport async function createPullRequest(input: CreatePullRequestInput): Promise<CreatedPullRequest> {\n const pull = pullRequestSchema.parse(\n await gitHubRequest(input, \"/pulls\", {\n method: \"POST\",\n body: JSON.stringify({\n title: input.title,\n head: input.head,\n base: input.base,\n ...(input.body === undefined ? {} : { body: input.body }),\n ...(input.draft === undefined ? {} : { draft: input.draft }),\n }),\n }),\n );\n return { prNumber: pull.number, prUrl: pull.html_url };\n}\n\n/** Create a check run for one commit. Requires a GitHub App token with checks:write. */\nexport async function createCheckRun(input: CreateCheckRunInput): Promise<GitHubCheckRun> {\n if (input.status === \"completed\" && input.conclusion === undefined) {\n throw new Error(\"completed check runs require a conclusion\");\n }\n if (input.status !== \"completed\" && input.conclusion !== undefined) {\n throw new Error(\"creating a check run with a conclusion requires completed status\");\n }\n return parseCheckRun(\n await gitHubRequest(input, \"/check-runs\", {\n method: \"POST\",\n body: JSON.stringify({\n name: input.name,\n head_sha: commitSha(input.headSha),\n ...checkRunFields(input),\n }),\n }),\n );\n}\n\n/** Update a check run previously created by the authenticated GitHub App. */\nexport async function updateCheckRun(input: UpdateCheckRunInput): Promise<GitHubCheckRun> {\n if (input.status !== undefined && input.status !== \"completed\" && input.conclusion !== undefined) {\n throw new Error(\"a check run conclusion conflicts with an incomplete status\");\n }\n return parseCheckRun(\n await gitHubRequest(input, `/check-runs/${positiveInteger(input.checkRunId, \"checkRunId\")}`, {\n method: \"PATCH\",\n body: JSON.stringify({\n ...(input.name === undefined ? {} : { name: input.name }),\n ...checkRunFields(input),\n }),\n }),\n );\n}\n\n/** List check runs reported for a commit, branch, or tag. */\nexport async function listCheckRunsForRef(input: ListCheckRunsForRefInput): Promise<GitHubCheckRun[]> {\n const query = new URLSearchParams({ per_page: \"100\" });\n if (input.checkName !== undefined) query.set(\"check_name\", input.checkName);\n const response = checkRunsSchema.parse(\n await gitHubRequest(input, `/commits/${encodeURIComponent(input.ref)}/check-runs?${query.toString()}`),\n );\n return response.check_runs.map(parseCheckRun);\n}\n\n/** Read one inline review comment after applying the author policy, which requires write access by default. */\nexport async function readReviewComment(\n input: ReadReviewCommentInput,\n): Promise<GitHubReviewComment> {\n const comment = parseReviewComment(\n await gitHubRequest(input, `/pulls/comments/${positiveInteger(input.commentId, \"commentId\")}`),\n );\n await assertReviewCommentAuthor(input, comment.author);\n return comment;\n}\n\n/** Reply to an inline review comment after applying the author policy, which requires write access by default. */\nexport async function answerReviewComment(\n input: AnswerReviewCommentInput,\n): Promise<GitHubReviewComment> {\n await readReviewComment(input);\n return parseReviewComment(\n await gitHubRequest(\n input,\n `/pulls/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/comments/${positiveInteger(input.commentId, \"commentId\")}/replies`,\n { method: \"POST\", body: JSON.stringify({ body: input.body }) },\n ),\n );\n}\n\n/** Submit a summary and optional inline comments against a reviewed pull request commit. */\nexport async function submitPullRequestReview(\n input: SubmitPullRequestReviewInput,\n): Promise<SubmittedPullRequestReview> {\n const commitId = z.string().regex(/^[0-9a-f]{40}$/).parse(input.commitId);\n const head = await readPullRequestHead(input);\n if (head.sha !== commitId) {\n throw new Error(`pull request changed after review: expected ${commitId}, found ${head.sha}`);\n }\n const review = submittedReviewSchema.parse(\n await gitHubRequest(\n input,\n `/pulls/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/reviews`,\n {\n method: \"POST\",\n body: JSON.stringify({\n commit_id: commitId,\n event: input.event,\n body: input.body,\n comments: (input.comments ?? []).map((comment) => ({\n path: comment.path,\n line: positiveInteger(comment.line, \"comment line\"),\n side: \"RIGHT\",\n body: comment.body,\n })),\n }),\n },\n ),\n );\n return { id: review.id, url: review.html_url, state: review.state };\n}\n\n/** Read the current head branch and commit of a pull request. */\nexport async function readPullRequestHead(\n input: ReadPullRequestHeadInput,\n): Promise<GitHubPullRequestHead> {\n const pull = pullRequestHeadSchema.parse(\n await gitHubRequest(input, `/pulls/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}`),\n );\n return {\n branch: pull.head.ref,\n sha: pull.head.sha,\n repository: pull.head.repo.full_name.toLowerCase(),\n };\n}\n\n/** List open, same-repository pull requests by one author that GitHub reports as conflicting. */\nexport async function listConflictedPullRequests(\n input: ListConflictedPullRequestsInput,\n): Promise<ConflictedPullRequest[]> {\n const pulls = openPullRequestsSchema.parse(\n await gitHubRequest(input, `/pulls?state=open&per_page=100`),\n );\n const candidates = pulls.filter(\n (pull) =>\n pull.user.type === \"Bot\" &&\n pull.head.ref.startsWith(\"factory/\") &&\n pull.head.repo.full_name.toLowerCase() === input.repository.toLowerCase(),\n );\n const conflicted: ConflictedPullRequest[] = [];\n for (const candidate of candidates) {\n const pull = pullRequestDetailSchema.parse(\n await gitHubRequest(input, `/pulls/${candidate.number}`),\n );\n if (pull.mergeable === false || pull.mergeable_state === \"dirty\") {\n conflicted.push({\n prNumber: pull.number,\n prUrl: pull.html_url,\n headBranch: pull.head.ref,\n headSha: pull.head.sha,\n baseBranch: pull.base.ref,\n baseSha: pull.base.sha,\n });\n }\n }\n return conflicted;\n}\n\n/** Add one label to a pull request. */\nexport async function addLabel(input: PullRequestLabelInput): Promise<string[]> {\n return parseLabels(\n await gitHubRequest(\n input,\n `/issues/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/labels`,\n { method: \"POST\", body: JSON.stringify({ labels: [input.label] }) },\n ),\n );\n}\n\n/** Remove one label from a pull request. */\nexport async function removeLabel(input: PullRequestLabelInput): Promise<string[]> {\n return parseLabels(\n await gitHubRequest(\n input,\n `/issues/${positiveInteger(input.pullRequestNumber, \"pullRequestNumber\")}/labels/${encodeURIComponent(input.label)}`,\n { method: \"DELETE\" },\n ),\n );\n}\n\nasync function gitHubRequest(\n input: GitHubRepositoryRequest,\n path: string,\n init: RequestInit = {},\n): Promise<unknown> {\n if (!repositorySlugPattern.test(input.repository)) {\n throw new Error(`invalid GitHub repository slug: ${input.repository}`);\n }\n const response = await (input.fetch ?? globalThis.fetch)(\n `${gitHubApiUrl}/repos/${input.repository}${path}`,\n {\n ...init,\n headers: {\n Accept: \"application/vnd.github+json\",\n Authorization: `Bearer ${input.token}`,\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...init.headers,\n },\n },\n );\n const body: unknown = await response.json();\n if (!response.ok) {\n const message = z.object({ message: z.string() }).safeParse(body);\n throw new Error(\n `GitHub API request failed (${response.status}): ${message.success ? message.data.message : response.statusText}`,\n );\n }\n return body;\n}\n\nfunction parseReviewComment(value: unknown): GitHubReviewComment {\n const comment = reviewCommentSchema.parse(value);\n return {\n id: comment.id,\n body: comment.body,\n url: comment.html_url,\n author: comment.user.login,\n inReplyToId: comment.in_reply_to_id ?? null,\n };\n}\n\nfunction parseLabels(value: unknown): string[] {\n return labelsSchema.parse(value).map(({ name }) => name);\n}\n\nfunction parseCheckRun(value: unknown): GitHubCheckRun {\n const checkRun = checkRunSchema.parse(value);\n return {\n id: checkRun.id,\n name: checkRun.name,\n headSha: checkRun.head_sha,\n status: checkRun.status,\n conclusion: checkRun.conclusion,\n url: checkRun.html_url,\n detailsUrl: checkRun.details_url,\n externalId: checkRun.external_id,\n startedAt: checkRun.started_at,\n completedAt: checkRun.completed_at,\n };\n}\n\nfunction checkRunFields(input: CheckRunFields): Record<string, unknown> {\n return {\n ...(input.status === undefined ? {} : { status: input.status }),\n ...(input.conclusion === undefined ? {} : { conclusion: input.conclusion }),\n ...(input.detailsUrl === undefined ? {} : { details_url: input.detailsUrl }),\n ...(input.externalId === undefined ? {} : { external_id: input.externalId }),\n ...(input.startedAt === undefined ? {} : { started_at: input.startedAt }),\n ...(input.completedAt === undefined ? {} : { completed_at: input.completedAt }),\n ...(input.output === undefined ? {} : { output: checkRunOutput(input.output) }),\n };\n}\n\nfunction checkRunOutput(output: CheckRunOutput): Record<string, unknown> {\n return {\n title: output.title,\n summary: output.summary,\n ...(output.text === undefined ? {} : { text: output.text }),\n ...(output.annotations === undefined\n ? {}\n : {\n annotations: output.annotations.map((annotation) => ({\n path: annotation.path,\n start_line: positiveInteger(annotation.startLine, \"annotation startLine\"),\n end_line: positiveInteger(annotation.endLine ?? annotation.startLine, \"annotation endLine\"),\n ...(annotation.startColumn === undefined\n ? {}\n : { start_column: positiveInteger(annotation.startColumn, \"annotation startColumn\") }),\n ...(annotation.endColumn === undefined\n ? {}\n : { end_column: positiveInteger(annotation.endColumn, \"annotation endColumn\") }),\n annotation_level: annotation.annotationLevel,\n message: annotation.message,\n ...(annotation.title === undefined ? {} : { title: annotation.title }),\n ...(annotation.rawDetails === undefined ? {} : { raw_details: annotation.rawDetails }),\n })),\n }),\n };\n}\n\nasync function assertReviewCommentAuthor(\n input: GitHubRepositoryRequest & ReviewCommentTrustInput,\n author: string,\n): Promise<void> {\n if (input.authorPolicy === \"any\") {\n return;\n }\n const { permission } = collaboratorPermissionSchema.parse(\n await gitHubRequest(input, `/collaborators/${encodeURIComponent(author)}/permission`),\n );\n if (!writePermissions.has(permission)) {\n throw new GitHubReviewCommentAuthorError(author);\n }\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`${name} must be a positive integer`);\n }\n return value;\n}\n\nfunction commitSha(value: string): string {\n return z.string().regex(/^[0-9a-f]{40}$/).parse(value);\n}\n\n/**\n * Verify a GitHub webhook HMAC signature (the x-hub-signature-256 header)\n * against the raw request body. Returns false for missing or malformed\n * signatures instead of throwing.\n */\nexport function verifyGitHubSignature(options: {\n secret: string;\n payload: string;\n signature: string | null;\n}): boolean {\n const { secret, payload, signature } = options;\n if (signature === null || !signature.startsWith(\"sha256=\")) {\n return false;\n }\n const expected = createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n const provided = signature.slice(\"sha256=\".length);\n if (provided.length !== expected.length) {\n return false;\n }\n return timingSafeEqual(Buffer.from(provided, \"hex\"), Buffer.from(expected, \"hex\"));\n}\n\nconst pushEventSchema = z.looseObject({\n ref: z.string().min(1),\n repository: z.looseObject({\n default_branch: z.string().min(1),\n full_name: z.string().min(1),\n }),\n});\n\nexport interface GitHubDefaultBranchPush {\n source: \"github_default_branch_push\";\n deliveryId: string;\n repositorySlug: string;\n defaultBranch: string;\n}\n\n/** Normalize a push to a repository's default branch for deterministic reconciliation. */\nexport function normalizeGitHubDefaultBranchPush(options: {\n deliveryId: string;\n event: string;\n payload: unknown;\n}): GitHubDefaultBranchPush | null {\n if (options.event !== \"push\") return null;\n const parsed = pushEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.ref !== `refs/heads/${parsed.data.repository.default_branch}`) {\n return null;\n }\n return {\n source: \"github_default_branch_push\",\n deliveryId: options.deliveryId,\n repositorySlug: parsed.data.repository.full_name.toLowerCase(),\n defaultBranch: parsed.data.repository.default_branch,\n };\n}\n\nconst pullRequestEventSchema = z.looseObject({\n action: z.string(),\n number: z.number().int().positive(),\n pull_request: z.looseObject({\n html_url: z.url(),\n draft: z.boolean(),\n user: z.looseObject({ login: z.string().min(1) }),\n head: z.looseObject({\n sha: z.string().regex(/^[0-9a-f]{40}$/),\n ref: z.string().min(1),\n repo: z.looseObject({ full_name: z.string().min(1) }),\n }),\n base: z.looseObject({\n sha: z.string().regex(/^[0-9a-f]{40}$/),\n ref: z.string().min(1),\n }),\n }),\n repository: z.looseObject({ full_name: z.string().min(1) }),\n sender: z.looseObject({ login: z.string().min(1) }),\n});\n\nconst reviewablePullRequestActions = new Set([\"opened\", \"reopened\", \"ready_for_review\", \"synchronize\"]);\n\nexport interface GitHubPullRequestSignal extends NormalizedSignal<\"github_pr\"> {\n repositorySlug: string;\n pullRequest: {\n number: number;\n url: string;\n author: string;\n draft: boolean;\n headSha: string;\n headBranch: string;\n headRepositorySlug: string;\n baseSha: string;\n baseBranch: string;\n sender: string;\n };\n}\n\n/** Normalize a newly reviewable or updated pull request into a factory signal. */\nexport function normalizeGitHubPullRequest(options: WebhookEvent): GitHubPullRequestSignal | null {\n if (options.event !== \"pull_request\") return null;\n const parsed = pullRequestEventSchema.safeParse(options.payload);\n if (!parsed.success || !reviewablePullRequestActions.has(parsed.data.action)) return null;\n if (parsed.data.pull_request.draft && parsed.data.action !== \"ready_for_review\") return null;\n\n const slug = parsed.data.repository.full_name.toLowerCase();\n const pull = parsed.data.pull_request;\n return {\n source: \"github_pr\",\n deliveryId: options.deliveryId,\n repositorySlug: slug,\n replyTo: { channel: \"github\", address: `${slug}/pull/${parsed.data.number}` },\n pullRequest: {\n number: parsed.data.number,\n url: pull.html_url,\n author: pull.user.login,\n draft: pull.draft,\n headSha: pull.head.sha,\n headBranch: pull.head.ref,\n headRepositorySlug: pull.head.repo.full_name.toLowerCase(),\n baseSha: pull.base.sha,\n baseBranch: pull.base.ref,\n sender: parsed.data.sender.login,\n },\n payload: options.payload,\n };\n}\n\nconst issueEventSchema = z.looseObject({\n action: z.string(),\n issue: z.looseObject({\n number: z.number().int().min(1),\n title: z.string(),\n body: z.string().nullable(),\n }),\n repository: z.looseObject({\n full_name: z.string().min(1),\n }),\n});\n\nexport interface GitHubIssueSignal extends NormalizedSignal<\"github_issue\"> {\n repositorySlug: string;\n issue: { number: number; title: string; body: string | null };\n}\n\nconst failedWorkflowConclusions = new Set([\n \"action_required\",\n \"failure\",\n \"stale\",\n \"startup_failure\",\n \"timed_out\",\n]);\n\nconst workflowRunEventSchema = z.looseObject({\n action: z.string(),\n repository: z.looseObject({\n default_branch: z.string().min(1),\n full_name: z.string().min(1),\n }),\n workflow_run: z.looseObject({\n id: z.number().int().min(1),\n name: z.string().min(1),\n event: z.string().min(1),\n head_branch: z.string().min(1).nullable(),\n head_repository: z\n .looseObject({\n full_name: z.string().min(1),\n })\n .nullable(),\n head_sha: z.string().min(1),\n html_url: z.url(),\n conclusion: z.string().nullable(),\n run_attempt: z.number().int().min(1),\n }),\n});\n\nexport interface GitHubCIFailureSignal extends NormalizedSignal<\"github_ci_failure\"> {\n repositoryDefaultBranch: string;\n repositorySlug: string;\n workflowRun: {\n id: number;\n name: string;\n trigger: string;\n branch: string | null;\n headRepositorySlug: string | null;\n headSha: string;\n url: string;\n conclusion: string;\n attempt: number;\n };\n}\n\n/**\n * Normalize a GitHub issues webhook into the factory's signal shape. Returns\n * null for payloads that are not an opened issue. The caller supplies the\n * repository id; the payload stays untrusted data.\n */\nexport function normalizeGitHubIssueOpened(options: WebhookEvent): GitHubIssueSignal | null {\n if (options.event !== \"issues\") {\n return null;\n }\n const parsed = issueEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"opened\") {\n return null;\n }\n const slug = parsed.data.repository.full_name.toLowerCase();\n const { number, title, body } = parsed.data.issue;\n return {\n source: \"github_issue\",\n deliveryId: options.deliveryId,\n repositorySlug: slug,\n replyTo: { channel: \"github\", address: `${slug}#${number}` },\n issue: { number, title, body },\n payload: options.payload,\n };\n}\n\nconst pullRequestClosedSchema = z.looseObject({\n action: z.string(),\n pull_request: z.looseObject({\n number: z.number().int().min(1),\n html_url: z.url(),\n merged: z.boolean(),\n merged_by: z.looseObject({ login: z.string().min(1) }).nullable().optional(),\n merge_commit_sha: z\n .string()\n .regex(/^[0-9a-f]{40}$/)\n .nullable()\n .optional(),\n }),\n repository: z.looseObject({\n full_name: z.string().min(1),\n }),\n sender: z.looseObject({ login: z.string().min(1) }),\n});\n\nexport interface GitHubPullRequestClosed {\n source: \"github_pull_request_closed\";\n deliveryId: string;\n repositorySlug: string;\n prNumber: number;\n prUrl: string;\n merged: boolean;\n /** The merge commit on the base branch; null when closed without merging. */\n mergeCommitSha: string | null;\n /** The GitHub login that merged the pull request, or closed it without merging. */\n decidedBy: string;\n}\n\n/**\n * Normalize a closed pull_request webhook so the factory can observe what\n * happened to its change: merged records merged_by (the sender when GitHub\n * omits it), a close without merge records the sender.\n */\nexport function normalizeGitHubPullRequestClosed(\n options: WebhookEvent,\n): GitHubPullRequestClosed | null {\n if (options.event !== \"pull_request\") {\n return null;\n }\n const parsed = pullRequestClosedSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"closed\") {\n return null;\n }\n const pr = parsed.data.pull_request;\n const sender = parsed.data.sender.login;\n return {\n source: \"github_pull_request_closed\",\n deliveryId: options.deliveryId,\n repositorySlug: parsed.data.repository.full_name.toLowerCase(),\n prNumber: pr.number,\n prUrl: pr.html_url,\n merged: pr.merged,\n mergeCommitSha: pr.merged ? (pr.merge_commit_sha ?? null) : null,\n decidedBy: pr.merged ? (pr.merged_by?.login ?? sender) : sender,\n };\n}\n\n/** Normalize a completed, unsuccessful GitHub Actions run into a CI failure signal. */\nexport function normalizeGitHubWorkflowRunFailure(\n options: WebhookEvent,\n): GitHubCIFailureSignal | null {\n if (options.event !== \"workflow_run\") {\n return null;\n }\n const parsed = workflowRunEventSchema.safeParse(options.payload);\n if (!parsed.success || parsed.data.action !== \"completed\") {\n return null;\n }\n\n const run = parsed.data.workflow_run;\n const conclusion = run.conclusion;\n if (conclusion === null || !failedWorkflowConclusions.has(conclusion)) {\n return null;\n }\n const slug = parsed.data.repository.full_name.toLowerCase();\n return {\n source: \"github_ci_failure\",\n deliveryId: options.deliveryId,\n repositoryDefaultBranch: parsed.data.repository.default_branch,\n repositorySlug: slug,\n replyTo: { channel: \"github\", address: `${slug}/actions/runs/${run.id}` },\n workflowRun: {\n id: run.id,\n name: run.name,\n trigger: run.event,\n branch: run.head_branch,\n headRepositorySlug: run.head_repository?.full_name.toLowerCase() ?? null,\n headSha: run.head_sha,\n url: run.html_url,\n conclusion,\n attempt: run.run_attempt,\n },\n payload: options.payload,\n };\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as StoredEntry, i as StoreDriver, n as RecordExistsError, o as StoredRecord, r as RecordNotFoundError, s as VersionConflictError, t as CollectionName } from "./driver-CrZsy7sm.mjs";
2
2
  import { a as factoryConfigSchema, i as factoryConfigRepositorySchema, n as FactoryConfigInput, r as defineFactory, t as FactoryConfig } from "./factory-config-Bu4mklm9.mjs";
3
3
  import { a as signalSchema, c as ReplyTo, d as replyToSchema, f as schemaVersionSchema, i as signalOutcomeSchema, l as SCHEMA_VERSION, m as vocabularySchema, n as SignalOutcome, o as signalSourceSchema, p as usdSchema, r as SignalSource, s as standardSignalSources, t as Signal, u as isoDateTimeSchema } from "./signal-CHVEmzvI.mjs";
4
- import { $ as ReceiptPhase, A as TaskPatch, B as taskDevboxSchema, C as ChangeTransitionOptions, Ct as changeIdSchema, D as CreateTaskInput, Dt as repositoryIdsSchema, E as CreateStoresOptions, Et as repositoryIdSchema, F as TaskKind, G as taskStateSchema, H as taskOriginSchema, I as TaskState, J as repositorySchema, K as Repository, L as harnessSchema, M as createStores, N as Task, O as DecideSignalOptions, Ot as signalIdSchema, P as TaskApproval, Q as ReceiptKind, R as standardTaskKinds, S as ChangePatch, St as TaskId, T as CreateSignalInput, Tt as receiptIdSchema, U as taskQuestionSchema, V as taskKindSchema, W as taskSchema, X as Cost, Y as repositorySlugSchema, Z as Receipt, _ as findingVerificationMethodSchema, _t as ChangeId, a as approvalRuleSchema, at as receiptStateSchema, b as ApprovalDecision, bt as RepositoryId, c as Finding, ct as standardReceiptStates, d as FindingVerification, dt as ChangeState, et as ReceiptState, f as findingCategorySchema, ft as Level, g as findingVerificationLevelSchema, gt as levelSchema, h as findingSchema, ht as changeStateSchema, i as approvalPolicySchema, it as receiptSchema, j as TaskTransitionOptions, k as FactoryStores, kt as taskIdSchema, l as FindingCategory, lt as Change, m as findingPrioritySchema, mt as changeSchema, n as ApprovalRule, nt as receiptKindSchema, o as defaultApprovalPolicy, ot as standardReceiptKinds, p as findingFingerprint, pt as changeEvidenceSchema, q as RepositorySlug, r as ApprovalSubject, rt as receiptPhaseSchema, s as requiresApproval, st as standardReceiptPhases, t as ApprovalPolicy, tt as costSchema, u as FindingPriority, ut as ChangeEvidence, v as findingVerificationSchema, vt as FactoryId, w as CreateChangeInput, wt as factoryIdSchema, x as ApprovalError, xt as SignalId, y as AppendReceiptInput, yt as ReceiptId, z as taskApprovalSchema } from "./approval-MoiwGpkh.mjs";
4
+ import { $ as Cost, A as FactoryStores, At as repositoryIdsSchema, B as standardTaskKinds, C as ChangePatch, Ct as RepositoryId, D as CreateStoresOptions, Dt as factoryIdSchema, E as CreateSignalInput, Et as changeIdSchema, F as TaskApproval, G as taskOriginSchema, H as taskDevboxSchema, I as TaskKind, J as taskStateSchema, K as taskQuestionSchema, L as TaskState, M as TaskTransitionOptions, Mt as taskIdSchema, N as createStores, O as CreateTaskInput, Ot as receiptIdSchema, P as Task, Q as repositorySlugSchema, R as coordinationRepositoryIdsSchema, S as ChangeAssociationError, St as ReceiptId, T as CreateChangeInput, Tt as TaskId, U as taskExecutionRepositoryIdsSchema, V as taskApprovalSchema, W as taskKindSchema, X as RepositorySlug, Y as Repository, Z as repositorySchema, _ as findingVerificationMethodSchema, _t as changeSchema, a as approvalRuleSchema, at as receiptKindSchema, b as ApprovalDecision, bt as ChangeId, c as Finding, ct as receiptStateSchema, d as FindingVerification, dt as standardReceiptStates, et as Receipt, f as findingCategorySchema, ft as Change, g as findingVerificationLevelSchema, gt as changeEvidenceSchema, h as findingSchema, ht as Level, i as approvalPolicySchema, it as costSchema, j as TaskPatch, jt as signalIdSchema, k as DecideSignalOptions, kt as repositoryIdSchema, l as FindingCategory, lt as standardReceiptKinds, m as findingPrioritySchema, mt as ChangeState, n as ApprovalRule, nt as ReceiptPhase, o as defaultApprovalPolicy, ot as receiptPhaseSchema, p as findingFingerprint, pt as ChangeEvidence, q as taskSchema, r as ApprovalSubject, rt as ReceiptState, s as requiresApproval, st as receiptSchema, t as ApprovalPolicy, tt as ReceiptKind, u as FindingPriority, ut as standardReceiptPhases, v as findingVerificationSchema, vt as changeStateSchema, w as ChangeTransitionOptions, wt as SignalId, x as ApprovalError, xt as FactoryId, y as AppendReceiptInput, yt as levelSchema, z as harnessSchema } from "./approval-CDiBco2V.mjs";
5
5
  import { z } from "zod";
6
6
  //#region src/briefs.d.ts
7
7
  /** The finding behind a task, when its signal carries one. */
@@ -23,6 +23,38 @@ interface AdoptPullRequestInput {
23
23
  }
24
24
  declare function adoptPullRequest(stores: Pick<FactoryStores, "changes">, input: AdoptPullRequestInput): Promise<Change>;
25
25
  //#endregion
26
+ //#region src/coordination.d.ts
27
+ interface CreateCoordinationInput {
28
+ repositoryIds: readonly [RepositoryId, RepositoryId, ...RepositoryId[]];
29
+ signalId: SignalId;
30
+ replyTo: ReplyTo;
31
+ }
32
+ interface CoordinationPlan {
33
+ parent: Task;
34
+ children: readonly Task[];
35
+ }
36
+ type CoordinationReconciliation = {
37
+ status: "pending";
38
+ parent: Task;
39
+ children: readonly Task[];
40
+ } | {
41
+ status: "succeeded" | "failed";
42
+ transitioned: boolean;
43
+ parent: Task;
44
+ children: readonly Task[];
45
+ };
46
+ interface ReconcileCoordinationOptions {
47
+ present(input: {
48
+ status: "succeeded" | "failed";
49
+ parent: Task;
50
+ children: readonly Task[];
51
+ }): Promise<void>;
52
+ }
53
+ /** Create one non-executable parent and one independently executable child per repository. */
54
+ declare function createCoordination(stores: FactoryStores, input: CreateCoordinationInput): Promise<CoordinationPlan>;
55
+ /** Reconcile a coordination parent from its direct children without ever dispatching the parent. */
56
+ declare function reconcileCoordination(stores: FactoryStores, parentTaskId: TaskId, options: ReconcileCoordinationOptions): Promise<CoordinationReconciliation>;
57
+ //#endregion
26
58
  //#region src/dispatch.d.ts
27
59
  declare class DispatchRefusedError extends Error {
28
60
  readonly taskId: TaskId;
@@ -50,6 +82,75 @@ declare const DEFAULT_MAX_LAUNCH_ATTEMPTS = 45;
50
82
  */
51
83
  declare function dispatchTask(stores: FactoryStores, taskId: TaskId, options: DispatchOptions): Promise<Task>;
52
84
  //#endregion
85
+ //#region src/metrics.d.ts
86
+ /**
87
+ * The derived review bucket from the default risk x confidence table. Derived
88
+ * at read time, never stored; "blocked" is a bucket, not a change state.
89
+ */
90
+ type ReviewBucket = "stamp" | "review" | "blocked";
91
+ declare function reviewBucket(risk: Level, confidence: Level): ReviewBucket;
92
+ interface LedgerRows {
93
+ changes: readonly Change[];
94
+ signals: readonly Signal[];
95
+ receipts: readonly Receipt[];
96
+ tasks: readonly Task[];
97
+ }
98
+ interface MetricsOptions {
99
+ /** Evaluation time; defaults to the current time. */
100
+ now?: Date;
101
+ /** Days a landed change must hold without a rollback. Default 7. */
102
+ holdDays?: number;
103
+ }
104
+ interface LedgerMetrics {
105
+ /**
106
+ * Changes a human merged that reached deployed (rolled_out for high risk)
107
+ * and did not roll back within the hold window. Includes provisional ones.
108
+ */
109
+ landed: number;
110
+ /** Landed changes still inside the hold window; the number may drop. */
111
+ provisional: number;
112
+ /** landed / (landed + rolled back + closed after ready). Null when nothing decided. */
113
+ stickRate: number | null;
114
+ /**
115
+ * Not computable from ledger rows: needs a record of human commits pushed
116
+ * to the pull request after ready, which nothing writes today.
117
+ */
118
+ stampedClean: null;
119
+ /** Median ms from the ready receipt to the merged receipt, per review bucket. */
120
+ humanTimeMs: {
121
+ stamp: number | null;
122
+ review: number | null;
123
+ };
124
+ /** Sum of settled task cost over landed changes / landed. Null until budgets settle. */
125
+ costPerLandedUsd: number | null;
126
+ /** Signals triage turned away plus changes closed in verification. */
127
+ filtered: number;
128
+ }
129
+ /**
130
+ * The six product metrics from ledger rows alone. One rule governs them: a
131
+ * change counts only after a human merged it and it stayed. Activity that
132
+ * never landed is not a result. Compute over rows already filtered to the
133
+ * period and repositories you are reporting on.
134
+ */
135
+ declare function computeLedgerMetrics(rows: LedgerRows, options?: MetricsOptions): LedgerMetrics;
136
+ type HealthColor = "green" | "yellow" | "red";
137
+ interface HealthOptions {
138
+ now?: Date;
139
+ /** Open-change cap from factory configuration; omitted disables that check. */
140
+ maxOpenChanges?: number;
141
+ }
142
+ interface RepositoryHealth {
143
+ color: HealthColor;
144
+ /** Every rule that fired, so the color is explainable from rows. */
145
+ reasons: string[];
146
+ }
147
+ /**
148
+ * Green, yellow, or red from rows, never from a model. Budget and onboarding
149
+ * signals are not evaluated yet: budgets do not settle and onboarding
150
+ * investigations are not recorded, so those spec rules have no rows to read.
151
+ */
152
+ declare function computeRepositoryHealth(rows: LedgerRows, options?: HealthOptions): RepositoryHealth;
153
+ //#endregion
53
154
  //#region src/schema/budget.d.ts
54
155
  declare const budgetMonthSchema: z.ZodString;
55
156
  declare const budgetSchema: z.ZodObject<{
@@ -139,5 +240,5 @@ interface SweepResult {
139
240
  */
140
241
  declare function sweepQueued(stores: FactoryStores, options: SweepOptions): Promise<SweepResult>;
141
242
  //#endregion
142
- export { AdoptPullRequestInput, AppendReceiptInput, ApprovalDecision, ApprovalError, ApprovalPolicy, ApprovalRule, ApprovalSubject, Budget, Change, ChangeEvidence, ChangeId, ChangePatch, ChangeState, ChangeTransitionOptions, CollectionName, Cost, CreateChangeInput, CreateSignalInput, CreateStoresOptions, CreateTaskInput, DEFAULT_MAX_LAUNCH_ATTEMPTS, DecideSignalOptions, DispatchOptions, DispatchRefusedError, FactoryConfig, FactoryConfigInput, FactoryId, FactoryStores, Finding, FindingCategory, FindingPriority, FindingVerification, InvalidTransitionError, Level, Receipt, ReceiptId, ReceiptKind, ReceiptPhase, ReceiptState, RecordExistsError, RecordNotFoundError, ReplyTo, Repository, RepositoryId, RepositorySlug, SCHEMA_VERSION, Signal, SignalCreator, SignalId, SignalOutcome, SignalSource, StoreDriver, StoredEntry, StoredRecord, SweepOptions, SweepResult, Task, TaskApproval, TaskId, TaskKind, TaskLauncher, TaskPatch, TaskState, TaskTransitionOptions, Transition, TransitionActor, VersionConflictError, adoptPullRequest, approvalPolicySchema, approvalRuleSchema, assertTransition, budgetMonthSchema, budgetSchema, changeEvidenceSchema, changeIdSchema, changeInitialState, changeSchema, changeStateSchema, changeTransitions, costSchema, createInMemoryDriver, createSignalCreator, createStores, defaultApprovalPolicy, defineFactory, dispatchTask, factoryConfigRepositorySchema, factoryConfigSchema, factoryIdSchema, findingCategorySchema, findingFingerprint, findingForTask, findingPrioritySchema, findingSchema, findingVerificationLevelSchema, findingVerificationMethodSchema, findingVerificationSchema, fixBrief, harnessSchema, isTransitionAllowed, isoDateTimeSchema, legalNextStates, levelSchema, receiptIdSchema, receiptKindSchema, receiptPhaseSchema, receiptSchema, receiptStateSchema, replyToSchema, repositoryIdSchema, repositoryIdsSchema, repositorySchema, repositorySlugSchema, requiresApproval, scanBrief, schemaVersionSchema, signalIdSchema, signalInitialOutcome, signalOutcomeSchema, signalOutcomeTransitions, signalSchema, signalSourceSchema, standardReceiptKinds, standardReceiptPhases, standardReceiptStates, standardSignalSources, standardTaskKinds, sweepQueued, taskApprovalSchema, taskDevboxSchema, taskIdSchema, taskInitialState, taskKindSchema, taskOriginSchema, taskQuestionSchema, taskSchema, taskStateSchema, taskTransitions, terminalStates, usdSchema, vocabularySchema };
243
+ export { AdoptPullRequestInput, AppendReceiptInput, ApprovalDecision, ApprovalError, ApprovalPolicy, ApprovalRule, ApprovalSubject, Budget, Change, ChangeAssociationError, ChangeEvidence, ChangeId, ChangePatch, ChangeState, ChangeTransitionOptions, CollectionName, CoordinationPlan, CoordinationReconciliation, Cost, CreateChangeInput, CreateCoordinationInput, CreateSignalInput, CreateStoresOptions, CreateTaskInput, DEFAULT_MAX_LAUNCH_ATTEMPTS, DecideSignalOptions, DispatchOptions, DispatchRefusedError, FactoryConfig, FactoryConfigInput, FactoryId, FactoryStores, Finding, FindingCategory, FindingPriority, FindingVerification, HealthColor, HealthOptions, InvalidTransitionError, LedgerMetrics, LedgerRows, Level, MetricsOptions, Receipt, ReceiptId, ReceiptKind, ReceiptPhase, ReceiptState, ReconcileCoordinationOptions, RecordExistsError, RecordNotFoundError, ReplyTo, Repository, RepositoryHealth, RepositoryId, RepositorySlug, ReviewBucket, SCHEMA_VERSION, Signal, SignalCreator, SignalId, SignalOutcome, SignalSource, StoreDriver, StoredEntry, StoredRecord, SweepOptions, SweepResult, Task, TaskApproval, TaskId, TaskKind, TaskLauncher, TaskPatch, TaskState, TaskTransitionOptions, Transition, TransitionActor, VersionConflictError, adoptPullRequest, approvalPolicySchema, approvalRuleSchema, assertTransition, budgetMonthSchema, budgetSchema, changeEvidenceSchema, changeIdSchema, changeInitialState, changeSchema, changeStateSchema, changeTransitions, computeLedgerMetrics, computeRepositoryHealth, coordinationRepositoryIdsSchema, costSchema, createCoordination, createInMemoryDriver, createSignalCreator, createStores, defaultApprovalPolicy, defineFactory, dispatchTask, factoryConfigRepositorySchema, factoryConfigSchema, factoryIdSchema, findingCategorySchema, findingFingerprint, findingForTask, findingPrioritySchema, findingSchema, findingVerificationLevelSchema, findingVerificationMethodSchema, findingVerificationSchema, fixBrief, harnessSchema, isTransitionAllowed, isoDateTimeSchema, legalNextStates, levelSchema, receiptIdSchema, receiptKindSchema, receiptPhaseSchema, receiptSchema, receiptStateSchema, reconcileCoordination, replyToSchema, repositoryIdSchema, repositoryIdsSchema, repositorySchema, repositorySlugSchema, requiresApproval, reviewBucket, scanBrief, schemaVersionSchema, signalIdSchema, signalInitialOutcome, signalOutcomeSchema, signalOutcomeTransitions, signalSchema, signalSourceSchema, standardReceiptKinds, standardReceiptPhases, standardReceiptStates, standardSignalSources, standardTaskKinds, sweepQueued, taskApprovalSchema, taskDevboxSchema, taskExecutionRepositoryIdsSchema, taskIdSchema, taskInitialState, taskKindSchema, taskOriginSchema, taskQuestionSchema, taskSchema, taskStateSchema, taskTransitions, terminalStates, usdSchema, vocabularySchema };
143
244
  //# sourceMappingURL=index.d.mts.map