@mastra/factory 0.8.0-alpha.11 → 0.8.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/integrations/github/routes.js +4 -3
  3. package/dist/integrations/github/routes.js.map +1 -1
  4. package/dist/integrations/platform/github/event-worker.d.ts +9 -0
  5. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  6. package/dist/integrations/platform/github/event-worker.js +24 -7
  7. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  8. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  9. package/dist/integrations/platform/github/integration.js +2 -1
  10. package/dist/integrations/platform/github/integration.js.map +1 -1
  11. package/dist/integrations/slack/slack.d.ts.map +1 -1
  12. package/dist/integrations/slack/slack.js +2 -1
  13. package/dist/integrations/slack/slack.js.map +1 -1
  14. package/dist/session/factory-session.d.ts.map +1 -1
  15. package/dist/session/factory-session.js +2 -1
  16. package/dist/session/factory-session.js.map +1 -1
  17. package/dist/storage/domains/source-control/base.d.ts +19 -1
  18. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  19. package/dist/storage/domains/source-control/base.js +8 -5
  20. package/dist/storage/domains/source-control/base.js.map +1 -1
  21. package/dist/storage/domains/source-control/inmemory.d.ts +2 -2
  22. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  23. package/dist/storage/domains/source-control/inmemory.js +2 -1
  24. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  25. package/dist/workspace.d.ts.map +1 -1
  26. package/dist/workspace.js +1 -1
  27. package/dist/workspace.js.map +1 -1
  28. package/factory-skills/factory-plan/SKILL.md +1 -1
  29. package/factory-skills/factory-rereview/SKILL.md +2 -2
  30. package/factory-skills/factory-review/SKILL.md +2 -2
  31. package/factory-skills/factory-triage/SKILL.md +2 -0
  32. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # @mastra/factory
2
2
 
