@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/platform/github/integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAwBV,cAAc,EACf,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/integration.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createGithubSubscriptionTools, parseCreatedPullRequest, subscribeCurrentSessionToPullRequest } from "../../github/session-subscriptions.js";
|
|
2
|
+
import { withBaseCheckpointWebhookTrigger } from "../../../sandbox/base-checkpoint-triggers.js";
|
|
3
|
+
import { GithubAppIdentity } from "../../github/app-identity.js";
|
|
2
4
|
import { attachGithubReconciler, attachGithubRules } from "../../github/rules.js";
|
|
3
5
|
import { attachGithubIssueReconciler } from "../../github/issue-reconciler.js";
|
|
4
6
|
import { reconcileInterval, reconciliationEnabled } from "../../github/reconciliation-config.js";
|
|
@@ -11,6 +13,13 @@ import { registerApiRoute } from "@mastra/core/server";
|
|
|
11
13
|
const PAGE_SIZE = 30;
|
|
12
14
|
const API_PREFIX = "/v1/server";
|
|
13
15
|
/**
|
|
16
|
+
* Slug of the GitHub App this integration posts as. Platform credentials do not
|
|
17
|
+
* carry their own identity, so Factory cannot otherwise recognise its own
|
|
18
|
+
* writes — and failing to recognise them makes Factory wake itself. Override
|
|
19
|
+
* with `MASTRA_PLATFORM_GITHUB_APP_SLUG` when pointing at a non-production App.
|
|
20
|
+
*/
|
|
21
|
+
const PLATFORM_GITHUB_APP_SLUG = "mastra-platform";
|
|
22
|
+
/**
|
|
14
23
|
* How long an installation's repository listing may be reused. The repos
|
|
15
24
|
* route and token minting both call it — often several times within one UI
|
|
16
25
|
* interaction — and each call is a full Platform round trip.
|
|
@@ -54,6 +63,12 @@ var PlatformGithubIntegration = class {
|
|
|
54
63
|
#endpointHost;
|
|
55
64
|
#slug;
|
|
56
65
|
/**
|
|
66
|
+
* Factory's own GitHub identity. Platform credentials do not carry the login
|
|
67
|
+
* they post as, so this starts from the configured slug (usually absent on a
|
|
68
|
+
* Platform deployment) and is corrected the first time Factory writes.
|
|
69
|
+
*/
|
|
70
|
+
identity;
|
|
71
|
+
/**
|
|
57
72
|
* Extra reviewer bot logins this deployment trusts for author-gated
|
|
58
73
|
* notifications, merged over the built-in defaults.
|
|
59
74
|
*/
|
|
@@ -303,6 +318,7 @@ var PlatformGithubIntegration = class {
|
|
|
303
318
|
this.#client = new PlatformApiClient(config);
|
|
304
319
|
this.#endpointHost = new URL(config.baseUrl).host;
|
|
305
320
|
this.#slug = options.slug;
|
|
321
|
+
this.identity = new GithubAppIdentity(process.env.MASTRA_PLATFORM_GITHUB_APP_SLUG?.trim() || PLATFORM_GITHUB_APP_SLUG);
|
|
306
322
|
this.authorizedBots = parseAuthorizedBotsEnv(process.env.MASTRACODE_GITHUB_AUTHORIZED_BOTS) ?? [];
|
|
307
323
|
this.#pollingEnabled = process.env.MASTRA_PLATFORM_GITHUB_POLLING_ENABLED?.trim().toLowerCase() !== "false";
|
|
308
324
|
this.#pollingIntervalMs = optionalPositiveIntegerEnv("MASTRA_PLATFORM_GITHUB_POLLING_INTERVAL_MS");
|
|
@@ -357,7 +373,7 @@ var PlatformGithubIntegration = class {
|
|
|
357
373
|
});
|
|
358
374
|
}
|
|
359
375
|
routes(ctx) {
|
|
360
|
-
const ingestFactoryEvent = attachGithubRules(this, ctx);
|
|
376
|
+
const ingestFactoryEvent = withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints);
|
|
361
377
|
return [
|
|
362
378
|
this.#statusRoute(ctx),
|
|
363
379
|
this.#connectRoute(ctx),
|
|
@@ -505,13 +521,21 @@ var PlatformGithubIntegration = class {
|
|
|
505
521
|
controller: ctx.controller,
|
|
506
522
|
github: this,
|
|
507
523
|
storage: ctx.storage.generic,
|
|
508
|
-
ingestFactoryEvent: attachGithubRules(this, ctx),
|
|
524
|
+
ingestFactoryEvent: withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints),
|
|
509
525
|
reconcileFactoryState: this.#pullRequestReconcileEnabled ? attachGithubReconciler(this, ctx, (input) => this.fetchPullRequestState(input)) : void 0,
|
|
510
526
|
reconcileIssuesFactoryState: this.#issueReconcileEnabled ? attachGithubIssueReconciler(this, ctx, (input) => this.fetchIssueState(input)) : void 0,
|
|
527
|
+
...ctx.baseCheckpoints ? { sweepBaseCheckpoints: () => ctx.baseCheckpoints.sweep() } : {},
|
|
511
528
|
pollEventsEnabled: this.#pollingEnabled,
|
|
512
529
|
intervalMs: this.#pollingIntervalMs,
|
|
513
530
|
pullRequestReconcileIntervalMs: this.#pullRequestReconcileIntervalMs,
|
|
514
|
-
issueReconcileIntervalMs: this.#issueReconcileIntervalMs
|
|
531
|
+
issueReconcileIntervalMs: this.#issueReconcileIntervalMs,
|
|
532
|
+
sourceControl: {
|
|
533
|
+
projectRepositories: {
|
|
534
|
+
listConfiguredExternalKeys: () => this.storage.projectRepositories.listConfiguredExternalKeys(),
|
|
535
|
+
listByExternalRepository: (args) => this.storage.projectRepositories.listByExternalRepository(args)
|
|
536
|
+
},
|
|
537
|
+
repositories: { findByExternalId: (args) => this.storage.repositories.findByExternalId(args) }
|
|
538
|
+
}
|
|
515
539
|
})];
|
|
516
540
|
}
|
|
517
541
|
/**
|
|
@@ -703,12 +727,22 @@ var PlatformGithubIntegration = class {
|
|
|
703
727
|
throw error;
|
|
704
728
|
}
|
|
705
729
|
}
|
|
730
|
+
/**
|
|
731
|
+
* Learn Factory's own login from a write it just made. Skipped when the write
|
|
732
|
+
* was made on behalf of a user — that comment is authored by the human, and
|
|
733
|
+
* recording it would teach Factory to mistake a person for itself.
|
|
734
|
+
*/
|
|
735
|
+
#observeSelfAuthor(comment, actingUserId) {
|
|
736
|
+
if (actingUserId) return;
|
|
737
|
+
this.identity.observeSelfAuthor(comment.user?.login);
|
|
738
|
+
}
|
|
706
739
|
async #createIssueComment(input) {
|
|
707
740
|
requireGithubConnection(input.connection);
|
|
708
741
|
const repository = requireSource(input.sourceId, "GitHub Intake requires a repository source.");
|
|
709
742
|
const issueNumber = requirePositiveId(input.issueId, "issue");
|
|
710
743
|
try {
|
|
711
744
|
const comment = await this.#client.request("POST", repositoryPath(repository, `issues/${issueNumber}/comments`), { body: input.body }, { actingUserId: input.actingUserId });
|
|
745
|
+
this.#observeSelfAuthor(comment, input.actingUserId);
|
|
712
746
|
return {
|
|
713
747
|
id: String(comment.id),
|
|
714
748
|
url: comment.htmlUrl
|
|
@@ -774,7 +808,9 @@ var PlatformGithubIntegration = class {
|
|
|
774
808
|
};
|
|
775
809
|
}
|
|
776
810
|
async #createComment(input) {
|
|
777
|
-
|
|
811
|
+
const comment = await this.#client.request("POST", repositoryPath(input.sourceId, `issues/${requirePositiveId(input.pullRequestId, "pull request")}/comments`), { body: input.body }, { actingUserId: input.actingUserId });
|
|
812
|
+
this.#observeSelfAuthor(comment, input.actingUserId);
|
|
813
|
+
return parseComment(comment);
|
|
778
814
|
}
|
|
779
815
|
async #updateComment(input) {
|
|
780
816
|
requireGithubConnection(input.connection);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","names":["#client","#endpointHost","#slug","#pollingEnabled","#pollingIntervalMs","#pullRequestReconcileEnabled","#issueReconcileEnabled","#pullRequestReconcileIntervalMs","#issueReconcileIntervalMs","#installationReposCache","#repositoryAccessCache","#resolveIntakeDispatch","#listIssues","#listPullRequests","#getIssue","#createIssueComment","#updateIntakeIssue","#storage","#getPullRequest","#createPullRequest","#updatePullRequest","#mergePullRequest","#listComments","#createComment","#updateComment","#deleteComment","#listReviews","#getReview","#createReview","#updateReview","#submitReview","#dismissReview","#deletePendingReview","#listReviewComments","#createReviewComment","#updateReviewComment","#deleteReviewComment","#requestedReviewers","#integrationStorage","#statusRoute","#connectRoute","#connectUserRoute","#syncInstallations","#fetchUserConnection"],"sources":["../../../../src/integrations/platform/github/integration.ts"],"sourcesContent":["import type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport type { Context } from 'hono';\n\nimport type { IntegrationConnection } from '../../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n UpdateIntakeIssueInput,\n} from '../../../capabilities/intake.js';\nimport type {\n CreatePullRequestCommentInput,\n CreatePullRequestInput,\n CreateReviewCommentInput,\n CreateReviewInput,\n DeletePullRequestCommentInput,\n DismissReviewInput,\n ListPullRequestCommentsInput,\n ListPullRequestsInput,\n ListReviewCommentsInput,\n ListReviewsInput,\n MergePullRequestInput,\n PullRequest,\n PullRequestComment,\n PullRequestRef,\n RepositoryAccess,\n Review,\n ReviewComment,\n ReviewRef,\n SubmitReviewInput,\n UpdatePullRequestCommentInput,\n UpdatePullRequestInput,\n UpdateReviewInput,\n UpdateReviewersInput,\n VersionControl,\n} from '../../../capabilities/version-control.js';\nimport type { IntegrationStorageHandle } from '../../../storage/domains/integrations/base.js';\nimport type {\n SourceControlInstallation,\n SourceControlStorageHandle,\n} from '../../../storage/domains/source-control/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';\nimport type { GithubIntegration, GithubRepositoryPermission, RepoSummary } from '../../github/integration.js';\nimport { attachGithubIssueReconciler } from '../../github/issue-reconciler.js';\nimport { reconcileInterval, reconciliationEnabled } from '../../github/reconciliation-config.js';\nimport { buildGithubRoutes } from '../../github/routes.js';\nimport { attachGithubReconciler, attachGithubRules } from '../../github/rules.js';\nimport type { ReconcileIssueState, ReconcilePullRequestState } from '../../github/rules.js';\nimport {\n createGithubSubscriptionTools,\n parseCreatedPullRequest,\n subscribeCurrentSessionToPullRequest,\n} from '../../github/session-subscriptions.js';\nimport type { GithubSubscriptionStorage } from '../../github/subscriptions.js';\nimport { parseAuthorizedBotsEnv } from '../../github/webhook.js';\nimport {\n logPlatformInfo,\n logPlatformWarn,\n PlatformApiClient,\n PlatformApiError,\n platformApiClientConfigFromEnv,\n} from '../api-client.js';\nimport { PlatformGithubEventWorker } from './event-worker.js';\nimport type { PlatformGithubEventStorage } from './event-worker.js';\n\ntype GithubActor = { login: string; avatarUrl: string | null; htmlUrl: string | null } | null;\n\ntype PlatformGithubInstallation = {\n installationId: number;\n accountLogin: string;\n accountType: string;\n suspendedAt: string | null;\n usable: boolean;\n};\n\ntype PlatformGithubUserConnection = {\n connected: boolean;\n githubUsername: string | null;\n reason?: 'token-invalid' | 'no-accessible-installation' | 'missing-permissions' | 'verification-unavailable' | null;\n};\n\ntype GithubIssue = {\n number: number;\n state: 'open' | 'closed';\n title: string;\n body: string | null;\n htmlUrl: string;\n labels: string[];\n assignees: string[];\n commentCount: number;\n user: GithubActor;\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubComment = {\n id: number;\n body: string;\n htmlUrl: string;\n user: GithubActor;\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubPullRequest = {\n number: number;\n title: string;\n body: string | null;\n state: 'open' | 'closed';\n htmlUrl: string;\n merged: boolean;\n mergeable: boolean | null;\n draft: boolean;\n head: { ref: string; sha: string };\n base: { ref: string; repo: { id: number; fullName: string } };\n user: GithubActor;\n assignees?: string[];\n requestedReviewers?: string[];\n labels?: string[];\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubReview = {\n id: number;\n htmlUrl: string | null;\n body: string | null;\n state: 'PENDING' | 'COMMENTED' | 'APPROVED' | 'CHANGES_REQUESTED' | 'DISMISSED';\n commitId: string | null;\n submittedAt: string | null;\n user: GithubActor;\n};\n\ntype GithubReviewComment = GithubComment & {\n path: string;\n line: number | null;\n side: 'LEFT' | 'RIGHT' | null;\n commitId: string;\n replyToId: number | null;\n};\n\nconst PAGE_SIZE = 30;\nconst API_PREFIX = '/v1/server';\n/**\n * How long an installation's repository listing may be reused. The repos\n * route and token minting both call it — often several times within one UI\n * interaction — and each call is a full Platform round trip.\n */\nconst INSTALLATION_REPOS_CACHE_TTL_MS = 30_000;\n/**\n * How long a minted repository-scoped token may be reused. GitHub\n * installation tokens live ~60 minutes; 5 minutes keeps a wide validity\n * margin while collapsing the per-session-materialization mint round trip.\n */\nconst REPOSITORY_ACCESS_CACHE_TTL_MS = 5 * 60_000;\n/**\n * Upper bound for both TTL caches. Entries expire lazily on re-access, so\n * without a hard cap keys that stop being queried would accumulate for the\n * integration's (long) lifetime. Insertion-order eviction — matches the\n * bounded verification cache in `@mastra/auth-studio`.\n */\nconst MAX_CACHE_ENTRIES = 1000;\n\nfunction setBounded<K, V>(cache: Map<K, V>, key: K, value: V): void {\n cache.delete(key);\n cache.set(key, value);\n if (cache.size > MAX_CACHE_ENTRIES) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n}\n\nconst REPOSITORY_TOKEN_PERMISSIONS = {\n contents: 'write',\n issues: 'write',\n pull_requests: 'write',\n} as const;\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction routeBaseUrl(ctx: IntegrationContext, requestUrl: string): string {\n return (ctx.baseUrl || new URL(requestUrl).origin).replace(/\\/+$/, '');\n}\n\nexport class PlatformGithubIntegration implements FactoryIntegration {\n readonly id = 'github';\n readonly #client: PlatformApiClient;\n readonly #endpointHost: string;\n readonly #slug: string | undefined;\n /**\n * Extra reviewer bot logins this deployment trusts for author-gated\n * notifications, merged over the built-in defaults.\n */\n readonly authorizedBots: readonly string[];\n readonly #pollingEnabled: boolean;\n readonly #pollingIntervalMs: number | undefined;\n readonly #pullRequestReconcileEnabled: boolean;\n readonly #issueReconcileEnabled: boolean;\n readonly #pullRequestReconcileIntervalMs: number | undefined;\n readonly #issueReconcileIntervalMs: number | undefined;\n #storage: SourceControlStorageHandle | undefined;\n #integrationStorage: GithubSubscriptionStorage | undefined;\n /** installationId → cached repository listing (TTL-bounded). */\n readonly #installationReposCache = new Map<number, { repos: RepoSummary[]; expiresAt: number }>();\n /** `orgId:repositoryId` → cached repository access (TTL-bounded). */\n readonly #repositoryAccessCache = new Map<string, { access: RepositoryAccess; expiresAt: number }>();\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async ({ orgId, userId }) => {\n const installations = await this.#client.request<{\n installations: Array<{\n installationId: number;\n accountLogin: string;\n accountType: string;\n suspendedAt: string | null;\n usable: boolean;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations`);\n const usable = installations.installations.filter(\n installation => installation.usable && !installation.suspendedAt,\n );\n const repositories = await Promise.all(\n usable.map(async installation => {\n const storedInstallation = await this.versionControl.registerInstallation({\n orgId,\n userId,\n installation: {\n externalId: String(installation.installationId),\n accountName: installation.accountLogin,\n accountType: installation.accountType,\n },\n });\n const result = await this.#client.request<{\n repositories: Array<{\n id: number;\n fullName: string;\n private: boolean;\n defaultBranch: string;\n htmlUrl: string;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations/${installation.installationId}/repositories`);\n await this.versionControl.registerRepositories({\n orgId,\n installationId: storedInstallation.id,\n repositories: result.repositories.map(repository => ({\n externalId: String(repository.id),\n slug: repository.fullName,\n defaultBranch: repository.defaultBranch,\n metadata: { private: repository.private, url: repository.htmlUrl },\n })),\n });\n return result.repositories.map(repository => ({ repository, installation }));\n }),\n );\n return repositories.flat().map(({ repository, installation }) => ({\n id: repository.fullName,\n name: repository.fullName,\n type: 'repository',\n metadata: {\n installationId: installation.installationId,\n accountLogin: installation.accountLogin,\n accountType: installation.accountType,\n repositoryId: repository.id,\n defaultBranch: repository.defaultBranch,\n private: repository.private,\n url: repository.htmlUrl,\n },\n }));\n },\n listItems: async ({ sourceIds, cursor }) => {\n const page = parsePositiveCursor(cursor);\n const pages = await Promise.all(\n sourceIds.map(async sourceId => {\n const connection = { type: 'app-installation' as const, installationId: 1 };\n const [issues, pullRequests] = await Promise.all([\n this.#listIssues(connection, sourceId, page),\n this.#listPullRequests({ connection, sourceId, includeDrafts: false, cursor: String(page) }),\n ]);\n return {\n items: [\n ...issues.issues.map(issue => ({\n source: { type: 'issue', externalId: `${sourceId}:${issue.id}`, url: issue.url },\n sourceId,\n title: issue.title,\n status: issue.state ?? undefined,\n labels: issue.labels,\n assignee: issue.assignee,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: { repository: sourceId, number: Number(issue.id), author: issue.author },\n })),\n ...pullRequests.pullRequests.map(pullRequest => ({\n source: { type: 'pull-request', externalId: `${sourceId}:${pullRequest.id}`, url: pullRequest.url },\n sourceId,\n title: pullRequest.title,\n status: pullRequest.state,\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n metadata: {\n repository: sourceId,\n number: Number(pullRequest.id),\n author: pullRequest.author,\n baseBranch: pullRequest.baseBranch,\n headBranch: pullRequest.headBranch,\n },\n })),\n ],\n hasNextPage: issues.nextCursor !== null || pullRequests.nextCursor !== null,\n };\n }),\n );\n return {\n items: pages.flatMap(result => result.items),\n nextCursor: pages.some(result => result.hasNextPage) ? String(page + 1) : null,\n };\n },\n listIssues: async input => {\n requireGithubConnection(input.connection);\n const sourceId = requireSingleSource(input.sourceIds, 'GitHub Intake requires exactly one repository source.');\n return this.#listIssues(input.connection, sourceId, parsePositiveCursor(input.cursor), input.labels);\n },\n getIssue: input => this.#getIssue(input.connection, input.sourceId, input.issueId),\n createComment: input => this.#createIssueComment(input),\n updateIssue: input => this.#updateIntakeIssue(input),\n };\n\n readonly versionControl: VersionControl = {\n initialize: ({ storage }) => {\n this.#storage = storage;\n },\n registerInstallation: ({ orgId, userId, installation }) =>\n this.storage.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.storage.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 // Every session materialization requests access; reuse a recent grant\n // instead of re-minting through the Platform each time. The TTL keeps\n // a wide margin under GitHub's ~60min installation-token lifetime.\n const cacheKey = `${orgId}:${repositoryId}`;\n const cached = this.#repositoryAccessCache.get(cacheKey);\n if (cached && cached.expiresAt > Date.now()) return cached.access;\n this.#repositoryAccessCache.delete(cacheKey);\n\n const repository = await this.storage.repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const cloneUrl = `https://github.com/${repository.slug}.git`;\n const installation = await this.storage.installations.get({ orgId, id: repository.installationId });\n if (!installation) throw new Error('Version-control installation not found.');\n const installationId = parsePositiveInteger(installation.externalId);\n if (installationId === null) throw new Error('GitHub installation id is invalid.');\n const repositoryName = splitRepository(repository.slug).repo;\n\n try {\n const token = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${installationId}/token`,\n { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n const access: RepositoryAccess = {\n cloneUrl,\n authorization: { scheme: 'bearer', token: token.token },\n };\n setBounded(this.#repositoryAccessCache, cacheKey, {\n access,\n expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,\n });\n return access;\n } catch (err) {\n // Recover from stale installation: when a GitHub App is uninstalled and reinstalled,\n // GitHub assigns a new installation ID. Platform creates a new installation row,\n // and Factory's intake.listSources creates a new local installation row with the\n // new externalId. Try to find the new installation by accountName.\n if (!isDeadInstallation(err) || !installation.accountName) throw err;\n const installations = await this.storage.installations.list({ orgId });\n const newInstallation = installations.find(\n inst => inst.accountName === installation.accountName && inst.id !== installation.id,\n );\n if (!newInstallation) throw err;\n const newInstallationId = parsePositiveInteger(newInstallation.externalId);\n if (newInstallationId === null) throw err;\n\n // Persist the migration so we don't hit the recovery path on every call.\n await this.storage.repositories.migrateInstallation({\n orgId,\n id: repositoryId,\n newInstallationId: newInstallation.id,\n });\n\n const token = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${newInstallationId}/token`,\n { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n const access: RepositoryAccess = {\n cloneUrl,\n authorization: { scheme: 'bearer', token: token.token },\n };\n setBounded(this.#repositoryAccessCache, cacheKey, {\n access,\n expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,\n });\n return access;\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.#updatePullRequest({ ...input, state: 'closed' }),\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.#requestedReviewers('GET', input),\n requestReviewers: input => this.#requestedReviewers('POST', input),\n removeRequestedReviewers: input => this.#requestedReviewers('DELETE', input),\n };\n\n constructor(\n options: {\n /** GitHub App slug used to recognize Factory's own webhook writes. */\n slug?: string;\n } = {},\n ) {\n const config = platformApiClientConfigFromEnv();\n this.#client = new PlatformApiClient(config);\n this.#endpointHost = new URL(config.baseUrl).host;\n this.#slug = options.slug;\n this.authorizedBots = parseAuthorizedBotsEnv(process.env.MASTRACODE_GITHUB_AUTHORIZED_BOTS) ?? [];\n this.#pollingEnabled = process.env.MASTRA_PLATFORM_GITHUB_POLLING_ENABLED?.trim().toLowerCase() !== 'false';\n this.#pollingIntervalMs = optionalPositiveIntegerEnv('MASTRA_PLATFORM_GITHUB_POLLING_INTERVAL_MS');\n const legacyReconcileEnabled = process.env.MASTRA_PLATFORM_GITHUB_RECONCILE_ENABLED;\n this.#pullRequestReconcileEnabled = reconciliationEnabled(\n process.env.MASTRACODE_PLATFORM_GITHUB_PR_RECONCILE_ENABLED,\n legacyReconcileEnabled,\n );\n this.#issueReconcileEnabled = reconciliationEnabled(\n process.env.MASTRACODE_PLATFORM_GITHUB_ISSUE_RECONCILE_ENABLED,\n legacyReconcileEnabled,\n );\n const legacyReconcileIntervalMs = reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_RECONCILE_INTERVAL_MS);\n this.#pullRequestReconcileIntervalMs =\n reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_PR_RECONCILE_INTERVAL_MS) ?? legacyReconcileIntervalMs;\n this.#issueReconcileIntervalMs =\n reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_ISSUE_RECONCILE_INTERVAL_MS) ?? legacyReconcileIntervalMs;\n }\n\n /** GitHub App slug when the deployment explicitly provides it. */\n get slug(): string | undefined {\n return this.#slug;\n }\n\n get storage(): SourceControlStorageHandle {\n if (!this.#storage) throw new Error('PlatformGithubIntegration source-control storage has not been initialized.');\n return this.#storage;\n }\n\n get sourceControlStorage(): SourceControlStorageHandle {\n return this.storage;\n }\n\n get integrationStorage(): GithubSubscriptionStorage {\n if (!this.#integrationStorage) {\n throw new Error('PlatformGithubIntegration generic storage has not been initialized.');\n }\n return this.#integrationStorage;\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 = target.repository.includes('/')\n ? target.repository\n : (await this.storage.repositories.findByExternalId({ orgId, externalId: target.repository }))?.slug;\n if (!repository) return null;\n return {\n connection: { type: 'app-installation', installationId: 1 },\n sourceId: repository,\n issueId: target.issueId,\n };\n }\n\n initialize({ storage }: { storage: IntegrationStorageHandle }): void {\n this.#integrationStorage = storage as unknown as GithubSubscriptionStorage;\n logPlatformInfo('Platform GitHub integration initialized', {\n endpointHost: this.#endpointHost,\n pollingEnabled: this.#pollingEnabled,\n pollingIntervalMs: this.#pollingIntervalMs,\n pullRequestReconcileEnabled: this.#pullRequestReconcileEnabled,\n issueReconcileEnabled: this.#issueReconcileEnabled,\n });\n }\n\n routes(ctx: IntegrationContext): ApiRoute[] {\n const ingestFactoryEvent = attachGithubRules(this, ctx);\n return [\n this.#statusRoute(ctx),\n this.#connectRoute(ctx),\n this.#connectUserRoute(ctx),\n ...buildGithubRoutes({\n auth: ctx.auth,\n fleet: ctx.fleet,\n storage: ctx.factoryStorage,\n github: this as unknown as GithubIntegration,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n controller: ctx.controller,\n projects: ctx.storage.projects,\n emitAudit: ctx.hooks?.emitAudit,\n ingestFactoryEvent,\n }).filter(\n route =>\n route.path !== '/web/github/status' &&\n route.path !== '/web/github/webhook' &&\n !route.path.startsWith('/auth/github/'),\n ),\n ];\n }\n\n #statusRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant) return c.json({ error: 'unauthorized', reason: 'auth_required' }, 401);\n if (!tenant.orgId) {\n return c.json({\n enabled: true,\n sandboxEnabled: ctx.fleet.enabled,\n organizationRequired: true,\n connected: false,\n installations: [],\n userConnected: false,\n userGithubUsername: null,\n reason: 'organization_required',\n diagnostics: this.diagnostics(),\n });\n }\n\n const [installations, userConnection] = await Promise.all([\n this.#syncInstallations(tenant.orgId, tenant.userId),\n this.#fetchUserConnection(tenant.userId),\n ]);\n return c.json({\n enabled: true,\n sandboxEnabled: ctx.fleet.enabled,\n connected: installations.length > 0,\n installations: installations.map(installation => ({\n installationId: Number(installation.externalId),\n accountLogin: installation.accountName,\n accountType: installation.accountType,\n })),\n userConnected: userConnection.connected,\n userGithubUsername: userConnection.githubUsername,\n reason: installations.length > 0 ? 'ready' : 'not_connected',\n diagnostics: this.diagnostics(),\n });\n },\n });\n }\n\n #connectRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/github/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const redirectTo = c.req.query('redirectTo') || c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform GitHub connect flow', {\n orgId: tenant.orgId,\n redirectTo,\n originator,\n });\n const query = new URLSearchParams({\n action: 'install',\n redirectTo,\n originator,\n });\n const { url } = await this.#client.request<{ url: string }>(\n 'GET',\n `${API_PREFIX}/github-app/install-url?${query}`,\n );\n return c.redirect(url);\n },\n });\n }\n\n #connectUserRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/github/connect-user', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const redirectTo = c.req.query('redirectTo') || c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform GitHub user authorization flow', {\n orgId: tenant.orgId,\n redirectTo,\n originator,\n });\n const query = new URLSearchParams({\n userId: tenant.userId,\n redirectTo,\n originator,\n });\n const { url } = await this.#client.request<{ url: string }>(\n 'GET',\n `${API_PREFIX}/github-app/authenticate?${query}`,\n );\n return c.redirect(url);\n },\n });\n }\n\n /**\n * Personal GitHub connection status for the acting user. Returns\n * not-connected when the platform predates the user-connection endpoint.\n */\n async #fetchUserConnection(userId: string): Promise<PlatformGithubUserConnection> {\n try {\n const connection = await this.#client.request<PlatformGithubUserConnection>(\n 'GET',\n `${API_PREFIX}/github-app/user-connection?${new URLSearchParams({ userId })}`,\n );\n if (!connection.connected && connection.reason) {\n logPlatformWarn('Platform GitHub user connection verification failed', {\n userId,\n reason: connection.reason,\n });\n }\n return connection;\n } catch {\n return { connected: false, githubUsername: null };\n }\n }\n\n async #syncInstallations(orgId: string, userId: string): Promise<SourceControlInstallation[]> {\n const result = await this.#client.request<{ installations: PlatformGithubInstallation[] }>(\n 'GET',\n `${API_PREFIX}/github-app/installations`,\n );\n const usableInstallations = result.installations.filter(\n installation => installation.usable && !installation.suspendedAt,\n );\n return Promise.all(\n usableInstallations.map(installation =>\n this.versionControl.registerInstallation({\n orgId,\n userId,\n installation: {\n externalId: String(installation.installationId),\n accountName: installation.accountLogin,\n accountType: installation.accountType,\n },\n }),\n ),\n );\n }\n\n workers(ctx: IntegrationContext): MastraWorker[] {\n if (!this.#pollingEnabled && !this.#pullRequestReconcileEnabled && !this.#issueReconcileEnabled) return [];\n if (!ctx.controller) {\n throw new Error('Platform GitHub event polling requires the mounted Mastra Code controller.');\n }\n return [\n new PlatformGithubEventWorker({\n client: this.#client,\n controller: ctx.controller,\n github: this,\n storage: ctx.storage.generic as unknown as PlatformGithubEventStorage,\n ingestFactoryEvent: attachGithubRules(this, ctx),\n reconcileFactoryState: this.#pullRequestReconcileEnabled\n ? attachGithubReconciler(this, ctx, input => this.fetchPullRequestState(input))\n : undefined,\n reconcileIssuesFactoryState: this.#issueReconcileEnabled\n ? attachGithubIssueReconciler(this, ctx, input => this.fetchIssueState(input))\n : undefined,\n pollEventsEnabled: this.#pollingEnabled,\n intervalMs: this.#pollingIntervalMs,\n pullRequestReconcileIntervalMs: this.#pullRequestReconcileIntervalMs,\n issueReconcileIntervalMs: this.#issueReconcileIntervalMs,\n }),\n ];\n }\n\n /**\n * Reads live PR state through the Platform GitHub proxy for the merge\n * reconciler. Returns undefined when the PR cannot be resolved (missing,\n * proxy error) 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 let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(input.repository);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{\n title?: string;\n html_url?: string;\n state?: string;\n draft?: boolean;\n merged?: boolean;\n created_at?: 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 merged_by?: { login?: string } | null;\n head?: { ref?: string };\n base?: { ref?: string };\n }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/pulls/${input.number}`,\n );\n return {\n title: result.title ?? `PR ${input.number}`,\n url: result.html_url ?? `https://github.com/${input.repository}/pull/${input.number}`,\n state: result.state === 'closed' ? 'closed' : 'open',\n draft: result.draft === true,\n merged: result.merged === true,\n assignees: (result.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n requestedReviewers: (result.requested_reviewers ?? []).flatMap(reviewer =>\n reviewer.login ? [reviewer.login] : [],\n ),\n labels: (result.labels ?? []).flatMap(label =>\n typeof label === 'string' ? [label] : label.name ? [label.name] : [],\n ),\n headBranch: result.head?.ref ?? '',\n baseBranch: result.base?.ref ?? '',\n ...(result.user?.login ? { author: result.user.login } : {}),\n ...(result.created_at ? { createdAt: result.created_at } : {}),\n ...(result.merged_by?.login ? { mergedBy: result.merged_by.login } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Reads live issue state through the Platform GitHub proxy for the\n * reconciler. Returns undefined when the issue cannot be resolved (missing,\n * is actually a PR, proxy error) so a sweep never fabricates a close.\n */\n async fetchIssueState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcileIssueState | undefined> {\n let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(input.repository);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{\n title?: string;\n html_url?: string;\n state?: string;\n state_reason?: string | null;\n created_at?: string;\n updated_at?: string;\n user?: { login?: string } | null;\n assignees?: Array<{ login?: string }> | null;\n labels?: Array<{ name?: string } | string> | null;\n pull_request?: unknown;\n }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/issues/${input.number}`,\n );\n if (result.pull_request) return undefined;\n return {\n title: result.title ?? `Issue ${input.number}`,\n url: result.html_url ?? `https://github.com/${input.repository}/issues/${input.number}`,\n state: result.state === 'closed' ? 'closed' : 'open',\n ...(result.state_reason ? { stateReason: result.state_reason } : {}),\n assignees: (result.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n labels: (result.labels ?? []).map(label => (typeof label === 'string' ? label : label.name)).filter((name): name is string => Boolean(name)),\n ...(result.user?.login ? { author: result.user.login } : {}),\n ...(result.created_at ? { createdAt: result.created_at } : {}),\n ...(result.updated_at ? { updatedAt: result.updated_at } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n sessionTools({ requestContext }: { requestContext: RequestContext }): IntegrationTools {\n return createGithubSubscriptionTools(requestContext, this as unknown as GithubIntegration);\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(\n requestContext,\n pullRequestUrl,\n 'auto-gh-pr-create',\n this as unknown as GithubIntegration,\n );\n }\n\n diagnostics(): Record<string, unknown> {\n return {\n mode: 'platform',\n endpointHost: this.#endpointHost,\n polling: {\n enabled: this.#pollingEnabled,\n ...(this.#pollingIntervalMs === undefined ? {} : { intervalMs: this.#pollingIntervalMs }),\n },\n reconcile: {\n pullRequests: {\n enabled: this.#pullRequestReconcileEnabled,\n ...(this.#pullRequestReconcileIntervalMs === undefined\n ? {}\n : { intervalMs: this.#pullRequestReconcileIntervalMs }),\n },\n issues: {\n enabled: this.#issueReconcileEnabled,\n ...(this.#issueReconcileIntervalMs === undefined ? {} : { intervalMs: this.#issueReconcileIntervalMs }),\n },\n },\n };\n }\n\n async getRepositoryCollaboratorPermission(\n _installationId: number,\n repoFullName: string,\n username: string,\n signal?: AbortSignal,\n ): Promise<GithubRepositoryPermission | undefined> {\n let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(repoFullName);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{ permission: GithubRepositoryPermission }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/collaborators/${encodeURIComponent(username)}/permission`,\n undefined,\n { signal },\n );\n return result.permission;\n } catch {\n return undefined;\n }\n }\n\n async listInstallationRepos(installationId: number): Promise<RepoSummary[]> {\n // Hot in two places — the repos route and token minting (which re-lists\n // only to validate the 1–10 repo rule). A short TTL collapses repeat\n // Platform round trips within one UI interaction.\n const cached = this.#installationReposCache.get(installationId);\n if (cached && cached.expiresAt > Date.now()) return cached.repos;\n this.#installationReposCache.delete(installationId);\n\n const result = await this.#client.request<{\n repositories: Array<{\n id: number;\n owner: string;\n name: string;\n fullName: string;\n private: boolean;\n defaultBranch: string;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations/${installationId}/repositories`);\n const repos = result.repositories.map(repository => ({ ...repository, installationId }));\n setBounded(this.#installationReposCache, installationId, {\n repos,\n expiresAt: Date.now() + INSTALLATION_REPOS_CACHE_TTL_MS,\n });\n return repos;\n }\n\n async mintInstallationToken(installationId: number): Promise<string> {\n const repositories = await this.listInstallationRepos(installationId);\n if (repositories.length === 0 || repositories.length > 10) {\n throw new Error('Platform GitHub token minting requires between one and ten installation repositories.');\n }\n const result = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${installationId}/token`,\n { repositories: repositories.map(repository => repository.name), permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n return result.token;\n }\n\n async addIssueLabels(\n _installationId: number,\n sourceId: string,\n issueNumber: number,\n labels: string[],\n ): Promise<string[]> {\n const result = await this.#client.request<{ labels: string[] }>(\n 'POST',\n repositoryPath(sourceId, `issues/${issueNumber}/labels`),\n { labels },\n );\n return result.labels;\n }\n\n getInstallationOctokit(_installationId: number): ReturnType<GithubIntegration['getInstallationOctokit']> {\n return {\n pulls: {\n get: async ({ owner, repo, pull_number }: { owner: string; repo: string; pull_number: number }) => {\n const data = await this.#client.request<GithubPullRequest>(\n 'GET',\n repositoryPath(`${owner}/${repo}`, `pulls/${pull_number}`),\n );\n return { data: { base: { repo: { id: data.base.repo.id } } } };\n },\n },\n } as unknown as ReturnType<GithubIntegration['getInstallationOctokit']>;\n }\n\n async #listIssues(connection: IntegrationConnection, sourceId: string, page: number, labels?: string[]) {\n requireGithubConnection(connection);\n const path = repositoryPath(sourceId, 'issues');\n const query = new URLSearchParams({ state: 'open', page: String(page), per_page: String(PAGE_SIZE) });\n const normalizedLabels = normalizeLabels(labels);\n if (normalizedLabels.length > 0) query.set('label', normalizedLabels.join(','));\n const result = await this.#client.request<{ issues: GithubIssue[] }>('GET', `${path}?${query}`);\n return {\n issues: result.issues.map(issue => parseIntakeIssue(sourceId, issue)),\n nextCursor: result.issues.length > 0 ? String(page + 1) : null,\n };\n }\n\n async #getIssue(connection: IntegrationConnection, sourceId: string | undefined, issueId: string) {\n requireGithubConnection(connection);\n const repository = requireSource(sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(issueId, 'issue');\n try {\n const [issue, comments] = await Promise.all([\n this.#client.request<GithubIssue>('GET', repositoryPath(repository, `issues/${issueNumber}`)),\n this.#client.request<{ comments: GithubComment[] }>(\n 'GET',\n `${repositoryPath(repository, `issues/${issueNumber}/comments`)}?per_page=100`,\n ),\n ]);\n return parseIntakeIssueDetail(repository, issue, comments.comments);\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #updateIntakeIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n requireGithubConnection(input.connection);\n const repository = requireSource(input.sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(input.issueId, 'issue');\n if (input.state.kind === 'byName') {\n logPlatformWarn(`Platform GitHub: 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 // Reject PR targets: probe the pulls endpoint. A 200 means the number is a\n // pull request, not an issue. Factory does not close PRs via updateIssue —\n // PR merges/closes go through the version-control pipeline.\n try {\n await this.#client.request<GithubPullRequest>('GET', repositoryPath(repository, `pulls/${issueNumber}`));\n logPlatformWarn(`Platform GitHub: updateIssue rejected — target ${repository}#${issueNumber} is a pull request.`);\n return null;\n } catch (error) {\n if (!isNotFound(error)) throw error;\n // 404 on pulls means it's an issue (or nothing) — fall through to PATCH.\n }\n try {\n const issue = await this.#client.request<GithubIssue>(\n 'PATCH',\n repositoryPath(repository, `issues/${issueNumber}`),\n {\n state: targetState,\n ...(stateReason ? { state_reason: stateReason } : {}),\n },\n { actingUserId: input.actingUserId },\n );\n return parseIntakeIssue(repository, issue);\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #createIssueComment(input: CreateIntakeCommentInput) {\n requireGithubConnection(input.connection);\n const repository = requireSource(input.sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(input.issueId, 'issue');\n try {\n const comment = await this.#client.request<GithubComment>(\n 'POST',\n repositoryPath(repository, `issues/${issueNumber}/comments`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return { id: String(comment.id), url: comment.htmlUrl };\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #listPullRequests(input: ListPullRequestsInput) {\n requireGithubConnection(input.connection);\n const page = parsePositiveCursor(input.cursor);\n const query = new URLSearchParams({\n state: input.state ?? 'open',\n page: String(page),\n per_page: String(PAGE_SIZE),\n });\n const result = await this.#client.request<{ pullRequests: GithubPullRequest[] }>(\n 'GET',\n `${repositoryPath(input.sourceId, 'pulls')}?${query}`,\n );\n return {\n pullRequests: result.pullRequests\n .filter(pullRequest => input.includeDrafts !== false || !pullRequest.draft)\n .map(parsePullRequest),\n nextCursor: result.pullRequests.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getPullRequest(input: PullRequestRef) {\n try {\n return parsePullRequest(\n await this.#client.request<GithubPullRequest>('GET', pullRequestPath(input, input.pullRequestId)),\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #createPullRequest(input: CreatePullRequestInput) {\n requireGithubConnection(input.connection);\n const result = await this.#client.request<GithubPullRequest>(\n 'POST',\n repositoryPath(input.sourceId, 'pulls'),\n {\n head: input.headBranch,\n base: input.baseBranch,\n title: input.title,\n body: input.body,\n draft: input.draft,\n },\n { actingUserId: input.actingUserId },\n );\n return parsePullRequest(result);\n }\n\n async #updatePullRequest(input: UpdatePullRequestInput) {\n const result = await this.#client.request<GithubPullRequest>(\n 'PATCH',\n pullRequestPath(input, input.pullRequestId),\n {\n title: input.title,\n body: input.body === null ? '' : input.body,\n base: input.baseBranch,\n state: input.state,\n },\n { actingUserId: input.actingUserId },\n );\n return parsePullRequest(result);\n }\n\n #mergePullRequest(input: MergePullRequestInput) {\n return this.#client.request<{ merged: boolean; message: string; sha: string | null }>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/merge`,\n { commitTitle: input.commitTitle, commitMessage: input.commitMessage, method: input.method },\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listComments(input: ListPullRequestCommentsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ comments: GithubComment[] }>(\n 'GET',\n `${repositoryPath(input.sourceId, `issues/${requirePositiveId(input.pullRequestId, 'pull request')}/comments`)}?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n comments: result.comments.map(parseComment),\n nextCursor: result.comments.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createComment(input: CreatePullRequestCommentInput) {\n const comment = await this.#client.request<GithubComment>(\n 'POST',\n repositoryPath(input.sourceId, `issues/${requirePositiveId(input.pullRequestId, 'pull request')}/comments`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return parseComment(comment);\n }\n\n async #updateComment(input: UpdatePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n const comment = await this.#client.request<GithubComment>(\n 'PATCH',\n repositoryPath(input.sourceId, `issues/comments/${requirePositiveId(input.commentId, 'comment')}`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return parseComment(comment);\n }\n\n async #deleteComment(input: DeletePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n await this.#client.request<void>(\n 'DELETE',\n repositoryPath(input.sourceId, `issues/comments/${requirePositiveId(input.commentId, 'comment')}`),\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listReviews(input: ListReviewsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ reviews: GithubReview[] }>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/reviews?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n reviews: result.reviews.map(parseReview),\n nextCursor: result.reviews.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getReview(input: ReviewRef) {\n try {\n return parseReview(\n await this.#client.request<GithubReview>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n ),\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #createReview(input: CreateReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/reviews`,\n { body: input.body, commitId: input.commitId, event: input.event ? reviewEvent(input.event) : undefined },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #updateReview(input: UpdateReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #submitReview(input: SubmitReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}/events`,\n { body: input.body, event: reviewEvent(input.event) },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #dismissReview(input: DismissReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}/dismissals`,\n { message: input.message },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #deletePendingReview(input: ReviewRef) {\n await this.#client.request<void>(\n 'DELETE',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listReviewComments(input: ListReviewCommentsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ comments: GithubReviewComment[] }>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/comments?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n comments: result.comments.map(parseReviewComment),\n nextCursor: result.comments.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createReviewComment(input: CreateReviewCommentInput) {\n let body: Record<string, unknown>;\n if (input.replyToId !== undefined) {\n body = { body: input.body, replyToId: requirePositiveId(input.replyToId, 'review comment') };\n } else {\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 body = {\n body: input.body,\n commitId: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side.toUpperCase(),\n startLine: input.startLine,\n startSide: input.startSide?.toUpperCase(),\n };\n }\n return parseReviewComment(\n await this.#client.request<GithubReviewComment>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/comments`,\n body,\n { actingUserId: input.actingUserId },\n ),\n );\n }\n\n async #updateReviewComment(input: UpdatePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n return parseReviewComment(\n await this.#client.request<GithubReviewComment>(\n 'PATCH',\n repositoryPath(input.sourceId, `pulls/comments/${requirePositiveId(input.commentId, 'review comment')}`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n ),\n );\n }\n\n async #deleteReviewComment(input: DeletePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n await this.#client.request<void>(\n 'DELETE',\n repositoryPath(input.sourceId, `pulls/comments/${requirePositiveId(input.commentId, 'review comment')}`),\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n #requestedReviewers(method: 'GET' | 'POST' | 'DELETE', input: UpdateReviewersInput) {\n requireGithubConnection(input.connection);\n return this.#client.request<{ users: string[]; teams: string[] }>(\n method,\n `${pullRequestPath(input, input.pullRequestId)}/requested-reviewers`,\n method === 'GET' ? undefined : { users: input.users, teams: input.teams },\n method === 'GET' ? undefined : { actingUserId: input.actingUserId },\n );\n }\n}\n\nfunction repositoryPath(sourceId: string, suffix: string): string {\n const { owner, repo } = splitRepository(sourceId);\n return `${API_PREFIX}/github/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/${suffix}`;\n}\n\nfunction pullRequestPath(\n input: { connection: IntegrationConnection; sourceId: string },\n pullRequestId: string,\n): string {\n requireGithubConnection(input.connection);\n return repositoryPath(input.sourceId, `pulls/${requirePositiveId(pullRequestId, 'pull request')}`);\n}\n\nfunction splitRepository(sourceId: string): { owner: string; repo: string } {\n const slash = sourceId.indexOf('/');\n if (slash <= 0 || slash === sourceId.length - 1) {\n throw new Error('GitHub capabilities require an owner/repository source.');\n }\n return { owner: sourceId.slice(0, slash), repo: sourceId.slice(slash + 1) };\n}\n\nfunction parseIntakeIssue(sourceId: string, issue: GithubIssue): IntakeIssue {\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.htmlUrl,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignees[0] ?? null,\n assignees: issue.assignees,\n source: sourceId,\n labels: issue.labels,\n commentCount: issue.commentCount,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n };\n}\n\nfunction parseIntakeIssueDetail(sourceId: string, issue: GithubIssue, comments: GithubComment[]): IntakeIssueDetail {\n return {\n ...parseIntakeIssue(sourceId, issue),\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.createdAt,\n })),\n };\n}\n\nfunction parsePullRequest(pullRequest: GithubPullRequest): PullRequest {\n return {\n id: String(pullRequest.number),\n title: pullRequest.title,\n url: pullRequest.htmlUrl,\n author: pullRequest.user?.login ?? null,\n assignees: pullRequest.assignees ?? [],\n requestedReviewers: pullRequest.requestedReviewers ?? [],\n labels: pullRequest.labels ?? [],\n body: pullRequest.body?.trim() ? pullRequest.body : null,\n state: pullRequest.state,\n draft: pullRequest.draft,\n merged: pullRequest.merged,\n mergeable: pullRequest.mergeable,\n baseBranch: pullRequest.base.ref,\n headBranch: pullRequest.head.ref,\n headSha: pullRequest.head.sha,\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n };\n}\n\nfunction parseComment(comment: GithubComment): PullRequestComment {\n return {\n id: String(comment.id),\n url: comment.htmlUrl,\n author: comment.user?.login ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n };\n}\n\nfunction parseReview(review: GithubReview): Review {\n const states: Record<GithubReview['state'], Review['state']> = {\n PENDING: 'pending',\n COMMENTED: 'commented',\n APPROVED: 'approved',\n CHANGES_REQUESTED: 'changes-requested',\n DISMISSED: 'dismissed',\n };\n return {\n id: String(review.id),\n url: review.htmlUrl,\n author: review.user?.login ?? null,\n body: review.body?.trim() ? review.body : null,\n state: states[review.state],\n commitId: review.commitId,\n submittedAt: review.submittedAt,\n };\n}\n\nfunction parseReviewComment(comment: GithubReviewComment): ReviewComment {\n return {\n ...parseComment(comment),\n path: comment.path,\n line: comment.line,\n side: comment.side?.toLowerCase() as 'left' | 'right' | null,\n commitId: comment.commitId,\n replyToId: comment.replyToId === null ? null : String(comment.replyToId),\n };\n}\n\nfunction requireGithubConnection(connection: IntegrationConnection): void {\n if (connection.type !== 'app-installation' && connection.type !== 'oauth') {\n throw new Error('GitHub capabilities require a GitHub connection.');\n }\n}\n\nfunction requireSingleSource(sourceIds: string[], message: string): string {\n if (sourceIds.length !== 1) throw new Error(message);\n return sourceIds[0]!;\n}\n\nfunction requireSource(sourceId: string | undefined, message: string): string {\n if (!sourceId) throw new Error(message);\n return sourceId;\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const parsed = parsePositiveInteger(cursor);\n if (parsed === null) throw new Error('GitHub cursor must be a positive page number.');\n return parsed;\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 parseGithubExternalTarget(externalId: string): { repository: string; issueId: string } | null {\n const match =\n externalId.match(/^(.+\\/.+):(\\d+)$/) ??\n externalId.match(/^github:(\\d+):(?:issue|pull-request):(\\d+)$/) ??\n externalId.match(/^(\\d+):(\\d+)$/);\n if (!match?.[1] || !match[2] || parsePositiveInteger(match[2]) === null) return null;\n return { repository: match[1], issueId: match[2] };\n}\n\nfunction optionalPositiveIntegerEnv(name: 'MASTRA_PLATFORM_GITHUB_POLLING_INTERVAL_MS'): number | undefined {\n const value = process.env[name]?.trim();\n if (!value) return undefined;\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new Error(`${name} must be a positive integer.`);\n return parsed;\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 reviewEvent(event: 'approve' | 'request-changes' | 'comment') {\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 isNotFound(error: unknown): boolean {\n return error instanceof PlatformApiError && error.status === 404;\n}\n\n// Platform answers 404 when the installation row is gone, 409 when it is suspended or soft-deleted.\n// A 502 also covers a dead installation but is indistinguishable from a transient GitHub outage.\nfunction isDeadInstallation(error: unknown): boolean {\n return error instanceof PlatformApiError && (error.status === 404 || error.status === 409);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"integration.js","names":["#client","#endpointHost","#slug","#pollingEnabled","#pollingIntervalMs","#pullRequestReconcileEnabled","#issueReconcileEnabled","#pullRequestReconcileIntervalMs","#issueReconcileIntervalMs","#installationReposCache","#repositoryAccessCache","#resolveIntakeDispatch","#listIssues","#listPullRequests","#getIssue","#createIssueComment","#updateIntakeIssue","#storage","#getPullRequest","#createPullRequest","#updatePullRequest","#mergePullRequest","#listComments","#createComment","#updateComment","#deleteComment","#listReviews","#getReview","#createReview","#updateReview","#submitReview","#dismissReview","#deletePendingReview","#listReviewComments","#createReviewComment","#updateReviewComment","#deleteReviewComment","#requestedReviewers","#integrationStorage","#statusRoute","#connectRoute","#connectUserRoute","#syncInstallations","#fetchUserConnection","#observeSelfAuthor"],"sources":["../../../../src/integrations/platform/github/integration.ts"],"sourcesContent":["import type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\nimport type { Context } from 'hono';\n\nimport type { IntegrationConnection } from '../../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n UpdateIntakeIssueInput,\n} from '../../../capabilities/intake.js';\nimport type {\n CreatePullRequestCommentInput,\n CreatePullRequestInput,\n CreateReviewCommentInput,\n CreateReviewInput,\n DeletePullRequestCommentInput,\n DismissReviewInput,\n ListPullRequestCommentsInput,\n ListPullRequestsInput,\n ListReviewCommentsInput,\n ListReviewsInput,\n MergePullRequestInput,\n PullRequest,\n PullRequestComment,\n PullRequestRef,\n RepositoryAccess,\n Review,\n ReviewComment,\n ReviewRef,\n SubmitReviewInput,\n UpdatePullRequestCommentInput,\n UpdatePullRequestInput,\n UpdateReviewInput,\n UpdateReviewersInput,\n VersionControl,\n} from '../../../capabilities/version-control.js';\nimport { withBaseCheckpointWebhookTrigger } from '../../../sandbox/base-checkpoint-triggers.js';\nimport type { IntegrationStorageHandle } from '../../../storage/domains/integrations/base.js';\nimport type {\n SourceControlInstallation,\n SourceControlStorageHandle,\n} from '../../../storage/domains/source-control/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';\nimport { GithubAppIdentity } from '../../github/app-identity.js';\nimport type { GithubIntegration, GithubRepositoryPermission, RepoSummary } from '../../github/integration.js';\nimport { attachGithubIssueReconciler } from '../../github/issue-reconciler.js';\nimport { reconcileInterval, reconciliationEnabled } from '../../github/reconciliation-config.js';\nimport { buildGithubRoutes } from '../../github/routes.js';\nimport { attachGithubReconciler, attachGithubRules } from '../../github/rules.js';\nimport type { ReconcileIssueState, ReconcilePullRequestState } from '../../github/rules.js';\nimport {\n createGithubSubscriptionTools,\n parseCreatedPullRequest,\n subscribeCurrentSessionToPullRequest,\n} from '../../github/session-subscriptions.js';\nimport type { GithubSubscriptionStorage } from '../../github/subscriptions.js';\nimport { parseAuthorizedBotsEnv } from '../../github/webhook.js';\nimport {\n logPlatformInfo,\n logPlatformWarn,\n PlatformApiClient,\n PlatformApiError,\n platformApiClientConfigFromEnv,\n} from '../api-client.js';\nimport { PlatformGithubEventWorker } from './event-worker.js';\nimport type { PlatformGithubEventStorage } from './event-worker.js';\n\ntype GithubActor = { login: string; avatarUrl: string | null; htmlUrl: string | null } | null;\n\ntype PlatformGithubInstallation = {\n installationId: number;\n accountLogin: string;\n accountType: string;\n suspendedAt: string | null;\n usable: boolean;\n};\n\ntype PlatformGithubUserConnection = {\n connected: boolean;\n githubUsername: string | null;\n reason?: 'token-invalid' | 'no-accessible-installation' | 'missing-permissions' | 'verification-unavailable' | null;\n};\n\ntype GithubIssue = {\n number: number;\n state: 'open' | 'closed';\n title: string;\n body: string | null;\n htmlUrl: string;\n labels: string[];\n assignees: string[];\n commentCount: number;\n user: GithubActor;\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubComment = {\n id: number;\n body: string;\n htmlUrl: string;\n user: GithubActor;\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubPullRequest = {\n number: number;\n title: string;\n body: string | null;\n state: 'open' | 'closed';\n htmlUrl: string;\n merged: boolean;\n mergeable: boolean | null;\n draft: boolean;\n head: { ref: string; sha: string };\n base: { ref: string; repo: { id: number; fullName: string } };\n user: GithubActor;\n assignees?: string[];\n requestedReviewers?: string[];\n labels?: string[];\n createdAt: string;\n updatedAt: string;\n};\n\ntype GithubReview = {\n id: number;\n htmlUrl: string | null;\n body: string | null;\n state: 'PENDING' | 'COMMENTED' | 'APPROVED' | 'CHANGES_REQUESTED' | 'DISMISSED';\n commitId: string | null;\n submittedAt: string | null;\n user: GithubActor;\n};\n\ntype GithubReviewComment = GithubComment & {\n path: string;\n line: number | null;\n side: 'LEFT' | 'RIGHT' | null;\n commitId: string;\n replyToId: number | null;\n};\n\nconst PAGE_SIZE = 30;\nconst API_PREFIX = '/v1/server';\n/**\n * Slug of the GitHub App this integration posts as. Platform credentials do not\n * carry their own identity, so Factory cannot otherwise recognise its own\n * writes — and failing to recognise them makes Factory wake itself. Override\n * with `MASTRA_PLATFORM_GITHUB_APP_SLUG` when pointing at a non-production App.\n */\nconst PLATFORM_GITHUB_APP_SLUG = 'mastra-platform';\n/**\n * How long an installation's repository listing may be reused. The repos\n * route and token minting both call it — often several times within one UI\n * interaction — and each call is a full Platform round trip.\n */\nconst INSTALLATION_REPOS_CACHE_TTL_MS = 30_000;\n/**\n * How long a minted repository-scoped token may be reused. GitHub\n * installation tokens live ~60 minutes; 5 minutes keeps a wide validity\n * margin while collapsing the per-session-materialization mint round trip.\n */\nconst REPOSITORY_ACCESS_CACHE_TTL_MS = 5 * 60_000;\n/**\n * Upper bound for both TTL caches. Entries expire lazily on re-access, so\n * without a hard cap keys that stop being queried would accumulate for the\n * integration's (long) lifetime. Insertion-order eviction — matches the\n * bounded verification cache in `@mastra/auth-studio`.\n */\nconst MAX_CACHE_ENTRIES = 1000;\n\nfunction setBounded<K, V>(cache: Map<K, V>, key: K, value: V): void {\n cache.delete(key);\n cache.set(key, value);\n if (cache.size > MAX_CACHE_ENTRIES) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n}\n\nconst REPOSITORY_TOKEN_PERMISSIONS = {\n contents: 'write',\n issues: 'write',\n pull_requests: 'write',\n} as const;\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction routeBaseUrl(ctx: IntegrationContext, requestUrl: string): string {\n return (ctx.baseUrl || new URL(requestUrl).origin).replace(/\\/+$/, '');\n}\n\nexport class PlatformGithubIntegration implements FactoryIntegration {\n readonly id = 'github';\n readonly #client: PlatformApiClient;\n readonly #endpointHost: string;\n readonly #slug: string | undefined;\n /**\n * Factory's own GitHub identity. Platform credentials do not carry the login\n * they post as, so this starts from the configured slug (usually absent on a\n * Platform deployment) and is corrected the first time Factory writes.\n */\n readonly identity: GithubAppIdentity;\n /**\n * Extra reviewer bot logins this deployment trusts for author-gated\n * notifications, merged over the built-in defaults.\n */\n readonly authorizedBots: readonly string[];\n readonly #pollingEnabled: boolean;\n readonly #pollingIntervalMs: number | undefined;\n readonly #pullRequestReconcileEnabled: boolean;\n readonly #issueReconcileEnabled: boolean;\n readonly #pullRequestReconcileIntervalMs: number | undefined;\n readonly #issueReconcileIntervalMs: number | undefined;\n #storage: SourceControlStorageHandle | undefined;\n #integrationStorage: GithubSubscriptionStorage | undefined;\n /** installationId → cached repository listing (TTL-bounded). */\n readonly #installationReposCache = new Map<number, { repos: RepoSummary[]; expiresAt: number }>();\n /** `orgId:repositoryId` → cached repository access (TTL-bounded). */\n readonly #repositoryAccessCache = new Map<string, { access: RepositoryAccess; expiresAt: number }>();\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: async ({ orgId, userId }) => {\n const installations = await this.#client.request<{\n installations: Array<{\n installationId: number;\n accountLogin: string;\n accountType: string;\n suspendedAt: string | null;\n usable: boolean;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations`);\n const usable = installations.installations.filter(\n installation => installation.usable && !installation.suspendedAt,\n );\n const repositories = await Promise.all(\n usable.map(async installation => {\n const storedInstallation = await this.versionControl.registerInstallation({\n orgId,\n userId,\n installation: {\n externalId: String(installation.installationId),\n accountName: installation.accountLogin,\n accountType: installation.accountType,\n },\n });\n const result = await this.#client.request<{\n repositories: Array<{\n id: number;\n fullName: string;\n private: boolean;\n defaultBranch: string;\n htmlUrl: string;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations/${installation.installationId}/repositories`);\n await this.versionControl.registerRepositories({\n orgId,\n installationId: storedInstallation.id,\n repositories: result.repositories.map(repository => ({\n externalId: String(repository.id),\n slug: repository.fullName,\n defaultBranch: repository.defaultBranch,\n metadata: { private: repository.private, url: repository.htmlUrl },\n })),\n });\n return result.repositories.map(repository => ({ repository, installation }));\n }),\n );\n return repositories.flat().map(({ repository, installation }) => ({\n id: repository.fullName,\n name: repository.fullName,\n type: 'repository',\n metadata: {\n installationId: installation.installationId,\n accountLogin: installation.accountLogin,\n accountType: installation.accountType,\n repositoryId: repository.id,\n defaultBranch: repository.defaultBranch,\n private: repository.private,\n url: repository.htmlUrl,\n },\n }));\n },\n listItems: async ({ sourceIds, cursor }) => {\n const page = parsePositiveCursor(cursor);\n const pages = await Promise.all(\n sourceIds.map(async sourceId => {\n const connection = { type: 'app-installation' as const, installationId: 1 };\n const [issues, pullRequests] = await Promise.all([\n this.#listIssues(connection, sourceId, page),\n this.#listPullRequests({ connection, sourceId, includeDrafts: false, cursor: String(page) }),\n ]);\n return {\n items: [\n ...issues.issues.map(issue => ({\n source: { type: 'issue', externalId: `${sourceId}:${issue.id}`, url: issue.url },\n sourceId,\n title: issue.title,\n status: issue.state ?? undefined,\n labels: issue.labels,\n assignee: issue.assignee,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: { repository: sourceId, number: Number(issue.id), author: issue.author },\n })),\n ...pullRequests.pullRequests.map(pullRequest => ({\n source: { type: 'pull-request', externalId: `${sourceId}:${pullRequest.id}`, url: pullRequest.url },\n sourceId,\n title: pullRequest.title,\n status: pullRequest.state,\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n metadata: {\n repository: sourceId,\n number: Number(pullRequest.id),\n author: pullRequest.author,\n baseBranch: pullRequest.baseBranch,\n headBranch: pullRequest.headBranch,\n },\n })),\n ],\n hasNextPage: issues.nextCursor !== null || pullRequests.nextCursor !== null,\n };\n }),\n );\n return {\n items: pages.flatMap(result => result.items),\n nextCursor: pages.some(result => result.hasNextPage) ? String(page + 1) : null,\n };\n },\n listIssues: async input => {\n requireGithubConnection(input.connection);\n const sourceId = requireSingleSource(input.sourceIds, 'GitHub Intake requires exactly one repository source.');\n return this.#listIssues(input.connection, sourceId, parsePositiveCursor(input.cursor), input.labels);\n },\n getIssue: input => this.#getIssue(input.connection, input.sourceId, input.issueId),\n createComment: input => this.#createIssueComment(input),\n updateIssue: input => this.#updateIntakeIssue(input),\n };\n\n readonly versionControl: VersionControl = {\n initialize: ({ storage }) => {\n this.#storage = storage;\n },\n registerInstallation: ({ orgId, userId, installation }) =>\n this.storage.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.storage.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 // Every session materialization requests access; reuse a recent grant\n // instead of re-minting through the Platform each time. The TTL keeps\n // a wide margin under GitHub's ~60min installation-token lifetime.\n const cacheKey = `${orgId}:${repositoryId}`;\n const cached = this.#repositoryAccessCache.get(cacheKey);\n if (cached && cached.expiresAt > Date.now()) return cached.access;\n this.#repositoryAccessCache.delete(cacheKey);\n\n const repository = await this.storage.repositories.get({ orgId, id: repositoryId });\n if (!repository) throw new Error('Version-control repository not found.');\n const cloneUrl = `https://github.com/${repository.slug}.git`;\n const installation = await this.storage.installations.get({ orgId, id: repository.installationId });\n if (!installation) throw new Error('Version-control installation not found.');\n const installationId = parsePositiveInteger(installation.externalId);\n if (installationId === null) throw new Error('GitHub installation id is invalid.');\n const repositoryName = splitRepository(repository.slug).repo;\n\n try {\n const token = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${installationId}/token`,\n { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n const access: RepositoryAccess = {\n cloneUrl,\n authorization: { scheme: 'bearer', token: token.token },\n };\n setBounded(this.#repositoryAccessCache, cacheKey, {\n access,\n expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,\n });\n return access;\n } catch (err) {\n // Recover from stale installation: when a GitHub App is uninstalled and reinstalled,\n // GitHub assigns a new installation ID. Platform creates a new installation row,\n // and Factory's intake.listSources creates a new local installation row with the\n // new externalId. Try to find the new installation by accountName.\n if (!isDeadInstallation(err) || !installation.accountName) throw err;\n const installations = await this.storage.installations.list({ orgId });\n const newInstallation = installations.find(\n inst => inst.accountName === installation.accountName && inst.id !== installation.id,\n );\n if (!newInstallation) throw err;\n const newInstallationId = parsePositiveInteger(newInstallation.externalId);\n if (newInstallationId === null) throw err;\n\n // Persist the migration so we don't hit the recovery path on every call.\n await this.storage.repositories.migrateInstallation({\n orgId,\n id: repositoryId,\n newInstallationId: newInstallation.id,\n });\n\n const token = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${newInstallationId}/token`,\n { repositories: [repositoryName], permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n const access: RepositoryAccess = {\n cloneUrl,\n authorization: { scheme: 'bearer', token: token.token },\n };\n setBounded(this.#repositoryAccessCache, cacheKey, {\n access,\n expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS,\n });\n return access;\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.#updatePullRequest({ ...input, state: 'closed' }),\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.#requestedReviewers('GET', input),\n requestReviewers: input => this.#requestedReviewers('POST', input),\n removeRequestedReviewers: input => this.#requestedReviewers('DELETE', input),\n };\n\n constructor(\n options: {\n /** GitHub App slug used to recognize Factory's own webhook writes. */\n slug?: string;\n } = {},\n ) {\n const config = platformApiClientConfigFromEnv();\n this.#client = new PlatformApiClient(config);\n this.#endpointHost = new URL(config.baseUrl).host;\n this.#slug = options.slug;\n // Identity is deliberately NOT taken from `options.slug`. That slug names\n // the deployment's own self-hosted GitHub App, which is a different App\n // than the one this integration posts as — and on a Platform deployment it\n // is legitimately unset. Borrowing it is what left every self-loop guard\n // comparing against `undefined[bot]`. This integration *is* the Platform\n // App, so it names itself, with an override for non-production Apps.\n this.identity = new GithubAppIdentity(\n process.env.MASTRA_PLATFORM_GITHUB_APP_SLUG?.trim() || PLATFORM_GITHUB_APP_SLUG,\n );\n this.authorizedBots = parseAuthorizedBotsEnv(process.env.MASTRACODE_GITHUB_AUTHORIZED_BOTS) ?? [];\n this.#pollingEnabled = process.env.MASTRA_PLATFORM_GITHUB_POLLING_ENABLED?.trim().toLowerCase() !== 'false';\n this.#pollingIntervalMs = optionalPositiveIntegerEnv('MASTRA_PLATFORM_GITHUB_POLLING_INTERVAL_MS');\n const legacyReconcileEnabled = process.env.MASTRA_PLATFORM_GITHUB_RECONCILE_ENABLED;\n this.#pullRequestReconcileEnabled = reconciliationEnabled(\n process.env.MASTRACODE_PLATFORM_GITHUB_PR_RECONCILE_ENABLED,\n legacyReconcileEnabled,\n );\n this.#issueReconcileEnabled = reconciliationEnabled(\n process.env.MASTRACODE_PLATFORM_GITHUB_ISSUE_RECONCILE_ENABLED,\n legacyReconcileEnabled,\n );\n const legacyReconcileIntervalMs = reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_RECONCILE_INTERVAL_MS);\n this.#pullRequestReconcileIntervalMs =\n reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_PR_RECONCILE_INTERVAL_MS) ?? legacyReconcileIntervalMs;\n this.#issueReconcileIntervalMs =\n reconcileInterval(process.env.MASTRACODE_PLATFORM_GITHUB_ISSUE_RECONCILE_INTERVAL_MS) ?? legacyReconcileIntervalMs;\n }\n\n /** GitHub App slug when the deployment explicitly provides it. */\n get slug(): string | undefined {\n return this.#slug;\n }\n\n get storage(): SourceControlStorageHandle {\n if (!this.#storage) throw new Error('PlatformGithubIntegration source-control storage has not been initialized.');\n return this.#storage;\n }\n\n get sourceControlStorage(): SourceControlStorageHandle {\n return this.storage;\n }\n\n get integrationStorage(): GithubSubscriptionStorage {\n if (!this.#integrationStorage) {\n throw new Error('PlatformGithubIntegration generic storage has not been initialized.');\n }\n return this.#integrationStorage;\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 = target.repository.includes('/')\n ? target.repository\n : (await this.storage.repositories.findByExternalId({ orgId, externalId: target.repository }))?.slug;\n if (!repository) return null;\n return {\n connection: { type: 'app-installation', installationId: 1 },\n sourceId: repository,\n issueId: target.issueId,\n };\n }\n\n initialize({ storage }: { storage: IntegrationStorageHandle }): void {\n this.#integrationStorage = storage as unknown as GithubSubscriptionStorage;\n logPlatformInfo('Platform GitHub integration initialized', {\n endpointHost: this.#endpointHost,\n pollingEnabled: this.#pollingEnabled,\n pollingIntervalMs: this.#pollingIntervalMs,\n pullRequestReconcileEnabled: this.#pullRequestReconcileEnabled,\n issueReconcileEnabled: this.#issueReconcileEnabled,\n });\n }\n\n routes(ctx: IntegrationContext): ApiRoute[] {\n const ingestFactoryEvent = withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints);\n return [\n this.#statusRoute(ctx),\n this.#connectRoute(ctx),\n this.#connectUserRoute(ctx),\n ...buildGithubRoutes({\n auth: ctx.auth,\n fleet: ctx.fleet,\n storage: ctx.factoryStorage,\n github: this as unknown as GithubIntegration,\n stateSigner: ctx.stateSigner,\n baseUrl: ctx.baseUrl,\n controller: ctx.controller,\n projects: ctx.storage.projects,\n emitAudit: ctx.hooks?.emitAudit,\n ingestFactoryEvent,\n }).filter(\n route =>\n route.path !== '/web/github/status' &&\n route.path !== '/web/github/webhook' &&\n !route.path.startsWith('/auth/github/'),\n ),\n ];\n }\n\n #statusRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant) return c.json({ error: 'unauthorized', reason: 'auth_required' }, 401);\n if (!tenant.orgId) {\n return c.json({\n enabled: true,\n sandboxEnabled: ctx.fleet.enabled,\n organizationRequired: true,\n connected: false,\n installations: [],\n userConnected: false,\n userGithubUsername: null,\n reason: 'organization_required',\n diagnostics: this.diagnostics(),\n });\n }\n\n const [installations, userConnection] = await Promise.all([\n this.#syncInstallations(tenant.orgId, tenant.userId),\n this.#fetchUserConnection(tenant.userId),\n ]);\n return c.json({\n enabled: true,\n sandboxEnabled: ctx.fleet.enabled,\n connected: installations.length > 0,\n installations: installations.map(installation => ({\n installationId: Number(installation.externalId),\n accountLogin: installation.accountName,\n accountType: installation.accountType,\n })),\n userConnected: userConnection.connected,\n userGithubUsername: userConnection.githubUsername,\n reason: installations.length > 0 ? 'ready' : 'not_connected',\n diagnostics: this.diagnostics(),\n });\n },\n });\n }\n\n #connectRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/github/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const redirectTo = c.req.query('redirectTo') || c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform GitHub connect flow', {\n orgId: tenant.orgId,\n redirectTo,\n originator,\n });\n const query = new URLSearchParams({\n action: 'install',\n redirectTo,\n originator,\n });\n const { url } = await this.#client.request<{ url: string }>(\n 'GET',\n `${API_PREFIX}/github-app/install-url?${query}`,\n );\n return c.redirect(url);\n },\n });\n }\n\n #connectUserRoute(ctx: IntegrationContext): ApiRoute {\n return registerApiRoute('/auth/github/connect-user', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await ctx.auth.ensureUser(loose(c));\n const tenant = ctx.auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const redirectTo = c.req.query('redirectTo') || c.req.query('return_to') || '/';\n const originator = routeBaseUrl(ctx, c.req.url);\n logPlatformInfo('Starting Platform GitHub user authorization flow', {\n orgId: tenant.orgId,\n redirectTo,\n originator,\n });\n const query = new URLSearchParams({\n userId: tenant.userId,\n redirectTo,\n originator,\n });\n const { url } = await this.#client.request<{ url: string }>(\n 'GET',\n `${API_PREFIX}/github-app/authenticate?${query}`,\n );\n return c.redirect(url);\n },\n });\n }\n\n /**\n * Personal GitHub connection status for the acting user. Returns\n * not-connected when the platform predates the user-connection endpoint.\n */\n async #fetchUserConnection(userId: string): Promise<PlatformGithubUserConnection> {\n try {\n const connection = await this.#client.request<PlatformGithubUserConnection>(\n 'GET',\n `${API_PREFIX}/github-app/user-connection?${new URLSearchParams({ userId })}`,\n );\n if (!connection.connected && connection.reason) {\n logPlatformWarn('Platform GitHub user connection verification failed', {\n userId,\n reason: connection.reason,\n });\n }\n return connection;\n } catch {\n return { connected: false, githubUsername: null };\n }\n }\n\n async #syncInstallations(orgId: string, userId: string): Promise<SourceControlInstallation[]> {\n const result = await this.#client.request<{ installations: PlatformGithubInstallation[] }>(\n 'GET',\n `${API_PREFIX}/github-app/installations`,\n );\n const usableInstallations = result.installations.filter(\n installation => installation.usable && !installation.suspendedAt,\n );\n return Promise.all(\n usableInstallations.map(installation =>\n this.versionControl.registerInstallation({\n orgId,\n userId,\n installation: {\n externalId: String(installation.installationId),\n accountName: installation.accountLogin,\n accountType: installation.accountType,\n },\n }),\n ),\n );\n }\n\n workers(ctx: IntegrationContext): MastraWorker[] {\n if (!this.#pollingEnabled && !this.#pullRequestReconcileEnabled && !this.#issueReconcileEnabled) return [];\n if (!ctx.controller) {\n throw new Error('Platform GitHub event polling requires the mounted Mastra Code controller.');\n }\n return [\n new PlatformGithubEventWorker({\n client: this.#client,\n controller: ctx.controller,\n github: this,\n storage: ctx.storage.generic as unknown as PlatformGithubEventStorage,\n ingestFactoryEvent: withBaseCheckpointWebhookTrigger(attachGithubRules(this, ctx), ctx.baseCheckpoints),\n reconcileFactoryState: this.#pullRequestReconcileEnabled\n ? attachGithubReconciler(this, ctx, input => this.fetchPullRequestState(input))\n : undefined,\n reconcileIssuesFactoryState: this.#issueReconcileEnabled\n ? attachGithubIssueReconciler(this, ctx, input => this.fetchIssueState(input))\n : undefined,\n ...(ctx.baseCheckpoints ? { sweepBaseCheckpoints: () => ctx.baseCheckpoints!.sweep() } : {}),\n pollEventsEnabled: this.#pollingEnabled,\n intervalMs: this.#pollingIntervalMs,\n pullRequestReconcileIntervalMs: this.#pullRequestReconcileIntervalMs,\n issueReconcileIntervalMs: this.#issueReconcileIntervalMs,\n // Resolved lazily: workers are constructed before versionControl\n // storage is initialized, and the worker only reads these slices once\n // it is running.\n sourceControl: {\n projectRepositories: {\n listConfiguredExternalKeys: () => this.storage.projectRepositories.listConfiguredExternalKeys(),\n listByExternalRepository: args => this.storage.projectRepositories.listByExternalRepository(args),\n },\n repositories: {\n findByExternalId: args => this.storage.repositories.findByExternalId(args),\n },\n },\n }),\n ];\n }\n\n /**\n * Reads live PR state through the Platform GitHub proxy for the merge\n * reconciler. Returns undefined when the PR cannot be resolved (missing,\n * proxy error) 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 let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(input.repository);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{\n title?: string;\n html_url?: string;\n state?: string;\n draft?: boolean;\n merged?: boolean;\n created_at?: 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 merged_by?: { login?: string } | null;\n head?: { ref?: string };\n base?: { ref?: string };\n }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/pulls/${input.number}`,\n );\n return {\n title: result.title ?? `PR ${input.number}`,\n url: result.html_url ?? `https://github.com/${input.repository}/pull/${input.number}`,\n state: result.state === 'closed' ? 'closed' : 'open',\n draft: result.draft === true,\n merged: result.merged === true,\n assignees: (result.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n requestedReviewers: (result.requested_reviewers ?? []).flatMap(reviewer =>\n reviewer.login ? [reviewer.login] : [],\n ),\n labels: (result.labels ?? []).flatMap(label =>\n typeof label === 'string' ? [label] : label.name ? [label.name] : [],\n ),\n headBranch: result.head?.ref ?? '',\n baseBranch: result.base?.ref ?? '',\n ...(result.user?.login ? { author: result.user.login } : {}),\n ...(result.created_at ? { createdAt: result.created_at } : {}),\n ...(result.merged_by?.login ? { mergedBy: result.merged_by.login } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n /**\n * Reads live issue state through the Platform GitHub proxy for the\n * reconciler. Returns undefined when the issue cannot be resolved (missing,\n * is actually a PR, proxy error) so a sweep never fabricates a close.\n */\n async fetchIssueState(input: {\n installationId: number;\n repository: string;\n number: number;\n }): Promise<ReconcileIssueState | undefined> {\n let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(input.repository);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{\n title?: string;\n html_url?: string;\n state?: string;\n state_reason?: string | null;\n created_at?: string;\n updated_at?: string;\n user?: { login?: string } | null;\n assignees?: Array<{ login?: string }> | null;\n labels?: Array<{ name?: string } | string> | null;\n pull_request?: unknown;\n }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/issues/${input.number}`,\n );\n if (result.pull_request) return undefined;\n return {\n title: result.title ?? `Issue ${input.number}`,\n url: result.html_url ?? `https://github.com/${input.repository}/issues/${input.number}`,\n state: result.state === 'closed' ? 'closed' : 'open',\n ...(result.state_reason ? { stateReason: result.state_reason } : {}),\n assignees: (result.assignees ?? []).flatMap(assignee => (assignee.login ? [assignee.login] : [])),\n labels: (result.labels ?? []).map(label => (typeof label === 'string' ? label : label.name)).filter((name): name is string => Boolean(name)),\n ...(result.user?.login ? { author: result.user.login } : {}),\n ...(result.created_at ? { createdAt: result.created_at } : {}),\n ...(result.updated_at ? { updatedAt: result.updated_at } : {}),\n };\n } catch {\n return undefined;\n }\n }\n\n sessionTools({ requestContext }: { requestContext: RequestContext }): IntegrationTools {\n return createGithubSubscriptionTools(requestContext, this as unknown as GithubIntegration);\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(\n requestContext,\n pullRequestUrl,\n 'auto-gh-pr-create',\n this as unknown as GithubIntegration,\n );\n }\n\n diagnostics(): Record<string, unknown> {\n return {\n mode: 'platform',\n endpointHost: this.#endpointHost,\n polling: {\n enabled: this.#pollingEnabled,\n ...(this.#pollingIntervalMs === undefined ? {} : { intervalMs: this.#pollingIntervalMs }),\n },\n reconcile: {\n pullRequests: {\n enabled: this.#pullRequestReconcileEnabled,\n ...(this.#pullRequestReconcileIntervalMs === undefined\n ? {}\n : { intervalMs: this.#pullRequestReconcileIntervalMs }),\n },\n issues: {\n enabled: this.#issueReconcileEnabled,\n ...(this.#issueReconcileIntervalMs === undefined ? {} : { intervalMs: this.#issueReconcileIntervalMs }),\n },\n },\n };\n }\n\n async getRepositoryCollaboratorPermission(\n _installationId: number,\n repoFullName: string,\n username: string,\n signal?: AbortSignal,\n ): Promise<GithubRepositoryPermission | undefined> {\n let repository: { owner: string; repo: string };\n try {\n repository = splitRepository(repoFullName);\n } catch {\n return undefined;\n }\n try {\n const result = await this.#client.request<{ permission: GithubRepositoryPermission }>(\n 'GET',\n `${API_PREFIX}/github/repos/${encodeURIComponent(repository.owner)}/${encodeURIComponent(repository.repo)}/collaborators/${encodeURIComponent(username)}/permission`,\n undefined,\n { signal },\n );\n return result.permission;\n } catch {\n return undefined;\n }\n }\n\n async listInstallationRepos(installationId: number): Promise<RepoSummary[]> {\n // Hot in two places — the repos route and token minting (which re-lists\n // only to validate the 1–10 repo rule). A short TTL collapses repeat\n // Platform round trips within one UI interaction.\n const cached = this.#installationReposCache.get(installationId);\n if (cached && cached.expiresAt > Date.now()) return cached.repos;\n this.#installationReposCache.delete(installationId);\n\n const result = await this.#client.request<{\n repositories: Array<{\n id: number;\n owner: string;\n name: string;\n fullName: string;\n private: boolean;\n defaultBranch: string;\n }>;\n }>('GET', `${API_PREFIX}/github-app/installations/${installationId}/repositories`);\n const repos = result.repositories.map(repository => ({ ...repository, installationId }));\n setBounded(this.#installationReposCache, installationId, {\n repos,\n expiresAt: Date.now() + INSTALLATION_REPOS_CACHE_TTL_MS,\n });\n return repos;\n }\n\n async mintInstallationToken(installationId: number): Promise<string> {\n const repositories = await this.listInstallationRepos(installationId);\n if (repositories.length === 0 || repositories.length > 10) {\n throw new Error('Platform GitHub token minting requires between one and ten installation repositories.');\n }\n const result = await this.#client.request<{ token: string }>(\n 'POST',\n `${API_PREFIX}/github-app/installations/${installationId}/token`,\n { repositories: repositories.map(repository => repository.name), permissions: REPOSITORY_TOKEN_PERMISSIONS },\n );\n return result.token;\n }\n\n async addIssueLabels(\n _installationId: number,\n sourceId: string,\n issueNumber: number,\n labels: string[],\n ): Promise<string[]> {\n const result = await this.#client.request<{ labels: string[] }>(\n 'POST',\n repositoryPath(sourceId, `issues/${issueNumber}/labels`),\n { labels },\n );\n return result.labels;\n }\n\n getInstallationOctokit(_installationId: number): ReturnType<GithubIntegration['getInstallationOctokit']> {\n return {\n pulls: {\n get: async ({ owner, repo, pull_number }: { owner: string; repo: string; pull_number: number }) => {\n const data = await this.#client.request<GithubPullRequest>(\n 'GET',\n repositoryPath(`${owner}/${repo}`, `pulls/${pull_number}`),\n );\n return { data: { base: { repo: { id: data.base.repo.id } } } };\n },\n },\n } as unknown as ReturnType<GithubIntegration['getInstallationOctokit']>;\n }\n\n async #listIssues(connection: IntegrationConnection, sourceId: string, page: number, labels?: string[]) {\n requireGithubConnection(connection);\n const path = repositoryPath(sourceId, 'issues');\n const query = new URLSearchParams({ state: 'open', page: String(page), per_page: String(PAGE_SIZE) });\n const normalizedLabels = normalizeLabels(labels);\n if (normalizedLabels.length > 0) query.set('label', normalizedLabels.join(','));\n const result = await this.#client.request<{ issues: GithubIssue[] }>('GET', `${path}?${query}`);\n return {\n issues: result.issues.map(issue => parseIntakeIssue(sourceId, issue)),\n nextCursor: result.issues.length > 0 ? String(page + 1) : null,\n };\n }\n\n async #getIssue(connection: IntegrationConnection, sourceId: string | undefined, issueId: string) {\n requireGithubConnection(connection);\n const repository = requireSource(sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(issueId, 'issue');\n try {\n const [issue, comments] = await Promise.all([\n this.#client.request<GithubIssue>('GET', repositoryPath(repository, `issues/${issueNumber}`)),\n this.#client.request<{ comments: GithubComment[] }>(\n 'GET',\n `${repositoryPath(repository, `issues/${issueNumber}/comments`)}?per_page=100`,\n ),\n ]);\n return parseIntakeIssueDetail(repository, issue, comments.comments);\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #updateIntakeIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n requireGithubConnection(input.connection);\n const repository = requireSource(input.sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(input.issueId, 'issue');\n if (input.state.kind === 'byName') {\n logPlatformWarn(`Platform GitHub: 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 // Reject PR targets: probe the pulls endpoint. A 200 means the number is a\n // pull request, not an issue. Factory does not close PRs via updateIssue —\n // PR merges/closes go through the version-control pipeline.\n try {\n await this.#client.request<GithubPullRequest>('GET', repositoryPath(repository, `pulls/${issueNumber}`));\n logPlatformWarn(`Platform GitHub: updateIssue rejected — target ${repository}#${issueNumber} is a pull request.`);\n return null;\n } catch (error) {\n if (!isNotFound(error)) throw error;\n // 404 on pulls means it's an issue (or nothing) — fall through to PATCH.\n }\n try {\n const issue = await this.#client.request<GithubIssue>(\n 'PATCH',\n repositoryPath(repository, `issues/${issueNumber}`),\n {\n state: targetState,\n ...(stateReason ? { state_reason: stateReason } : {}),\n },\n { actingUserId: input.actingUserId },\n );\n return parseIntakeIssue(repository, issue);\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n /**\n * Learn Factory's own login from a write it just made. Skipped when the write\n * was made on behalf of a user — that comment is authored by the human, and\n * recording it would teach Factory to mistake a person for itself.\n */\n #observeSelfAuthor(comment: GithubComment, actingUserId: string | undefined): void {\n if (actingUserId) return;\n this.identity.observeSelfAuthor(comment.user?.login);\n }\n\n async #createIssueComment(input: CreateIntakeCommentInput) {\n requireGithubConnection(input.connection);\n const repository = requireSource(input.sourceId, 'GitHub Intake requires a repository source.');\n const issueNumber = requirePositiveId(input.issueId, 'issue');\n try {\n const comment = await this.#client.request<GithubComment>(\n 'POST',\n repositoryPath(repository, `issues/${issueNumber}/comments`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n this.#observeSelfAuthor(comment, input.actingUserId);\n return { id: String(comment.id), url: comment.htmlUrl };\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #listPullRequests(input: ListPullRequestsInput) {\n requireGithubConnection(input.connection);\n const page = parsePositiveCursor(input.cursor);\n const query = new URLSearchParams({\n state: input.state ?? 'open',\n page: String(page),\n per_page: String(PAGE_SIZE),\n });\n const result = await this.#client.request<{ pullRequests: GithubPullRequest[] }>(\n 'GET',\n `${repositoryPath(input.sourceId, 'pulls')}?${query}`,\n );\n return {\n pullRequests: result.pullRequests\n .filter(pullRequest => input.includeDrafts !== false || !pullRequest.draft)\n .map(parsePullRequest),\n nextCursor: result.pullRequests.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getPullRequest(input: PullRequestRef) {\n try {\n return parsePullRequest(\n await this.#client.request<GithubPullRequest>('GET', pullRequestPath(input, input.pullRequestId)),\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #createPullRequest(input: CreatePullRequestInput) {\n requireGithubConnection(input.connection);\n const result = await this.#client.request<GithubPullRequest>(\n 'POST',\n repositoryPath(input.sourceId, 'pulls'),\n {\n head: input.headBranch,\n base: input.baseBranch,\n title: input.title,\n body: input.body,\n draft: input.draft,\n },\n { actingUserId: input.actingUserId },\n );\n return parsePullRequest(result);\n }\n\n async #updatePullRequest(input: UpdatePullRequestInput) {\n const result = await this.#client.request<GithubPullRequest>(\n 'PATCH',\n pullRequestPath(input, input.pullRequestId),\n {\n title: input.title,\n body: input.body === null ? '' : input.body,\n base: input.baseBranch,\n state: input.state,\n },\n { actingUserId: input.actingUserId },\n );\n return parsePullRequest(result);\n }\n\n #mergePullRequest(input: MergePullRequestInput) {\n return this.#client.request<{ merged: boolean; message: string; sha: string | null }>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/merge`,\n { commitTitle: input.commitTitle, commitMessage: input.commitMessage, method: input.method },\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listComments(input: ListPullRequestCommentsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ comments: GithubComment[] }>(\n 'GET',\n `${repositoryPath(input.sourceId, `issues/${requirePositiveId(input.pullRequestId, 'pull request')}/comments`)}?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n comments: result.comments.map(parseComment),\n nextCursor: result.comments.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createComment(input: CreatePullRequestCommentInput) {\n const comment = await this.#client.request<GithubComment>(\n 'POST',\n repositoryPath(input.sourceId, `issues/${requirePositiveId(input.pullRequestId, 'pull request')}/comments`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n this.#observeSelfAuthor(comment, input.actingUserId);\n return parseComment(comment);\n }\n\n async #updateComment(input: UpdatePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n const comment = await this.#client.request<GithubComment>(\n 'PATCH',\n repositoryPath(input.sourceId, `issues/comments/${requirePositiveId(input.commentId, 'comment')}`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return parseComment(comment);\n }\n\n async #deleteComment(input: DeletePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n await this.#client.request<void>(\n 'DELETE',\n repositoryPath(input.sourceId, `issues/comments/${requirePositiveId(input.commentId, 'comment')}`),\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listReviews(input: ListReviewsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ reviews: GithubReview[] }>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/reviews?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n reviews: result.reviews.map(parseReview),\n nextCursor: result.reviews.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #getReview(input: ReviewRef) {\n try {\n return parseReview(\n await this.#client.request<GithubReview>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n ),\n );\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n }\n\n async #createReview(input: CreateReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/reviews`,\n { body: input.body, commitId: input.commitId, event: input.event ? reviewEvent(input.event) : undefined },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #updateReview(input: UpdateReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n { body: input.body },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #submitReview(input: SubmitReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}/events`,\n { body: input.body, event: reviewEvent(input.event) },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #dismissReview(input: DismissReviewInput) {\n const review = await this.#client.request<GithubReview>(\n 'PUT',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}/dismissals`,\n { message: input.message },\n { actingUserId: input.actingUserId },\n );\n return parseReview(review);\n }\n\n async #deletePendingReview(input: ReviewRef) {\n await this.#client.request<void>(\n 'DELETE',\n `${pullRequestPath(input, input.pullRequestId)}/reviews/${requirePositiveId(input.reviewId, 'review')}`,\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n async #listReviewComments(input: ListReviewCommentsInput) {\n const page = parsePositiveCursor(input.cursor);\n const result = await this.#client.request<{ comments: GithubReviewComment[] }>(\n 'GET',\n `${pullRequestPath(input, input.pullRequestId)}/comments?page=${page}&per_page=${PAGE_SIZE}`,\n );\n return {\n comments: result.comments.map(parseReviewComment),\n nextCursor: result.comments.length === PAGE_SIZE ? String(page + 1) : null,\n };\n }\n\n async #createReviewComment(input: CreateReviewCommentInput) {\n let body: Record<string, unknown>;\n if (input.replyToId !== undefined) {\n body = { body: input.body, replyToId: requirePositiveId(input.replyToId, 'review comment') };\n } else {\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 body = {\n body: input.body,\n commitId: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side.toUpperCase(),\n startLine: input.startLine,\n startSide: input.startSide?.toUpperCase(),\n };\n }\n return parseReviewComment(\n await this.#client.request<GithubReviewComment>(\n 'POST',\n `${pullRequestPath(input, input.pullRequestId)}/comments`,\n body,\n { actingUserId: input.actingUserId },\n ),\n );\n }\n\n async #updateReviewComment(input: UpdatePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n return parseReviewComment(\n await this.#client.request<GithubReviewComment>(\n 'PATCH',\n repositoryPath(input.sourceId, `pulls/comments/${requirePositiveId(input.commentId, 'review comment')}`),\n { body: input.body },\n { actingUserId: input.actingUserId },\n ),\n );\n }\n\n async #deleteReviewComment(input: DeletePullRequestCommentInput) {\n requireGithubConnection(input.connection);\n await this.#client.request<void>(\n 'DELETE',\n repositoryPath(input.sourceId, `pulls/comments/${requirePositiveId(input.commentId, 'review comment')}`),\n undefined,\n { actingUserId: input.actingUserId },\n );\n }\n\n #requestedReviewers(method: 'GET' | 'POST' | 'DELETE', input: UpdateReviewersInput) {\n requireGithubConnection(input.connection);\n return this.#client.request<{ users: string[]; teams: string[] }>(\n method,\n `${pullRequestPath(input, input.pullRequestId)}/requested-reviewers`,\n method === 'GET' ? undefined : { users: input.users, teams: input.teams },\n method === 'GET' ? undefined : { actingUserId: input.actingUserId },\n );\n }\n}\n\nfunction repositoryPath(sourceId: string, suffix: string): string {\n const { owner, repo } = splitRepository(sourceId);\n return `${API_PREFIX}/github/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/${suffix}`;\n}\n\nfunction pullRequestPath(\n input: { connection: IntegrationConnection; sourceId: string },\n pullRequestId: string,\n): string {\n requireGithubConnection(input.connection);\n return repositoryPath(input.sourceId, `pulls/${requirePositiveId(pullRequestId, 'pull request')}`);\n}\n\nfunction splitRepository(sourceId: string): { owner: string; repo: string } {\n const slash = sourceId.indexOf('/');\n if (slash <= 0 || slash === sourceId.length - 1) {\n throw new Error('GitHub capabilities require an owner/repository source.');\n }\n return { owner: sourceId.slice(0, slash), repo: sourceId.slice(slash + 1) };\n}\n\nfunction parseIntakeIssue(sourceId: string, issue: GithubIssue): IntakeIssue {\n return {\n id: String(issue.number),\n identifier: `#${issue.number}`,\n title: issue.title,\n url: issue.htmlUrl,\n author: issue.user?.login ?? null,\n state: issue.state,\n stateType: issue.state,\n priority: null,\n assignee: issue.assignees[0] ?? null,\n assignees: issue.assignees,\n source: sourceId,\n labels: issue.labels,\n commentCount: issue.commentCount,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n };\n}\n\nfunction parseIntakeIssueDetail(sourceId: string, issue: GithubIssue, comments: GithubComment[]): IntakeIssueDetail {\n return {\n ...parseIntakeIssue(sourceId, issue),\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.createdAt,\n })),\n };\n}\n\nfunction parsePullRequest(pullRequest: GithubPullRequest): PullRequest {\n return {\n id: String(pullRequest.number),\n title: pullRequest.title,\n url: pullRequest.htmlUrl,\n author: pullRequest.user?.login ?? null,\n assignees: pullRequest.assignees ?? [],\n requestedReviewers: pullRequest.requestedReviewers ?? [],\n labels: pullRequest.labels ?? [],\n body: pullRequest.body?.trim() ? pullRequest.body : null,\n state: pullRequest.state,\n draft: pullRequest.draft,\n merged: pullRequest.merged,\n mergeable: pullRequest.mergeable,\n baseBranch: pullRequest.base.ref,\n headBranch: pullRequest.head.ref,\n headSha: pullRequest.head.sha,\n createdAt: pullRequest.createdAt,\n updatedAt: pullRequest.updatedAt,\n };\n}\n\nfunction parseComment(comment: GithubComment): PullRequestComment {\n return {\n id: String(comment.id),\n url: comment.htmlUrl,\n author: comment.user?.login ?? null,\n body: comment.body,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n };\n}\n\nfunction parseReview(review: GithubReview): Review {\n const states: Record<GithubReview['state'], Review['state']> = {\n PENDING: 'pending',\n COMMENTED: 'commented',\n APPROVED: 'approved',\n CHANGES_REQUESTED: 'changes-requested',\n DISMISSED: 'dismissed',\n };\n return {\n id: String(review.id),\n url: review.htmlUrl,\n author: review.user?.login ?? null,\n body: review.body?.trim() ? review.body : null,\n state: states[review.state],\n commitId: review.commitId,\n submittedAt: review.submittedAt,\n };\n}\n\nfunction parseReviewComment(comment: GithubReviewComment): ReviewComment {\n return {\n ...parseComment(comment),\n path: comment.path,\n line: comment.line,\n side: comment.side?.toLowerCase() as 'left' | 'right' | null,\n commitId: comment.commitId,\n replyToId: comment.replyToId === null ? null : String(comment.replyToId),\n };\n}\n\nfunction requireGithubConnection(connection: IntegrationConnection): void {\n if (connection.type !== 'app-installation' && connection.type !== 'oauth') {\n throw new Error('GitHub capabilities require a GitHub connection.');\n }\n}\n\nfunction requireSingleSource(sourceIds: string[], message: string): string {\n if (sourceIds.length !== 1) throw new Error(message);\n return sourceIds[0]!;\n}\n\nfunction requireSource(sourceId: string | undefined, message: string): string {\n if (!sourceId) throw new Error(message);\n return sourceId;\n}\n\nfunction normalizeLabels(labels: string[] | undefined): string[] {\n return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];\n}\n\nfunction parsePositiveCursor(cursor: string | undefined): number {\n if (cursor === undefined) return 1;\n const parsed = parsePositiveInteger(cursor);\n if (parsed === null) throw new Error('GitHub cursor must be a positive page number.');\n return parsed;\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 parseGithubExternalTarget(externalId: string): { repository: string; issueId: string } | null {\n const match =\n externalId.match(/^(.+\\/.+):(\\d+)$/) ??\n externalId.match(/^github:(\\d+):(?:issue|pull-request):(\\d+)$/) ??\n externalId.match(/^(\\d+):(\\d+)$/);\n if (!match?.[1] || !match[2] || parsePositiveInteger(match[2]) === null) return null;\n return { repository: match[1], issueId: match[2] };\n}\n\nfunction optionalPositiveIntegerEnv(name: 'MASTRA_PLATFORM_GITHUB_POLLING_INTERVAL_MS'): number | undefined {\n const value = process.env[name]?.trim();\n if (!value) return undefined;\n const parsed = parsePositiveInteger(value);\n if (parsed === null) throw new Error(`${name} must be a positive integer.`);\n return parsed;\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 reviewEvent(event: 'approve' | 'request-changes' | 'comment') {\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 isNotFound(error: unknown): boolean {\n return error instanceof PlatformApiError && error.status === 404;\n}\n\n// Platform answers 404 when the installation row is gone, 409 when it is suspended or soft-deleted.\n// A 502 also covers a dead installation but is indistinguishable from a transient GitHub outage.\nfunction isDeadInstallation(error: unknown): boolean {\n return error instanceof PlatformApiError && (error.status === 404 || error.status === 409);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/slack/slack.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAS/D,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAC3F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8CAA8C,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOxD,KAAK,aAAa,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,KAAK,cAAc,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpD,uFAAuF;AACvF,UAAU,gBAAgB;IACxB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAC3C;;;OAGG;IACH,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,yBAAyB,CAAC;CAC5C;AAqCD,+DAA+D;AAC/D,KAAK,kBAAkB;AACrB,0EAA0E;AACxE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,8EAA8E;GAC5E;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,6EAA6E;GAC3E;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,GAAG,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAE/E;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,MAAM,EACN,OAAO,EACP,YAAY,GACb,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,sBAAsB,CAAC;CACvC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAmB9B;AAsBD,0EAA0E;AAC1E,KAAK,kBAAkB;AACrB,mEAAmE;AACjE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,iFAAiF;GAC/E;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,uDAAuD;GACrD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,qBAAqB,EAAE,OAAO,CAAA;CAAE,CAAC;AAErF;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,MAAM,EACN,OAAO,EACP,IAAI,EACJ,GAAG,EACH,YAAY,EACZ,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,kBAAkB,CAAC;IACzB,GAAG,EAAE,qBAAqB,CAAC;IAC3B,YAAY,EAAE,sBAAsB,CAAC;IACrC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CACnC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoD9B;AAmBD;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,gBAAgB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../../src/integrations/slack/slack.ts"],"names":[],"mappings":"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"}
|
|
@@ -191,7 +191,8 @@ function createChannelResourceIdResolver(deps) {
|
|
|
191
191
|
orgId,
|
|
192
192
|
userId: link.userId,
|
|
193
193
|
branch,
|
|
194
|
-
baseBranch: repo.baseBranch
|
|
194
|
+
baseBranch: repo.baseBranch,
|
|
195
|
+
visibility: thread.isDM ? "private" : "org"
|
|
195
196
|
})).sessionId;
|
|
196
197
|
} catch (error) {
|
|
197
198
|
console.warn("[slack] repo-backed session resolution failed for thread", thread.id, error);
|