@mastra/factory 0.7.0-alpha.3 → 0.7.0-alpha.4

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 +37 -0
  2. package/dist/integrations/github/routes.js +2 -2
  3. package/dist/integrations/github/routes.js.map +1 -1
  4. package/dist/integrations/github/sandbox-release.d.ts +1 -0
  5. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  6. package/dist/integrations/github/sandbox-release.js +6 -4
  7. package/dist/integrations/github/sandbox-release.js.map +1 -1
  8. package/dist/integrations/github/sandbox.d.ts +7 -5
  9. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  10. package/dist/integrations/github/sandbox.js +32 -15
  11. package/dist/integrations/github/sandbox.js.map +1 -1
  12. package/dist/integrations/slack/integration.d.ts +16 -0
  13. package/dist/integrations/slack/integration.d.ts.map +1 -1
  14. package/dist/integrations/slack/integration.js +25 -1
  15. package/dist/integrations/slack/integration.js.map +1 -1
  16. package/dist/integrations/slack/slack.d.ts +3 -0
  17. package/dist/integrations/slack/slack.d.ts.map +1 -1
  18. package/dist/integrations/slack/slack.js +8 -3
  19. package/dist/integrations/slack/slack.js.map +1 -1
  20. package/dist/routes/fs.d.ts.map +1 -1
  21. package/dist/routes/fs.js +4 -1
  22. package/dist/routes/fs.js.map +1 -1
  23. package/dist/sandbox/fleet.d.ts +4 -0
  24. package/dist/sandbox/fleet.d.ts.map +1 -1
  25. package/dist/sandbox/fleet.js +8 -4
  26. package/dist/sandbox/fleet.js.map +1 -1
  27. package/dist/sandbox/reattach.js +1 -1
  28. package/dist/sandbox/reattach.js.map +1 -1
  29. package/dist/workspace.d.ts.map +1 -1
  30. package/dist/workspace.js +4 -1
  31. package/dist/workspace.js.map +1 -1
  32. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @mastra/factory
2
2
 