3
+ ## 0.8.0-alpha.13
4
+
5
+ ### Minor Changes
6
+
7
+ - Added org-visible Factory sessions: sessions store a visibility property derived from origin, org members can open org-visible sessions, and factory-ui shows session owners and access errors. ([#21460](https://github.com/mastra-ai/mastra/pull/21460))
8
+
9
+ ### Patch Changes
10
+
11
+ - Prevent Factory handoff files from colliding across work items ([#21763](https://github.com/mastra-ai/mastra/pull/21763))
12
+
13
+ - Fixed workspace failures vanishing from the chat transcript. A workspace that failed to clone or start only flipped an internal flag that nothing rendered, so the session simply looked stuck with no reason given. The failure now appears as an error notice in the transcript — the same message the terminal already printed — for both the `workspace_error` and the failing `workspace_status_changed` event. ([#21746](https://github.com/mastra-ai/mastra/pull/21746))
14
+
15
+ - Make the board honest about runs it is waiting on, and about clicks that fail. ([#21766](https://github.com/mastra-ai/mastra/pull/21766))
16
+
17
+ Four gaps closed on the work board:
18
+
19
+ - A card click that failed while refreshing workspaces before starting a run did
20
+ nothing at all — no run, no error. It now surfaces the failure instead of
21
+ swallowing it, so an expired session reads as an expired session.
22
+ - A run a rule proposed could not be approved from the card. The card menu now
23
+ offers it.
24
+ - After a plan was approved, the Building run became unreachable from the card,
25
+ leaving the item stranded mid-loop.
26
+ - A card with a proposed run looked idle. It now says it is waiting on someone,
27
+ with the approval inline.
28
+
29
+ - Stop showing "Linked card could not be filed" when nothing failed. ([#21766](https://github.com/mastra-ai/mastra/pull/21766))
30
+
31
+ A linked-card decision that already succeeded is deliberately reset to `retry`
32
+ when its card is rematerialized, so the card gets re-filed. The board read any
33
+ `retry` as "already failed at least once" and put an error on the card, so a
34
+ routine replay looked like a broken automation — 16 cards were showing a failure
35
+ nobody caused.
36
+
37
+ A card now reports an error only when the effect has actually been attempted or
38
+ left an error behind. A replay reads as what it is: the work it is doing.
39
+
40
+ - Platform GitHub event polling is now scoped to the repositories linked to a Factory project. Previously the worker polled every repository the underlying GitHub App installation exposed, which for customers who grant broad org access meant hundreds of unnecessary requests per polling cycle. With this change, no polling happens for repositories that are not linked to a project, and repositories added or removed from a project are picked up automatically on the next polling cycle — no worker restart or additional configuration required. ([#21772](https://github.com/mastra-ai/mastra/pull/21772))
41
+
42
+ - Updated dependencies [[`6db7a5d`](https://github.com/mastra-ai/mastra/commit/6db7a5dd3dd2b6f7ef75dcd804fcffef5fa83963), [`0cdc5dc`](https://github.com/mastra-ai/mastra/commit/0cdc5dc69024957815da4f51acc4119eb4f447d7)]:
43
+ - @mastra/core@1.60.0-alpha.12
44
+ - @mastra/code-sdk@1.3.0-alpha.12
45
+
46
+ ## 0.8.0-alpha.12
47
+
48
+ ### Patch Changes
49
+
50
+ - Speed up the local dev watch for the design system: `pnpm dev:ui` now rebuilds `@mastra/playground-ui` on save, so design-system edits show up in the Factory UI without a manual rebuild. `pnpm dev:playground` picks up the same watch. The watch starts from a full build and then skips type declaration emit on every rebuild, which brings each save from ~9s down to ~1.5s. ([#21646](https://github.com/mastra-ai/mastra/pull/21646))
51
+
52
+ Declarations stay frozen at that starting build for the length of a dev session — run `pnpm --filter @mastra/playground-ui build` after changing a component's props. The published build is unchanged and still emits declarations.
53
+
54
+ - Fixed how the Factory chat transcript reads agent controller events. It branched on an `om_activation.enabled` flag the controller never sends, and cast token usage and memory progress into hand-written shapes that had drifted from the streamed payloads. Both now read the shapes the controller actually emits, so the status line and memory rings stay correct as those payloads evolve. ([#21739](https://github.com/mastra-ai/mastra/pull/21739))
55
+
56
+ - Updated dependencies [[`6223446`](https://github.com/mastra-ai/mastra/commit/6223446ddce6166e96e0ba5e00d628b615dee8ca), [`583e235`](https://github.com/mastra-ai/mastra/commit/583e23519c13af16c1746f9c49722d011216611b), [`a77f8d4`](https://github.com/mastra-ai/mastra/commit/a77f8d4740d2178a74c41e4bf678b4fcd8fa0bb2), [`40d358e`](https://github.com/mastra-ai/mastra/commit/40d358e29d55543803e64b49241122f598ffabc7), [`e80cd7e`](https://github.com/mastra-ai/mastra/commit/e80cd7e7683e7d732e1cc6784bcac1d2640d2ce3), [`20504b2`](https://github.com/mastra-ai/mastra/commit/20504b2ecebd0e077acda3d457ab57480a98ed3e)]:
57
+ - @mastra/core@1.60.0-alpha.11
58
+ - @mastra/code-sdk@1.3.0-alpha.11
59
+
3
60
  ## 0.8.0-alpha.11
4
61
 
5
62
  ### Patch Changes
@@ -908,7 +908,7 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
908
908
  if (!project) return c.json({ error: "Project repository not found" }, 404);
909
909
  const sessions = await github.sourceControlStorage.sessions.list({
910
910
  projectRepositoryId: project.id,
911
- userId
911
+ viewerUserId: userId
912
912
  });
913
913
  return c.json({ sessions });
914
914
  }
@@ -963,7 +963,8 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
963
963
  userId,
964
964
  branch,
965
965
  baseBranch,
966
- title: normalizedTitle
966
+ title: normalizedTitle,
967
+ visibility: "org"
967
968
  }).catch(async (error) => {
968
969
  if (!(error instanceof UniqueViolationError) || requestedSessionId === void 0) throw error;
969
970
  const conflict = await github.sourceControlStorage.sessions.getBySessionId(sessionId);
@@ -981,7 +982,7 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
981
982
  const resolved = await resolveOrgTenant(loose(c), auth);
982
983
  if ("response" in resolved) return resolved.response;
983
984
  const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param("sessionId"));
984
- if (!session || session.orgId !== resolved.tenant.orgId || session.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
985
+ if (!session || session.orgId !== resolved.tenant.orgId || session.visibility === "private" && session.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
985
986
  return c.json({ session });
986
987
  }
987
988
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","names":["isValidGitRefSandbox"],"sources":["../../../src/integrations/github/routes.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for the GitHub App project feature.\n *\n * Registered alongside the other `/web/*` routes, behind the host auth gate.\n * Every route additionally re-checks the authenticated user via the injected\n * `RouteAuth` seam and scopes all rows by that user's stable id, so a user can\n * only ever see and operate on their own installations and projects.\n *\n * When the feature is disabled (`isGithubFeatureEnabled()` false), `buildGithubRoutes`\n * returns only `GET /web/github/status`, which reports `enabled:false`\n * so the SPA can cleanly hide all GitHub UI.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MountedMastraCode } from '@mastra/code-sdk';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport { UniqueViolationError } from '@mastra/core/storage';\nimport type { FactoryStorage } from '@mastra/core/storage';\nimport type { Context } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport type { RouteAuth } from '../../routes/route.js';\nimport { SandboxBudgetError } from '../../sandbox/fleet.js';\nimport type { MaterializationSandbox, PrepareProgress, ProgressFn, SandboxFleet } from '../../sandbox/fleet.js';\nimport type { StateSigner } from '../../state-signing.js';\nimport type { AuditEmitter } from '../../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ProjectRepository,\n ProjectRepositorySandbox,\n ProjectSourceControlConnection,\n SourceControlInstallation,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from './config.js';\nimport type { GithubIntegration } from './integration.js';\nimport { clearGithubPat, getGithubPat, getGithubPatStatus, setGithubPat } from './pat.js';\nimport type { GithubPatKind } from './pat.js';\n\nimport { reclaimDeletedSessionSandbox } from './sandbox-release.js';\nimport {\n commitAll,\n computeWorktreePath,\n ensureProjectSandbox,\n isValidGitRef as isValidGitRefSandbox,\n materializeRepo,\n MaterializeError,\n pushBranch,\n teardownProjectSandbox,\n WorktreeError,\n} from './sandbox.js';\nimport type { GitIdentity } from './sandbox.js';\n\nconst sessionOperationLocks = new Map<string, Promise<unknown>>();\nconst MAX_SESSION_TITLE_LENGTH = 80;\nconst USER_SESSION_BRANCH_PREFIX = 'user/session-';\n// lowercase only (crypto.randomUUID output), so casing cannot fork one logical ID into two sessions\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n/**\n * Serialize same-session mutations within one Factory process. Factory sessions\n * normally issue these operations sequentially, so this lock is probably not\n * necessary; keep the cheap local guard until that invariant is enforced by\n * the request protocol. It intentionally does not consume a database connection.\n */\nfunction withSessionOperationLock<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const previous = sessionOperationLocks.get(sessionId) ?? Promise.resolve();\n const next = previous.then(fn, fn);\n const tail = next.then(\n () => undefined,\n () => undefined,\n );\n sessionOperationLocks.set(sessionId, tail);\n void tail.then(() => {\n if (sessionOperationLocks.get(sessionId) === tail) sessionOperationLocks.delete(sessionId);\n });\n return next;\n}\nimport { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from './subscriptions.js';\nimport { handleGithubWebhook } from './webhook.js';\nimport type { ParsedGithubWebhook } from './webhook.js';\n\n/**\n * Loose Hono context accepted by the shared GitHub route helpers. The\n * `registerApiRoute` handlers receive a path-parameterized context whose\n * `HonoRequest` literal-path generics are invariant and don't flow into a\n * shared helper signature. The helpers only ever touch cookies/query/tenant, so\n * we erase the path to a plain `Context` at the call boundary via `loose()`.\n */\ntype RouteContext = Context;\n\n/** Erase a route handler's path-parameterized context to a plain `Context`. */\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport interface MountGithubRoutesOptions {\n /** Host auth seam — resolves the signed-in user/tenant for each request. */\n auth: RouteAuth;\n /**\n * Sandbox fleet for per-project sandboxes. A fleet constructed without a\n * machine config reports `enabled: false` and the sandbox-backed routes\n * respond 503.\n */\n fleet: SandboxFleet;\n /** Factory storage backend used for the `appDbConfigured` diagnostic. */\n storage?: FactoryStorage;\n /**\n * The GitHub App integration the handlers operate on (Octokit access, token\n * minting, OAuth URLs). Normally supplied by `GithubIntegration.routes()`;\n * when absent, only the disabled `status` route is served.\n */\n github?: GithubIntegration;\n /**\n * Shared OAuth/install `state` signer (created once per boot by the\n * factory). Required for the OAuth/install flow; when absent, only the\n * disabled `status` route is served.\n */\n stateSigner?: StateSigner;\n /**\n * Absolute base URL of the web server (e.g. `http://localhost:4111`), used to\n * build the OAuth/install redirect URI when one isn't explicitly configured.\n */\n baseUrl?: string;\n /** Explicit OAuth callback URI; defaults to `<baseUrl>/auth/github/callback`. */\n redirectUri?: string;\n /** Controller used to route verified webhook notifications to exact subscribed sessions. */\n controller?: MountedMastraCode['controller'];\n /** Best-effort audit emission supplied by the factory-owned audit domain. */\n emitAudit?: AuditEmitter['emit'];\n /** Factory projects domain — resolves a project's default triage model. */\n projects?: FactoryProjectsStorage;\n sessionRetirement?: import('../../sandbox/session-retirement.js').SessionRetirementCoordinator;\n /** Authoritative Factory rule ingress for normalized, signature-verified GitHub deliveries. */\n ingestFactoryEvent?: (event: ParsedGithubWebhook) => Promise<unknown>;\n}\n\nfunction pullRequestNumberFromUrl(value: string, expectedRepo: string): number | undefined {\n try {\n const url = new URL(value);\n const match = url.pathname.match(/^\\/([^/]+\\/[^/]+)\\/pull\\/(\\d+)\\/?$/);\n if (\n url.protocol !== 'https:' ||\n url.hostname !== 'github.com' ||\n match?.[1]?.toLowerCase() !== expectedRepo.toLowerCase()\n ) {\n return undefined;\n }\n const number = Number(match[2]);\n return Number.isInteger(number) && number > 0 ? number : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Validate a git branch/ref name against a strict whitelist. The value is later\n * interpolated into a shell `git clone --branch` command, so it must never\n * contain shell metacharacters. We accept only git-ref-safe characters and\n * reject anything else rather than relying on shell quoting alone.\n */\nfunction isValidGitRef(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= 255 && /^[A-Za-z0-9_./-]+$/.test(value);\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction normalizeSessionTitle(title: string): string | null {\n // Cap code points, not UTF-16 units: an emoji straddling the cap would store a lone surrogate.\n const capped = [...title.replace(/\\s+/g, ' ').trim()].slice(0, MAX_SESSION_TITLE_LENGTH).join('');\n return capped.trimEnd() || null;\n}\n\n/**\n * Resolve the org-scoped tenant for a GitHub request. GitHub project features\n * are org-owned, so they require both a signed-in user and a WorkOS\n * organization. Returns the `(orgId, userId)` tenant (with `orgId` narrowed to a\n * non-null string) or a ready-to-return error response: 401 when unauthenticated,\n * 403 when the user has no organization (personal account).\n *\n * Resolves the session from the request cookie itself (via `auth.ensureUser`)\n * instead of relying on the auth gate's context stash: on platform deploys\n * custom `apiRoutes` run on an isolated sub-app context where the gate's\n * `c.set(...)` is invisible. When the gate stash IS visible (local Hono\n * server), `auth.ensureUser` returns the cached user and this is a no-op.\n */\nasync function resolveOrgTenant(\n c: RouteContext,\n auth: RouteAuth,\n): Promise<{ tenant: { orgId: string; userId: string } } | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'GitHub projects require a WorkOS organization. Personal accounts cannot connect repositories.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\n/**\n * Parse a 1-based `page` query param. Missing means page 1; anything that is\n * not a small positive integer is rejected (`null`).\n */\nfunction parseListPage(raw: string | undefined): number | null {\n if (raw === undefined) return 1;\n if (!/^\\d{1,5}$/.test(raw)) return null;\n const page = Number(raw);\n return page >= 1 ? page : null;\n}\n\nconst VALID_ISSUE_LABEL_FILTERS = new Set(['status: auto-triaged', 'status: needs approval']);\n\nfunction parseIssueLabelFilter(raw: string | undefined): string | undefined | null {\n if (raw === undefined || raw === '') return undefined;\n if (VALID_ISSUE_LABEL_FILTERS.has(raw)) return raw;\n return null;\n}\n\ninterface ResolvedProjectRepository extends ProjectRepository {\n connection: ProjectSourceControlConnection;\n installation: SourceControlInstallation;\n repository: SourceControlRepository;\n factoryProjectId: string;\n defaultBranch: string;\n}\n\nasync function resolveProjectRepository(args: {\n github: GithubIntegration;\n orgId: string;\n projectRepositoryId: string;\n}): Promise<ResolvedProjectRepository | null> {\n const projectRepository = await args.github.sourceControlStorage.projectRepositories.get({\n orgId: args.orgId,\n id: args.projectRepositoryId,\n });\n if (!projectRepository) return null;\n const connection = await args.github.sourceControlStorage.connections.get({\n orgId: args.orgId,\n id: projectRepository.connectionId,\n });\n if (!connection) return null;\n const repository = await args.github.sourceControlStorage.repositories.get({\n orgId: args.orgId,\n id: projectRepository.repositoryId,\n });\n if (!repository) return null;\n const installation = await args.github.sourceControlStorage.installations.get({\n orgId: args.orgId,\n id: connection.installationId,\n });\n if (!installation) return null;\n return {\n ...projectRepository,\n connection,\n installation,\n repository,\n factoryProjectId: connection.factoryProjectId,\n defaultBranch: projectRepository.branch ?? repository.defaultBranch,\n };\n}\n\nfunction polledIssueEvent(\n project: ResolvedProjectRepository,\n issue: {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignee: string | null;\n assignees?: string[];\n labels: string[];\n createdAt: string;\n },\n): ParsedGithubWebhook {\n const repositoryId = Number(project.repository.externalId);\n const assigneeLogins = issue.assignees ?? (issue.assignee ? [issue.assignee] : []);\n return {\n event: 'issues',\n deliveryId: `poll:${repositoryId}:issue:${issue.number}:${issue.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: Number(project.installation.externalId) },\n repository: { id: repositoryId, full_name: project.repository.slug },\n sender: { login: issue.author ?? '__unknown__' },\n issue: {\n number: issue.number,\n title: issue.title,\n html_url: issue.url,\n created_at: issue.createdAt,\n assignees: assigneeLogins.map(login => ({ login })),\n labels: issue.labels.map(name => ({ name })),\n },\n },\n };\n}\n\nfunction polledPullRequestEvent(\n project: ResolvedProjectRepository,\n pullRequest: {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignees: string[];\n requestedReviewers: string[];\n headBranch: string;\n baseBranch: string;\n createdAt: string;\n },\n): ParsedGithubWebhook {\n const repositoryId = Number(project.repository.externalId);\n return {\n event: 'pull_request',\n deliveryId: `poll:${repositoryId}:pull-request:${pullRequest.number}:${pullRequest.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: Number(project.installation.externalId) },\n repository: { id: repositoryId, full_name: project.repository.slug },\n sender: { login: pullRequest.author ?? '__unknown__' },\n pull_request: {\n number: pullRequest.number,\n title: pullRequest.title,\n html_url: pullRequest.url,\n created_at: pullRequest.createdAt,\n state: 'open',\n merged: false,\n assignees: pullRequest.assignees.map(login => ({ login })),\n requested_reviewers: pullRequest.requestedReviewers.map(login => ({ login })),\n head: { ref: pullRequest.headBranch },\n base: { ref: pullRequest.baseBranch },\n },\n },\n };\n}\n\nasync function ingestPolledEvents(\n events: ParsedGithubWebhook[],\n ingestFactoryEvent: MountGithubRoutesOptions['ingestFactoryEvent'],\n): Promise<void> {\n if (!ingestFactoryEvent) return;\n const results = await Promise.allSettled(events.map(event => ingestFactoryEvent(event)));\n const rejected = results.find((result): result is PromiseRejectedResult => result.status === 'rejected');\n if (rejected) throw rejected.reason;\n}\n\n/**\n * Build the GitHub routes as Mastra `apiRoutes`. When the feature is disabled,\n * returns only the `status` route so the SPA can detect the disabled state.\n */\nexport function buildGithubRoutes(options: MountGithubRoutesOptions): ApiRoute[] {\n const routes: ApiRoute[] = [];\n const { auth, fleet, storage, github, stateSigner, controller, emitAudit, sessionRetirement } = options;\n const diagnostics = () =>\n getGithubFeatureDiagnostics({ github, auth, appDbConfigured: storage !== undefined, stateSigner, fleet });\n\n // The status route is always registered so the SPA can detect the disabled state.\n routes.push(\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n if (!isGithubFeatureEnabled({ github, auth }) || !github || !stateSigner) {\n return c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: diagnostics(),\n });\n }\n // Resolve the session from the request cookie: on platform deploys custom\n // apiRoutes run on an isolated context where the gate's stash is invisible.\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant) return c.json({ error: 'unauthorized', reason: 'auth_required' }, 401);\n\n // Org-scoped: personal (no-org) users have GitHub projects disabled. Report\n // enabled (so the SPA can show the org-required hint) but never connected.\n if (!tenant.orgId) {\n return c.json({\n enabled: true,\n sandboxEnabled: fleet.enabled,\n organizationRequired: true,\n connected: false,\n installations: [],\n reason: 'organization_required',\n diagnostics: diagnostics(),\n });\n }\n\n const rows = options.github\n ? await options.github.sourceControlStorage.installations.list({ orgId: tenant.orgId })\n : [];\n\n const connected = rows.length > 0;\n return c.json({\n enabled: true,\n sandboxEnabled: fleet.enabled,\n connected,\n installations: rows.map(r => ({\n installationId: Number(r.externalId),\n accountLogin: r.accountName,\n accountType: r.accountType,\n })),\n reason: connected ? 'ready' : 'not_connected',\n diagnostics: diagnostics(),\n });\n },\n }),\n );\n\n // Without an integration instance + state signer there is nothing the\n // remaining handlers can do — serve only the disabled `status` route\n // (mirrors the feature gate).\n if (!isGithubFeatureEnabled({ github, auth }) || !github || !stateSigner) {\n return routes;\n }\n const signState = (orgId: string, userId: string): string => stateSigner.sign(orgId, userId);\n const verifyState = (state: string | undefined) => stateSigner.verify(state);\n\n routes.push(\n registerApiRoute('/web/github/subscriptions', {\n method: 'GET',\n handler: async c => {\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const resourceId = c.req.query('resourceId');\n const threadId = c.req.query('threadId');\n const sessionScope = c.req.query('scope');\n if (!resourceId || !threadId) return c.json({ error: 'resourceId and threadId are required' }, 400);\n\n const subscriptions = await listPullRequestSubscriptionsForThread(\n {\n orgId: tenant.orgId,\n resourceId,\n threadId,\n sessionScope,\n },\n github.integrationStorage,\n );\n return c.json({\n subscriptions: subscriptions.map(subscription => ({\n id: subscription.id,\n repoFullName: subscription.data.repositorySlug,\n pullRequestNumber: Number(subscription.data.changeRequestId),\n status: subscription.status,\n url: `https://github.com/${subscription.data.repositorySlug}/pull/${subscription.data.changeRequestId}`,\n })),\n });\n },\n }),\n registerApiRoute('/web/github/webhook', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const result = await handleGithubWebhook(loose(c), {\n github,\n ingestFactoryEvent: options.ingestFactoryEvent,\n ...(options.controller\n ? {\n controller: options.controller,\n onTargetError: (subscription, error) => {\n console.warn(\n `[GitHub Webhook] Delivery failed for subscription ${subscription.id} (${subscription.resourceId}/${subscription.threadId}).`,\n error,\n );\n },\n }\n : {}),\n });\n return c.json(result.body, result.status);\n },\n }),\n );\n\n const redirectUri = options.redirectUri ?? `${(options.baseUrl ?? '').replace(/\\/$/, '')}/auth/github/callback`;\n\n // ── Connect: bounce through the OAuth identify flow ─────────────────────\n // Identify-first (rather than install-first) so an app that is *already*\n // installed on the org re-syncs into our DB: GitHub's install page dead-ends\n // on the installation settings screen for existing installs and never\n // redirects back to us. The callback persists whatever installations the\n // verified user token can see, and only redirects to the install URL when\n // there are none.\n //\n // `?manage=1` skips the identify bounce and sends the user straight to\n // GitHub's installation page — used by \"Manage GitHub connection\" to\n // add/remove accounts and repo access. For an already-authorized user the\n // identify flow completes instantly and invisibly, so without this the\n // manage button would appear to do nothing. GitHub's post-install \"Save\"\n // redirect lands back on the callback, which re-syncs installations.\n routes.push(\n registerApiRoute('/auth/github/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const state = signState(resolved.tenant.orgId, resolved.tenant.userId);\n if (c.req.query('manage')) return c.redirect(github.buildInstallUrl(state));\n return c.redirect(github.buildOAuthIdentifyUrl(state, redirectUri));\n },\n }),\n );\n\n // ── Callback: confirm identity, persist the installation against the org ──\n routes.push(\n registerApiRoute('/auth/github/callback', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n\n const state = c.req.query('state');\n if (!state) {\n // GitHub's \"Save\"/update redirect from the installation settings page\n // arrives with `installation_id` + `setup_action` but no state. We\n // never trust the raw installation_id; start a fresh identify bounce\n // bound to the current session so the update re-syncs installations.\n return c.redirect(github.buildOAuthIdentifyUrl(signState(orgId, userId), redirectUri));\n }\n const stateTenant = verifyState(state);\n if (!stateTenant || stateTenant.userId !== userId || stateTenant.orgId !== orgId) {\n // CSRF / cross-user/org linking protection: the signed state must belong\n // to the same logged-in user *and* their current org.\n console.warn(\n '[GitHub] Install callback rejected: state/tenant mismatch.',\n JSON.stringify({\n stateValid: Boolean(stateTenant),\n stateOrgId: stateTenant?.orgId,\n stateUserId: stateTenant?.userId,\n sessionOrgId: orgId,\n sessionUserId: userId,\n }),\n );\n return c.redirect('/?github=error');\n }\n\n const code = c.req.query('code');\n // We only ever persist installations that GitHub confirms belong to *this*\n // user via the OAuth code path. The raw `installation_id` from the install\n // redirect is not trusted on its own — anyone with a valid state could pass\n // an arbitrary id — so when no code is present we bounce through the OAuth\n // identify flow to obtain a verified user token first.\n if (!code) {\n return c.redirect(github.buildOAuthIdentifyUrl(signState(orgId, userId), redirectUri));\n }\n\n try {\n const userToken = await github.exchangeOAuthCode(code, redirectUri);\n const installations = await github.listUserInstallations(userToken);\n if (installations.length === 0) {\n // Verified user has no installations yet — send them to the actual\n // install page. After installing, GitHub redirects back here with\n // the same state (and no code), which bounces through identify\n // again and lands in the persist path below.\n return c.redirect(github.buildInstallUrl(signState(orgId, userId)));\n }\n for (const inst of installations) {\n // The installation is org-owned; `userId` records who connected it.\n await github.sourceControlStorage.installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: inst.installationId.toString(),\n accountName: inst.accountLogin,\n accountType: inst.accountType,\n });\n }\n } catch (error) {\n console.warn(\n `[GitHub] Install callback failed to persist installations for org ${orgId} / user ${userId}.`,\n error,\n );\n return c.redirect('/?github=error');\n }\n\n return c.redirect('/?github=connected');\n },\n }),\n );\n\n // ── List repos across the org's installations ───────────────────────────\n routes.push(\n registerApiRoute('/web/github/repos', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n const orgId = resolved.tenant.orgId;\n const installs = await github.sourceControlStorage.installations.list({ orgId });\n\n const query = (c.req.query('q') ?? '').toLowerCase();\n // List every installation's repositories in parallel — installations\n // are independent upstream calls, and serial listing multiplied\n // worst-case latency by installation count.\n const listed = await Promise.all(\n installs.map(async inst => {\n try {\n return { inst, list: await github.listInstallationRepos(Number(inst.externalId)) };\n } catch (err) {\n // GitHub 404s when the installation no longer exists for this app\n // (app uninstalled/reinstalled, or the row was recorded under\n // different app credentials). Prune the stale row so `/status`\n // reflects reality and the UI prompts a reconnect, then keep\n // listing the remaining installations.\n if ((err as { status?: number }).status !== 404) throw err;\n console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);\n await github.sourceControlStorage.installations.delete({ orgId, id: inst.id });\n return { inst, list: [] };\n }\n }),\n );\n\n // Filter + dedupe by repo id in installation order — same result\n // ordering as the previous serial loop.\n const matches = [];\n const seenRepositoryIds = new Set<number>();\n for (const { inst, list } of listed) {\n for (const repo of list) {\n if (query && !repo.fullName.toLowerCase().includes(query)) continue;\n if (seenRepositoryIds.has(repo.id)) continue;\n seenRepositoryIds.add(repo.id);\n matches.push({ inst, repo });\n }\n }\n\n // Mirror matches into storage with bounded concurrency instead of one\n // awaited upsert per repository.\n const repos = new Array(matches.length);\n const upsertConcurrency = 10;\n for (let start = 0; start < matches.length; start += upsertConcurrency) {\n await Promise.all(\n matches.slice(start, start + upsertConcurrency).map(async ({ inst, repo }, offset) => {\n const repository = await github.sourceControlStorage.repositories.upsert({\n orgId,\n input: {\n installationId: inst.id,\n externalId: repo.id.toString(),\n slug: repo.fullName,\n defaultBranch: isValidGitRef(repo.defaultBranch) ? repo.defaultBranch : 'main',\n providerMetadata: { private: repo.private, owner: repo.owner },\n },\n });\n repos[start + offset] = {\n ...repo,\n installationStorageId: inst.id,\n repositoryStorageId: repository.id,\n sandboxProvider: fleet.provider,\n sandboxWorkdir: fleet.computeWorkdir(repo.fullName),\n };\n }),\n );\n }\n return c.json({ repos });\n },\n }),\n );\n\n // ── Materialize a project into the caller's per-user sandbox ─────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/ensure', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n\n if (!fleet.enabled) {\n return c.json({ error: 'sandbox_not_configured', message: 'No sandbox provider is configured.' }, 503);\n }\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) return c.json({ error: 'Project repository not found' }, 404);\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return c.json({ error: 'Project repository not found' }, 404);\n }\n\n // Stream live server-side progress when the client asks for it (EventSource\n // / fetch with `Accept: text/event-stream`); otherwise fall back to a single\n // JSON response so non-streaming callers and tests keep working unchanged.\n const wantsStream = (c.req.header('accept') ?? '').includes('text/event-stream');\n if (wantsStream) {\n return streamSSE(loose(c), async stream => {\n try {\n const result = await prepareProject({\n github,\n fleet,\n project,\n userId,\n onProgress: ev => void stream.writeSSE({ event: 'progress', data: JSON.stringify(ev) }),\n });\n await stream.writeSSE({ event: 'done', data: JSON.stringify(result) });\n } catch (err) {\n await stream.writeSSE({ event: 'error', data: JSON.stringify(ensureErrorPayload(err).body) });\n }\n });\n }\n\n try {\n const result = await prepareProject({ github, fleet, project, userId });\n return c.json(result);\n } catch (err) {\n const { status, body } = ensureErrorPayload(err);\n return c.json(body, status);\n }\n },\n }),\n );\n\n // ── List a project's open GitHub issues ──────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/issues', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n const page = parseListPage(c.req.query('page'));\n if (page === null) return c.json({ error: 'invalid_page' }, 400);\n const label = parseIssueLabelFilter(c.req.query('label'));\n if (label === null) return c.json({ error: 'invalid_label' }, 400);\n try {\n const { issues, nextCursor } = await github.intake.listIssues({\n connection: {\n type: 'app-installation',\n installationId: Number(loaded.project.installation.externalId),\n },\n sourceIds: [loaded.project.repository.slug],\n labels: label ? [label] : undefined,\n cursor: String(page),\n });\n const responseIssues = issues.map(issue => ({\n number: Number(issue.id),\n title: issue.title,\n url: issue.url,\n author: issue.author,\n assignee: issue.assignee,\n assignees: issue.assignees,\n labels: issue.labels,\n comments: issue.commentCount ?? 0,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n }));\n await ingestPolledEvents(\n responseIssues.map(issue => polledIssueEvent(loaded.project, issue)),\n options.ingestFactoryEvent,\n );\n return c.json({\n issues: responseIssues,\n nextPage: nextCursor === null ? null : Number(nextCursor),\n });\n } catch (err) {\n return c.json(\n { error: 'github_fetch_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n );\n\n // ── List a project's open (non-draft) pull requests ─────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/prs', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n const page = parseListPage(c.req.query('page'));\n if (page === null) return c.json({ error: 'invalid_page' }, 400);\n try {\n const { pullRequests, nextCursor } = await github.versionControl.listPullRequests({\n connection: {\n type: 'app-installation',\n installationId: Number(loaded.project.installation.externalId),\n },\n sourceId: loaded.project.repository.slug,\n includeDrafts: false,\n cursor: String(page),\n });\n const responsePullRequests = pullRequests.map(pr => ({\n number: Number(pr.id),\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n }));\n await ingestPolledEvents(\n responsePullRequests.map(pullRequest => polledPullRequestEvent(loaded.project, pullRequest)),\n options.ingestFactoryEvent,\n );\n return c.json({\n pullRequests: responsePullRequests,\n nextPage: nextCursor === null ? null : Number(nextCursor),\n });\n } catch (err) {\n return c.json(\n { error: 'github_fetch_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n );\n\n // ── Read per-project settings ────────────────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/settings', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n return c.json({\n setupCommand: loaded.project.setupCommand,\n teardownCommand: loaded.project.teardownCommand,\n });\n },\n }),\n );\n\n // ── Update per-project settings ──────────────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/settings', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n\n let body: { setupCommand?: unknown; teardownCommand?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n\n const commands = ['setupCommand', 'teardownCommand'] as const;\n for (const command of commands) {\n const value = body[command];\n if (value === undefined) continue;\n if (value !== null && typeof value !== 'string') {\n return c.json({ error: `Invalid ${command}` }, 400);\n }\n if (typeof value === 'string' && value.length > 2000) {\n return c.json({ error: `${command} too long (max 2000 characters)` }, 400);\n }\n // Reject control characters (except newline/tab). Commands are shell\n // scripts by design, but escape sequences and NULs can spoof logs or\n // confuse the sandbox shell.\n if (typeof value === 'string' && /[\\0-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/.test(value)) {\n return c.json({ error: `${command} contains control characters` }, 400);\n }\n }\n\n const normalizeCommand = (value: unknown): string | null | undefined => {\n if (value === undefined) return undefined;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;\n };\n const setupCommand = normalizeCommand(body.setupCommand);\n const teardownCommand = normalizeCommand(body.teardownCommand);\n\n await github.sourceControlStorage.projectRepositories.update({\n orgId: loaded.project.installation.orgId,\n id: loaded.project.id,\n input: {\n ...(setupCommand !== undefined ? { setupCommand } : {}),\n ...(teardownCommand !== undefined ? { teardownCommand } : {}),\n },\n });\n return c.json({\n setupCommand: setupCommand === undefined ? loaded.project.setupCommand : setupCommand,\n teardownCommand: teardownCommand === undefined ? loaded.project.teardownCommand : teardownCommand,\n });\n },\n }),\n );\n\n // ── Org GitHub PATs ──────────────────────────────────────────────────────\n // Installation tokens are the wrong credential for the `gh` CLI (integration\n // -restricted endpoints 403 regardless of permissions), so orgs paste\n // classic PATs the sandboxes use instead: a `default` worker token, and an\n // optional `reviewer` token that review-board sessions use so PR reviews\n // come from a different account. Tokens are never sent back to the browser —\n // only whether each is configured.\n const parsePatKind = (value: unknown): GithubPatKind | null => {\n if (value === undefined || value === null || value === 'default') return 'default';\n if (value === 'reviewer') return 'reviewer';\n return null;\n };\n routes.push(\n registerApiRoute('/web/github/pat', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n registerApiRoute('/web/github/pat', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n let body: { token?: unknown; kind?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const kind = parsePatKind(body.kind);\n if (!kind) return c.json({ error: \"kind must be 'default' or 'reviewer'\" }, 400);\n const token = typeof body.token === 'string' ? body.token.trim() : '';\n if (!token) return c.json({ error: 'A token is required' }, 400);\n if (token.length > 500) return c.json({ error: 'Token too long (max 500 characters)' }, 400);\n if (/\\s/.test(token)) return c.json({ error: 'Token must not contain whitespace' }, 400);\n\n await setGithubPat(github.integrationStorage, resolved.tenant.orgId, token, kind);\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n registerApiRoute('/web/github/pat', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const kind = parsePatKind(c.req.query('kind'));\n if (!kind) return c.json({ error: \"kind must be 'default' or 'reviewer'\" }, 400);\n await clearGithubPat(github.integrationStorage, resolved.tenant.orgId, kind);\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n );\n\n // ── Sessions / commit / push / PR ────────────────────────────────────────\n routes.push(...buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, sessionRetirement }));\n\n return routes;\n}\n\n/**\n * Load the org-owned project for a read-only GitHub API route. Unlike\n * `loadOwnedProject`, this never touches sandbox state — the issues/PR list\n * routes only need the repo + installation, so they work before a sandbox is\n * ever provisioned.\n */\nasync function loadOrgProject(options: {\n github: GithubIntegration;\n auth: RouteAuth;\n c: RouteContext;\n}): Promise<{ project: ResolvedProjectRepository; userId: string } | { response: Response }> {\n const { github, auth, c } = options;\n const resolved = await resolveOrgTenant(c, auth);\n if ('response' in resolved) return { response: resolved.response };\n const { orgId, userId } = resolved.tenant;\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n return { project, userId };\n}\n\n/** Derive a commit/author identity from the authenticated host user. */\nfunction identityFromUser(user: unknown): GitIdentity {\n const u = user as { name?: string; email?: string } | null | undefined;\n return { name: u?.name ?? null, email: u?.email ?? null };\n}\n\n/**\n * Resolve a live, started sandbox for the caller's per-user sandbox binding. The\n * sandbox must already have been provisioned (`sandboxId` set) — the git write\n * routes never clone, they operate on the existing checkout.\n */\nasync function resolveProjectSandbox(options: {\n fleet: SandboxFleet;\n sandboxRow: ProjectRepositorySandbox;\n}): Promise<MaterializationSandbox> {\n const { fleet, sandboxRow } = options;\n if (!sandboxRow.sandboxId) {\n throw new MaterializeError('Project sandbox is not provisioned. Open the project first.', 'clone-failed');\n }\n return fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });\n}\n\n/**\n * Load (or create) the caller's per-(project,user) sandbox binding row. The\n * binding inherits its workdir from the org-owned project, but `sandboxId` /\n * `materializedAt` stay null until the user first opens the project.\n */\nasync function loadOrCreateSandboxRow(\n github: GithubIntegration,\n project: ResolvedProjectRepository,\n userId: string,\n): Promise<ProjectRepositorySandbox> {\n return github.sourceControlStorage.sandboxes.getOrCreate({ projectRepository: project, userId });\n}\n\ninterface EnsureResult {\n resourceId: string;\n factoryProjectId: string;\n projectRepositoryId: string;\n sandboxId: string | null;\n sandboxWorkdir: string;\n}\n\n/**\n * Provision/reattach the caller's sandbox and materialize the repo into it,\n * emitting coarse progress events as each server step happens. Shared by both\n * the JSON and SSE variants of the `/ensure` route. Throws on failure so the\n * caller can shape the response (HTTP status vs SSE `error` event).\n */\nasync function prepareProject(options: {\n github: GithubIntegration;\n fleet: SandboxFleet;\n project: ResolvedProjectRepository;\n userId: string;\n onProgress?: ProgressFn;\n}): Promise<EnsureResult> {\n const { github, fleet, userId, onProgress } = options;\n // Self-heal a sandbox provider switch. The project row snapshots\n // sandboxProvider/sandboxWorkdir at link time, so when the server's provider\n // later changes (platform ↔ local) the stored workdir points into the old\n // provider's filesystem (e.g. `/workspace/…` on a macOS host, where the\n // clone dies on the read-only root volume). Recompute against the current\n // fleet and persist so every later open uses the corrected target.\n let project = options.project;\n if (project.sandboxProvider !== fleet.provider) {\n const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);\n await github.sourceControlStorage.projectRepositories.update({\n orgId: project.installation.orgId,\n id: project.id,\n input: { sandboxProvider: fleet.provider, sandboxWorkdir },\n });\n project = { ...project, sandboxProvider: fleet.provider, sandboxWorkdir };\n }\n let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);\n // The per-user binding inherits its workdir at creation time — re-point it\n // (and force a re-clone) whenever the project's workdir has since moved.\n if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {\n await github.sourceControlStorage.sandboxes.setWorkdir({\n id: sandboxRow.id,\n sandboxWorkdir: project.sandboxWorkdir,\n });\n sandboxRow = { ...sandboxRow, sandboxWorkdir: project.sandboxWorkdir, materializedAt: null };\n }\n const access = await github.versionControl.getRepositoryAccess({\n orgId: project.installation.orgId,\n repositoryId: project.repository.id,\n });\n if (!access.authorization) {\n throw new MaterializeError('Repository access did not include a bearer token.', 'clone-failed');\n }\n // The sandbox env token feeds the `gh` CLI — a configured org PAT wins\n // there. Git clone/pull below keep the minted installation token.\n const ghCliToken =\n (await getGithubPat(() => github.integrationStorage, project.installation.orgId)) ?? access.authorization.token;\n const sandbox = await ensureProjectSandbox({\n fleet,\n row: sandboxRow,\n storage: github.sourceControlStorage.sandboxes,\n token: ghCliToken,\n onProgress,\n });\n // Re-read the sandbox binding so we have the freshly persisted sandboxId.\n const fresh = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id });\n const finalRow = fresh ?? sandboxRow;\n await materializeRepo({\n row: finalRow,\n repoInfo: { repoFullName: project.repository.slug, defaultBranch: project.defaultBranch },\n sandbox,\n token: access.authorization.token,\n storage: github.sourceControlStorage.sandboxes,\n onProgress,\n });\n const result: EnsureResult = {\n resourceId: project.factoryProjectId,\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n sandboxId: finalRow.sandboxId,\n sandboxWorkdir: finalRow.sandboxWorkdir,\n };\n const done: PrepareProgress = { phase: 'done', message: 'Workspace ready.' };\n onProgress?.(done);\n return result;\n}\n\n/** Shape an /ensure failure into an HTTP status + JSON body (also used as the SSE error payload). */\nfunction ensureErrorPayload(err: unknown): {\n status: 429 | 502 | 500;\n body: { error: string; message: string };\n} {\n if (err instanceof SandboxBudgetError) {\n return { status: 429, body: { error: err.code, message: err.message } };\n }\n if (err instanceof MaterializeError) {\n return { status: 502, body: { error: err.code, message: err.message } };\n }\n return {\n status: 500,\n body: { error: 'materialize_failed', message: err instanceof Error ? err.message : String(err) },\n };\n}\n\n/** Map a sandbox/worktree error to an actionable HTTP response. */\nfunction gitErrorResponse(c: Context, err: unknown) {\n if (err instanceof WorktreeError) {\n return c.json({ error: err.code, message: err.message }, err.code === 'invalid-branch' ? 400 : 502);\n }\n if (err instanceof MaterializeError) {\n return c.json({ error: err.code, message: err.message }, 502);\n }\n return c.json({ error: 'git_failed', message: err instanceof Error ? err.message : String(err) }, 500);\n}\n\n/**\n * Load the org-owned project and the caller's per-user sandbox binding for a git\n * route. Centralizes the auth + org/ownership checks every git route shares:\n * the project is scoped by `(id, orgId)`, the sandbox binding by\n * `(projectRepositoryId, userId)`. Returns the tenant, project, and sandbox row, or\n * a ready-to-return error response.\n */\nasync function loadOwnedProject(options: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n c: RouteContext;\n}): Promise<\n | { orgId: string; userId: string; project: ResolvedProjectRepository; sandboxRow: ProjectRepositorySandbox }\n | { response: Response }\n> {\n const { github, auth, fleet, c } = options;\n const resolved = await resolveOrgTenant(c, auth);\n if ('response' in resolved) return { response: resolved.response };\n const { orgId, userId } = resolved.tenant;\n\n if (!fleet.enabled) {\n return {\n response: c.json({ error: 'sandbox_not_configured', message: 'No sandbox provider is configured.' }, 503),\n };\n }\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const sandboxRow = await loadOrCreateSandboxRow(github, project, userId);\n return { orgId, userId, project, sandboxRow };\n}\n\nfunction buildProjectGitRoutes({\n github,\n auth,\n fleet,\n controller,\n emitAudit,\n sessionRetirement,\n}: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n controller?: MountedMastraCode['controller'];\n emitAudit?: AuditEmitter['emit'];\n sessionRetirement?: MountGithubRoutesOptions['sessionRetirement'];\n}): ApiRoute[] {\n return [\n // ── Create / list Factory sessions ──────────────────────────────────────\n registerApiRoute('/web/github/projects/:id/sessions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository({ github, orgId, projectRepositoryId })\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n const sessions = await github.sourceControlStorage.sessions.list({ projectRepositoryId: project.id, userId });\n return c.json({ sessions });\n },\n }),\n registerApiRoute('/web/github/projects/:id/sessions', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository({ github, orgId, projectRepositoryId })\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isJsonObject(body)) return c.json({ error: 'Invalid JSON body' }, 400);\n const requestedBaseBranch = body.baseBranch;\n if (requestedBaseBranch !== undefined && typeof requestedBaseBranch !== 'string') {\n return c.json({ error: 'Invalid baseBranch' }, 400);\n }\n const baseBranch = requestedBaseBranch ?? project.defaultBranch;\n if (!isValidGitRefSandbox(baseBranch)) return c.json({ error: 'Invalid baseBranch' }, 400);\n\n const requestedSessionId = body.sessionId;\n if (\n requestedSessionId !== undefined &&\n (typeof requestedSessionId !== 'string' || !UUID_PATTERN.test(requestedSessionId))\n ) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const sessionId = requestedSessionId ?? randomUUID();\n\n const requestedTitle = body.title;\n if (requestedTitle !== undefined && typeof requestedTitle !== 'string') {\n return c.json({ error: 'Invalid title' }, 400);\n }\n const normalizedTitle = requestedTitle === undefined ? null : normalizeSessionTitle(requestedTitle);\n\n const requestedBranch = body.branch;\n let branch: string;\n if (requestedBranch === undefined) {\n branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;\n } else if (typeof requestedBranch === 'string' && isValidGitRefSandbox(requestedBranch)) {\n branch = requestedBranch;\n } else {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n\n if (requestedSessionId !== undefined) {\n const existing = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (existing) {\n if (\n existing.projectRepositoryId !== project.id ||\n existing.orgId !== orgId ||\n existing.userId !== userId ||\n existing.branch !== branch\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n return c.json({ session: existing });\n }\n }\n\n const session = await github.sourceControlStorage.sessions\n .create({\n sessionId,\n projectRepositoryId: project.id,\n orgId,\n userId,\n branch,\n baseBranch,\n title: normalizedTitle,\n })\n .catch(async error => {\n if (!(error instanceof UniqueViolationError) || requestedSessionId === undefined) throw error;\n const conflict = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (!conflict) throw error;\n return conflict;\n });\n if (\n requestedSessionId !== undefined &&\n (session.sessionId !== sessionId ||\n session.projectRepositoryId !== project.id ||\n session.orgId !== orgId ||\n session.userId !== userId ||\n session.branch !== branch)\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n return c.json({ session });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param('sessionId'));\n if (!session || session.orgId !== resolved.tenant.orgId || session.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param('sessionId'));\n if (!session || session.orgId !== resolved.tenant.orgId || session.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n try {\n await controller?.deleteSession({ resourceId: session.sessionId });\n } catch (error) {\n console.error('[GitHub Sessions] Failed to tear down live controller session', {\n sessionId: session.sessionId,\n error,\n });\n }\n if (sessionRetirement) {\n await sessionRetirement.retireSession({\n sourceControl: github.sourceControlStorage,\n orgId: session.orgId,\n sessionId: session.sessionId,\n deleteSession: true,\n });\n } else {\n await github.sourceControlStorage.sessions.delete(session.id);\n void reclaimDeletedSessionSandbox({\n fleet,\n sourceControl: github.sourceControlStorage,\n session,\n }).catch((error: unknown) => {\n console.error('[GitHub Sessions] Failed to reclaim sandbox for deleted session', {\n sessionId: session.sessionId,\n sandboxId: session.sandboxId,\n error,\n });\n });\n }\n return c.json({ removed: true });\n },\n }),\n\n // ── Stage all + commit inside a Factory session workspace ──────────────\n registerApiRoute('/web/github/projects/:id/commit', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { userId, project } = owned;\n\n let body: { message?: unknown; sessionId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (typeof body.message !== 'string' || body.message.trim().length === 0 || body.message.length > 5000) {\n return c.json({ error: 'Invalid message' }, 400);\n }\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const { workdir, sandboxBinding } = sessionWorkspace;\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const sandbox = await resolveProjectSandbox({ fleet, sandboxRow: sandboxBinding });\n const result = await commitAll(\n sandbox,\n workdir,\n body.message as string,\n identityFromUser(await auth.ensureUser(loose(c))),\n );\n if (result.committed) {\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.commit',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'session', id: sessionWorkspace.session.sessionId }],\n metadata: { sessionId: sessionWorkspace.session.sessionId },\n },\n });\n }\n return c.json({ committed: result.committed });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n\n // ── Push a branch back to GitHub ────────────────────────────────────────\n registerApiRoute('/web/github/projects/:id/push', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { orgId, userId, project } = owned;\n\n let body: { branch?: unknown; sessionId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isValidGitRefSandbox(body.branch)) {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n const branch = body.branch;\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const { workdir, sandboxBinding } = sessionWorkspace;\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const sandbox = await resolveProjectSandbox({ fleet, sandboxRow: sandboxBinding });\n const access = await github.versionControl.getRepositoryAccess({\n orgId,\n repositoryId: project.repository.id,\n });\n if (!access.authorization) throw new Error('Repository access did not include a bearer token.');\n await pushBranch(sandbox, workdir, branch, access.authorization.token, project.repository.slug);\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.push',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'branch', id: branch }],\n metadata: { branch, sessionId: sessionWorkspace.session.sessionId },\n },\n });\n return c.json({ pushed: true, branch });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n\n // ── Open a pull request through the version-control capability ─────────\n registerApiRoute('/web/github/projects/:id/pr', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { orgId, userId, project } = owned;\n\n let body: {\n branch?: unknown;\n base?: unknown;\n title?: unknown;\n body?: unknown;\n sessionId?: unknown;\n };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isValidGitRefSandbox(body.branch)) {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n const base = body.base === undefined ? project.defaultBranch : body.base;\n if (!isValidGitRefSandbox(base)) {\n return c.json({ error: 'Invalid base' }, 400);\n }\n if (typeof body.title !== 'string' || body.title.trim().length === 0 || body.title.length > 256) {\n return c.json({ error: 'Invalid title' }, 400);\n }\n if (body.body !== undefined && (typeof body.body !== 'string' || body.body.length > 65536)) {\n return c.json({ error: 'Invalid body' }, 400);\n }\n const head = body.branch;\n const title = body.title;\n const prBody = body.body as string | undefined;\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const result = await github.versionControl.createPullRequest({\n connection: {\n type: 'app-installation',\n installationId: Number(project.installation.externalId),\n },\n sourceId: project.repository.slug,\n baseBranch: base,\n headBranch: head,\n title,\n body: prBody,\n actingUserId: userId,\n });\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.pr_opened',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'pull_request', id: result.url, name: title }],\n metadata: { branch: head, base, url: result.url },\n },\n });\n const pullRequestNumber = pullRequestNumberFromUrl(result.url, project.repository.slug);\n if (pullRequestNumber) {\n const sessionId = sessionWorkspace.session.sessionId;\n await subscribeToPullRequest(\n {\n orgId,\n installationExternalId: project.installation.externalId,\n projectRepositoryId: project.id,\n repositoryExternalId: project.repository.externalId,\n repositorySlug: project.repository.slug,\n changeRequestId: pullRequestNumber.toString(),\n sessionId,\n ownerId: userId,\n resourceId: sessionId,\n threadId: sessionId,\n source: 'factory-pr-create',\n subscribedByUserId: userId,\n },\n github.integrationStorage,\n ).catch((error: unknown) => {\n console.warn(\n `[GitHub] Pull request ${result.url} was created but automatic subscription failed.`,\n error,\n );\n });\n }\n return c.json({ url: result.url });\n });\n } catch (err) {\n return c.json(\n { error: 'github_pr_create_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n\n // ── Tear down the caller's sandbox for a project ────────────────────────\n // Per-user teardown only: drops the caller's `(project, user)` sandbox\n // binding and stops the VM, freeing a slot in the per-replica budget. Project\n // deletion at the org level is out of scope (org admin model is later).\n registerApiRoute('/web/github/projects/:id/sandbox', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { sandboxRow } = owned;\n\n if (!sandboxRow.sandboxId) {\n // Nothing provisioned for this user — idempotent success.\n return c.json({ tornDown: false });\n }\n\n try {\n return await withSessionOperationLock(`sandbox:${sandboxRow.id}`, async () => {\n const sandbox = await fleet.reattachSandbox(sandboxRow.sandboxId!, {\n actingUserId: sandboxRow.userId,\n });\n await teardownProjectSandbox({\n fleet,\n row: sandboxRow,\n storage: github.sourceControlStorage.sandboxes,\n sandbox,\n });\n return c.json({ tornDown: true });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n ];\n}\n\n/** Resolve the materialized workspace owned by a Factory session. */\nasync function resolveSessionWorkspace(\n github: GithubIntegration,\n projectId: string,\n userId: string,\n sessionId: unknown,\n) {\n if (typeof sessionId !== 'string') {\n return undefined;\n }\n const session = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (\n session?.projectRepositoryId !== projectId ||\n session.userId !== userId ||\n !session.sandboxId ||\n !session.sandboxWorkdir\n ) {\n return undefined;\n }\n return {\n session,\n workdir: session.sandboxWorkdir,\n sandboxBinding: {\n id: session.id,\n projectRepositoryId: session.projectRepositoryId,\n userId: session.userId,\n sandboxId: session.sandboxId,\n sandboxWorkdir: session.sandboxWorkdir,\n materializedAt: session.materializedAt,\n createdAt: session.createdAt,\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","names":["isValidGitRefSandbox"],"sources":["../../../src/integrations/github/routes.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for the GitHub App project feature.\n *\n * Registered alongside the other `/web/*` routes, behind the host auth gate.\n * Every route additionally re-checks the authenticated user via the injected\n * `RouteAuth` seam and scopes all rows by that user's stable id, so a user can\n * only ever see and operate on their own installations and projects.\n *\n * When the feature is disabled (`isGithubFeatureEnabled()` false), `buildGithubRoutes`\n * returns only `GET /web/github/status`, which reports `enabled:false`\n * so the SPA can cleanly hide all GitHub UI.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { MountedMastraCode } from '@mastra/code-sdk';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport { UniqueViolationError } from '@mastra/core/storage';\nimport type { FactoryStorage } from '@mastra/core/storage';\nimport type { Context } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport type { RouteAuth } from '../../routes/route.js';\nimport { SandboxBudgetError } from '../../sandbox/fleet.js';\nimport type { MaterializationSandbox, PrepareProgress, ProgressFn, SandboxFleet } from '../../sandbox/fleet.js';\nimport type { StateSigner } from '../../state-signing.js';\nimport type { AuditEmitter } from '../../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ProjectRepository,\n ProjectRepositorySandbox,\n ProjectSourceControlConnection,\n SourceControlInstallation,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from './config.js';\nimport type { GithubIntegration } from './integration.js';\nimport { clearGithubPat, getGithubPat, getGithubPatStatus, setGithubPat } from './pat.js';\nimport type { GithubPatKind } from './pat.js';\n\nimport { reclaimDeletedSessionSandbox } from './sandbox-release.js';\nimport {\n commitAll,\n computeWorktreePath,\n ensureProjectSandbox,\n isValidGitRef as isValidGitRefSandbox,\n materializeRepo,\n MaterializeError,\n pushBranch,\n teardownProjectSandbox,\n WorktreeError,\n} from './sandbox.js';\nimport type { GitIdentity } from './sandbox.js';\n\nconst sessionOperationLocks = new Map<string, Promise<unknown>>();\nconst MAX_SESSION_TITLE_LENGTH = 80;\nconst USER_SESSION_BRANCH_PREFIX = 'user/session-';\n// lowercase only (crypto.randomUUID output), so casing cannot fork one logical ID into two sessions\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n/**\n * Serialize same-session mutations within one Factory process. Factory sessions\n * normally issue these operations sequentially, so this lock is probably not\n * necessary; keep the cheap local guard until that invariant is enforced by\n * the request protocol. It intentionally does not consume a database connection.\n */\nfunction withSessionOperationLock<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const previous = sessionOperationLocks.get(sessionId) ?? Promise.resolve();\n const next = previous.then(fn, fn);\n const tail = next.then(\n () => undefined,\n () => undefined,\n );\n sessionOperationLocks.set(sessionId, tail);\n void tail.then(() => {\n if (sessionOperationLocks.get(sessionId) === tail) sessionOperationLocks.delete(sessionId);\n });\n return next;\n}\nimport { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from './subscriptions.js';\nimport { handleGithubWebhook } from './webhook.js';\nimport type { ParsedGithubWebhook } from './webhook.js';\n\n/**\n * Loose Hono context accepted by the shared GitHub route helpers. The\n * `registerApiRoute` handlers receive a path-parameterized context whose\n * `HonoRequest` literal-path generics are invariant and don't flow into a\n * shared helper signature. The helpers only ever touch cookies/query/tenant, so\n * we erase the path to a plain `Context` at the call boundary via `loose()`.\n */\ntype RouteContext = Context;\n\n/** Erase a route handler's path-parameterized context to a plain `Context`. */\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport interface MountGithubRoutesOptions {\n /** Host auth seam — resolves the signed-in user/tenant for each request. */\n auth: RouteAuth;\n /**\n * Sandbox fleet for per-project sandboxes. A fleet constructed without a\n * machine config reports `enabled: false` and the sandbox-backed routes\n * respond 503.\n */\n fleet: SandboxFleet;\n /** Factory storage backend used for the `appDbConfigured` diagnostic. */\n storage?: FactoryStorage;\n /**\n * The GitHub App integration the handlers operate on (Octokit access, token\n * minting, OAuth URLs). Normally supplied by `GithubIntegration.routes()`;\n * when absent, only the disabled `status` route is served.\n */\n github?: GithubIntegration;\n /**\n * Shared OAuth/install `state` signer (created once per boot by the\n * factory). Required for the OAuth/install flow; when absent, only the\n * disabled `status` route is served.\n */\n stateSigner?: StateSigner;\n /**\n * Absolute base URL of the web server (e.g. `http://localhost:4111`), used to\n * build the OAuth/install redirect URI when one isn't explicitly configured.\n */\n baseUrl?: string;\n /** Explicit OAuth callback URI; defaults to `<baseUrl>/auth/github/callback`. */\n redirectUri?: string;\n /** Controller used to route verified webhook notifications to exact subscribed sessions. */\n controller?: MountedMastraCode['controller'];\n /** Best-effort audit emission supplied by the factory-owned audit domain. */\n emitAudit?: AuditEmitter['emit'];\n /** Factory projects domain — resolves a project's default triage model. */\n projects?: FactoryProjectsStorage;\n sessionRetirement?: import('../../sandbox/session-retirement.js').SessionRetirementCoordinator;\n /** Authoritative Factory rule ingress for normalized, signature-verified GitHub deliveries. */\n ingestFactoryEvent?: (event: ParsedGithubWebhook) => Promise<unknown>;\n}\n\nfunction pullRequestNumberFromUrl(value: string, expectedRepo: string): number | undefined {\n try {\n const url = new URL(value);\n const match = url.pathname.match(/^\\/([^/]+\\/[^/]+)\\/pull\\/(\\d+)\\/?$/);\n if (\n url.protocol !== 'https:' ||\n url.hostname !== 'github.com' ||\n match?.[1]?.toLowerCase() !== expectedRepo.toLowerCase()\n ) {\n return undefined;\n }\n const number = Number(match[2]);\n return Number.isInteger(number) && number > 0 ? number : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Validate a git branch/ref name against a strict whitelist. The value is later\n * interpolated into a shell `git clone --branch` command, so it must never\n * contain shell metacharacters. We accept only git-ref-safe characters and\n * reject anything else rather than relying on shell quoting alone.\n */\nfunction isValidGitRef(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && value.length <= 255 && /^[A-Za-z0-9_./-]+$/.test(value);\n}\n\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction normalizeSessionTitle(title: string): string | null {\n // Cap code points, not UTF-16 units: an emoji straddling the cap would store a lone surrogate.\n const capped = [...title.replace(/\\s+/g, ' ').trim()].slice(0, MAX_SESSION_TITLE_LENGTH).join('');\n return capped.trimEnd() || null;\n}\n\n/**\n * Resolve the org-scoped tenant for a GitHub request. GitHub project features\n * are org-owned, so they require both a signed-in user and a WorkOS\n * organization. Returns the `(orgId, userId)` tenant (with `orgId` narrowed to a\n * non-null string) or a ready-to-return error response: 401 when unauthenticated,\n * 403 when the user has no organization (personal account).\n *\n * Resolves the session from the request cookie itself (via `auth.ensureUser`)\n * instead of relying on the auth gate's context stash: on platform deploys\n * custom `apiRoutes` run on an isolated sub-app context where the gate's\n * `c.set(...)` is invisible. When the gate stash IS visible (local Hono\n * server), `auth.ensureUser` returns the cached user and this is a no-op.\n */\nasync function resolveOrgTenant(\n c: RouteContext,\n auth: RouteAuth,\n): Promise<{ tenant: { orgId: string; userId: string } } | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'GitHub projects require a WorkOS organization. Personal accounts cannot connect repositories.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\n/**\n * Parse a 1-based `page` query param. Missing means page 1; anything that is\n * not a small positive integer is rejected (`null`).\n */\nfunction parseListPage(raw: string | undefined): number | null {\n if (raw === undefined) return 1;\n if (!/^\\d{1,5}$/.test(raw)) return null;\n const page = Number(raw);\n return page >= 1 ? page : null;\n}\n\nconst VALID_ISSUE_LABEL_FILTERS = new Set(['status: auto-triaged', 'status: needs approval']);\n\nfunction parseIssueLabelFilter(raw: string | undefined): string | undefined | null {\n if (raw === undefined || raw === '') return undefined;\n if (VALID_ISSUE_LABEL_FILTERS.has(raw)) return raw;\n return null;\n}\n\ninterface ResolvedProjectRepository extends ProjectRepository {\n connection: ProjectSourceControlConnection;\n installation: SourceControlInstallation;\n repository: SourceControlRepository;\n factoryProjectId: string;\n defaultBranch: string;\n}\n\nasync function resolveProjectRepository(args: {\n github: GithubIntegration;\n orgId: string;\n projectRepositoryId: string;\n}): Promise<ResolvedProjectRepository | null> {\n const projectRepository = await args.github.sourceControlStorage.projectRepositories.get({\n orgId: args.orgId,\n id: args.projectRepositoryId,\n });\n if (!projectRepository) return null;\n const connection = await args.github.sourceControlStorage.connections.get({\n orgId: args.orgId,\n id: projectRepository.connectionId,\n });\n if (!connection) return null;\n const repository = await args.github.sourceControlStorage.repositories.get({\n orgId: args.orgId,\n id: projectRepository.repositoryId,\n });\n if (!repository) return null;\n const installation = await args.github.sourceControlStorage.installations.get({\n orgId: args.orgId,\n id: connection.installationId,\n });\n if (!installation) return null;\n return {\n ...projectRepository,\n connection,\n installation,\n repository,\n factoryProjectId: connection.factoryProjectId,\n defaultBranch: projectRepository.branch ?? repository.defaultBranch,\n };\n}\n\nfunction polledIssueEvent(\n project: ResolvedProjectRepository,\n issue: {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignee: string | null;\n assignees?: string[];\n labels: string[];\n createdAt: string;\n },\n): ParsedGithubWebhook {\n const repositoryId = Number(project.repository.externalId);\n const assigneeLogins = issue.assignees ?? (issue.assignee ? [issue.assignee] : []);\n return {\n event: 'issues',\n deliveryId: `poll:${repositoryId}:issue:${issue.number}:${issue.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: Number(project.installation.externalId) },\n repository: { id: repositoryId, full_name: project.repository.slug },\n sender: { login: issue.author ?? '__unknown__' },\n issue: {\n number: issue.number,\n title: issue.title,\n html_url: issue.url,\n created_at: issue.createdAt,\n assignees: assigneeLogins.map(login => ({ login })),\n labels: issue.labels.map(name => ({ name })),\n },\n },\n };\n}\n\nfunction polledPullRequestEvent(\n project: ResolvedProjectRepository,\n pullRequest: {\n number: number;\n title: string;\n url: string;\n author: string | null;\n assignees: string[];\n requestedReviewers: string[];\n headBranch: string;\n baseBranch: string;\n createdAt: string;\n },\n): ParsedGithubWebhook {\n const repositoryId = Number(project.repository.externalId);\n return {\n event: 'pull_request',\n deliveryId: `poll:${repositoryId}:pull-request:${pullRequest.number}:${pullRequest.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: Number(project.installation.externalId) },\n repository: { id: repositoryId, full_name: project.repository.slug },\n sender: { login: pullRequest.author ?? '__unknown__' },\n pull_request: {\n number: pullRequest.number,\n title: pullRequest.title,\n html_url: pullRequest.url,\n created_at: pullRequest.createdAt,\n state: 'open',\n merged: false,\n assignees: pullRequest.assignees.map(login => ({ login })),\n requested_reviewers: pullRequest.requestedReviewers.map(login => ({ login })),\n head: { ref: pullRequest.headBranch },\n base: { ref: pullRequest.baseBranch },\n },\n },\n };\n}\n\nasync function ingestPolledEvents(\n events: ParsedGithubWebhook[],\n ingestFactoryEvent: MountGithubRoutesOptions['ingestFactoryEvent'],\n): Promise<void> {\n if (!ingestFactoryEvent) return;\n const results = await Promise.allSettled(events.map(event => ingestFactoryEvent(event)));\n const rejected = results.find((result): result is PromiseRejectedResult => result.status === 'rejected');\n if (rejected) throw rejected.reason;\n}\n\n/**\n * Build the GitHub routes as Mastra `apiRoutes`. When the feature is disabled,\n * returns only the `status` route so the SPA can detect the disabled state.\n */\nexport function buildGithubRoutes(options: MountGithubRoutesOptions): ApiRoute[] {\n const routes: ApiRoute[] = [];\n const { auth, fleet, storage, github, stateSigner, controller, emitAudit, sessionRetirement } = options;\n const diagnostics = () =>\n getGithubFeatureDiagnostics({ github, auth, appDbConfigured: storage !== undefined, stateSigner, fleet });\n\n // The status route is always registered so the SPA can detect the disabled state.\n routes.push(\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n if (!isGithubFeatureEnabled({ github, auth }) || !github || !stateSigner) {\n return c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: diagnostics(),\n });\n }\n // Resolve the session from the request cookie: on platform deploys custom\n // apiRoutes run on an isolated context where the gate's stash is invisible.\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant) return c.json({ error: 'unauthorized', reason: 'auth_required' }, 401);\n\n // Org-scoped: personal (no-org) users have GitHub projects disabled. Report\n // enabled (so the SPA can show the org-required hint) but never connected.\n if (!tenant.orgId) {\n return c.json({\n enabled: true,\n sandboxEnabled: fleet.enabled,\n organizationRequired: true,\n connected: false,\n installations: [],\n reason: 'organization_required',\n diagnostics: diagnostics(),\n });\n }\n\n const rows = options.github\n ? await options.github.sourceControlStorage.installations.list({ orgId: tenant.orgId })\n : [];\n\n const connected = rows.length > 0;\n return c.json({\n enabled: true,\n sandboxEnabled: fleet.enabled,\n connected,\n installations: rows.map(r => ({\n installationId: Number(r.externalId),\n accountLogin: r.accountName,\n accountType: r.accountType,\n })),\n reason: connected ? 'ready' : 'not_connected',\n diagnostics: diagnostics(),\n });\n },\n }),\n );\n\n // Without an integration instance + state signer there is nothing the\n // remaining handlers can do — serve only the disabled `status` route\n // (mirrors the feature gate).\n if (!isGithubFeatureEnabled({ github, auth }) || !github || !stateSigner) {\n return routes;\n }\n const signState = (orgId: string, userId: string): string => stateSigner.sign(orgId, userId);\n const verifyState = (state: string | undefined) => stateSigner.verify(state);\n\n routes.push(\n registerApiRoute('/web/github/subscriptions', {\n method: 'GET',\n handler: async c => {\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const resourceId = c.req.query('resourceId');\n const threadId = c.req.query('threadId');\n const sessionScope = c.req.query('scope');\n if (!resourceId || !threadId) return c.json({ error: 'resourceId and threadId are required' }, 400);\n\n const subscriptions = await listPullRequestSubscriptionsForThread(\n {\n orgId: tenant.orgId,\n resourceId,\n threadId,\n sessionScope,\n },\n github.integrationStorage,\n );\n return c.json({\n subscriptions: subscriptions.map(subscription => ({\n id: subscription.id,\n repoFullName: subscription.data.repositorySlug,\n pullRequestNumber: Number(subscription.data.changeRequestId),\n status: subscription.status,\n url: `https://github.com/${subscription.data.repositorySlug}/pull/${subscription.data.changeRequestId}`,\n })),\n });\n },\n }),\n registerApiRoute('/web/github/webhook', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const result = await handleGithubWebhook(loose(c), {\n github,\n ingestFactoryEvent: options.ingestFactoryEvent,\n ...(options.controller\n ? {\n controller: options.controller,\n onTargetError: (subscription, error) => {\n console.warn(\n `[GitHub Webhook] Delivery failed for subscription ${subscription.id} (${subscription.resourceId}/${subscription.threadId}).`,\n error,\n );\n },\n }\n : {}),\n });\n return c.json(result.body, result.status);\n },\n }),\n );\n\n const redirectUri = options.redirectUri ?? `${(options.baseUrl ?? '').replace(/\\/$/, '')}/auth/github/callback`;\n\n // ── Connect: bounce through the OAuth identify flow ─────────────────────\n // Identify-first (rather than install-first) so an app that is *already*\n // installed on the org re-syncs into our DB: GitHub's install page dead-ends\n // on the installation settings screen for existing installs and never\n // redirects back to us. The callback persists whatever installations the\n // verified user token can see, and only redirects to the install URL when\n // there are none.\n //\n // `?manage=1` skips the identify bounce and sends the user straight to\n // GitHub's installation page — used by \"Manage GitHub connection\" to\n // add/remove accounts and repo access. For an already-authorized user the\n // identify flow completes instantly and invisibly, so without this the\n // manage button would appear to do nothing. GitHub's post-install \"Save\"\n // redirect lands back on the callback, which re-syncs installations.\n routes.push(\n registerApiRoute('/auth/github/connect', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const state = signState(resolved.tenant.orgId, resolved.tenant.userId);\n if (c.req.query('manage')) return c.redirect(github.buildInstallUrl(state));\n return c.redirect(github.buildOAuthIdentifyUrl(state, redirectUri));\n },\n }),\n );\n\n // ── Callback: confirm identity, persist the installation against the org ──\n routes.push(\n registerApiRoute('/auth/github/callback', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n\n const state = c.req.query('state');\n if (!state) {\n // GitHub's \"Save\"/update redirect from the installation settings page\n // arrives with `installation_id` + `setup_action` but no state. We\n // never trust the raw installation_id; start a fresh identify bounce\n // bound to the current session so the update re-syncs installations.\n return c.redirect(github.buildOAuthIdentifyUrl(signState(orgId, userId), redirectUri));\n }\n const stateTenant = verifyState(state);\n if (!stateTenant || stateTenant.userId !== userId || stateTenant.orgId !== orgId) {\n // CSRF / cross-user/org linking protection: the signed state must belong\n // to the same logged-in user *and* their current org.\n console.warn(\n '[GitHub] Install callback rejected: state/tenant mismatch.',\n JSON.stringify({\n stateValid: Boolean(stateTenant),\n stateOrgId: stateTenant?.orgId,\n stateUserId: stateTenant?.userId,\n sessionOrgId: orgId,\n sessionUserId: userId,\n }),\n );\n return c.redirect('/?github=error');\n }\n\n const code = c.req.query('code');\n // We only ever persist installations that GitHub confirms belong to *this*\n // user via the OAuth code path. The raw `installation_id` from the install\n // redirect is not trusted on its own — anyone with a valid state could pass\n // an arbitrary id — so when no code is present we bounce through the OAuth\n // identify flow to obtain a verified user token first.\n if (!code) {\n return c.redirect(github.buildOAuthIdentifyUrl(signState(orgId, userId), redirectUri));\n }\n\n try {\n const userToken = await github.exchangeOAuthCode(code, redirectUri);\n const installations = await github.listUserInstallations(userToken);\n if (installations.length === 0) {\n // Verified user has no installations yet — send them to the actual\n // install page. After installing, GitHub redirects back here with\n // the same state (and no code), which bounces through identify\n // again and lands in the persist path below.\n return c.redirect(github.buildInstallUrl(signState(orgId, userId)));\n }\n for (const inst of installations) {\n // The installation is org-owned; `userId` records who connected it.\n await github.sourceControlStorage.installations.upsert({\n orgId,\n connectedByUserId: userId,\n externalId: inst.installationId.toString(),\n accountName: inst.accountLogin,\n accountType: inst.accountType,\n });\n }\n } catch (error) {\n console.warn(\n `[GitHub] Install callback failed to persist installations for org ${orgId} / user ${userId}.`,\n error,\n );\n return c.redirect('/?github=error');\n }\n\n return c.redirect('/?github=connected');\n },\n }),\n );\n\n // ── List repos across the org's installations ───────────────────────────\n routes.push(\n registerApiRoute('/web/github/repos', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n const orgId = resolved.tenant.orgId;\n const installs = await github.sourceControlStorage.installations.list({ orgId });\n\n const query = (c.req.query('q') ?? '').toLowerCase();\n // List every installation's repositories in parallel — installations\n // are independent upstream calls, and serial listing multiplied\n // worst-case latency by installation count.\n const listed = await Promise.all(\n installs.map(async inst => {\n try {\n return { inst, list: await github.listInstallationRepos(Number(inst.externalId)) };\n } catch (err) {\n // GitHub 404s when the installation no longer exists for this app\n // (app uninstalled/reinstalled, or the row was recorded under\n // different app credentials). Prune the stale row so `/status`\n // reflects reality and the UI prompts a reconnect, then keep\n // listing the remaining installations.\n if ((err as { status?: number }).status !== 404) throw err;\n console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);\n await github.sourceControlStorage.installations.delete({ orgId, id: inst.id });\n return { inst, list: [] };\n }\n }),\n );\n\n // Filter + dedupe by repo id in installation order — same result\n // ordering as the previous serial loop.\n const matches = [];\n const seenRepositoryIds = new Set<number>();\n for (const { inst, list } of listed) {\n for (const repo of list) {\n if (query && !repo.fullName.toLowerCase().includes(query)) continue;\n if (seenRepositoryIds.has(repo.id)) continue;\n seenRepositoryIds.add(repo.id);\n matches.push({ inst, repo });\n }\n }\n\n // Mirror matches into storage with bounded concurrency instead of one\n // awaited upsert per repository.\n const repos = new Array(matches.length);\n const upsertConcurrency = 10;\n for (let start = 0; start < matches.length; start += upsertConcurrency) {\n await Promise.all(\n matches.slice(start, start + upsertConcurrency).map(async ({ inst, repo }, offset) => {\n const repository = await github.sourceControlStorage.repositories.upsert({\n orgId,\n input: {\n installationId: inst.id,\n externalId: repo.id.toString(),\n slug: repo.fullName,\n defaultBranch: isValidGitRef(repo.defaultBranch) ? repo.defaultBranch : 'main',\n providerMetadata: { private: repo.private, owner: repo.owner },\n },\n });\n repos[start + offset] = {\n ...repo,\n installationStorageId: inst.id,\n repositoryStorageId: repository.id,\n sandboxProvider: fleet.provider,\n sandboxWorkdir: fleet.computeWorkdir(repo.fullName),\n };\n }),\n );\n }\n return c.json({ repos });\n },\n }),\n );\n\n // ── Materialize a project into the caller's per-user sandbox ─────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/ensure', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n\n if (!fleet.enabled) {\n return c.json({ error: 'sandbox_not_configured', message: 'No sandbox provider is configured.' }, 503);\n }\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) return c.json({ error: 'Project repository not found' }, 404);\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return c.json({ error: 'Project repository not found' }, 404);\n }\n\n // Stream live server-side progress when the client asks for it (EventSource\n // / fetch with `Accept: text/event-stream`); otherwise fall back to a single\n // JSON response so non-streaming callers and tests keep working unchanged.\n const wantsStream = (c.req.header('accept') ?? '').includes('text/event-stream');\n if (wantsStream) {\n return streamSSE(loose(c), async stream => {\n try {\n const result = await prepareProject({\n github,\n fleet,\n project,\n userId,\n onProgress: ev => void stream.writeSSE({ event: 'progress', data: JSON.stringify(ev) }),\n });\n await stream.writeSSE({ event: 'done', data: JSON.stringify(result) });\n } catch (err) {\n await stream.writeSSE({ event: 'error', data: JSON.stringify(ensureErrorPayload(err).body) });\n }\n });\n }\n\n try {\n const result = await prepareProject({ github, fleet, project, userId });\n return c.json(result);\n } catch (err) {\n const { status, body } = ensureErrorPayload(err);\n return c.json(body, status);\n }\n },\n }),\n );\n\n // ── List a project's open GitHub issues ──────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/issues', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n const page = parseListPage(c.req.query('page'));\n if (page === null) return c.json({ error: 'invalid_page' }, 400);\n const label = parseIssueLabelFilter(c.req.query('label'));\n if (label === null) return c.json({ error: 'invalid_label' }, 400);\n try {\n const { issues, nextCursor } = await github.intake.listIssues({\n connection: {\n type: 'app-installation',\n installationId: Number(loaded.project.installation.externalId),\n },\n sourceIds: [loaded.project.repository.slug],\n labels: label ? [label] : undefined,\n cursor: String(page),\n });\n const responseIssues = issues.map(issue => ({\n number: Number(issue.id),\n title: issue.title,\n url: issue.url,\n author: issue.author,\n assignee: issue.assignee,\n assignees: issue.assignees,\n labels: issue.labels,\n comments: issue.commentCount ?? 0,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n }));\n await ingestPolledEvents(\n responseIssues.map(issue => polledIssueEvent(loaded.project, issue)),\n options.ingestFactoryEvent,\n );\n return c.json({\n issues: responseIssues,\n nextPage: nextCursor === null ? null : Number(nextCursor),\n });\n } catch (err) {\n return c.json(\n { error: 'github_fetch_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n );\n\n // ── List a project's open (non-draft) pull requests ─────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/prs', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n const page = parseListPage(c.req.query('page'));\n if (page === null) return c.json({ error: 'invalid_page' }, 400);\n try {\n const { pullRequests, nextCursor } = await github.versionControl.listPullRequests({\n connection: {\n type: 'app-installation',\n installationId: Number(loaded.project.installation.externalId),\n },\n sourceId: loaded.project.repository.slug,\n includeDrafts: false,\n cursor: String(page),\n });\n const responsePullRequests = pullRequests.map(pr => ({\n number: Number(pr.id),\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n }));\n await ingestPolledEvents(\n responsePullRequests.map(pullRequest => polledPullRequestEvent(loaded.project, pullRequest)),\n options.ingestFactoryEvent,\n );\n return c.json({\n pullRequests: responsePullRequests,\n nextPage: nextCursor === null ? null : Number(nextCursor),\n });\n } catch (err) {\n return c.json(\n { error: 'github_fetch_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n );\n\n // ── Read per-project settings ────────────────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/settings', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n return c.json({\n setupCommand: loaded.project.setupCommand,\n teardownCommand: loaded.project.teardownCommand,\n });\n },\n }),\n );\n\n // ── Update per-project settings ──────────────────────────────────────────\n routes.push(\n registerApiRoute('/web/github/projects/:id/settings', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const loaded = await loadOrgProject({ github, auth, c: loose(c) });\n if ('response' in loaded) return loaded.response;\n\n let body: { setupCommand?: unknown; teardownCommand?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n\n const commands = ['setupCommand', 'teardownCommand'] as const;\n for (const command of commands) {\n const value = body[command];\n if (value === undefined) continue;\n if (value !== null && typeof value !== 'string') {\n return c.json({ error: `Invalid ${command}` }, 400);\n }\n if (typeof value === 'string' && value.length > 2000) {\n return c.json({ error: `${command} too long (max 2000 characters)` }, 400);\n }\n // Reject control characters (except newline/tab). Commands are shell\n // scripts by design, but escape sequences and NULs can spoof logs or\n // confuse the sandbox shell.\n if (typeof value === 'string' && /[\\0-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/.test(value)) {\n return c.json({ error: `${command} contains control characters` }, 400);\n }\n }\n\n const normalizeCommand = (value: unknown): string | null | undefined => {\n if (value === undefined) return undefined;\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;\n };\n const setupCommand = normalizeCommand(body.setupCommand);\n const teardownCommand = normalizeCommand(body.teardownCommand);\n\n await github.sourceControlStorage.projectRepositories.update({\n orgId: loaded.project.installation.orgId,\n id: loaded.project.id,\n input: {\n ...(setupCommand !== undefined ? { setupCommand } : {}),\n ...(teardownCommand !== undefined ? { teardownCommand } : {}),\n },\n });\n return c.json({\n setupCommand: setupCommand === undefined ? loaded.project.setupCommand : setupCommand,\n teardownCommand: teardownCommand === undefined ? loaded.project.teardownCommand : teardownCommand,\n });\n },\n }),\n );\n\n // ── Org GitHub PATs ──────────────────────────────────────────────────────\n // Installation tokens are the wrong credential for the `gh` CLI (integration\n // -restricted endpoints 403 regardless of permissions), so orgs paste\n // classic PATs the sandboxes use instead: a `default` worker token, and an\n // optional `reviewer` token that review-board sessions use so PR reviews\n // come from a different account. Tokens are never sent back to the browser —\n // only whether each is configured.\n const parsePatKind = (value: unknown): GithubPatKind | null => {\n if (value === undefined || value === null || value === 'default') return 'default';\n if (value === 'reviewer') return 'reviewer';\n return null;\n };\n routes.push(\n registerApiRoute('/web/github/pat', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n registerApiRoute('/web/github/pat', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n let body: { token?: unknown; kind?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const kind = parsePatKind(body.kind);\n if (!kind) return c.json({ error: \"kind must be 'default' or 'reviewer'\" }, 400);\n const token = typeof body.token === 'string' ? body.token.trim() : '';\n if (!token) return c.json({ error: 'A token is required' }, 400);\n if (token.length > 500) return c.json({ error: 'Token too long (max 500 characters)' }, 400);\n if (/\\s/.test(token)) return c.json({ error: 'Token must not contain whitespace' }, 400);\n\n await setGithubPat(github.integrationStorage, resolved.tenant.orgId, token, kind);\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n registerApiRoute('/web/github/pat', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const kind = parsePatKind(c.req.query('kind'));\n if (!kind) return c.json({ error: \"kind must be 'default' or 'reviewer'\" }, 400);\n await clearGithubPat(github.integrationStorage, resolved.tenant.orgId, kind);\n return c.json(await getGithubPatStatus(() => github.integrationStorage, resolved.tenant.orgId));\n },\n }),\n );\n\n // ── Sessions / commit / push / PR ────────────────────────────────────────\n routes.push(...buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, sessionRetirement }));\n\n return routes;\n}\n\n/**\n * Load the org-owned project for a read-only GitHub API route. Unlike\n * `loadOwnedProject`, this never touches sandbox state — the issues/PR list\n * routes only need the repo + installation, so they work before a sandbox is\n * ever provisioned.\n */\nasync function loadOrgProject(options: {\n github: GithubIntegration;\n auth: RouteAuth;\n c: RouteContext;\n}): Promise<{ project: ResolvedProjectRepository; userId: string } | { response: Response }> {\n const { github, auth, c } = options;\n const resolved = await resolveOrgTenant(c, auth);\n if ('response' in resolved) return { response: resolved.response };\n const { orgId, userId } = resolved.tenant;\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n return { project, userId };\n}\n\n/** Derive a commit/author identity from the authenticated host user. */\nfunction identityFromUser(user: unknown): GitIdentity {\n const u = user as { name?: string; email?: string } | null | undefined;\n return { name: u?.name ?? null, email: u?.email ?? null };\n}\n\n/**\n * Resolve a live, started sandbox for the caller's per-user sandbox binding. The\n * sandbox must already have been provisioned (`sandboxId` set) — the git write\n * routes never clone, they operate on the existing checkout.\n */\nasync function resolveProjectSandbox(options: {\n fleet: SandboxFleet;\n sandboxRow: ProjectRepositorySandbox;\n}): Promise<MaterializationSandbox> {\n const { fleet, sandboxRow } = options;\n if (!sandboxRow.sandboxId) {\n throw new MaterializeError('Project sandbox is not provisioned. Open the project first.', 'clone-failed');\n }\n return fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });\n}\n\n/**\n * Load (or create) the caller's per-(project,user) sandbox binding row. The\n * binding inherits its workdir from the org-owned project, but `sandboxId` /\n * `materializedAt` stay null until the user first opens the project.\n */\nasync function loadOrCreateSandboxRow(\n github: GithubIntegration,\n project: ResolvedProjectRepository,\n userId: string,\n): Promise<ProjectRepositorySandbox> {\n return github.sourceControlStorage.sandboxes.getOrCreate({ projectRepository: project, userId });\n}\n\ninterface EnsureResult {\n resourceId: string;\n factoryProjectId: string;\n projectRepositoryId: string;\n sandboxId: string | null;\n sandboxWorkdir: string;\n}\n\n/**\n * Provision/reattach the caller's sandbox and materialize the repo into it,\n * emitting coarse progress events as each server step happens. Shared by both\n * the JSON and SSE variants of the `/ensure` route. Throws on failure so the\n * caller can shape the response (HTTP status vs SSE `error` event).\n */\nasync function prepareProject(options: {\n github: GithubIntegration;\n fleet: SandboxFleet;\n project: ResolvedProjectRepository;\n userId: string;\n onProgress?: ProgressFn;\n}): Promise<EnsureResult> {\n const { github, fleet, userId, onProgress } = options;\n // Self-heal a sandbox provider switch. The project row snapshots\n // sandboxProvider/sandboxWorkdir at link time, so when the server's provider\n // later changes (platform ↔ local) the stored workdir points into the old\n // provider's filesystem (e.g. `/workspace/…` on a macOS host, where the\n // clone dies on the read-only root volume). Recompute against the current\n // fleet and persist so every later open uses the corrected target.\n let project = options.project;\n if (project.sandboxProvider !== fleet.provider) {\n const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);\n await github.sourceControlStorage.projectRepositories.update({\n orgId: project.installation.orgId,\n id: project.id,\n input: { sandboxProvider: fleet.provider, sandboxWorkdir },\n });\n project = { ...project, sandboxProvider: fleet.provider, sandboxWorkdir };\n }\n let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);\n // The per-user binding inherits its workdir at creation time — re-point it\n // (and force a re-clone) whenever the project's workdir has since moved.\n if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {\n await github.sourceControlStorage.sandboxes.setWorkdir({\n id: sandboxRow.id,\n sandboxWorkdir: project.sandboxWorkdir,\n });\n sandboxRow = { ...sandboxRow, sandboxWorkdir: project.sandboxWorkdir, materializedAt: null };\n }\n const access = await github.versionControl.getRepositoryAccess({\n orgId: project.installation.orgId,\n repositoryId: project.repository.id,\n });\n if (!access.authorization) {\n throw new MaterializeError('Repository access did not include a bearer token.', 'clone-failed');\n }\n // The sandbox env token feeds the `gh` CLI — a configured org PAT wins\n // there. Git clone/pull below keep the minted installation token.\n const ghCliToken =\n (await getGithubPat(() => github.integrationStorage, project.installation.orgId)) ?? access.authorization.token;\n const sandbox = await ensureProjectSandbox({\n fleet,\n row: sandboxRow,\n storage: github.sourceControlStorage.sandboxes,\n token: ghCliToken,\n onProgress,\n });\n // Re-read the sandbox binding so we have the freshly persisted sandboxId.\n const fresh = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id });\n const finalRow = fresh ?? sandboxRow;\n await materializeRepo({\n row: finalRow,\n repoInfo: { repoFullName: project.repository.slug, defaultBranch: project.defaultBranch },\n sandbox,\n token: access.authorization.token,\n storage: github.sourceControlStorage.sandboxes,\n onProgress,\n });\n const result: EnsureResult = {\n resourceId: project.factoryProjectId,\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n sandboxId: finalRow.sandboxId,\n sandboxWorkdir: finalRow.sandboxWorkdir,\n };\n const done: PrepareProgress = { phase: 'done', message: 'Workspace ready.' };\n onProgress?.(done);\n return result;\n}\n\n/** Shape an /ensure failure into an HTTP status + JSON body (also used as the SSE error payload). */\nfunction ensureErrorPayload(err: unknown): {\n status: 429 | 502 | 500;\n body: { error: string; message: string };\n} {\n if (err instanceof SandboxBudgetError) {\n return { status: 429, body: { error: err.code, message: err.message } };\n }\n if (err instanceof MaterializeError) {\n return { status: 502, body: { error: err.code, message: err.message } };\n }\n return {\n status: 500,\n body: { error: 'materialize_failed', message: err instanceof Error ? err.message : String(err) },\n };\n}\n\n/** Map a sandbox/worktree error to an actionable HTTP response. */\nfunction gitErrorResponse(c: Context, err: unknown) {\n if (err instanceof WorktreeError) {\n return c.json({ error: err.code, message: err.message }, err.code === 'invalid-branch' ? 400 : 502);\n }\n if (err instanceof MaterializeError) {\n return c.json({ error: err.code, message: err.message }, 502);\n }\n return c.json({ error: 'git_failed', message: err instanceof Error ? err.message : String(err) }, 500);\n}\n\n/**\n * Load the org-owned project and the caller's per-user sandbox binding for a git\n * route. Centralizes the auth + org/ownership checks every git route shares:\n * the project is scoped by `(id, orgId)`, the sandbox binding by\n * `(projectRepositoryId, userId)`. Returns the tenant, project, and sandbox row, or\n * a ready-to-return error response.\n */\nasync function loadOwnedProject(options: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n c: RouteContext;\n}): Promise<\n | { orgId: string; userId: string; project: ResolvedProjectRepository; sandboxRow: ProjectRepositorySandbox }\n | { response: Response }\n> {\n const { github, auth, fleet, c } = options;\n const resolved = await resolveOrgTenant(c, auth);\n if ('response' in resolved) return { response: resolved.response };\n const { orgId, userId } = resolved.tenant;\n\n if (!fleet.enabled) {\n return {\n response: c.json({ error: 'sandbox_not_configured', message: 'No sandbox provider is configured.' }, 503),\n };\n }\n\n const projectRepositoryId = c.req.param('id');\n if (!projectRepositoryId) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const project = await resolveProjectRepository({ github, orgId, projectRepositoryId });\n if (!project) {\n return { response: c.json({ error: 'Project repository not found' }, 404) };\n }\n const sandboxRow = await loadOrCreateSandboxRow(github, project, userId);\n return { orgId, userId, project, sandboxRow };\n}\n\nfunction buildProjectGitRoutes({\n github,\n auth,\n fleet,\n controller,\n emitAudit,\n sessionRetirement,\n}: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n controller?: MountedMastraCode['controller'];\n emitAudit?: AuditEmitter['emit'];\n sessionRetirement?: MountGithubRoutesOptions['sessionRetirement'];\n}): ApiRoute[] {\n return [\n // ── Create / list Factory sessions ──────────────────────────────────────\n registerApiRoute('/web/github/projects/:id/sessions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository({ github, orgId, projectRepositoryId })\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n const sessions = await github.sourceControlStorage.sessions.list({\n projectRepositoryId: project.id,\n viewerUserId: userId,\n });\n return c.json({ sessions });\n },\n }),\n registerApiRoute('/web/github/projects/:id/sessions', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const { orgId, userId } = resolved.tenant;\n const projectRepositoryId = c.req.param('id');\n const project = projectRepositoryId\n ? await resolveProjectRepository({ github, orgId, projectRepositoryId })\n : null;\n if (!project) return c.json({ error: 'Project repository not found' }, 404);\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isJsonObject(body)) return c.json({ error: 'Invalid JSON body' }, 400);\n const requestedBaseBranch = body.baseBranch;\n if (requestedBaseBranch !== undefined && typeof requestedBaseBranch !== 'string') {\n return c.json({ error: 'Invalid baseBranch' }, 400);\n }\n const baseBranch = requestedBaseBranch ?? project.defaultBranch;\n if (!isValidGitRefSandbox(baseBranch)) return c.json({ error: 'Invalid baseBranch' }, 400);\n\n const requestedSessionId = body.sessionId;\n if (\n requestedSessionId !== undefined &&\n (typeof requestedSessionId !== 'string' || !UUID_PATTERN.test(requestedSessionId))\n ) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const sessionId = requestedSessionId ?? randomUUID();\n\n const requestedTitle = body.title;\n if (requestedTitle !== undefined && typeof requestedTitle !== 'string') {\n return c.json({ error: 'Invalid title' }, 400);\n }\n const normalizedTitle = requestedTitle === undefined ? null : normalizeSessionTitle(requestedTitle);\n\n const requestedBranch = body.branch;\n let branch: string;\n if (requestedBranch === undefined) {\n branch = `${USER_SESSION_BRANCH_PREFIX}${sessionId}`;\n } else if (typeof requestedBranch === 'string' && isValidGitRefSandbox(requestedBranch)) {\n branch = requestedBranch;\n } else {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n\n if (requestedSessionId !== undefined) {\n const existing = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (existing) {\n if (\n existing.projectRepositoryId !== project.id ||\n existing.orgId !== orgId ||\n existing.userId !== userId ||\n existing.branch !== branch\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n return c.json({ session: existing });\n }\n }\n\n const session = await github.sourceControlStorage.sessions\n .create({\n sessionId,\n projectRepositoryId: project.id,\n orgId,\n userId,\n branch,\n baseBranch,\n title: normalizedTitle,\n visibility: 'org',\n })\n .catch(async error => {\n if (!(error instanceof UniqueViolationError) || requestedSessionId === undefined) throw error;\n const conflict = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (!conflict) throw error;\n return conflict;\n });\n if (\n requestedSessionId !== undefined &&\n (session.sessionId !== sessionId ||\n session.projectRepositoryId !== project.id ||\n session.orgId !== orgId ||\n session.userId !== userId ||\n session.branch !== branch)\n ) {\n return c.json({ error: 'Session ID conflict' }, 409);\n }\n return c.json({ session });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param('sessionId'));\n // Private sessions 404 (not 403) for non-owners so their IDs do not\n // leak existence; the body must match the genuinely-missing case.\n if (\n !session ||\n session.orgId !== resolved.tenant.orgId ||\n (session.visibility === 'private' && session.userId !== resolved.tenant.userId)\n ) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n },\n }),\n registerApiRoute('/web/user-sessions/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param('sessionId'));\n if (!session || session.orgId !== resolved.tenant.orgId || session.userId !== resolved.tenant.userId) {\n return c.json({ error: 'Session not found' }, 404);\n }\n try {\n await controller?.deleteSession({ resourceId: session.sessionId });\n } catch (error) {\n console.error('[GitHub Sessions] Failed to tear down live controller session', {\n sessionId: session.sessionId,\n error,\n });\n }\n if (sessionRetirement) {\n await sessionRetirement.retireSession({\n sourceControl: github.sourceControlStorage,\n orgId: session.orgId,\n sessionId: session.sessionId,\n deleteSession: true,\n });\n } else {\n await github.sourceControlStorage.sessions.delete(session.id);\n void reclaimDeletedSessionSandbox({\n fleet,\n sourceControl: github.sourceControlStorage,\n session,\n }).catch((error: unknown) => {\n console.error('[GitHub Sessions] Failed to reclaim sandbox for deleted session', {\n sessionId: session.sessionId,\n sandboxId: session.sandboxId,\n error,\n });\n });\n }\n return c.json({ removed: true });\n },\n }),\n\n // ── Stage all + commit inside a Factory session workspace ──────────────\n registerApiRoute('/web/github/projects/:id/commit', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { userId, project } = owned;\n\n let body: { message?: unknown; sessionId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (typeof body.message !== 'string' || body.message.trim().length === 0 || body.message.length > 5000) {\n return c.json({ error: 'Invalid message' }, 400);\n }\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const { workdir, sandboxBinding } = sessionWorkspace;\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const sandbox = await resolveProjectSandbox({ fleet, sandboxRow: sandboxBinding });\n const result = await commitAll(\n sandbox,\n workdir,\n body.message as string,\n identityFromUser(await auth.ensureUser(loose(c))),\n );\n if (result.committed) {\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.commit',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'session', id: sessionWorkspace.session.sessionId }],\n metadata: { sessionId: sessionWorkspace.session.sessionId },\n },\n });\n }\n return c.json({ committed: result.committed });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n\n // ── Push a branch back to GitHub ────────────────────────────────────────\n registerApiRoute('/web/github/projects/:id/push', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { orgId, userId, project } = owned;\n\n let body: { branch?: unknown; sessionId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isValidGitRefSandbox(body.branch)) {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n const branch = body.branch;\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n const { workdir, sandboxBinding } = sessionWorkspace;\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const sandbox = await resolveProjectSandbox({ fleet, sandboxRow: sandboxBinding });\n const access = await github.versionControl.getRepositoryAccess({\n orgId,\n repositoryId: project.repository.id,\n });\n if (!access.authorization) throw new Error('Repository access did not include a bearer token.');\n await pushBranch(sandbox, workdir, branch, access.authorization.token, project.repository.slug);\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.push',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'branch', id: branch }],\n metadata: { branch, sessionId: sessionWorkspace.session.sessionId },\n },\n });\n return c.json({ pushed: true, branch });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n\n // ── Open a pull request through the version-control capability ─────────\n registerApiRoute('/web/github/projects/:id/pr', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { orgId, userId, project } = owned;\n\n let body: {\n branch?: unknown;\n base?: unknown;\n title?: unknown;\n body?: unknown;\n sessionId?: unknown;\n };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (!isValidGitRefSandbox(body.branch)) {\n return c.json({ error: 'Invalid branch' }, 400);\n }\n const base = body.base === undefined ? project.defaultBranch : body.base;\n if (!isValidGitRefSandbox(base)) {\n return c.json({ error: 'Invalid base' }, 400);\n }\n if (typeof body.title !== 'string' || body.title.trim().length === 0 || body.title.length > 256) {\n return c.json({ error: 'Invalid title' }, 400);\n }\n if (body.body !== undefined && (typeof body.body !== 'string' || body.body.length > 65536)) {\n return c.json({ error: 'Invalid body' }, 400);\n }\n const head = body.branch;\n const title = body.title;\n const prBody = body.body as string | undefined;\n const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);\n if (!sessionWorkspace) {\n return c.json({ error: 'Invalid sessionId' }, 400);\n }\n\n try {\n return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {\n const result = await github.versionControl.createPullRequest({\n connection: {\n type: 'app-installation',\n installationId: Number(project.installation.externalId),\n },\n sourceId: project.repository.slug,\n baseBranch: base,\n headBranch: head,\n title,\n body: prBody,\n actingUserId: userId,\n });\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.git.pr_opened',\n factoryProjectId: project.factoryProjectId,\n projectRepositoryId: project.id,\n targets: [{ type: 'pull_request', id: result.url, name: title }],\n metadata: { branch: head, base, url: result.url },\n },\n });\n const pullRequestNumber = pullRequestNumberFromUrl(result.url, project.repository.slug);\n if (pullRequestNumber) {\n const sessionId = sessionWorkspace.session.sessionId;\n await subscribeToPullRequest(\n {\n orgId,\n installationExternalId: project.installation.externalId,\n projectRepositoryId: project.id,\n repositoryExternalId: project.repository.externalId,\n repositorySlug: project.repository.slug,\n changeRequestId: pullRequestNumber.toString(),\n sessionId,\n ownerId: userId,\n resourceId: sessionId,\n threadId: sessionId,\n source: 'factory-pr-create',\n subscribedByUserId: userId,\n },\n github.integrationStorage,\n ).catch((error: unknown) => {\n console.warn(\n `[GitHub] Pull request ${result.url} was created but automatic subscription failed.`,\n error,\n );\n });\n }\n return c.json({ url: result.url });\n });\n } catch (err) {\n return c.json(\n { error: 'github_pr_create_failed', message: err instanceof Error ? err.message : String(err) },\n 502,\n );\n }\n },\n }),\n\n // ── Tear down the caller's sandbox for a project ────────────────────────\n // Per-user teardown only: drops the caller's `(project, user)` sandbox\n // binding and stops the VM, freeing a slot in the per-replica budget. Project\n // deletion at the org level is out of scope (org admin model is later).\n registerApiRoute('/web/github/projects/:id/sandbox', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const owned = await loadOwnedProject({ github, auth, fleet, c: loose(c) });\n if ('response' in owned) return owned.response;\n const { sandboxRow } = owned;\n\n if (!sandboxRow.sandboxId) {\n // Nothing provisioned for this user — idempotent success.\n return c.json({ tornDown: false });\n }\n\n try {\n return await withSessionOperationLock(`sandbox:${sandboxRow.id}`, async () => {\n const sandbox = await fleet.reattachSandbox(sandboxRow.sandboxId!, {\n actingUserId: sandboxRow.userId,\n });\n await teardownProjectSandbox({\n fleet,\n row: sandboxRow,\n storage: github.sourceControlStorage.sandboxes,\n sandbox,\n });\n return c.json({ tornDown: true });\n });\n } catch (err) {\n return gitErrorResponse(loose(c), err);\n }\n },\n }),\n ];\n}\n\n/** Resolve the materialized workspace owned by a Factory session. */\nasync function resolveSessionWorkspace(\n github: GithubIntegration,\n projectId: string,\n userId: string,\n sessionId: unknown,\n) {\n if (typeof sessionId !== 'string') {\n return undefined;\n }\n const session = await github.sourceControlStorage.sessions.getBySessionId(sessionId);\n if (\n session?.projectRepositoryId !== projectId ||\n session.userId !== userId ||\n !session.sandboxId ||\n !session.sandboxWorkdir\n ) {\n return undefined;\n }\n return {\n session,\n workdir: session.sandboxWorkdir,\n sandboxBinding: {\n id: session.id,\n projectRepositoryId: session.projectRepositoryId,\n userId: session.userId,\n sandboxId: session.sandboxId,\n sandboxWorkdir: session.sandboxWorkdir,\n materializedAt: session.materializedAt,\n createdAt: session.createdAt,\n },\n };\n}\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { MastraWorker } from '@mastra/core/worker';
3
3
  import type { WorkerDeps } from '@mastra/core/worker';
4
4
  import type { IntegrationStorageHandle } from '../../../storage/domains/integrations/base.js';
5
5
  import type { GithubIssueReconciler } from '../../github/issue-reconciler.js';
6
+ import type { GithubReconcileRepositorySource } from '../../github/reconcile-worker.js';
6
7
  import type { GithubPullRequestReconciler } from '../../github/rules.js';
7
8
  import { dispatchGithubWebhook } from '../../github/webhook.js';
8
9
  import type { GithubWebhookDispatchIntegration, ParsedGithubWebhook } from '../../github/webhook.js';
@@ -23,6 +24,14 @@ export interface PlatformGithubEventWorkerConfig {
23
24
  controller: MountedMastraCode['controller'];
24
25
  github: PlatformGithubEventDispatchIntegration;
25
26
  storage: PlatformGithubEventStorage;
27
+ /**
28
+ * Source-control storage used to resolve the set of repositories the worker
29
+ * should poll. The worker restricts itself to `(installation, repository)`
30
+ * pairs linked to a factory project — the same set the reconciler uses —
31
+ * so polling scales with Factory usage, not with the size of the underlying
32
+ * GitHub org.
33
+ */
34
+ sourceControl: GithubReconcileRepositorySource;
26
35
  ingestFactoryEvent?: (event: ParsedGithubWebhook) => Promise<unknown>;
27
36
  reconcileFactoryState?: GithubPullRequestReconciler;
28
37
  reconcileIssuesFactoryState?: GithubIssueReconciler;
@@ -1 +1 @@
1
- {"version":3,"file":"event-worker.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/event-worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAE9F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,2BAA2B,EAAuB,MAAM,uBAAuB,CAAC;AAE9F,OAAO,EAAE,qBAAqB,EAAyB,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EACV,gCAAgC,EAEhC,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA0B1D,KAAK,WAAW,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AACzE,KAAK,iCAAiC,GAAG;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,wBAAwB,CAC/D,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,iCAAiC,EACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxB,CAAC;AAWF,MAAM,MAAM,sCAAsC,GAAG,gCAAgC,CAAC;AAEtF,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,EAAE,sCAAsC,CAAC;IAC/C,OAAO,EAAE,0BAA0B,CAAC;IACpC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,qBAAqB,CAAC,EAAE,2BAA2B,CAAC;IACpD,2BAA2B,CAAC,EAAE,qBAAqB,CAAC;IACpD,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,qBAAqB,CAAC;CACzC;AAED,qBAAa,yBAA0B,SAAQ,YAAY;;IACzD,QAAQ,CAAC,IAAI,4BAA4B;gBA6B7B,MAAM,EAAE,+BAA+B;IA+B7C,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,IAAI,SAAS,IAAI,OAAO,CAEvB;CA6TF"}
1
+ {"version":3,"file":"event-worker.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/event-worker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAE9F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACxF,OAAO,KAAK,EAAE,2BAA2B,EAAuB,MAAM,uBAAuB,CAAC;AAE9F,OAAO,EAAE,qBAAqB,EAAyB,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EACV,gCAAgC,EAEhC,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA0B1D,KAAK,WAAW,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AACzE,KAAK,iCAAiC,GAAG;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,wBAAwB,CAC/D,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,iCAAiC,EACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxB,CAAC;AAWF,MAAM,MAAM,sCAAsC,GAAG,gCAAgC,CAAC;AAEtF,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,EAAE,sCAAsC,CAAC;IAC/C,OAAO,EAAE,0BAA0B,CAAC;IACpC;;;;;;OAMG;IACH,aAAa,EAAE,+BAA+B,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,qBAAqB,CAAC,EAAE,2BAA2B,CAAC;IACpD,2BAA2B,CAAC,EAAE,qBAAqB,CAAC;IACpD,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,qBAAqB,CAAC;CACzC;AAED,qBAAa,yBAA0B,SAAQ,YAAY;;IACzD,QAAQ,CAAC,IAAI,4BAA4B;gBA8B7B,MAAM,EAAE,+BAA+B;IAgC7C,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,IAAI,SAAS,IAAI,OAAO,CAEvB;CA4UF"}