@mastra/factory 0.8.0-alpha.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +630 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +41 -3
- package/dist/factory.js.map +1 -1
- package/dist/integrations/base.d.ts +8 -0
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/github/app-identity.d.ts +43 -0
- package/dist/integrations/github/app-identity.d.ts.map +1 -0
- package/dist/integrations/github/app-identity.js +62 -0
- package/dist/integrations/github/app-identity.js.map +1 -0
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +3 -1
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts +5 -0
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js +7 -0
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +11 -6
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts +8 -0
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +30 -8
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +39 -6
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +48 -14
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/webhook.d.ts +20 -0
- package/dist/integrations/github/webhook.d.ts.map +1 -1
- package/dist/integrations/github/webhook.js +32 -5
- package/dist/integrations/github/webhook.js.map +1 -1
- package/dist/integrations/linear/rules.d.ts.map +1 -1
- package/dist/integrations/linear/rules.js +2 -1
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts +11 -0
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +53 -14
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts +7 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +40 -4
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/slack/slack.d.ts.map +1 -1
- package/dist/integrations/slack/slack.js +2 -1
- package/dist/integrations/slack/slack.js.map +1 -1
- package/dist/routes/config.d.ts +12 -6
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +97 -56
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/knowledge.d.ts +152 -0
- package/dist/routes/knowledge.d.ts.map +1 -0
- package/dist/routes/knowledge.js +442 -0
- package/dist/routes/knowledge.js.map +1 -0
- package/dist/routes/projects.d.ts +9 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +8 -0
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/surface.d.ts +6 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +9 -0
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +3 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.d.ts.map +1 -1
- package/dist/rules/binding-context.js +4 -1
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/defaults.d.ts.map +1 -1
- package/dist/rules/defaults.js +87 -4
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +6 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +118 -16
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +20 -7
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/resolve.d.ts +1 -0
- package/dist/rules/resolve.d.ts.map +1 -1
- package/dist/rules/resolve.js +3 -2
- package/dist/rules/resolve.js.map +1 -1
- package/dist/rules/start-coordinator.d.ts +2 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +3 -1
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts +23 -0
- package/dist/rules/terminal-cleanup.d.ts.map +1 -0
- package/dist/rules/terminal-cleanup.js +43 -0
- package/dist/rules/terminal-cleanup.js.map +1 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +24 -2
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +3 -0
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +10 -6
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +32 -3
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +2 -0
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.d.ts.map +1 -1
- package/dist/rules/validation.js +8 -3
- package/dist/rules/validation.js.map +1 -1
- package/dist/sandbox/base-checkpoint-triggers.d.ts +77 -0
- package/dist/sandbox/base-checkpoint-triggers.d.ts.map +1 -0
- package/dist/sandbox/base-checkpoint-triggers.js +137 -0
- package/dist/sandbox/base-checkpoint-triggers.js.map +1 -0
- package/dist/sandbox/base-checkpoint.d.ts +59 -0
- package/dist/sandbox/base-checkpoint.d.ts.map +1 -0
- package/dist/sandbox/base-checkpoint.js +145 -0
- package/dist/sandbox/base-checkpoint.js.map +1 -0
- package/dist/sandbox/fleet.d.ts +32 -0
- package/dist/sandbox/fleet.d.ts.map +1 -1
- package/dist/sandbox/fleet.js +39 -10
- package/dist/sandbox/fleet.js.map +1 -1
- package/dist/session/checkpoint-capture.d.ts +3 -2
- package/dist/session/checkpoint-capture.d.ts.map +1 -1
- package/dist/session/checkpoint-capture.js +3 -3
- package/dist/session/checkpoint-capture.js.map +1 -1
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +2 -1
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/model-pack-hydration.d.ts +55 -0
- package/dist/session/model-pack-hydration.d.ts.map +1 -0
- package/dist/session/model-pack-hydration.js +56 -0
- package/dist/session/model-pack-hydration.js.map +1 -0
- package/dist/skills/service.d.ts +9 -0
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +10 -1
- package/dist/skills/service.js.map +1 -1
- package/dist/storage/domains/model-packs/base.d.ts +26 -0
- package/dist/storage/domains/model-packs/base.d.ts.map +1 -1
- package/dist/storage/domains/model-packs/base.js +102 -13
- package/dist/storage/domains/model-packs/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +47 -1
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +78 -19
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +11 -3
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +10 -1
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +67 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +140 -12
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/workspace.d.ts +31 -2
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +225 -54
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-plan/SKILL.md +1 -1
- package/factory-skills/factory-rereview/SKILL.md +3 -3
- package/factory-skills/factory-review/SKILL.md +3 -3
- package/factory-skills/factory-triage/SKILL.md +2 -0
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,EAGV,MAAM,EAKP,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAKV,cAAc,EACf,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createGithubSubscriptionTools, parseCreatedPullRequest, subscribeCurrentSessionToPullRequest } from "./session-subscriptions.js";
|
|
2
|
+
import { withBaseCheckpointWebhookTrigger } from "../../sandbox/base-checkpoint-triggers.js";
|
|
2
3
|
import { attachGithubReconciler, attachGithubRules } from "./rules.js";
|
|
3
4
|
import { attachGithubIssueReconciler } from "./issue-reconciler.js";
|
|
4
5
|
import { reconcileInterval, reconciliationEnabled } from "./reconciliation-config.js";
|
|
@@ -931,7 +932,7 @@ var GithubIntegration = class {
|
|
|
931
932
|
*/
|
|
932
933
|
routes(ctx) {
|
|
933
934
|
this.#storage = ctx.storage;
|
|
934
|
-
const ingestFactoryEvent = attachGithubRules(this, ctx);
|
|
935
|
+
const ingestFactoryEvent = withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints);
|
|
935
936
|
return buildGithubRoutes({
|
|
936
937
|
github: this,
|
|
937
938
|
auth: ctx.auth,
|
|
@@ -964,6 +965,7 @@ var GithubIntegration = class {
|
|
|
964
965
|
...reconcile ? { reconcile } : {},
|
|
965
966
|
...issues ? { reconcileIssues: issues } : {},
|
|
966
967
|
sourceControl: ctx.storage.sourceControl,
|
|
968
|
+
...ctx.baseCheckpoints ? { sweepBaseCheckpoints: () => ctx.baseCheckpoints.sweep() } : {},
|
|
967
969
|
...intervalMs ? { intervalMs } : {},
|
|
968
970
|
...issueIntervalMs ? { issueIntervalMs } : {}
|
|
969
971
|
})];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","names":["#resolveIntakeDispatch","#listIntakeIssues","#getIntakeIssue","#createIntakeComment","#updateIntakeIssue","#sourceControlStorage","#listPullRequests","#getPullRequest","#createPullRequest","#updatePullRequest","#closePullRequest","#mergePullRequest","#listComments","#createComment","#updateComment","#deleteComment","#listReviews","#getReview","#createReview","#updateReview","#submitReview","#dismissReview","#deletePendingReview","#listReviewComments","#createReviewComment","#updateReviewComment","#deleteReviewComment","#listRequestedReviewers","#requestReviewers","#removeReviewers","#appId","#privateKey","#clientId","#clientSecret","#slug","#webhookSecret","#authorizedBots","#storage","#appAuth","#repositoryClient"],"sources":["../../../src/integrations/github/integration.ts"],"sourcesContent":["/**\n * `GithubIntegration` — the injectable GitHub App integration for the web\n * factory.\n *\n * The deploy entry (`src/mastra/index.ts`) reads the `GITHUB_APP_*` env vars\n * once, constructs an instance, and passes it to `MastraFactory` (the same\n * dependency-injection pattern as the auth adapter and the sandbox machine).\n * The factory seeds it into the runtime-config registry for the feature gate\n * (`./config.ts`) and hands the instance to every consumer explicitly — route\n * handlers receive it through `routes()`, the webhook fan-out and session\n * subscription tools through their deps.\n *\n * The class owns:\n * - the GitHub App credentials (validated + PEM-normalized at construction),\n * - every GitHub API operation the web surface performs (Octokit factories,\n * token minting, installation/repo/issue/PR listings, OAuth exchange),\n * - the webhook secret used to verify GitHub webhook deliveries,\n * - its own HTTP surface: `routes()` returns the `/web/github/*` +\n * `/auth/github/*` Mastra `apiRoutes`.\n *\n * A custom integration (different app per tenant, custom Octokit config) can\n * subclass this and override individual methods — everything downstream only\n * talks to the instance.\n */\n\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport { createAppAuth } from '@octokit/auth-app';\nimport { Octokit } from '@octokit/rest';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n GetIntakeIssueInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n ListIntakeIssuesInput,\n UpdateIntakeIssueInput,\n} from '../../capabilities/intake.js';\nimport type {\n PullRequest,\n PullRequestComment,\n Review,\n ReviewComment,\n VersionControl,\n} from '../../capabilities/version-control.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../base.js';\nimport { attachGithubIssueReconciler } from './issue-reconciler.js';\nimport { GithubReconcileWorker } from './reconcile-worker.js';\nimport { reconcileInterval, reconciliationEnabled } from './reconciliation-config.js';\nimport { buildGithubRoutes } from './routes.js';\nimport { attachGithubReconciler, attachGithubRules } from './rules.js';\nimport type { ReconcileIssueState, ReconcilePullRequestState } from './rules.js';\nimport {\n createGithubSubscriptionTools,\n parseCreatedPullRequest,\n subscribeCurrentSessionToPullRequest,\n} from './session-subscriptions.js';\nimport type { GithubSubscriptionStorage } from './subscriptions.js';\n\ntype InputOf<TMethod extends keyof VersionControl> = VersionControl[TMethod] extends (input: infer TInput) => unknown\n ? TInput\n : never;\n\n/**\n * Normalize a PEM private key supplied via env. Env tooling tends to mangle\n * multi-line PEMs, so two single-line forms are supported:\n * - `\\n`-escaped: literal `\\n` sequences become real newlines\n * - fully flattened: newlines stripped entirely — the PEM is rebuilt by\n * re-wrapping the base64 body (Node's decoder rejects header/body/footer\n * on one line with `error:1E08010C:DECODER routines::unsupported`)\n */\nexport function normalizePrivateKey(raw: string): string {\n const key = raw.replace(/\\\\n/g, '\\n');\n if (key.includes('\\n')) return key;\n const flattened = key.trim().match(/^(-----BEGIN [A-Z0-9 ]+-----)\\s*(.+?)\\s*(-----END [A-Z0-9 ]+-----)$/);\n if (!flattened) return key;\n const body = flattened[2]!.replace(/\\s+/g, '');\n return `${flattened[1]}\\n${body.match(/.{1,64}/g)!.join('\\n')}\\n${flattened[3]}\\n`;\n}\n\nexport interface UserInstallation {\n installationId: number;\n accountLogin: string | null;\n accountType: string | null;\n}\n\nexport interface RepoSummary {\n id: number;\n fullName: string;\n name: string;\n owner: string;\n defaultBranch: string;\n private: boolean;\n installationId: number;\n}\n\nexport type GithubRepositoryPermission = 'admin' | 'maintain' | 'write' | 'triage' | 'read' | 'none';\n\nexport interface IssueSummary {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignees: string[];\n labels: string[];\n comments: number;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Page size for issue/PR listings; one GitHub API call per page. */\nexport const LIST_PAGE_SIZE = 30;\n\nexport interface IssuePage {\n issues: IssueSummary[];\n /** Next page number to request, or `null` when this was the last page. */\n nextPage: number | null;\n}\n\nexport interface ListRepoOpenIssuesOptions {\n label?: string;\n}\n\nexport interface GithubIntegrationConfig {\n /** GitHub App id (the numeric id, as a string). */\n appId: string;\n /**\n * App private key (PEM). Multi-line, `\\n`-escaped, and fully flattened\n * single-line forms are all accepted (normalized at construction).\n */\n privateKey: string;\n /** OAuth client id of the GitHub App. */\n clientId: string;\n /** OAuth client secret of the GitHub App. */\n clientSecret: string;\n /** App slug — the URL name used to build the install URL. */\n slug: string;\n /**\n * Secret GitHub uses to sign webhook deliveries. Omitted → webhook\n * signature verification rejects all deliveries. Also serves as the default\n * replica-stable OAuth/install `state` secret (see `./config.ts`).\n */\n webhookSecret?: string;\n /**\n * Extra bot logins authorized to trigger author-gated PR notifications\n * (reviews and comments). Merged over the built-in defaults, matched\n * case-insensitively. Deployments running their own reviewer bots opt them\n * in here; every other bot stays gated.\n */\n authorizedBots?: string[];\n}\n\n/** Human-readable names of the required config fields, for construction errors. */\nconst REQUIRED_FIELDS = ['appId', 'privateKey', 'clientId', 'clientSecret', 'slug'] as const;\n\nexport class GithubIntegration implements FactoryIntegration {\n /** Stable integration identifier (see `../factory-integration.ts`). */\n readonly id = 'github';\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async ({ orgId }) => {\n const installations = await this.sourceControlStorage.installations.list({ orgId });\n const repositories = await Promise.all(\n installations.map(installation =>\n this.sourceControlStorage.repositories.list({ orgId, installationId: installation.id }),\n ),\n );\n return repositories.flat().map(repository => ({\n id: repository.id,\n name: repository.slug,\n type: 'repository',\n metadata: { defaultBranch: repository.defaultBranch },\n }));\n },\n listItems: async ({ orgId, sourceIds, cursor }) => {\n const page = cursor ? Number.parseInt(cursor, 10) : 1;\n const requestedPage = Number.isSafeInteger(page) && page > 0 ? page : 1;\n const pages = await Promise.all(\n sourceIds.map(async sourceId => {\n const repository = await this.sourceControlStorage.repositories.get({ orgId, id: sourceId });\n if (!repository) return { items: [], hasNextPage: false };\n const installation = await this.sourceControlStorage.installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) return { items: [], hasNextPage: false };\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) return { items: [], hasNextPage: false };\n const [issues, pullRequests] = await Promise.all([\n this.listRepoOpenIssues(installationId, repository.slug, requestedPage),\n this.versionControl.listPullRequests({\n connection: { type: 'app-installation', installationId },\n sourceId: repository.slug,\n includeDrafts: false,\n cursor: String(requestedPage),\n }),\n ]);\n return {\n items: [\n ...issues.issues.map(issue => ({\n source: { type: 'issue', externalId: `${repository.externalId}:${issue.number}`, url: issue.url },\n sourceId: repository.id,\n title: issue.title,\n status: 'open',\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: { repository: repository.slug, number: issue.number, author: issue.author },\n })),\n ...pullRequests.pullRequests.map(pullRequest => ({\n source: {\n type: 'pull-request',\n externalId: `${repository.externalId}:${pullRequest.id}`,\n url: pullRequest.url,\n },\n sourceId: repository.id,\n title: pullRequest.title,\n status: 'open',\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n metadata: {\n repository: repository.slug,\n number: Number(pullRequest.id),\n author: pullRequest.author,\n baseBranch: pullRequest.baseBranch,\n headBranch: pullRequest.headBranch,\n },\n })),\n ],\n hasNextPage: issues.nextPage !== null || pullRequests.nextCursor !== null,\n };\n }),\n );\n return {\n items: pages.flatMap(result => result.items),\n nextCursor: pages.some(result => result.hasNextPage) ? String(requestedPage + 1) : null,\n };\n },\n listIssues: input => this.#listIntakeIssues(input),\n getIssue: input => this.#getIntakeIssue(input),\n createComment: input => this.#createIntakeComment(input),\n updateIssue: input => this.#updateIntakeIssue(input),\n };\n readonly versionControl: VersionControl = {\n initialize: ({ storage }) => {\n this.#sourceControlStorage = storage;\n },\n registerInstallation: ({ orgId, userId, installation }) =>\n this.sourceControlStorage.installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: installation.externalId,\n accountName: installation.accountName,\n accountType: installation.accountType,\n providerMetadata: installation.metadata,\n }),\n registerRepositories: ({ orgId, installationId, repositories }) =>\n Promise.all(\n repositories.map(repository =>\n this.sourceControlStorage.repositories.upsert({\n orgId,\n input: {\n installationId,\n externalId: repository.externalId,\n slug: repository.slug,\n defaultBranch: repository.defaultBranch,\n providerMetadata: repository.metadata,\n },\n }),\n ),\n ),\n getRepositoryAccess: async ({ orgId, repositoryId }) => {\n const repository = await this.sourceControlStorage.repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await this.sourceControlStorage.installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) throw new Error('GitHub installation id is invalid.');\n return {\n cloneUrl: `https://github.com/${repository.slug}.git`,\n authorization: { scheme: 'bearer', token: await this.mintInstallationToken(installationId) },\n };\n },\n listPullRequests: input => this.#listPullRequests(input),\n getPullRequest: input => this.#getPullRequest(input),\n createPullRequest: input => this.#createPullRequest(input),\n updatePullRequest: input => this.#updatePullRequest(input),\n closePullRequest: input => this.#closePullRequest(input),\n mergePullRequest: input => this.#mergePullRequest(input),\n listComments: input => this.#listComments(input),\n createComment: input => this.#createComment(input),\n updateComment: input => this.#updateComment(input),\n deleteComment: input => this.#deleteComment(input),\n listReviews: input => this.#listReviews(input),\n getReview: input => this.#getReview(input),\n createReview: input => this.#createReview(input),\n updateReview: input => this.#updateReview(input),\n submitReview: input => this.#submitReview(input),\n dismissReview: input => this.#dismissReview(input),\n deletePendingReview: input => this.#deletePendingReview(input),\n listReviewComments: input => this.#listReviewComments(input),\n createReviewComment: input => this.#createReviewComment(input),\n updateReviewComment: input => this.#updateReviewComment(input),\n deleteReviewComment: input => this.#deleteReviewComment(input),\n listRequestedReviewers: input => this.#listRequestedReviewers(input),\n requestReviewers: input => this.#requestReviewers(input),\n removeRequestedReviewers: input => this.#removeReviewers(input),\n };\n /**\n * The OAuth/install flow round-trips a signed `state` through GitHub, so a\n * multi-replica deploy needs a deployment-stable state secret.\n */\n readonly requiresStableStateSigner = true;\n\n readonly #appId: string;\n readonly #privateKey: string;\n readonly #clientId: string;\n readonly #clientSecret: string;\n readonly #slug: string;\n readonly #webhookSecret: string | undefined;\n readonly #authorizedBots: readonly string[];\n #storage: IntegrationContext['storage'] | undefined;\n #sourceControlStorage: IntegrationContext['storage']['sourceControl'] | undefined;\n\n constructor(config: GithubIntegrationConfig) {\n const missing = REQUIRED_FIELDS.filter(field => !config[field]);\n if (missing.length > 0) {\n throw new Error(\n `GithubIntegration: missing required config field(s): ${missing.join(', ')}. ` +\n `Provide the full GitHub App credentials (appId, privateKey, clientId, clientSecret, slug) ` +\n `or omit the integration to disable GitHub-backed repositories.`,\n );\n }\n this.#appId = config.appId;\n this.#privateKey = normalizePrivateKey(config.privateKey);\n this.#clientId = config.clientId;\n this.#clientSecret = config.clientSecret;\n this.#slug = config.slug;\n this.#webhookSecret = config.webhookSecret || undefined;\n this.#authorizedBots = (config.authorizedBots ?? []).map(bot => bot.trim()).filter(Boolean);\n }\n\n /** App slug — the URL name used to build the install URL. */\n get slug(): string {\n return this.#slug;\n }\n\n /** Extra bot logins authorized to trigger author-gated PR notifications. */\n get authorizedBots(): readonly string[] {\n return this.#authorizedBots;\n }\n\n get genericStorage(): IntegrationContext['storage']['generic'] {\n if (!this.#storage) throw new Error('GithubIntegration storage has not been initialized.');\n return this.#storage.generic;\n }\n\n get sourceControlStorage(): IntegrationContext['storage']['sourceControl'] {\n const storage = this.#sourceControlStorage ?? this.#storage?.sourceControl;\n if (!storage) throw new Error('GithubIntegration source-control storage has not been initialized.');\n return storage;\n }\n\n get integrationStorage(): GithubSubscriptionStorage {\n if (!this.#storage) throw new Error('GithubIntegration storage has not been initialized.');\n return this.#storage.generic as unknown as GithubSubscriptionStorage;\n }\n\n /** Resolve a stored GitHub locator without scanning installations or repositories. */\n async #resolveIntakeDispatch({\n orgId,\n externalSource,\n }: {\n orgId: string;\n externalSource: { type: string; externalId: string };\n }): Promise<{ connection: IntegrationConnection; sourceId: string; issueId: string } | null> {\n const target = parseGithubExternalTarget(externalSource.externalId);\n if (!target) return null;\n const repository = await this.sourceControlStorage.repositories.findByExternalId({\n orgId,\n externalId: target.repositoryId,\n });\n if (!repository) return null;\n const installation = await this.sourceControlStorage.installations.get({ orgId, id: repository.installationId });\n if (!installation) return null;\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) return null;\n return {\n connection: { type: 'app-installation', installationId },\n sourceId: repository.slug,\n issueId: target.issueId,\n };\n }\n\n /** Secret GitHub uses to sign webhook deliveries, when configured. */\n get webhookSecret(): string | undefined {\n return this.#webhookSecret;\n }\n\n #appAuth() {\n return {\n appId: this.#appId,\n privateKey: this.#privateKey,\n clientId: this.#clientId,\n clientSecret: this.#clientSecret,\n };\n }\n\n /**\n * Octokit authenticated as the GitHub App itself (app JWT). Used for\n * app-level operations and to mint installation tokens.\n */\n getAppOctokit(): Octokit {\n return new Octokit({ authStrategy: createAppAuth, auth: this.#appAuth() });\n }\n\n /**\n * Octokit authenticated as a specific installation (installation access\n * token). Used to list repos and to operate on a repo on the user's behalf.\n */\n getInstallationOctokit(installationId: number): Octokit {\n return new Octokit({ authStrategy: createAppAuth, auth: { ...this.#appAuth(), installationId } });\n }\n\n /** Octokit authenticated as a user via their OAuth token (the identify step). */\n getUserOctokit(userToken: string): Octokit {\n return new Octokit({ auth: userToken });\n }\n\n /**\n * Mint a short-lived installation access token. Returned token is used only\n * server-side / inside the sandbox clone URL and never sent to the browser.\n */\n async mintInstallationToken(installationId: number): Promise<string> {\n const auth = createAppAuth(this.#appAuth());\n const installationAuth = await auth({ type: 'installation', installationId });\n return installationAuth.token;\n }\n\n /**\n * List the installations the authenticated user can access, via their OAuth\n * token (`GET /user/installations`).\n */\n async listUserInstallations(userToken: string): Promise<UserInstallation[]> {\n const octokit = this.getUserOctokit(userToken);\n const installations = await octokit.paginate(octokit.apps.listInstallationsForAuthenticatedUser, {\n per_page: 100,\n });\n return installations.map(inst => ({\n installationId: inst.id,\n accountLogin: inst.account && 'login' in inst.account ? inst.account.login : null,\n accountType: inst.account && 'type' in inst.account ? inst.account.type : null,\n }));\n }\n\n /** List repos accessible to an installation (paginated). */\n async listInstallationRepos(installationId: number): Promise<RepoSummary[]> {\n const octokit = this.getInstallationOctokit(installationId);\n const repos = await octokit.paginate(octokit.apps.listReposAccessibleToInstallation, {\n per_page: 100,\n });\n return repos.map(repo => ({\n id: repo.id,\n fullName: repo.full_name,\n name: repo.name,\n owner: repo.owner.login,\n defaultBranch: repo.default_branch,\n private: repo.private,\n installationId,\n }));\n }\n\n /**\n * The authenticated user's permission level on a repo, through the\n * installation. `undefined` when the repo/user is not accessible.\n */\n async getRepositoryCollaboratorPermission(\n installationId: number,\n repoFullName: string,\n username: string,\n signal?: AbortSignal,\n ): Promise<GithubRepositoryPermission | undefined> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return undefined;\n try {\n const { data } = await this.getInstallationOctokit(installationId).repos.getCollaboratorPermissionLevel({\n ...parts,\n username,\n request: { signal },\n });\n return data.permission as GithubRepositoryPermission;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Fetch a single repo's metadata through an installation token and confirm\n * the installation actually has access to it. Returns `null` when the repo\n * is not accessible to the installation (so a client can't create a project\n * for an arbitrary repo under an installation id it merely owns).\n */\n async getInstallationRepo(installationId: number, repoFullName: string): Promise<RepoSummary | null> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const { data } = await octokit.repos.get(parts);\n return {\n id: data.id,\n fullName: data.full_name,\n name: data.name,\n owner: data.owner.login,\n defaultBranch: data.default_branch,\n private: data.private,\n installationId,\n };\n } catch {\n return null;\n }\n }\n\n async #listIntakeIssues(input: ListIntakeIssuesInput): Promise<{ issues: IntakeIssue[]; nextCursor: string | null }> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = getSingleSourceId(input.sourceIds, 'GitHub Intake requires exactly one repository source.');\n const page = parsePositiveCursor(input.cursor);\n const labels = normalizeLabels(input.labels);\n const result = await this.listRepoOpenIssues(installationId, repoFullName, page, {\n label: labels.length > 0 ? labels.join(',') : undefined,\n });\n return {\n issues: result.issues.map(issue => ({\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.url,\n author: issue.author,\n state: 'open',\n stateType: 'open',\n priority: null,\n assignee: issue.assignees[0] ?? null,\n assignees: issue.assignees,\n source: repoFullName,\n labels: issue.labels,\n commentCount: issue.comments,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n })),\n nextCursor: result.nextPage === null ? null : String(result.nextPage),\n };\n }\n\n async #getIntakeIssue(input: GetIntakeIssueInput): Promise<IntakeIssueDetail | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const [{ data: issue }, comments] = await Promise.all([\n octokit.issues.get({ owner: parts.owner, repo: parts.repo, issue_number: issueNumber }),\n octokit.paginate(octokit.issues.listComments, {\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n per_page: 100,\n }),\n ]);\n if (issue.pull_request) return null;\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignee?.login ?? null,\n assignees: (issue.assignees ?? []).map(user => user.login).filter((login): login is string => Boolean(login)),\n source: repoFullName,\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n commentCount: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n description: issue.body?.trim() ? issue.body : null,\n comments: comments.map(comment => ({\n author: comment.user?.login ?? null,\n body: comment.body ?? '',\n createdAt: comment.created_at,\n })),\n };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #updateIntakeIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n // GitHub has no custom workflow states; only open/closed. `byName` is a\n // no-op with a warn log.\n if (input.state.kind === 'byName') {\n console.warn(`GitHub integration: updateIssue byName is not supported (name=${input.state.name}); ignoring.`);\n return null;\n }\n const targetState: 'open' | 'closed' =\n input.state.stateType === 'unstarted' || input.state.stateType === 'started' ? 'open' : 'closed';\n const stateReason: 'completed' | 'not_planned' | null =\n targetState === 'closed' ? (input.state.stateType === 'canceled' ? 'not_planned' : 'completed') : null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n // Pre-flight: Factory does not close pull requests via `updateIssue`.\n // PR merges/closes belong to the version-control pipeline.\n const { data: current } = await octokit.issues.get({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n });\n if (current.pull_request) {\n console.warn(\n `GitHub integration: updateIssue rejected — target ${repoFullName}#${issueNumber} is a pull request.`,\n );\n return null;\n }\n const { data: issue } = await octokit.issues.update({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n state: targetState,\n ...(stateReason ? { state_reason: stateReason } : {}),\n });\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignee?.login ?? null,\n assignees: (issue.assignees ?? []).map(user => user.login).filter((login): login is string => Boolean(login)),\n source: repoFullName,\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n commentCount: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createIntakeComment(input: CreateIntakeCommentInput): Promise<{ id: string; url: string } | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const { data } = await octokit.issues.createComment({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n body: input.body,\n });\n return { id: String(data.id), url: data.html_url };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n #repositoryClient(connection: IntegrationConnection, sourceId: string) {\n const installationId = getGithubInstallationId(connection);\n const parts = splitRepoFullName(sourceId);\n if (!parts) throw new Error('GitHub pull requests require an owner/repository source.');\n return { octokit: this.getInstallationOctokit(installationId), parts };\n }\n\n async #listPullRequests(input: InputOf<'listPullRequests'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.list({\n ...parts,\n state: input.state ?? 'open',\n per_page: LIST_PAGE_SIZE,\n page,\n });\n const pullRequests = response.data\n .filter(pr => input.includeDrafts !== false || !pr.draft)\n .map(pr => parsePullRequest(pr));\n return {\n pullRequests,\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getPullRequest(input: InputOf<'getPullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const pullNumber = requirePullRequestNumber(input.pullRequestId);\n try {\n const { data } = await octokit.pulls.get({ ...parts, pull_number: pullNumber });\n return parsePullRequest(data);\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createPullRequest(input: InputOf<'createPullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.create({\n ...parts,\n title: input.title,\n body: input.body,\n base: input.baseBranch,\n head: input.headBranch,\n draft: input.draft,\n });\n return parsePullRequest(data);\n }\n\n async #updatePullRequest(input: InputOf<'updatePullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.update({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n title: input.title,\n body: input.body === null ? '' : input.body,\n base: input.baseBranch,\n state: input.state,\n });\n return parsePullRequest(data);\n }\n\n async #closePullRequest(input: InputOf<'closePullRequest'>) {\n return this.#updatePullRequest({ ...input, state: 'closed' });\n }\n\n async #mergePullRequest(input: InputOf<'mergePullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.merge({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n commit_title: input.commitTitle,\n commit_message: input.commitMessage,\n merge_method: input.method,\n });\n return { merged: data.merged, message: data.message, sha: data.sha ?? null };\n }\n\n async #listComments(input: InputOf<'listComments'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.issues.listComments({\n ...parts,\n issue_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n comments: response.data.map(comment => parsePullRequestComment(comment)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createComment(input: InputOf<'createComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.issues.createComment({\n ...parts,\n issue_number: requirePullRequestNumber(input.pullRequestId),\n body: input.body,\n });\n return parsePullRequestComment(data);\n }\n\n async #updateComment(input: InputOf<'updateComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.issues.updateComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'comment'),\n body: input.body,\n });\n return parsePullRequestComment(data);\n }\n\n async #deleteComment(input: InputOf<'deleteComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.issues.deleteComment({ ...parts, comment_id: requirePositiveId(input.commentId, 'comment') });\n }\n\n async #listReviews(input: InputOf<'listReviews'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.listReviews({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n reviews: response.data.map(review => parseReview(review)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getReview(input: InputOf<'getReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n try {\n const { data } = await octokit.pulls.getReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n });\n return parseReview(data);\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createReview(input: InputOf<'createReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.createReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n body: input.body,\n commit_id: input.commitId,\n event: input.event ? reviewEventToGithub(input.event) : undefined,\n });\n return parseReview(data);\n }\n\n async #updateReview(input: InputOf<'updateReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.updateReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n body: input.body,\n });\n return parseReview(data);\n }\n\n async #submitReview(input: InputOf<'submitReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.submitReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n body: input.body,\n event: reviewEventToGithub(input.event),\n });\n return parseReview(data);\n }\n\n async #dismissReview(input: InputOf<'dismissReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.dismissReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n message: input.message,\n });\n return parseReview(data);\n }\n\n async #deletePendingReview(input: InputOf<'deletePendingReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.pulls.deletePendingReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n });\n }\n\n async #listReviewComments(input: InputOf<'listReviewComments'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.listReviewComments({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n comments: response.data.map(comment => parseReviewComment(comment)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createReviewComment(input: InputOf<'createReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const pullNumber = requirePullRequestNumber(input.pullRequestId);\n if (input.replyToId) {\n const { data } = await octokit.pulls.createReplyForReviewComment({\n ...parts,\n pull_number: pullNumber,\n comment_id: requirePositiveId(input.replyToId, 'review comment'),\n body: input.body,\n });\n return parseReviewComment(data);\n }\n if (!input.commitId || !input.path || input.line === undefined || !input.side) {\n throw new Error('A review comment requires commitId, path, line, and side unless it is a reply.');\n }\n if ((input.startLine === undefined) !== (input.startSide === undefined)) {\n throw new Error('A multi-line review comment requires both startLine and startSide.');\n }\n const { data } = await octokit.pulls.createReviewComment({\n ...parts,\n pull_number: pullNumber,\n body: input.body,\n commit_id: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side.toUpperCase() as 'LEFT' | 'RIGHT',\n start_line: input.startLine,\n start_side: input.startSide?.toUpperCase() as 'LEFT' | 'RIGHT' | undefined,\n });\n return parseReviewComment(data);\n }\n\n async #updateReviewComment(input: InputOf<'updateReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.updateReviewComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'review comment'),\n body: input.body,\n });\n return parseReviewComment(data);\n }\n\n async #deleteReviewComment(input: InputOf<'deleteReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.pulls.deleteReviewComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'review comment'),\n });\n }\n\n async #listRequestedReviewers(input: InputOf<'listRequestedReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.listRequestedReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n });\n return parseRequestedReviewers(data);\n }\n\n async #requestReviewers(input: InputOf<'requestReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.requestReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n reviewers: input.users ?? [],\n team_reviewers: input.teams ?? [],\n });\n return parseRequestedReviewers(data);\n }\n\n async #removeReviewers(input: InputOf<'removeRequestedReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.removeRequestedReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n reviewers: input.users ?? [],\n team_reviewers: input.teams ?? [],\n });\n return parseRequestedReviewers(data);\n }\n\n /** Add labels to an issue (deduplicated; no-op on empty/malformed input). */\n async addIssueLabels(\n installationId: number,\n repoFullName: string,\n issueNumber: number,\n labels: string[],\n ): Promise<void> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return;\n const uniqueLabels = [...new Set(labels.map(label => label.trim()).filter(Boolean))];\n if (uniqueLabels.length === 0) return;\n const octokit = this.getInstallationOctokit(installationId);\n await octokit.issues.addLabels({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n labels: uniqueLabels,\n });\n }\n\n /** Remove one label from an issue. */\n async removeIssueLabel(\n installationId: number,\n repoFullName: string,\n issueNumber: number,\n label: string,\n ): Promise<void> {\n const parts = splitRepoFullName(repoFullName);\n const labelName = label.trim();\n if (!parts || !labelName) return;\n const octokit = this.getInstallationOctokit(installationId);\n await octokit.issues.removeLabel({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n name: labelName,\n });\n }\n\n /**\n * List one page of a repo's open issues through an installation token. The\n * issues API also returns pull requests, so those are filtered out (the\n * filter can make a non-final page shorter than the page size — `nextPage`\n * is derived from the raw response length, not the filtered one).\n */\n async listRepoOpenIssues(\n installationId: number,\n repoFullName: string,\n page: number,\n options: ListRepoOpenIssuesOptions = {},\n ): Promise<IssuePage> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return { issues: [], nextPage: null };\n const octokit = this.getInstallationOctokit(installationId);\n const response = await octokit.issues.listForRepo({\n owner: parts.owner,\n repo: parts.repo,\n state: 'open',\n labels: options.label,\n per_page: LIST_PAGE_SIZE,\n page,\n });\n const issues = response.data\n .filter(issue => !issue.pull_request)\n .map(issue => ({\n number: issue.number,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n assignees: issue.assignees?.flatMap(assignee => (assignee.login ? [assignee.login] : [])) ?? [],\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n comments: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n }));\n return { issues, nextPage: response.data.length === LIST_PAGE_SIZE ? page + 1 : null };\n }\n\n /**\n * Build the GitHub App install URL. `state` is carried through the install\n * flow and validated on callback.\n */\n buildInstallUrl(state: string): string {\n const url = new URL(`https://github.com/apps/${this.#slug}/installations/new`);\n url.searchParams.set('state', state);\n return url.toString();\n }\n\n /**\n * Build the OAuth identify URL (authorize) used to confirm the user's\n * identity and obtain a user token for listing their installations.\n */\n buildOAuthIdentifyUrl(state: string, redirectUri: string): string {\n const url = new URL('https://github.com/login/oauth/authorize');\n url.searchParams.set('client_id', this.#clientId);\n url.searchParams.set('redirect_uri', redirectUri);\n url.searchParams.set('state', state);\n return url.toString();\n }\n\n /** Exchange an OAuth `code` for a user access token. */\n async exchangeOAuthCode(code: string, redirectUri: string): Promise<string> {\n const res = await fetch('https://github.com/login/oauth/access_token', {\n method: 'POST',\n signal: AbortSignal.timeout(10_000),\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify({\n client_id: this.#clientId,\n client_secret: this.#clientSecret,\n code,\n redirect_uri: redirectUri,\n }),\n });\n if (!res.ok) {\n throw new Error(`GitHub OAuth token exchange failed: ${res.status}`);\n }\n const data = (await res.json()) as { access_token?: string; error?: string; error_description?: string };\n if (!data.access_token) {\n throw new Error(\n `GitHub OAuth token exchange returned no token: ${data.error_description ?? data.error ?? 'unknown'}`,\n );\n }\n return data.access_token;\n }\n\n /**\n * The integration's HTTP surface: the `/web/github/*` + `/auth/github/*`\n * Mastra `apiRoutes` (webhook handler, install/OAuth flow, project +\n * worktree + session operations). The factory folds these into the server's\n * `apiRoutes` when the feature is ready. Handlers operate on this instance.\n */\n routes(ctx: IntegrationContext): ApiRoute[] {\n this.#storage = ctx.storage;\n const ingestFactoryEvent = attachGithubRules(this, ctx);\n return buildGithubRoutes({\n github: this,\n auth: ctx.auth,\n fleet: ctx.fleet,\n storage: ctx.factoryStorage,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n controller: ctx.controller,\n emitAudit: ctx.hooks?.emitAudit,\n projects: ctx.storage.projects,\n ingestFactoryEvent,\n sessionRetirement: ctx.sessionRetirement,\n });\n }\n\n /**\n * Pull-request and issue sweeps share a worker and lease, but can be enabled\n * and paced independently. The legacy combined controls remain the fallback.\n */\n workers(ctx: IntegrationContext): MastraWorker[] {\n const pullRequestEnabled = reconciliationEnabled(\n process.env.MASTRACODE_GITHUB_PR_RECONCILE_ENABLED,\n process.env.MASTRACODE_GITHUB_RECONCILE_ENABLED,\n );\n const issueEnabled = reconciliationEnabled(\n process.env.MASTRACODE_GITHUB_ISSUE_RECONCILE_ENABLED,\n process.env.MASTRACODE_GITHUB_RECONCILE_ENABLED,\n );\n if (!pullRequestEnabled && !issueEnabled) return [];\n\n const reconcile = pullRequestEnabled\n ? attachGithubReconciler(this, ctx, input => this.fetchPullRequestState(input))\n : undefined;\n const issues = issueEnabled ? attachGithubIssueReconciler(this, ctx, input => this.fetchIssueState(input)) : undefined;\n if (!reconcile && !issues) return [];\n\n const legacyInterval = reconcileInterval(process.env.MASTRACODE_GITHUB_RECONCILE_INTERVAL_MS);\n const intervalMs = reconcileInterval(process.env.MASTRACODE_GITHUB_PR_RECONCILE_INTERVAL_MS) ?? legacyInterval;\n const issueIntervalMs = reconcileInterval(process.env.MASTRACODE_GITHUB_ISSUE_RECONCILE_INTERVAL_MS) ?? legacyInterval;\n return [\n new GithubReconcileWorker({\n ...(reconcile ? { reconcile } : {}),\n ...(issues ? { reconcileIssues: issues } : {}),\n sourceControl: ctx.storage.sourceControl,\n ...(intervalMs ? { intervalMs } : {}),\n ...(issueIntervalMs ? { issueIntervalMs } : {}),\n }),\n ];\n }\n\n /**\n * Reads live PR state for the merge reconciler. Returns undefined when the PR\n * cannot be resolved so a sweep never fabricates a merge.\n */\n async fetchPullRequestState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcilePullRequestState | undefined> {\n try {\n const pullRequest = await this.#getPullRequest({\n connection: { type: 'app-installation', installationId: input.installationId },\n sourceId: input.repository,\n pullRequestId: String(input.number),\n });\n if (!pullRequest) return undefined;\n return {\n title: pullRequest.title,\n url: pullRequest.url,\n state: pullRequest.state === 'closed' ? 'closed' : 'open',\n draft: pullRequest.draft,\n merged: pullRequest.merged,\n assignees: pullRequest.assignees ?? [],\n requestedReviewers: pullRequest.requestedReviewers ?? [],\n labels: pullRequest.labels ?? [],\n headBranch: pullRequest.headBranch,\n baseBranch: pullRequest.baseBranch,\n ...(pullRequest.author ? { author: pullRequest.author } : {}),\n ...(pullRequest.createdAt ? { createdAt: pullRequest.createdAt } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Reads live issue state for the reconciler. Returns undefined when the\n * issue cannot be resolved (missing, is actually a PR, API error) so a\n * sweep never fabricates a close.\n */\n async fetchIssueState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcileIssueState | undefined> {\n const parts = splitRepoFullName(input.repository);\n if (!parts) return undefined;\n try {\n const octokit = this.getInstallationOctokit(input.installationId);\n const { data: issue } = await octokit.issues.get({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: input.number,\n });\n if (issue.pull_request) return undefined;\n return {\n title: issue.title,\n url: issue.html_url,\n state: issue.state === 'closed' ? 'closed' : 'open',\n ...(issue.state_reason ? { stateReason: issue.state_reason } : {}),\n assignees: (issue.assignees ?? [])\n .map(user => user.login)\n .filter((login): login is string => Boolean(login)),\n labels: (issue.labels ?? [])\n .map(label => (typeof label === 'string' ? label : label.name))\n .filter((name): name is string => Boolean(name)),\n ...(issue.user?.login ? { author: issue.user.login } : {}),\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Session-scoped agent tools for token refresh and PR subscriptions in\n * sessions bound to a GitHub-backed project. Empty elsewhere.\n */\n sessionTools({ requestContext }: { requestContext: RequestContext }): IntegrationTools {\n return createGithubSubscriptionTools(requestContext, this);\n }\n\n async postToolObserver({\n toolContext,\n requestContext,\n }: Parameters<NonNullable<FactoryIntegration['postToolObserver']>>[0]): Promise<void> {\n const pullRequestUrl = parseCreatedPullRequest(toolContext);\n if (!pullRequestUrl || !requestContext) return;\n await subscribeCurrentSessionToPullRequest(requestContext, pullRequestUrl, 'auto-gh-pr-create', this);\n }\n\n /** Non-secret config snapshot for system diagnostics/startup logs. */\n diagnostics(): Record<string, unknown> {\n return {\n slug: this.#slug,\n webhookSecretConfigured: this.#webhookSecret !== undefined,\n };\n }\n}\n\ninterface GithubPullRequestData {\n number: number;\n title: string;\n html_url: string;\n user: { login?: string } | null;\n assignees?: Array<{ login?: string }> | null;\n requested_reviewers?: Array<{ login?: string }> | null;\n labels?: Array<{ name?: string } | string> | null;\n body?: string | null;\n state: string;\n draft?: boolean | null;\n merged?: boolean;\n merged_at?: string | null;\n mergeable?: boolean | null;\n base: { ref: string };\n head: { ref: string; sha: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GithubCommentData {\n id: number;\n html_url: string;\n user: { login?: string } | null;\n body?: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface GithubReviewData {\n id: number;\n html_url?: string;\n user: { login?: string } | null;\n body?: string | null;\n state: string;\n commit_id?: string | null;\n submitted_at?: string | null;\n}\n\ninterface GithubReviewCommentData extends GithubCommentData {\n path: string;\n line?: number | null;\n side?: string | null;\n commit_id: string;\n in_reply_to_id?: number | null;\n}\n\nfunction parsePullRequest(pr: GithubPullRequestData): PullRequest {\n return {\n id: String(pr.number),\n title: pr.title,\n url: pr.html_url,\n author: pr.user?.login ?? null,\n assignees: (pr.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n requestedReviewers: (pr.requested_reviewers ?? []).flatMap(reviewer => (reviewer.login ? [reviewer.login] : [])),\n labels: (pr.labels ?? []).flatMap(label =>\n typeof label === 'string' ? [label] : label.name ? [label.name] : [],\n ),\n body: pr.body?.trim() ? pr.body : null,\n state: pr.state === 'closed' ? 'closed' : 'open',\n draft: pr.draft ?? false,\n merged: pr.merged ?? Boolean(pr.merged_at),\n mergeable: typeof pr.mergeable === 'boolean' ? pr.mergeable : null,\n baseBranch: pr.base.ref,\n headBranch: pr.head.ref,\n headSha: pr.head.sha,\n createdAt: pr.created_at,\n updatedAt: pr.updated_at,\n };\n}\n\nfunction parsePullRequestComment(comment: GithubCommentData): PullRequestComment {\n return {\n id: String(comment.id),\n url: comment.html_url,\n author: comment.user?.login ?? null,\n body: comment.body ?? '',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n}\n\nfunction parseReview(review: GithubReviewData): Review {\n return {\n id: String(review.id),\n url: review.html_url ?? null,\n author: review.user?.login ?? null,\n body: review.body?.trim() ? review.body : null,\n state: parseReviewState(review.state),\n commitId: review.commit_id ?? null,\n submittedAt: review.submitted_at ?? null,\n };\n}\n\nfunction parseReviewComment(comment: GithubReviewCommentData): ReviewComment {\n const parsed = parsePullRequestComment(comment);\n const side = comment.side?.toLowerCase();\n return {\n ...parsed,\n path: comment.path,\n line: comment.line ?? null,\n side: side === 'left' || side === 'right' ? side : null,\n commitId: comment.commit_id,\n replyToId: comment.in_reply_to_id ? String(comment.in_reply_to_id) : null,\n };\n}\n\nfunction parseRequestedReviewers(data: {\n users?: Array<{ login?: string }> | null;\n teams?: Array<{ slug?: string }> | null;\n requested_reviewers?: Array<{ login?: string }> | null;\n requested_teams?: Array<{ slug?: string }> | null;\n}) {\n return {\n users: (data.users ?? data.requested_reviewers ?? []).flatMap(user => (user.login ? [user.login] : [])),\n teams: (data.teams ?? data.requested_teams ?? []).flatMap(team => (team.slug ? [team.slug] : [])),\n };\n}\n\nfunction parseReviewState(state: string): Review['state'] {\n if (state === 'PENDING') return 'pending';\n if (state === 'COMMENTED') return 'commented';\n if (state === 'APPROVED') return 'approved';\n if (state === 'CHANGES_REQUESTED') return 'changes-requested';\n if (state === 'DISMISSED') return 'dismissed';\n throw new Error(`Unsupported GitHub review state: ${state}`);\n}\n\nfunction reviewEventToGithub(event: Exclude<InputOf<'createReview'>['event'], undefined>) {\n if (event === 'approve') return 'APPROVE' as const;\n if (event === 'request-changes') return 'REQUEST_CHANGES' as const;\n return 'COMMENT' as const;\n}\n\nfunction requirePullRequestNumber(value: string): number {\n return requirePositiveId(value, 'pull request');\n}\n\nfunction requirePositiveId(value: string, resource: string): number {\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new Error(`GitHub ${resource} id must be a positive integer.`);\n return parsed;\n}\n\nfunction getGithubInstallationId(connection: IntegrationConnection): number {\n if (connection.type !== 'app-installation') {\n throw new Error('GitHub capabilities require an app-installation connection.');\n }\n return connection.installationId;\n}\n\nfunction getSingleSourceId(sourceIds: string[], message: string): string {\n if (sourceIds.length !== 1) throw new Error(message);\n return sourceIds[0]!;\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\nfunction requireSourceId(sourceId: string | undefined, message: string): string {\n if (!sourceId) throw new Error(message);\n return sourceId;\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const page = parsePositiveInteger(cursor);\n if (page === null) throw new Error('GitHub cursor must be a positive page number.');\n return page;\n}\n\nfunction parsePositiveInteger(value: string): number | null {\n if (!/^\\d+$/.test(value)) return null;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'status' in error && error.status === 404;\n}\n\n/** Split an `owner/name` full name into its parts, or `null` when malformed. */\nfunction splitRepoFullName(repoFullName: string): { owner: string; repo: string } | null {\n const slash = repoFullName.indexOf('/');\n if (slash <= 0 || slash === repoFullName.length - 1) return null;\n return { owner: repoFullName.slice(0, slash), repo: repoFullName.slice(slash + 1) };\n}\n\nfunction parseGithubExternalTarget(externalId: string): { repositoryId: string; issueId: string } | null {\n const match = externalId.match(/^github:(\\d+):(?:issue|pull-request):(\\d+)$/) ?? externalId.match(/^(\\d+):(\\d+)$/);\n if (!match?.[1] || !match[2]) return null;\n const repositoryId = parsePositiveInteger(match[1]);\n const issueId = parsePositiveInteger(match[2]);\n return repositoryId && issueId ? { repositoryId: String(repositoryId), issueId: String(issueId) } : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integration.js","names":["#resolveIntakeDispatch","#listIntakeIssues","#getIntakeIssue","#createIntakeComment","#updateIntakeIssue","#sourceControlStorage","#listPullRequests","#getPullRequest","#createPullRequest","#updatePullRequest","#closePullRequest","#mergePullRequest","#listComments","#createComment","#updateComment","#deleteComment","#listReviews","#getReview","#createReview","#updateReview","#submitReview","#dismissReview","#deletePendingReview","#listReviewComments","#createReviewComment","#updateReviewComment","#deleteReviewComment","#listRequestedReviewers","#requestReviewers","#removeReviewers","#appId","#privateKey","#clientId","#clientSecret","#slug","#webhookSecret","#authorizedBots","#storage","#appAuth","#repositoryClient"],"sources":["../../../src/integrations/github/integration.ts"],"sourcesContent":["/**\n * `GithubIntegration` — the injectable GitHub App integration for the web\n * factory.\n *\n * The deploy entry (`src/mastra/index.ts`) reads the `GITHUB_APP_*` env vars\n * once, constructs an instance, and passes it to `MastraFactory` (the same\n * dependency-injection pattern as the auth adapter and the sandbox machine).\n * The factory seeds it into the runtime-config registry for the feature gate\n * (`./config.ts`) and hands the instance to every consumer explicitly — route\n * handlers receive it through `routes()`, the webhook fan-out and session\n * subscription tools through their deps.\n *\n * The class owns:\n * - the GitHub App credentials (validated + PEM-normalized at construction),\n * - every GitHub API operation the web surface performs (Octokit factories,\n * token minting, installation/repo/issue/PR listings, OAuth exchange),\n * - the webhook secret used to verify GitHub webhook deliveries,\n * - its own HTTP surface: `routes()` returns the `/web/github/*` +\n * `/auth/github/*` Mastra `apiRoutes`.\n *\n * A custom integration (different app per tenant, custom Octokit config) can\n * subclass this and override individual methods — everything downstream only\n * talks to the instance.\n */\n\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport { createAppAuth } from '@octokit/auth-app';\nimport { Octokit } from '@octokit/rest';\n\nimport type { IntegrationConnection } from '../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n GetIntakeIssueInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n ListIntakeIssuesInput,\n UpdateIntakeIssueInput,\n} from '../../capabilities/intake.js';\nimport type {\n PullRequest,\n PullRequestComment,\n Review,\n ReviewComment,\n VersionControl,\n} from '../../capabilities/version-control.js';\nimport { withBaseCheckpointWebhookTrigger } from '../../sandbox/base-checkpoint-triggers.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../base.js';\nimport { attachGithubIssueReconciler } from './issue-reconciler.js';\nimport { GithubReconcileWorker } from './reconcile-worker.js';\nimport { reconcileInterval, reconciliationEnabled } from './reconciliation-config.js';\nimport { buildGithubRoutes } from './routes.js';\nimport { attachGithubReconciler, attachGithubRules } from './rules.js';\nimport type { ReconcileIssueState, ReconcilePullRequestState } from './rules.js';\nimport {\n createGithubSubscriptionTools,\n parseCreatedPullRequest,\n subscribeCurrentSessionToPullRequest,\n} from './session-subscriptions.js';\nimport type { GithubSubscriptionStorage } from './subscriptions.js';\n\ntype InputOf<TMethod extends keyof VersionControl> = VersionControl[TMethod] extends (input: infer TInput) => unknown\n ? TInput\n : never;\n\n/**\n * Normalize a PEM private key supplied via env. Env tooling tends to mangle\n * multi-line PEMs, so two single-line forms are supported:\n * - `\\n`-escaped: literal `\\n` sequences become real newlines\n * - fully flattened: newlines stripped entirely — the PEM is rebuilt by\n * re-wrapping the base64 body (Node's decoder rejects header/body/footer\n * on one line with `error:1E08010C:DECODER routines::unsupported`)\n */\nexport function normalizePrivateKey(raw: string): string {\n const key = raw.replace(/\\\\n/g, '\\n');\n if (key.includes('\\n')) return key;\n const flattened = key.trim().match(/^(-----BEGIN [A-Z0-9 ]+-----)\\s*(.+?)\\s*(-----END [A-Z0-9 ]+-----)$/);\n if (!flattened) return key;\n const body = flattened[2]!.replace(/\\s+/g, '');\n return `${flattened[1]}\\n${body.match(/.{1,64}/g)!.join('\\n')}\\n${flattened[3]}\\n`;\n}\n\nexport interface UserInstallation {\n installationId: number;\n accountLogin: string | null;\n accountType: string | null;\n}\n\nexport interface RepoSummary {\n id: number;\n fullName: string;\n name: string;\n owner: string;\n defaultBranch: string;\n private: boolean;\n installationId: number;\n}\n\nexport type GithubRepositoryPermission = 'admin' | 'maintain' | 'write' | 'triage' | 'read' | 'none';\n\nexport interface IssueSummary {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignees: string[];\n labels: string[];\n comments: number;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Page size for issue/PR listings; one GitHub API call per page. */\nexport const LIST_PAGE_SIZE = 30;\n\nexport interface IssuePage {\n issues: IssueSummary[];\n /** Next page number to request, or `null` when this was the last page. */\n nextPage: number | null;\n}\n\nexport interface ListRepoOpenIssuesOptions {\n label?: string;\n}\n\nexport interface GithubIntegrationConfig {\n /** GitHub App id (the numeric id, as a string). */\n appId: string;\n /**\n * App private key (PEM). Multi-line, `\\n`-escaped, and fully flattened\n * single-line forms are all accepted (normalized at construction).\n */\n privateKey: string;\n /** OAuth client id of the GitHub App. */\n clientId: string;\n /** OAuth client secret of the GitHub App. */\n clientSecret: string;\n /** App slug — the URL name used to build the install URL. */\n slug: string;\n /**\n * Secret GitHub uses to sign webhook deliveries. Omitted → webhook\n * signature verification rejects all deliveries. Also serves as the default\n * replica-stable OAuth/install `state` secret (see `./config.ts`).\n */\n webhookSecret?: string;\n /**\n * Extra bot logins authorized to trigger author-gated PR notifications\n * (reviews and comments). Merged over the built-in defaults, matched\n * case-insensitively. Deployments running their own reviewer bots opt them\n * in here; every other bot stays gated.\n */\n authorizedBots?: string[];\n}\n\n/** Human-readable names of the required config fields, for construction errors. */\nconst REQUIRED_FIELDS = ['appId', 'privateKey', 'clientId', 'clientSecret', 'slug'] as const;\n\nexport class GithubIntegration implements FactoryIntegration {\n /** Stable integration identifier (see `../factory-integration.ts`). */\n readonly id = 'github';\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async ({ orgId }) => {\n const installations = await this.sourceControlStorage.installations.list({ orgId });\n const repositories = await Promise.all(\n installations.map(installation =>\n this.sourceControlStorage.repositories.list({ orgId, installationId: installation.id }),\n ),\n );\n return repositories.flat().map(repository => ({\n id: repository.id,\n name: repository.slug,\n type: 'repository',\n metadata: { defaultBranch: repository.defaultBranch },\n }));\n },\n listItems: async ({ orgId, sourceIds, cursor }) => {\n const page = cursor ? Number.parseInt(cursor, 10) : 1;\n const requestedPage = Number.isSafeInteger(page) && page > 0 ? page : 1;\n const pages = await Promise.all(\n sourceIds.map(async sourceId => {\n const repository = await this.sourceControlStorage.repositories.get({ orgId, id: sourceId });\n if (!repository) return { items: [], hasNextPage: false };\n const installation = await this.sourceControlStorage.installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) return { items: [], hasNextPage: false };\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) return { items: [], hasNextPage: false };\n const [issues, pullRequests] = await Promise.all([\n this.listRepoOpenIssues(installationId, repository.slug, requestedPage),\n this.versionControl.listPullRequests({\n connection: { type: 'app-installation', installationId },\n sourceId: repository.slug,\n includeDrafts: false,\n cursor: String(requestedPage),\n }),\n ]);\n return {\n items: [\n ...issues.issues.map(issue => ({\n source: { type: 'issue', externalId: `${repository.externalId}:${issue.number}`, url: issue.url },\n sourceId: repository.id,\n title: issue.title,\n status: 'open',\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: { repository: repository.slug, number: issue.number, author: issue.author },\n })),\n ...pullRequests.pullRequests.map(pullRequest => ({\n source: {\n type: 'pull-request',\n externalId: `${repository.externalId}:${pullRequest.id}`,\n url: pullRequest.url,\n },\n sourceId: repository.id,\n title: pullRequest.title,\n status: 'open',\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n metadata: {\n repository: repository.slug,\n number: Number(pullRequest.id),\n author: pullRequest.author,\n baseBranch: pullRequest.baseBranch,\n headBranch: pullRequest.headBranch,\n },\n })),\n ],\n hasNextPage: issues.nextPage !== null || pullRequests.nextCursor !== null,\n };\n }),\n );\n return {\n items: pages.flatMap(result => result.items),\n nextCursor: pages.some(result => result.hasNextPage) ? String(requestedPage + 1) : null,\n };\n },\n listIssues: input => this.#listIntakeIssues(input),\n getIssue: input => this.#getIntakeIssue(input),\n createComment: input => this.#createIntakeComment(input),\n updateIssue: input => this.#updateIntakeIssue(input),\n };\n readonly versionControl: VersionControl = {\n initialize: ({ storage }) => {\n this.#sourceControlStorage = storage;\n },\n registerInstallation: ({ orgId, userId, installation }) =>\n this.sourceControlStorage.installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: installation.externalId,\n accountName: installation.accountName,\n accountType: installation.accountType,\n providerMetadata: installation.metadata,\n }),\n registerRepositories: ({ orgId, installationId, repositories }) =>\n Promise.all(\n repositories.map(repository =>\n this.sourceControlStorage.repositories.upsert({\n orgId,\n input: {\n installationId,\n externalId: repository.externalId,\n slug: repository.slug,\n defaultBranch: repository.defaultBranch,\n providerMetadata: repository.metadata,\n },\n }),\n ),\n ),\n getRepositoryAccess: async ({ orgId, repositoryId }) => {\n const repository = await this.sourceControlStorage.repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const installation = await this.sourceControlStorage.installations.get({\n orgId,\n id: repository.installationId,\n });\n if (!installation) throw new Error('Version-control installation not found.');\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) throw new Error('GitHub installation id is invalid.');\n return {\n cloneUrl: `https://github.com/${repository.slug}.git`,\n authorization: { scheme: 'bearer', token: await this.mintInstallationToken(installationId) },\n };\n },\n listPullRequests: input => this.#listPullRequests(input),\n getPullRequest: input => this.#getPullRequest(input),\n createPullRequest: input => this.#createPullRequest(input),\n updatePullRequest: input => this.#updatePullRequest(input),\n closePullRequest: input => this.#closePullRequest(input),\n mergePullRequest: input => this.#mergePullRequest(input),\n listComments: input => this.#listComments(input),\n createComment: input => this.#createComment(input),\n updateComment: input => this.#updateComment(input),\n deleteComment: input => this.#deleteComment(input),\n listReviews: input => this.#listReviews(input),\n getReview: input => this.#getReview(input),\n createReview: input => this.#createReview(input),\n updateReview: input => this.#updateReview(input),\n submitReview: input => this.#submitReview(input),\n dismissReview: input => this.#dismissReview(input),\n deletePendingReview: input => this.#deletePendingReview(input),\n listReviewComments: input => this.#listReviewComments(input),\n createReviewComment: input => this.#createReviewComment(input),\n updateReviewComment: input => this.#updateReviewComment(input),\n deleteReviewComment: input => this.#deleteReviewComment(input),\n listRequestedReviewers: input => this.#listRequestedReviewers(input),\n requestReviewers: input => this.#requestReviewers(input),\n removeRequestedReviewers: input => this.#removeReviewers(input),\n };\n /**\n * The OAuth/install flow round-trips a signed `state` through GitHub, so a\n * multi-replica deploy needs a deployment-stable state secret.\n */\n readonly requiresStableStateSigner = true;\n\n readonly #appId: string;\n readonly #privateKey: string;\n readonly #clientId: string;\n readonly #clientSecret: string;\n readonly #slug: string;\n readonly #webhookSecret: string | undefined;\n readonly #authorizedBots: readonly string[];\n #storage: IntegrationContext['storage'] | undefined;\n #sourceControlStorage: IntegrationContext['storage']['sourceControl'] | undefined;\n\n constructor(config: GithubIntegrationConfig) {\n const missing = REQUIRED_FIELDS.filter(field => !config[field]);\n if (missing.length > 0) {\n throw new Error(\n `GithubIntegration: missing required config field(s): ${missing.join(', ')}. ` +\n `Provide the full GitHub App credentials (appId, privateKey, clientId, clientSecret, slug) ` +\n `or omit the integration to disable GitHub-backed repositories.`,\n );\n }\n this.#appId = config.appId;\n this.#privateKey = normalizePrivateKey(config.privateKey);\n this.#clientId = config.clientId;\n this.#clientSecret = config.clientSecret;\n this.#slug = config.slug;\n this.#webhookSecret = config.webhookSecret || undefined;\n this.#authorizedBots = (config.authorizedBots ?? []).map(bot => bot.trim()).filter(Boolean);\n }\n\n /** App slug — the URL name used to build the install URL. */\n get slug(): string {\n return this.#slug;\n }\n\n /** Extra bot logins authorized to trigger author-gated PR notifications. */\n get authorizedBots(): readonly string[] {\n return this.#authorizedBots;\n }\n\n get genericStorage(): IntegrationContext['storage']['generic'] {\n if (!this.#storage) throw new Error('GithubIntegration storage has not been initialized.');\n return this.#storage.generic;\n }\n\n get sourceControlStorage(): IntegrationContext['storage']['sourceControl'] {\n const storage = this.#sourceControlStorage ?? this.#storage?.sourceControl;\n if (!storage) throw new Error('GithubIntegration source-control storage has not been initialized.');\n return storage;\n }\n\n get integrationStorage(): GithubSubscriptionStorage {\n if (!this.#storage) throw new Error('GithubIntegration storage has not been initialized.');\n return this.#storage.generic as unknown as GithubSubscriptionStorage;\n }\n\n /** Resolve a stored GitHub locator without scanning installations or repositories. */\n async #resolveIntakeDispatch({\n orgId,\n externalSource,\n }: {\n orgId: string;\n externalSource: { type: string; externalId: string };\n }): Promise<{ connection: IntegrationConnection; sourceId: string; issueId: string } | null> {\n const target = parseGithubExternalTarget(externalSource.externalId);\n if (!target) return null;\n const repository = await this.sourceControlStorage.repositories.findByExternalId({\n orgId,\n externalId: target.repositoryId,\n });\n if (!repository) return null;\n const installation = await this.sourceControlStorage.installations.get({ orgId, id: repository.installationId });\n if (!installation) return null;\n const installationId = Number.parseInt(installation.externalId, 10);\n if (!Number.isSafeInteger(installationId)) return null;\n return {\n connection: { type: 'app-installation', installationId },\n sourceId: repository.slug,\n issueId: target.issueId,\n };\n }\n\n /** Secret GitHub uses to sign webhook deliveries, when configured. */\n get webhookSecret(): string | undefined {\n return this.#webhookSecret;\n }\n\n #appAuth() {\n return {\n appId: this.#appId,\n privateKey: this.#privateKey,\n clientId: this.#clientId,\n clientSecret: this.#clientSecret,\n };\n }\n\n /**\n * Octokit authenticated as the GitHub App itself (app JWT). Used for\n * app-level operations and to mint installation tokens.\n */\n getAppOctokit(): Octokit {\n return new Octokit({ authStrategy: createAppAuth, auth: this.#appAuth() });\n }\n\n /**\n * Octokit authenticated as a specific installation (installation access\n * token). Used to list repos and to operate on a repo on the user's behalf.\n */\n getInstallationOctokit(installationId: number): Octokit {\n return new Octokit({ authStrategy: createAppAuth, auth: { ...this.#appAuth(), installationId } });\n }\n\n /** Octokit authenticated as a user via their OAuth token (the identify step). */\n getUserOctokit(userToken: string): Octokit {\n return new Octokit({ auth: userToken });\n }\n\n /**\n * Mint a short-lived installation access token. Returned token is used only\n * server-side / inside the sandbox clone URL and never sent to the browser.\n */\n async mintInstallationToken(installationId: number): Promise<string> {\n const auth = createAppAuth(this.#appAuth());\n const installationAuth = await auth({ type: 'installation', installationId });\n return installationAuth.token;\n }\n\n /**\n * List the installations the authenticated user can access, via their OAuth\n * token (`GET /user/installations`).\n */\n async listUserInstallations(userToken: string): Promise<UserInstallation[]> {\n const octokit = this.getUserOctokit(userToken);\n const installations = await octokit.paginate(octokit.apps.listInstallationsForAuthenticatedUser, {\n per_page: 100,\n });\n return installations.map(inst => ({\n installationId: inst.id,\n accountLogin: inst.account && 'login' in inst.account ? inst.account.login : null,\n accountType: inst.account && 'type' in inst.account ? inst.account.type : null,\n }));\n }\n\n /** List repos accessible to an installation (paginated). */\n async listInstallationRepos(installationId: number): Promise<RepoSummary[]> {\n const octokit = this.getInstallationOctokit(installationId);\n const repos = await octokit.paginate(octokit.apps.listReposAccessibleToInstallation, {\n per_page: 100,\n });\n return repos.map(repo => ({\n id: repo.id,\n fullName: repo.full_name,\n name: repo.name,\n owner: repo.owner.login,\n defaultBranch: repo.default_branch,\n private: repo.private,\n installationId,\n }));\n }\n\n /**\n * The authenticated user's permission level on a repo, through the\n * installation. `undefined` when the repo/user is not accessible.\n */\n async getRepositoryCollaboratorPermission(\n installationId: number,\n repoFullName: string,\n username: string,\n signal?: AbortSignal,\n ): Promise<GithubRepositoryPermission | undefined> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return undefined;\n try {\n const { data } = await this.getInstallationOctokit(installationId).repos.getCollaboratorPermissionLevel({\n ...parts,\n username,\n request: { signal },\n });\n return data.permission as GithubRepositoryPermission;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Fetch a single repo's metadata through an installation token and confirm\n * the installation actually has access to it. Returns `null` when the repo\n * is not accessible to the installation (so a client can't create a project\n * for an arbitrary repo under an installation id it merely owns).\n */\n async getInstallationRepo(installationId: number, repoFullName: string): Promise<RepoSummary | null> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const { data } = await octokit.repos.get(parts);\n return {\n id: data.id,\n fullName: data.full_name,\n name: data.name,\n owner: data.owner.login,\n defaultBranch: data.default_branch,\n private: data.private,\n installationId,\n };\n } catch {\n return null;\n }\n }\n\n async #listIntakeIssues(input: ListIntakeIssuesInput): Promise<{ issues: IntakeIssue[]; nextCursor: string | null }> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = getSingleSourceId(input.sourceIds, 'GitHub Intake requires exactly one repository source.');\n const page = parsePositiveCursor(input.cursor);\n const labels = normalizeLabels(input.labels);\n const result = await this.listRepoOpenIssues(installationId, repoFullName, page, {\n label: labels.length > 0 ? labels.join(',') : undefined,\n });\n return {\n issues: result.issues.map(issue => ({\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.url,\n author: issue.author,\n state: 'open',\n stateType: 'open',\n priority: null,\n assignee: issue.assignees[0] ?? null,\n assignees: issue.assignees,\n source: repoFullName,\n labels: issue.labels,\n commentCount: issue.comments,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n })),\n nextCursor: result.nextPage === null ? null : String(result.nextPage),\n };\n }\n\n async #getIntakeIssue(input: GetIntakeIssueInput): Promise<IntakeIssueDetail | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const [{ data: issue }, comments] = await Promise.all([\n octokit.issues.get({ owner: parts.owner, repo: parts.repo, issue_number: issueNumber }),\n octokit.paginate(octokit.issues.listComments, {\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n per_page: 100,\n }),\n ]);\n if (issue.pull_request) return null;\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignee?.login ?? null,\n assignees: (issue.assignees ?? []).map(user => user.login).filter((login): login is string => Boolean(login)),\n source: repoFullName,\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n commentCount: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n description: issue.body?.trim() ? issue.body : null,\n comments: comments.map(comment => ({\n author: comment.user?.login ?? null,\n body: comment.body ?? '',\n createdAt: comment.created_at,\n })),\n };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #updateIntakeIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n // GitHub has no custom workflow states; only open/closed. `byName` is a\n // no-op with a warn log.\n if (input.state.kind === 'byName') {\n console.warn(`GitHub integration: updateIssue byName is not supported (name=${input.state.name}); ignoring.`);\n return null;\n }\n const targetState: 'open' | 'closed' =\n input.state.stateType === 'unstarted' || input.state.stateType === 'started' ? 'open' : 'closed';\n const stateReason: 'completed' | 'not_planned' | null =\n targetState === 'closed' ? (input.state.stateType === 'canceled' ? 'not_planned' : 'completed') : null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n // Pre-flight: Factory does not close pull requests via `updateIssue`.\n // PR merges/closes belong to the version-control pipeline.\n const { data: current } = await octokit.issues.get({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n });\n if (current.pull_request) {\n console.warn(\n `GitHub integration: updateIssue rejected — target ${repoFullName}#${issueNumber} is a pull request.`,\n );\n return null;\n }\n const { data: issue } = await octokit.issues.update({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n state: targetState,\n ...(stateReason ? { state_reason: stateReason } : {}),\n });\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignee?.login ?? null,\n assignees: (issue.assignees ?? []).map(user => user.login).filter((login): login is string => Boolean(login)),\n source: repoFullName,\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n commentCount: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createIntakeComment(input: CreateIntakeCommentInput): Promise<{ id: string; url: string } | null> {\n const installationId = getGithubInstallationId(input.connection);\n const repoFullName = requireSourceId(input.sourceId, 'GitHub Intake requires a repository source.');\n const parts = splitRepoFullName(repoFullName);\n const issueNumber = parsePositiveInteger(input.issueId);\n if (!parts || issueNumber === null) return null;\n const octokit = this.getInstallationOctokit(installationId);\n try {\n const { data } = await octokit.issues.createComment({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n body: input.body,\n });\n return { id: String(data.id), url: data.html_url };\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n #repositoryClient(connection: IntegrationConnection, sourceId: string) {\n const installationId = getGithubInstallationId(connection);\n const parts = splitRepoFullName(sourceId);\n if (!parts) throw new Error('GitHub pull requests require an owner/repository source.');\n return { octokit: this.getInstallationOctokit(installationId), parts };\n }\n\n async #listPullRequests(input: InputOf<'listPullRequests'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.list({\n ...parts,\n state: input.state ?? 'open',\n per_page: LIST_PAGE_SIZE,\n page,\n });\n const pullRequests = response.data\n .filter(pr => input.includeDrafts !== false || !pr.draft)\n .map(pr => parsePullRequest(pr));\n return {\n pullRequests,\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getPullRequest(input: InputOf<'getPullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const pullNumber = requirePullRequestNumber(input.pullRequestId);\n try {\n const { data } = await octokit.pulls.get({ ...parts, pull_number: pullNumber });\n return parsePullRequest(data);\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createPullRequest(input: InputOf<'createPullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.create({\n ...parts,\n title: input.title,\n body: input.body,\n base: input.baseBranch,\n head: input.headBranch,\n draft: input.draft,\n });\n return parsePullRequest(data);\n }\n\n async #updatePullRequest(input: InputOf<'updatePullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.update({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n title: input.title,\n body: input.body === null ? '' : input.body,\n base: input.baseBranch,\n state: input.state,\n });\n return parsePullRequest(data);\n }\n\n async #closePullRequest(input: InputOf<'closePullRequest'>) {\n return this.#updatePullRequest({ ...input, state: 'closed' });\n }\n\n async #mergePullRequest(input: InputOf<'mergePullRequest'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.merge({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n commit_title: input.commitTitle,\n commit_message: input.commitMessage,\n merge_method: input.method,\n });\n return { merged: data.merged, message: data.message, sha: data.sha ?? null };\n }\n\n async #listComments(input: InputOf<'listComments'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.issues.listComments({\n ...parts,\n issue_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n comments: response.data.map(comment => parsePullRequestComment(comment)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createComment(input: InputOf<'createComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.issues.createComment({\n ...parts,\n issue_number: requirePullRequestNumber(input.pullRequestId),\n body: input.body,\n });\n return parsePullRequestComment(data);\n }\n\n async #updateComment(input: InputOf<'updateComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.issues.updateComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'comment'),\n body: input.body,\n });\n return parsePullRequestComment(data);\n }\n\n async #deleteComment(input: InputOf<'deleteComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.issues.deleteComment({ ...parts, comment_id: requirePositiveId(input.commentId, 'comment') });\n }\n\n async #listReviews(input: InputOf<'listReviews'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.listReviews({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n reviews: response.data.map(review => parseReview(review)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getReview(input: InputOf<'getReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n try {\n const { data } = await octokit.pulls.getReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n });\n return parseReview(data);\n } catch (err) {\n if (isNotFoundError(err)) return null;\n throw err;\n }\n }\n\n async #createReview(input: InputOf<'createReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.createReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n body: input.body,\n commit_id: input.commitId,\n event: input.event ? reviewEventToGithub(input.event) : undefined,\n });\n return parseReview(data);\n }\n\n async #updateReview(input: InputOf<'updateReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.updateReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n body: input.body,\n });\n return parseReview(data);\n }\n\n async #submitReview(input: InputOf<'submitReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.submitReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n body: input.body,\n event: reviewEventToGithub(input.event),\n });\n return parseReview(data);\n }\n\n async #dismissReview(input: InputOf<'dismissReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.dismissReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n message: input.message,\n });\n return parseReview(data);\n }\n\n async #deletePendingReview(input: InputOf<'deletePendingReview'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.pulls.deletePendingReview({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n review_id: requirePositiveId(input.reviewId, 'review'),\n });\n }\n\n async #listReviewComments(input: InputOf<'listReviewComments'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const page = parsePositiveCursor(input.cursor);\n const response = await octokit.pulls.listReviewComments({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n per_page: LIST_PAGE_SIZE,\n page,\n });\n return {\n comments: response.data.map(comment => parseReviewComment(comment)),\n nextCursor: response.data.length === LIST_PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createReviewComment(input: InputOf<'createReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const pullNumber = requirePullRequestNumber(input.pullRequestId);\n if (input.replyToId) {\n const { data } = await octokit.pulls.createReplyForReviewComment({\n ...parts,\n pull_number: pullNumber,\n comment_id: requirePositiveId(input.replyToId, 'review comment'),\n body: input.body,\n });\n return parseReviewComment(data);\n }\n if (!input.commitId || !input.path || input.line === undefined || !input.side) {\n throw new Error('A review comment requires commitId, path, line, and side unless it is a reply.');\n }\n if ((input.startLine === undefined) !== (input.startSide === undefined)) {\n throw new Error('A multi-line review comment requires both startLine and startSide.');\n }\n const { data } = await octokit.pulls.createReviewComment({\n ...parts,\n pull_number: pullNumber,\n body: input.body,\n commit_id: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side.toUpperCase() as 'LEFT' | 'RIGHT',\n start_line: input.startLine,\n start_side: input.startSide?.toUpperCase() as 'LEFT' | 'RIGHT' | undefined,\n });\n return parseReviewComment(data);\n }\n\n async #updateReviewComment(input: InputOf<'updateReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.updateReviewComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'review comment'),\n body: input.body,\n });\n return parseReviewComment(data);\n }\n\n async #deleteReviewComment(input: InputOf<'deleteReviewComment'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n await octokit.pulls.deleteReviewComment({\n ...parts,\n comment_id: requirePositiveId(input.commentId, 'review comment'),\n });\n }\n\n async #listRequestedReviewers(input: InputOf<'listRequestedReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.listRequestedReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n });\n return parseRequestedReviewers(data);\n }\n\n async #requestReviewers(input: InputOf<'requestReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.requestReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n reviewers: input.users ?? [],\n team_reviewers: input.teams ?? [],\n });\n return parseRequestedReviewers(data);\n }\n\n async #removeReviewers(input: InputOf<'removeRequestedReviewers'>) {\n const { octokit, parts } = this.#repositoryClient(input.connection, input.sourceId);\n const { data } = await octokit.pulls.removeRequestedReviewers({\n ...parts,\n pull_number: requirePullRequestNumber(input.pullRequestId),\n reviewers: input.users ?? [],\n team_reviewers: input.teams ?? [],\n });\n return parseRequestedReviewers(data);\n }\n\n /** Add labels to an issue (deduplicated; no-op on empty/malformed input). */\n async addIssueLabels(\n installationId: number,\n repoFullName: string,\n issueNumber: number,\n labels: string[],\n ): Promise<void> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return;\n const uniqueLabels = [...new Set(labels.map(label => label.trim()).filter(Boolean))];\n if (uniqueLabels.length === 0) return;\n const octokit = this.getInstallationOctokit(installationId);\n await octokit.issues.addLabels({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n labels: uniqueLabels,\n });\n }\n\n /** Remove one label from an issue. */\n async removeIssueLabel(\n installationId: number,\n repoFullName: string,\n issueNumber: number,\n label: string,\n ): Promise<void> {\n const parts = splitRepoFullName(repoFullName);\n const labelName = label.trim();\n if (!parts || !labelName) return;\n const octokit = this.getInstallationOctokit(installationId);\n await octokit.issues.removeLabel({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: issueNumber,\n name: labelName,\n });\n }\n\n /**\n * List one page of a repo's open issues through an installation token. The\n * issues API also returns pull requests, so those are filtered out (the\n * filter can make a non-final page shorter than the page size — `nextPage`\n * is derived from the raw response length, not the filtered one).\n */\n async listRepoOpenIssues(\n installationId: number,\n repoFullName: string,\n page: number,\n options: ListRepoOpenIssuesOptions = {},\n ): Promise<IssuePage> {\n const parts = splitRepoFullName(repoFullName);\n if (!parts) return { issues: [], nextPage: null };\n const octokit = this.getInstallationOctokit(installationId);\n const response = await octokit.issues.listForRepo({\n owner: parts.owner,\n repo: parts.repo,\n state: 'open',\n labels: options.label,\n per_page: LIST_PAGE_SIZE,\n page,\n });\n const issues = response.data\n .filter(issue => !issue.pull_request)\n .map(issue => ({\n number: issue.number,\n title: issue.title,\n url: issue.html_url,\n author: issue.user?.login ?? null,\n assignees: issue.assignees?.flatMap(assignee => (assignee.login ? [assignee.login] : [])) ?? [],\n labels: issue.labels.map(label => (typeof label === 'string' ? label : (label.name ?? ''))).filter(Boolean),\n comments: issue.comments,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n }));\n return { issues, nextPage: response.data.length === LIST_PAGE_SIZE ? page + 1 : null };\n }\n\n /**\n * Build the GitHub App install URL. `state` is carried through the install\n * flow and validated on callback.\n */\n buildInstallUrl(state: string): string {\n const url = new URL(`https://github.com/apps/${this.#slug}/installations/new`);\n url.searchParams.set('state', state);\n return url.toString();\n }\n\n /**\n * Build the OAuth identify URL (authorize) used to confirm the user's\n * identity and obtain a user token for listing their installations.\n */\n buildOAuthIdentifyUrl(state: string, redirectUri: string): string {\n const url = new URL('https://github.com/login/oauth/authorize');\n url.searchParams.set('client_id', this.#clientId);\n url.searchParams.set('redirect_uri', redirectUri);\n url.searchParams.set('state', state);\n return url.toString();\n }\n\n /** Exchange an OAuth `code` for a user access token. */\n async exchangeOAuthCode(code: string, redirectUri: string): Promise<string> {\n const res = await fetch('https://github.com/login/oauth/access_token', {\n method: 'POST',\n signal: AbortSignal.timeout(10_000),\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify({\n client_id: this.#clientId,\n client_secret: this.#clientSecret,\n code,\n redirect_uri: redirectUri,\n }),\n });\n if (!res.ok) {\n throw new Error(`GitHub OAuth token exchange failed: ${res.status}`);\n }\n const data = (await res.json()) as { access_token?: string; error?: string; error_description?: string };\n if (!data.access_token) {\n throw new Error(\n `GitHub OAuth token exchange returned no token: ${data.error_description ?? data.error ?? 'unknown'}`,\n );\n }\n return data.access_token;\n }\n\n /**\n * The integration's HTTP surface: the `/web/github/*` + `/auth/github/*`\n * Mastra `apiRoutes` (webhook handler, install/OAuth flow, project +\n * worktree + session operations). The factory folds these into the server's\n * `apiRoutes` when the feature is ready. Handlers operate on this instance.\n */\n routes(ctx: IntegrationContext): ApiRoute[] {\n this.#storage = ctx.storage;\n // Every parsed webhook also feeds the base-checkpoint triggers (merged\n // PRs / pushes to the default branch rebuild the repo's warm checkpoint).\n const ingestFactoryEvent = withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints);\n return buildGithubRoutes({\n github: this,\n auth: ctx.auth,\n fleet: ctx.fleet,\n storage: ctx.factoryStorage,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n controller: ctx.controller,\n emitAudit: ctx.hooks?.emitAudit,\n projects: ctx.storage.projects,\n ingestFactoryEvent,\n sessionRetirement: ctx.sessionRetirement,\n });\n }\n\n /**\n * Pull-request and issue sweeps share a worker and lease, but can be enabled\n * and paced independently. The legacy combined controls remain the fallback.\n */\n workers(ctx: IntegrationContext): MastraWorker[] {\n const pullRequestEnabled = reconciliationEnabled(\n process.env.MASTRACODE_GITHUB_PR_RECONCILE_ENABLED,\n process.env.MASTRACODE_GITHUB_RECONCILE_ENABLED,\n );\n const issueEnabled = reconciliationEnabled(\n process.env.MASTRACODE_GITHUB_ISSUE_RECONCILE_ENABLED,\n process.env.MASTRACODE_GITHUB_RECONCILE_ENABLED,\n );\n if (!pullRequestEnabled && !issueEnabled) return [];\n\n const reconcile = pullRequestEnabled\n ? attachGithubReconciler(this, ctx, input => this.fetchPullRequestState(input))\n : undefined;\n const issues = issueEnabled ? attachGithubIssueReconciler(this, ctx, input => this.fetchIssueState(input)) : undefined;\n if (!reconcile && !issues) return [];\n\n const legacyInterval = reconcileInterval(process.env.MASTRACODE_GITHUB_RECONCILE_INTERVAL_MS);\n const intervalMs = reconcileInterval(process.env.MASTRACODE_GITHUB_PR_RECONCILE_INTERVAL_MS) ?? legacyInterval;\n const issueIntervalMs = reconcileInterval(process.env.MASTRACODE_GITHUB_ISSUE_RECONCILE_INTERVAL_MS) ?? legacyInterval;\n return [\n new GithubReconcileWorker({\n ...(reconcile ? { reconcile } : {}),\n ...(issues ? { reconcileIssues: issues } : {}),\n sourceControl: ctx.storage.sourceControl,\n ...(ctx.baseCheckpoints ? { sweepBaseCheckpoints: () => ctx.baseCheckpoints!.sweep() } : {}),\n ...(intervalMs ? { intervalMs } : {}),\n ...(issueIntervalMs ? { issueIntervalMs } : {}),\n }),\n ];\n }\n\n /**\n * Reads live PR state for the merge reconciler. Returns undefined when the PR\n * cannot be resolved so a sweep never fabricates a merge.\n */\n async fetchPullRequestState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcilePullRequestState | undefined> {\n try {\n const pullRequest = await this.#getPullRequest({\n connection: { type: 'app-installation', installationId: input.installationId },\n sourceId: input.repository,\n pullRequestId: String(input.number),\n });\n if (!pullRequest) return undefined;\n return {\n title: pullRequest.title,\n url: pullRequest.url,\n state: pullRequest.state === 'closed' ? 'closed' : 'open',\n draft: pullRequest.draft,\n merged: pullRequest.merged,\n assignees: pullRequest.assignees ?? [],\n requestedReviewers: pullRequest.requestedReviewers ?? [],\n labels: pullRequest.labels ?? [],\n headBranch: pullRequest.headBranch,\n baseBranch: pullRequest.baseBranch,\n ...(pullRequest.author ? { author: pullRequest.author } : {}),\n ...(pullRequest.createdAt ? { createdAt: pullRequest.createdAt } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Reads live issue state for the reconciler. Returns undefined when the\n * issue cannot be resolved (missing, is actually a PR, API error) so a\n * sweep never fabricates a close.\n */\n async fetchIssueState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcileIssueState | undefined> {\n const parts = splitRepoFullName(input.repository);\n if (!parts) return undefined;\n try {\n const octokit = this.getInstallationOctokit(input.installationId);\n const { data: issue } = await octokit.issues.get({\n owner: parts.owner,\n repo: parts.repo,\n issue_number: input.number,\n });\n if (issue.pull_request) return undefined;\n return {\n title: issue.title,\n url: issue.html_url,\n state: issue.state === 'closed' ? 'closed' : 'open',\n ...(issue.state_reason ? { stateReason: issue.state_reason } : {}),\n assignees: (issue.assignees ?? [])\n .map(user => user.login)\n .filter((login): login is string => Boolean(login)),\n labels: (issue.labels ?? [])\n .map(label => (typeof label === 'string' ? label : label.name))\n .filter((name): name is string => Boolean(name)),\n ...(issue.user?.login ? { author: issue.user.login } : {}),\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Session-scoped agent tools for token refresh and PR subscriptions in\n * sessions bound to a GitHub-backed project. Empty elsewhere.\n */\n sessionTools({ requestContext }: { requestContext: RequestContext }): IntegrationTools {\n return createGithubSubscriptionTools(requestContext, this);\n }\n\n async postToolObserver({\n toolContext,\n requestContext,\n }: Parameters<NonNullable<FactoryIntegration['postToolObserver']>>[0]): Promise<void> {\n const pullRequestUrl = parseCreatedPullRequest(toolContext);\n if (!pullRequestUrl || !requestContext) return;\n await subscribeCurrentSessionToPullRequest(requestContext, pullRequestUrl, 'auto-gh-pr-create', this);\n }\n\n /** Non-secret config snapshot for system diagnostics/startup logs. */\n diagnostics(): Record<string, unknown> {\n return {\n slug: this.#slug,\n webhookSecretConfigured: this.#webhookSecret !== undefined,\n };\n }\n}\n\ninterface GithubPullRequestData {\n number: number;\n title: string;\n html_url: string;\n user: { login?: string } | null;\n assignees?: Array<{ login?: string }> | null;\n requested_reviewers?: Array<{ login?: string }> | null;\n labels?: Array<{ name?: string } | string> | null;\n body?: string | null;\n state: string;\n draft?: boolean | null;\n merged?: boolean;\n merged_at?: string | null;\n mergeable?: boolean | null;\n base: { ref: string };\n head: { ref: string; sha: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GithubCommentData {\n id: number;\n html_url: string;\n user: { login?: string } | null;\n body?: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface GithubReviewData {\n id: number;\n html_url?: string;\n user: { login?: string } | null;\n body?: string | null;\n state: string;\n commit_id?: string | null;\n submitted_at?: string | null;\n}\n\ninterface GithubReviewCommentData extends GithubCommentData {\n path: string;\n line?: number | null;\n side?: string | null;\n commit_id: string;\n in_reply_to_id?: number | null;\n}\n\nfunction parsePullRequest(pr: GithubPullRequestData): PullRequest {\n return {\n id: String(pr.number),\n title: pr.title,\n url: pr.html_url,\n author: pr.user?.login ?? null,\n assignees: (pr.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n requestedReviewers: (pr.requested_reviewers ?? []).flatMap(reviewer => (reviewer.login ? [reviewer.login] : [])),\n labels: (pr.labels ?? []).flatMap(label =>\n typeof label === 'string' ? [label] : label.name ? [label.name] : [],\n ),\n body: pr.body?.trim() ? pr.body : null,\n state: pr.state === 'closed' ? 'closed' : 'open',\n draft: pr.draft ?? false,\n merged: pr.merged ?? Boolean(pr.merged_at),\n mergeable: typeof pr.mergeable === 'boolean' ? pr.mergeable : null,\n baseBranch: pr.base.ref,\n headBranch: pr.head.ref,\n headSha: pr.head.sha,\n createdAt: pr.created_at,\n updatedAt: pr.updated_at,\n };\n}\n\nfunction parsePullRequestComment(comment: GithubCommentData): PullRequestComment {\n return {\n id: String(comment.id),\n url: comment.html_url,\n author: comment.user?.login ?? null,\n body: comment.body ?? '',\n createdAt: comment.created_at,\n updatedAt: comment.updated_at,\n };\n}\n\nfunction parseReview(review: GithubReviewData): Review {\n return {\n id: String(review.id),\n url: review.html_url ?? null,\n author: review.user?.login ?? null,\n body: review.body?.trim() ? review.body : null,\n state: parseReviewState(review.state),\n commitId: review.commit_id ?? null,\n submittedAt: review.submitted_at ?? null,\n };\n}\n\nfunction parseReviewComment(comment: GithubReviewCommentData): ReviewComment {\n const parsed = parsePullRequestComment(comment);\n const side = comment.side?.toLowerCase();\n return {\n ...parsed,\n path: comment.path,\n line: comment.line ?? null,\n side: side === 'left' || side === 'right' ? side : null,\n commitId: comment.commit_id,\n replyToId: comment.in_reply_to_id ? String(comment.in_reply_to_id) : null,\n };\n}\n\nfunction parseRequestedReviewers(data: {\n users?: Array<{ login?: string }> | null;\n teams?: Array<{ slug?: string }> | null;\n requested_reviewers?: Array<{ login?: string }> | null;\n requested_teams?: Array<{ slug?: string }> | null;\n}) {\n return {\n users: (data.users ?? data.requested_reviewers ?? []).flatMap(user => (user.login ? [user.login] : [])),\n teams: (data.teams ?? data.requested_teams ?? []).flatMap(team => (team.slug ? [team.slug] : [])),\n };\n}\n\nfunction parseReviewState(state: string): Review['state'] {\n if (state === 'PENDING') return 'pending';\n if (state === 'COMMENTED') return 'commented';\n if (state === 'APPROVED') return 'approved';\n if (state === 'CHANGES_REQUESTED') return 'changes-requested';\n if (state === 'DISMISSED') return 'dismissed';\n throw new Error(`Unsupported GitHub review state: ${state}`);\n}\n\nfunction reviewEventToGithub(event: Exclude<InputOf<'createReview'>['event'], undefined>) {\n if (event === 'approve') return 'APPROVE' as const;\n if (event === 'request-changes') return 'REQUEST_CHANGES' as const;\n return 'COMMENT' as const;\n}\n\nfunction requirePullRequestNumber(value: string): number {\n return requirePositiveId(value, 'pull request');\n}\n\nfunction requirePositiveId(value: string, resource: string): number {\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new Error(`GitHub ${resource} id must be a positive integer.`);\n return parsed;\n}\n\nfunction getGithubInstallationId(connection: IntegrationConnection): number {\n if (connection.type !== 'app-installation') {\n throw new Error('GitHub capabilities require an app-installation connection.');\n }\n return connection.installationId;\n}\n\nfunction getSingleSourceId(sourceIds: string[], message: string): string {\n if (sourceIds.length !== 1) throw new Error(message);\n return sourceIds[0]!;\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\nfunction requireSourceId(sourceId: string | undefined, message: string): string {\n if (!sourceId) throw new Error(message);\n return sourceId;\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const page = parsePositiveInteger(cursor);\n if (page === null) throw new Error('GitHub cursor must be a positive page number.');\n return page;\n}\n\nfunction parsePositiveInteger(value: string): number | null {\n if (!/^\\d+$/.test(value)) return null;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'status' in error && error.status === 404;\n}\n\n/** Split an `owner/name` full name into its parts, or `null` when malformed. */\nfunction splitRepoFullName(repoFullName: string): { owner: string; repo: string } | null {\n const slash = repoFullName.indexOf('/');\n if (slash <= 0 || slash === repoFullName.length - 1) return null;\n return { owner: repoFullName.slice(0, slash), repo: repoFullName.slice(slash + 1) };\n}\n\nfunction parseGithubExternalTarget(externalId: string): { repositoryId: string; issueId: string } | null {\n const match = externalId.match(/^github:(\\d+):(?:issue|pull-request):(\\d+)$/) ?? externalId.match(/^(\\d+):(\\d+)$/);\n if (!match?.[1] || !match[2]) return null;\n const repositoryId = parsePositiveInteger(match[1]);\n const issueId = parsePositiveInteger(match[2]);\n return repositoryId && issueId ? { repositoryId: String(repositoryId), issueId: String(issueId) } : null;\n}\n"],"mappings":"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"}
|
|
@@ -24,6 +24,11 @@ export interface GithubReconcileWorkerConfig {
|
|
|
24
24
|
reconcile?: GithubPullRequestReconciler;
|
|
25
25
|
reconcileIssues?: GithubIssueReconciler;
|
|
26
26
|
sourceControl: GithubReconcileRepositorySource;
|
|
27
|
+
/**
|
|
28
|
+
* Base-checkpoint freshness sweep, run after the reconcilers within the same
|
|
29
|
+
* lease. Rebuilds stale/missing base checkpoints for configured repos.
|
|
30
|
+
*/
|
|
31
|
+
sweepBaseCheckpoints?: () => Promise<void>;
|
|
27
32
|
intervalMs?: number;
|
|
28
33
|
issueIntervalMs?: number;
|
|
29
34
|
now?: () => number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-worker.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/reconcile-worker.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAC/B,uBAAuB,EACxB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,2BAA2B,EAAuB,MAAM,YAAY,CAAC;AAEnF,eAAO,MAAM,oCAAoC,QAAa,CAAC;AAI/D,kFAAkF;AAClF,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE;QACnB,0BAA0B,IAAI,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;QACzE,wBAAwB,CAAC,IAAI,EAAE;YAC7B,sBAAsB,EAAE,MAAM,CAAC;YAC/B,oBAAoB,EAAE,MAAM,CAAC;SAC9B,GAAG,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;KAChD,CAAC;IACF,YAAY,EAAE;QACZ,gBAAgB,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;KACxG,CAAC;CACH;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACxC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,aAAa,EAAE,+BAA+B,CAAC;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;;IACrD,QAAQ,CAAC,IAAI,mCAAmC;
|
|
1
|
+
{"version":3,"file":"reconcile-worker.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/reconcile-worker.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAC/B,uBAAuB,EACxB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,2BAA2B,EAAuB,MAAM,YAAY,CAAC;AAEnF,eAAO,MAAM,oCAAoC,QAAa,CAAC;AAI/D,kFAAkF;AAClF,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE;QACnB,0BAA0B,IAAI,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;QACzE,wBAAwB,CAAC,IAAI,EAAE;YAC7B,sBAAsB,EAAE,MAAM,CAAC;YAC/B,oBAAoB,EAAE,MAAM,CAAC;SAC9B,GAAG,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;KAChD,CAAC;IACF,YAAY,EAAE;QACZ,gBAAgB,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;KACxG,CAAC;CACH;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACxC,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,aAAa,EAAE,+BAA+B,CAAC;IAC/C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;;IACrD,QAAQ,CAAC,IAAI,mCAAmC;gBAmBpC,MAAM,EAAE,2BAA2B;IAqBzC,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,IAAI,SAAS,IAAI,OAAO,CAEvB;CAsJF"}
|
|
@@ -15,6 +15,7 @@ var GithubReconcileWorker = class extends MastraWorker {
|
|
|
15
15
|
#reconcile;
|
|
16
16
|
#reconcileIssues;
|
|
17
17
|
#sourceControl;
|
|
18
|
+
#sweepBaseCheckpoints;
|
|
18
19
|
#intervalMs;
|
|
19
20
|
#issueIntervalMs;
|
|
20
21
|
#leaseTtlMs;
|
|
@@ -32,6 +33,7 @@ var GithubReconcileWorker = class extends MastraWorker {
|
|
|
32
33
|
this.#reconcile = config.reconcile;
|
|
33
34
|
this.#reconcileIssues = config.reconcileIssues;
|
|
34
35
|
this.#sourceControl = config.sourceControl;
|
|
36
|
+
this.#sweepBaseCheckpoints = config.sweepBaseCheckpoints;
|
|
35
37
|
this.#intervalMs = config.intervalMs ?? 3e5;
|
|
36
38
|
this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;
|
|
37
39
|
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) throw new Error("GitHub pull request reconcile interval must be a positive number.");
|
|
@@ -145,6 +147,11 @@ var GithubReconcileWorker = class extends MastraWorker {
|
|
|
145
147
|
this.deps?.logger.warn("GitHub issue reconcile sweep failed", { error: error instanceof Error ? error.message : String(error) });
|
|
146
148
|
}
|
|
147
149
|
} else if (reconcileIssues && this.#reconcileIssues && !hasLease) this.deps?.logger.debug("GitHub issue reconcile skipped: lease lost during pull-request sweep");
|
|
150
|
+
if (this.#sweepBaseCheckpoints && hasLease) try {
|
|
151
|
+
await this.#sweepBaseCheckpoints();
|
|
152
|
+
} catch (error) {
|
|
153
|
+
this.deps?.logger.warn("GitHub base-checkpoint freshness sweep failed", { error: error instanceof Error ? error.message : String(error) });
|
|
154
|
+
}
|
|
148
155
|
} finally {
|
|
149
156
|
clearInterval(renewalTimer);
|
|
150
157
|
if (hasLease) await this.#leaseProvider.releaseLease(LEASE_KEY, this.#leaseOwner).catch(() => void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-worker.js","names":["#reconcile","#reconcileIssues","#sourceControl","#intervalMs","#issueIntervalMs","#leaseTtlMs","#leaseOwner","#now","#leaseProvider","#running","#schedule","#timer","#inFlight","#tick","#nextDelay","#nextPullRequestReconcileAt","#nextIssueReconcileAt","#targets"],"sources":["../../../src/integrations/github/reconcile-worker.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { isLeaseProvider, NoopLeaseProvider } from '@mastra/core/events';\nimport type { LeaseProvider, PubSub } from '@mastra/core/events';\nimport { MastraWorker } from '@mastra/core/worker';\nimport type { WorkerDeps } from '@mastra/core/worker';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n ExternalRepositoryProjectTarget,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GithubIssueReconciler } from './issue-reconciler.js';\nimport type { GithubPullRequestReconciler, ReconcileRepository } from './rules.js';\n\nexport const DEFAULT_GITHUB_RECONCILE_INTERVAL_MS = 5 * 60_000;\nconst MIN_LEASE_TTL_MS = 30_000;\nconst LEASE_KEY = 'github:pull-request-reconcile';\n\n/** Storage slice the sweep needs to turn configured repositories into targets. */\nexport interface GithubReconcileRepositorySource {\n projectRepositories: {\n listConfiguredExternalKeys(): Promise<ConfiguredExternalRepositoryKey[]>;\n listByExternalRepository(args: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]>;\n };\n repositories: {\n findByExternalId(args: { orgId: string; externalId: string }): Promise<SourceControlRepository | null>;\n };\n}\n\nexport interface GithubReconcileWorkerConfig {\n reconcile?: GithubPullRequestReconciler;\n reconcileIssues?: GithubIssueReconciler;\n sourceControl: GithubReconcileRepositorySource;\n intervalMs?: number;\n issueIntervalMs?: number;\n now?: () => number;\n}\n\n/**\n * Periodic GitHub state sweeps for the self-hosted integration. Pull requests\n * drive review cards and issues drive work cards, but both share discovery and\n * a lease so replicas never sweep the same configured repositories together.\n */\nexport class GithubReconcileWorker extends MastraWorker {\n readonly name = 'github-pull-request-reconcile';\n\n readonly #reconcile: GithubPullRequestReconciler | undefined;\n readonly #reconcileIssues: GithubIssueReconciler | undefined;\n readonly #sourceControl: GithubReconcileRepositorySource;\n readonly #intervalMs: number;\n readonly #issueIntervalMs: number;\n readonly #leaseTtlMs: number;\n readonly #leaseOwner = randomUUID();\n readonly #now: () => number;\n\n #running = false;\n #timer: ReturnType<typeof setTimeout> | undefined;\n #inFlight: Promise<void> | undefined;\n #leaseProvider: LeaseProvider = NoopLeaseProvider;\n #nextPullRequestReconcileAt = 0;\n #nextIssueReconcileAt = 0;\n\n constructor(config: GithubReconcileWorkerConfig) {\n super();\n if (!config.reconcile && !config.reconcileIssues) {\n throw new Error('GitHub reconcile worker requires a pull request or issue reconciler.');\n }\n this.#reconcile = config.reconcile;\n this.#reconcileIssues = config.reconcileIssues;\n this.#sourceControl = config.sourceControl;\n this.#intervalMs = config.intervalMs ?? DEFAULT_GITHUB_RECONCILE_INTERVAL_MS;\n this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;\n if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n throw new Error('GitHub pull request reconcile interval must be a positive number.');\n }\n if (!Number.isFinite(this.#issueIntervalMs) || this.#issueIntervalMs <= 0) {\n throw new Error('GitHub issue reconcile interval must be a positive number.');\n }\n this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, Math.min(this.#intervalMs, this.#issueIntervalMs) * 3);\n this.#now = config.now ?? Date.now;\n }\n\n async init(deps: WorkerDeps): Promise<void> {\n await super.init(deps);\n this.#leaseProvider = getLeaseProvider(deps.pubsub);\n }\n\n async start(): Promise<void> {\n if (this.#running) return;\n if (!this.deps) throw new Error('GithubReconcileWorker: call init() before start()');\n this.#running = true;\n this.deps.logger.info('GitHub reconcile worker started', {\n pullRequestIntervalMs: this.#reconcile ? this.#intervalMs : undefined,\n issueIntervalMs: this.#reconcileIssues ? this.#issueIntervalMs : undefined,\n });\n // Sweep on boot: a restart is exactly when webhooks were most likely missed.\n this.#schedule(0);\n }\n\n async stop(): Promise<void> {\n if (!this.#running) return;\n this.#running = false;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n await this.#inFlight;\n }\n\n get isRunning(): boolean {\n return this.#running;\n }\n\n #schedule(delayMs: number): void {\n if (!this.#running) return;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n const run = this.#tick().finally(() => {\n this.#inFlight = undefined;\n this.#schedule(this.#nextDelay());\n });\n this.#inFlight = run;\n }, delayMs);\n this.#timer.unref?.();\n }\n\n #nextDelay(): number {\n const now = this.#now();\n const due = [\n this.#reconcile ? this.#nextPullRequestReconcileAt : undefined,\n this.#reconcileIssues ? this.#nextIssueReconcileAt : undefined,\n ].filter((at): at is number => at !== undefined);\n return Math.max(0, Math.min(...due) - now);\n }\n\n async #tick(): Promise<void> {\n const now = this.#now();\n const reconcilePullRequests = Boolean(this.#reconcile && now >= this.#nextPullRequestReconcileAt);\n const reconcileIssues = Boolean(this.#reconcileIssues && now >= this.#nextIssueReconcileAt);\n if (!reconcilePullRequests && !reconcileIssues) return;\n if (reconcilePullRequests) this.#nextPullRequestReconcileAt = now + this.#intervalMs;\n if (reconcileIssues) this.#nextIssueReconcileAt = now + this.#issueIntervalMs;\n\n // Replicas share one sweep: the ingress dedupes duplicate writes, but the\n // reads still burn the installation's rate limit.\n const lease = await this.#leaseProvider\n .acquireLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .catch(() => ({ acquired: false }));\n if (!lease.acquired) return;\n\n let hasLease = true;\n const renewalTimer = setInterval(\n () => {\n void this.#leaseProvider\n .renewLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .then(renewed => {\n if (!renewed) {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease was lost mid-sweep; aborting further writes');\n }\n })\n .catch(error => {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease renewal failed; aborting further writes', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n },\n Math.max(1_000, Math.floor(this.#leaseTtlMs / 3)),\n );\n renewalTimer.unref?.();\n\n try {\n const targets = await this.#targets();\n if (targets.length === 0) return;\n\n if (reconcilePullRequests && this.#reconcile) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcile(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.merged > 0 || counts.closed > 0) {\n this.deps?.logger.info('GitHub pull request reconcile replayed missed merges/closes', context);\n } else {\n this.deps?.logger.debug('GitHub pull request reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (reconcileIssues && this.#reconcileIssues && hasLease) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcileIssues(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub issue reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.closed > 0) {\n this.deps?.logger.info('GitHub issue reconcile replayed closed work items', context);\n } else if (counts.updated > 0) {\n this.deps?.logger.info('GitHub issue reconcile patched stale metadata', context);\n } else {\n this.deps?.logger.debug('GitHub issue reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub issue reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n } else if (reconcileIssues && this.#reconcileIssues && !hasLease) {\n this.deps?.logger.debug('GitHub issue reconcile skipped: lease lost during pull-request sweep');\n }\n } finally {\n clearInterval(renewalTimer);\n if (hasLease) {\n await this.#leaseProvider.releaseLease(LEASE_KEY, this.#leaseOwner).catch(() => undefined);\n }\n }\n }\n\n /**\n * Configured (installation, repository) pairs resolved to the numeric ids and\n * slug the sweep addresses GitHub with. A pair whose repository row is gone\n * is skipped rather than failing the sweep for the others.\n */\n async #targets(): Promise<ReconcileRepository[]> {\n const keys = await this.#sourceControl.projectRepositories.listConfiguredExternalKeys();\n const targets: ReconcileRepository[] = [];\n for (const key of keys) {\n const installationId = Number(key.installationExternalId);\n const repositoryId = Number(key.repositoryExternalId);\n if (!Number.isSafeInteger(installationId) || !Number.isSafeInteger(repositoryId)) continue;\n const projects = await this.#sourceControl.projectRepositories.listByExternalRepository(key);\n const orgId = projects[0]?.orgId;\n if (!orgId) continue;\n const repository = await this.#sourceControl.repositories.findByExternalId({\n orgId,\n externalId: key.repositoryExternalId,\n });\n if (!repository?.slug) continue;\n targets.push({ id: repositoryId, fullName: repository.slug, installationId });\n }\n return targets;\n }\n}\n\nfunction getLeaseProvider(pubsub: PubSub): LeaseProvider {\n const getProvider = (pubsub as PubSub & { getLeaseProvider?: () => LeaseProvider | undefined }).getLeaseProvider;\n if (typeof getProvider === 'function') return getProvider.call(pubsub) ?? NoopLeaseProvider;\n return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reconcile-worker.js","names":["#reconcile","#reconcileIssues","#sourceControl","#sweepBaseCheckpoints","#intervalMs","#issueIntervalMs","#leaseTtlMs","#leaseOwner","#now","#leaseProvider","#running","#schedule","#timer","#inFlight","#tick","#nextDelay","#nextPullRequestReconcileAt","#nextIssueReconcileAt","#targets"],"sources":["../../../src/integrations/github/reconcile-worker.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { isLeaseProvider, NoopLeaseProvider } from '@mastra/core/events';\nimport type { LeaseProvider, PubSub } from '@mastra/core/events';\nimport { MastraWorker } from '@mastra/core/worker';\nimport type { WorkerDeps } from '@mastra/core/worker';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n ExternalRepositoryProjectTarget,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GithubIssueReconciler } from './issue-reconciler.js';\nimport type { GithubPullRequestReconciler, ReconcileRepository } from './rules.js';\n\nexport const DEFAULT_GITHUB_RECONCILE_INTERVAL_MS = 5 * 60_000;\nconst MIN_LEASE_TTL_MS = 30_000;\nconst LEASE_KEY = 'github:pull-request-reconcile';\n\n/** Storage slice the sweep needs to turn configured repositories into targets. */\nexport interface GithubReconcileRepositorySource {\n projectRepositories: {\n listConfiguredExternalKeys(): Promise<ConfiguredExternalRepositoryKey[]>;\n listByExternalRepository(args: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]>;\n };\n repositories: {\n findByExternalId(args: { orgId: string; externalId: string }): Promise<SourceControlRepository | null>;\n };\n}\n\nexport interface GithubReconcileWorkerConfig {\n reconcile?: GithubPullRequestReconciler;\n reconcileIssues?: GithubIssueReconciler;\n sourceControl: GithubReconcileRepositorySource;\n /**\n * Base-checkpoint freshness sweep, run after the reconcilers within the same\n * lease. Rebuilds stale/missing base checkpoints for configured repos.\n */\n sweepBaseCheckpoints?: () => Promise<void>;\n intervalMs?: number;\n issueIntervalMs?: number;\n now?: () => number;\n}\n\n/**\n * Periodic GitHub state sweeps for the self-hosted integration. Pull requests\n * drive review cards and issues drive work cards, but both share discovery and\n * a lease so replicas never sweep the same configured repositories together.\n */\nexport class GithubReconcileWorker extends MastraWorker {\n readonly name = 'github-pull-request-reconcile';\n\n readonly #reconcile: GithubPullRequestReconciler | undefined;\n readonly #reconcileIssues: GithubIssueReconciler | undefined;\n readonly #sourceControl: GithubReconcileRepositorySource;\n readonly #sweepBaseCheckpoints: (() => Promise<void>) | undefined;\n readonly #intervalMs: number;\n readonly #issueIntervalMs: number;\n readonly #leaseTtlMs: number;\n readonly #leaseOwner = randomUUID();\n readonly #now: () => number;\n\n #running = false;\n #timer: ReturnType<typeof setTimeout> | undefined;\n #inFlight: Promise<void> | undefined;\n #leaseProvider: LeaseProvider = NoopLeaseProvider;\n #nextPullRequestReconcileAt = 0;\n #nextIssueReconcileAt = 0;\n\n constructor(config: GithubReconcileWorkerConfig) {\n super();\n if (!config.reconcile && !config.reconcileIssues) {\n throw new Error('GitHub reconcile worker requires a pull request or issue reconciler.');\n }\n this.#reconcile = config.reconcile;\n this.#reconcileIssues = config.reconcileIssues;\n this.#sourceControl = config.sourceControl;\n this.#sweepBaseCheckpoints = config.sweepBaseCheckpoints;\n this.#intervalMs = config.intervalMs ?? DEFAULT_GITHUB_RECONCILE_INTERVAL_MS;\n this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;\n if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n throw new Error('GitHub pull request reconcile interval must be a positive number.');\n }\n if (!Number.isFinite(this.#issueIntervalMs) || this.#issueIntervalMs <= 0) {\n throw new Error('GitHub issue reconcile interval must be a positive number.');\n }\n this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, Math.min(this.#intervalMs, this.#issueIntervalMs) * 3);\n this.#now = config.now ?? Date.now;\n }\n\n async init(deps: WorkerDeps): Promise<void> {\n await super.init(deps);\n this.#leaseProvider = getLeaseProvider(deps.pubsub);\n }\n\n async start(): Promise<void> {\n if (this.#running) return;\n if (!this.deps) throw new Error('GithubReconcileWorker: call init() before start()');\n this.#running = true;\n this.deps.logger.info('GitHub reconcile worker started', {\n pullRequestIntervalMs: this.#reconcile ? this.#intervalMs : undefined,\n issueIntervalMs: this.#reconcileIssues ? this.#issueIntervalMs : undefined,\n });\n // Sweep on boot: a restart is exactly when webhooks were most likely missed.\n this.#schedule(0);\n }\n\n async stop(): Promise<void> {\n if (!this.#running) return;\n this.#running = false;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n await this.#inFlight;\n }\n\n get isRunning(): boolean {\n return this.#running;\n }\n\n #schedule(delayMs: number): void {\n if (!this.#running) return;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n const run = this.#tick().finally(() => {\n this.#inFlight = undefined;\n this.#schedule(this.#nextDelay());\n });\n this.#inFlight = run;\n }, delayMs);\n this.#timer.unref?.();\n }\n\n #nextDelay(): number {\n const now = this.#now();\n const due = [\n this.#reconcile ? this.#nextPullRequestReconcileAt : undefined,\n this.#reconcileIssues ? this.#nextIssueReconcileAt : undefined,\n ].filter((at): at is number => at !== undefined);\n return Math.max(0, Math.min(...due) - now);\n }\n\n async #tick(): Promise<void> {\n const now = this.#now();\n const reconcilePullRequests = Boolean(this.#reconcile && now >= this.#nextPullRequestReconcileAt);\n const reconcileIssues = Boolean(this.#reconcileIssues && now >= this.#nextIssueReconcileAt);\n if (!reconcilePullRequests && !reconcileIssues) return;\n if (reconcilePullRequests) this.#nextPullRequestReconcileAt = now + this.#intervalMs;\n if (reconcileIssues) this.#nextIssueReconcileAt = now + this.#issueIntervalMs;\n\n // Replicas share one sweep: the ingress dedupes duplicate writes, but the\n // reads still burn the installation's rate limit.\n const lease = await this.#leaseProvider\n .acquireLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .catch(() => ({ acquired: false }));\n if (!lease.acquired) return;\n\n let hasLease = true;\n const renewalTimer = setInterval(\n () => {\n void this.#leaseProvider\n .renewLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .then(renewed => {\n if (!renewed) {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease was lost mid-sweep; aborting further writes');\n }\n })\n .catch(error => {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease renewal failed; aborting further writes', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n },\n Math.max(1_000, Math.floor(this.#leaseTtlMs / 3)),\n );\n renewalTimer.unref?.();\n\n try {\n const targets = await this.#targets();\n if (targets.length === 0) return;\n\n if (reconcilePullRequests && this.#reconcile) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcile(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.merged > 0 || counts.closed > 0) {\n this.deps?.logger.info('GitHub pull request reconcile replayed missed merges/closes', context);\n } else {\n this.deps?.logger.debug('GitHub pull request reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (reconcileIssues && this.#reconcileIssues && hasLease) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcileIssues(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub issue reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.closed > 0) {\n this.deps?.logger.info('GitHub issue reconcile replayed closed work items', context);\n } else if (counts.updated > 0) {\n this.deps?.logger.info('GitHub issue reconcile patched stale metadata', context);\n } else {\n this.deps?.logger.debug('GitHub issue reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub issue reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n } else if (reconcileIssues && this.#reconcileIssues && !hasLease) {\n this.deps?.logger.debug('GitHub issue reconcile skipped: lease lost during pull-request sweep');\n }\n\n if (this.#sweepBaseCheckpoints && hasLease) {\n try {\n await this.#sweepBaseCheckpoints();\n } catch (error) {\n this.deps?.logger.warn('GitHub base-checkpoint freshness sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n } finally {\n clearInterval(renewalTimer);\n if (hasLease) {\n await this.#leaseProvider.releaseLease(LEASE_KEY, this.#leaseOwner).catch(() => undefined);\n }\n }\n }\n\n /**\n * Configured (installation, repository) pairs resolved to the numeric ids and\n * slug the sweep addresses GitHub with. A pair whose repository row is gone\n * is skipped rather than failing the sweep for the others.\n */\n async #targets(): Promise<ReconcileRepository[]> {\n const keys = await this.#sourceControl.projectRepositories.listConfiguredExternalKeys();\n const targets: ReconcileRepository[] = [];\n for (const key of keys) {\n const installationId = Number(key.installationExternalId);\n const repositoryId = Number(key.repositoryExternalId);\n if (!Number.isSafeInteger(installationId) || !Number.isSafeInteger(repositoryId)) continue;\n const projects = await this.#sourceControl.projectRepositories.listByExternalRepository(key);\n const orgId = projects[0]?.orgId;\n if (!orgId) continue;\n const repository = await this.#sourceControl.repositories.findByExternalId({\n orgId,\n externalId: key.repositoryExternalId,\n });\n if (!repository?.slug) continue;\n targets.push({ id: repositoryId, fullName: repository.slug, installationId });\n }\n return targets;\n }\n}\n\nfunction getLeaseProvider(pubsub: PubSub): LeaseProvider {\n const getProvider = (pubsub as PubSub & { getLeaseProvider?: () => LeaseProvider | undefined }).getLeaseProvider;\n if (typeof getProvider === 'function') return getProvider.call(pubsub) ?? NoopLeaseProvider;\n return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;\n}\n"],"mappings":"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"}
|