3
+ ## 0.7.0-alpha.4
4
+
5
+ ### Minor Changes
6
+
7
+ - Added Slack channel adapter options to `SlackIntegration` and made concise thinking, typing, and working statuses the default. ([#21381](https://github.com/mastra-ai/mastra/pull/21381))
8
+
9
+ ```ts
10
+ new SlackIntegration({
11
+ signingSecret,
12
+ adapterOptions: {
13
+ streaming: true,
14
+ toolDisplay: 'grouped',
15
+ },
16
+ });
17
+ ```
18
+
19
+ ### Patch Changes
20
+
21
+ - Fixed a failed branch push being reported as a token cleanup error. When the push failed and the token cleanup failed too, the cleanup error replaced the push error, so a push blocked by the network was reported with an unrelated error code. The push error is now reported as-is with its own code, and the cleanup error is added to the end of its message. ([#21407](https://github.com/mastra-ai/mastra/pull/21407))
22
+
23
+ - Send opaque acting-user subjects with Platform sandbox requests, including Factory creation and reattachment flows. ([#20754](https://github.com/mastra-ai/mastra/pull/20754))
24
+
25
+ ```typescript
26
+ import { PlatformSandbox } from '@mastra/platform-workspace';
27
+
28
+ const sandbox = new PlatformSandbox({
29
+ environmentId: 'env_abc',
30
+ actingUserId: auth.user.id,
31
+ });
32
+ ```
33
+
34
+ - Fixed workspace completion sounds and activity indicators to remain synchronized when switching threads. Running indicators no longer require an open workspace session, so they stay live on the board and overview pages too. ([#21353](https://github.com/mastra-ai/mastra/pull/21353))
35
+
36
+ - Updated dependencies [[`79dd7c2`](https://github.com/mastra-ai/mastra/commit/79dd7c261ee6be1fafedd4651959394db21d2cba), [`b9a28ec`](https://github.com/mastra-ai/mastra/commit/b9a28ecf7acdc0cb7a543d5b660f9fbee301df9a), [`be31796`](https://github.com/mastra-ai/mastra/commit/be3179624ad5f77cff5fa342cd08046bf7605283)]:
37
+ - @mastra/core@1.59.0-alpha.4
38
+ - @mastra/code-sdk@1.2.1-alpha.4
39
+
3
40
  ## 0.7.0-alpha.3
4
41
 
5
42
  ### Patch Changes
@@ -713,7 +713,7 @@ function identityFromUser(user) {
713
713
  async function resolveProjectSandbox(options) {
714
714
  const { fleet, sandboxRow } = options;
715
715
  if (!sandboxRow.sandboxId) throw new MaterializeError("Project sandbox is not provisioned. Open the project first.", "clone-failed");
716
- return fleet.reattachSandbox(sandboxRow.sandboxId);
716
+ return fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });
717
717
  }
718
718
  /**
719
719
  * Load (or create) the caller's per-(project,user) sandbox binding row. The
@@ -1211,7 +1211,7 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit }) {
1211
1211
  if (!sandboxRow.sandboxId) return c.json({ tornDown: false });
1212
1212
  try {
1213
1213
  return await withSessionOperationLock(`sandbox:${sandboxRow.id}`, async () => {
1214
- const sandbox = await fleet.reattachSandbox(sandboxRow.sandboxId);
1214
+ const sandbox = await fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });
1215
1215
  await teardownProjectSandbox({
1216
1216
  fleet,
1217
1217
  row: sandboxRow,
@@ -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 /** 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 } = 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({ setupCommand: loaded.project.setupCommand });\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 };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (body.setupCommand !== null && typeof body.setupCommand !== 'string') {\n return c.json({ error: 'Invalid setupCommand' }, 400);\n }\n if (typeof body.setupCommand === 'string' && body.setupCommand.length > 2000) {\n return c.json({ error: 'setupCommand too long (max 2000 characters)' }, 400);\n }\n // Reject control characters (except newline/tab). The command is a\n // shell script by design, but escape sequences and NULs have no\n // legitimate use and can spoof logs or confuse the sandbox shell.\n if (typeof body.setupCommand === 'string' && /[\\0-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/.test(body.setupCommand)) {\n return c.json({ error: 'setupCommand contains control characters' }, 400);\n }\n // An empty/whitespace command means \"no setup step\".\n const setupCommand =\n typeof body.setupCommand === 'string' && body.setupCommand.trim().length > 0\n ? body.setupCommand.trim()\n : null;\n\n await github.sourceControlStorage.projectRepositories.update({\n orgId: loaded.project.installation.orgId,\n id: loaded.project.id,\n input: { setupCommand },\n });\n return c.json({ setupCommand });\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 }));\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);\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}: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n controller?: MountedMastraCode['controller'];\n emitAudit?: AuditEmitter['emit'];\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 // Answer as soon as the workspace is actually gone. Reclaiming its\n // sandbox wakes the VM and scrubs the checkout, which takes minutes on\n // a large repository — the caller must not sit through that for a\n // workspace that has already been removed.\n await github.sourceControlStorage.sessions.delete(session.id);\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 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 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 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 /** 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 } = 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({ setupCommand: loaded.project.setupCommand });\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 };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (body.setupCommand !== null && typeof body.setupCommand !== 'string') {\n return c.json({ error: 'Invalid setupCommand' }, 400);\n }\n if (typeof body.setupCommand === 'string' && body.setupCommand.length > 2000) {\n return c.json({ error: 'setupCommand too long (max 2000 characters)' }, 400);\n }\n // Reject control characters (except newline/tab). The command is a\n // shell script by design, but escape sequences and NULs have no\n // legitimate use and can spoof logs or confuse the sandbox shell.\n if (typeof body.setupCommand === 'string' && /[\\0-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/.test(body.setupCommand)) {\n return c.json({ error: 'setupCommand contains control characters' }, 400);\n }\n // An empty/whitespace command means \"no setup step\".\n const setupCommand =\n typeof body.setupCommand === 'string' && body.setupCommand.trim().length > 0\n ? body.setupCommand.trim()\n : null;\n\n await github.sourceControlStorage.projectRepositories.update({\n orgId: loaded.project.installation.orgId,\n id: loaded.project.id,\n input: { setupCommand },\n });\n return c.json({ setupCommand });\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 }));\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}: {\n github: GithubIntegration;\n auth: RouteAuth;\n fleet: SandboxFleet;\n controller?: MountedMastraCode['controller'];\n emitAudit?: AuditEmitter['emit'];\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 // Answer as soon as the workspace is actually gone. Reclaiming its\n // sandbox wakes the VM and scrubs the checkout, which takes minutes on\n // a large repository — the caller must not sit through that for a\n // workspace that has already been removed.\n await github.sourceControlStorage.sessions.delete(session.id);\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 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 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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"}
@@ -17,6 +17,7 @@ export declare function cleanReleasedSandbox(options: {
17
17
  projectRepositoryId: string;
18
18
  sandboxId: string;
19
19
  sandboxWorkdir: string;
20
+ actingUserId: string;
20
21
  }): Promise<void>;
21
22
  /**
22
23
  * Reclaim the sandbox a just-deleted user session was holding: return a remote
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-release.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/sandbox-release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,8CAA8C,CAAC;AACrH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAGjF;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IAC7C,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE;IAC1D,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;IAC9E,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,aAAa,GAAG,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACxG,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,QAAQ,GAAG,qBAAqB,GAAG,WAAW,GAAG,gBAAgB,CAAC,CAAC;CAClH,GAAG,OAAO,CAAC,IAAI,CAAC,CAqChB;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACtD,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACzC,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,UAAU,GAAG,aAAa,GAAG,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACrH,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BhB"}
1
+ {"version":3,"file":"sandbox-release.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/sandbox-release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,8CAA8C,CAAC;AACrH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAGjF;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IAC7C,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB;AAED;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE;IAC1D,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;IAC9E,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,aAAa,GAAG,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACxG,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,QAAQ,GAAG,qBAAqB,GAAG,WAAW,GAAG,gBAAgB,CAAC,CAAC;CAClH,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChB;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACtD,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACzC,aAAa,EAAE,IAAI,CAAC,0BAA0B,EAAE,UAAU,GAAG,aAAa,GAAG,qBAAqB,GAAG,cAAc,CAAC,CAAC;IACrH,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB"}
@@ -21,7 +21,7 @@ async function cleanReleasedSandbox(options) {
21
21
  id: projectRepository.repositoryId
22
22
  });
23
23
  if (!repository) return;
24
- await recycleClaimedWorkdir(await options.fleet.reattachSandbox(options.sandboxId), options.sandboxWorkdir, repository.defaultBranch);
24
+ await recycleClaimedWorkdir(await options.fleet.reattachSandbox(options.sandboxId, { actingUserId: options.actingUserId }), options.sandboxWorkdir, repository.defaultBranch);
25
25
  } catch {}
26
26
  }
27
27
  /**
@@ -44,7 +44,8 @@ async function reclaimDeletedSessionSandbox(options) {
44
44
  orgId: session.orgId,
45
45
  projectRepositoryId: session.projectRepositoryId,
46
46
  sandboxId: session.sandboxId,
47
- sandboxWorkdir: session.sandboxWorkdir
47
+ sandboxWorkdir: session.sandboxWorkdir,
48
+ actingUserId: session.userId
48
49
  });
49
50
  await sourceControl.sandboxPool.release({
50
51
  orgId: session.orgId,
@@ -57,7 +58,7 @@ async function reclaimDeletedSessionSandbox(options) {
57
58
  }
58
59
  let sandbox;
59
60
  try {
60
- sandbox = await fleet.reattachSandbox(session.sandboxId);
61
+ sandbox = await fleet.reattachSandbox(session.sandboxId, { actingUserId: session.userId });
61
62
  } catch {}
62
63
  await fleet.teardownSandbox({
63
64
  sandboxId: session.sandboxId,
@@ -93,7 +94,8 @@ async function releaseWorkItemSandboxes(options) {
93
94
  orgId: session.orgId,
94
95
  projectRepositoryId: session.projectRepositoryId,
95
96
  sandboxId: session.sandboxId,
96
- sandboxWorkdir: session.sandboxWorkdir
97
+ sandboxWorkdir: session.sandboxWorkdir,
98
+ actingUserId: session.userId
97
99
  });
98
100
  await sourceControl.sandboxPool.release({
99
101
  orgId: session.orgId,