@mastra/factory 0.7.1-alpha.4 → 0.8.0-alpha.6

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 (46) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/factory.d.ts.map +1 -1
  3. package/dist/factory.js +21 -15
  4. package/dist/factory.js.map +1 -1
  5. package/dist/integrations/base.d.ts +3 -0
  6. package/dist/integrations/base.d.ts.map +1 -1
  7. package/dist/integrations/github/integration.d.ts.map +1 -1
  8. package/dist/integrations/github/integration.js +2 -1
  9. package/dist/integrations/github/integration.js.map +1 -1
  10. package/dist/integrations/github/routes.d.ts +1 -0
  11. package/dist/integrations/github/routes.d.ts.map +1 -1
  12. package/dist/integrations/github/routes.js +48 -21
  13. package/dist/integrations/github/routes.js.map +1 -1
  14. package/dist/integrations/github/sandbox-release.d.ts +2 -1
  15. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  16. package/dist/integrations/github/sandbox-release.js +1 -1
  17. package/dist/integrations/github/sandbox-release.js.map +1 -1
  18. package/dist/integrations/github/sandbox.d.ts +17 -21
  19. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  20. package/dist/integrations/github/sandbox.js +26 -8
  21. package/dist/integrations/github/sandbox.js.map +1 -1
  22. package/dist/routes/projects.d.ts +3 -0
  23. package/dist/routes/projects.d.ts.map +1 -1
  24. package/dist/routes/projects.js +41 -10
  25. package/dist/routes/projects.js.map +1 -1
  26. package/dist/routes/surface.d.ts +1 -0
  27. package/dist/routes/surface.d.ts.map +1 -1
  28. package/dist/routes/surface.js.map +1 -1
  29. package/dist/rules/start-coordinator.js +1 -1
  30. package/dist/sandbox/session-retirement.d.ts +40 -0
  31. package/dist/sandbox/session-retirement.d.ts.map +1 -0
  32. package/dist/sandbox/session-retirement.js +221 -0
  33. package/dist/sandbox/session-retirement.js.map +1 -0
  34. package/dist/storage/domains/source-control/base.d.ts +6 -0
  35. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  36. package/dist/storage/domains/source-control/base.js +11 -0
  37. package/dist/storage/domains/source-control/base.js.map +1 -1
  38. package/dist/storage/domains/source-control/inmemory.d.ts +3 -0
  39. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  40. package/dist/storage/domains/source-control/inmemory.js +2 -0
  41. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  42. package/dist/workspace.d.ts +10 -0
  43. package/dist/workspace.d.ts.map +1 -1
  44. package/dist/workspace.js +54 -8
  45. package/dist/workspace.js.map +1 -1
  46. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"inmemory.js","names":[],"sources":["../../../../src/storage/domains/source-control/inmemory.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { UniqueViolationError } from '@mastra/core/storage';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n CreateProjectSourceControlConnectionInput,\n CreateSourceControlSessionInput,\n ExternalRepositoryProjectTarget,\n LinkProjectRepositoryInput,\n PooledSandbox,\n ProjectRepository,\n ProjectRepositorySandbox,\n ProjectSourceControlConnection,\n ReleasePooledSandboxInput,\n SourceControlInstallation,\n SourceControlRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n SourceControlWorktree,\n UpdateProjectRepositoryInput,\n UpsertSourceControlInstallationInput,\n UpsertSourceControlRepositoryInput,\n UpsertSourceControlWorktreeInput,\n} from './base.js';\n\n/** In-memory provider-scoped source-control handle for route tests. */\nexport class SourceControlStorageInMemory implements SourceControlStorageHandle {\n readonly integrationId: string;\n installationsRows: SourceControlInstallation[] = [];\n repositoriesRows: SourceControlRepository[] = [];\n connectionsRows: ProjectSourceControlConnection[] = [];\n projectRepositoriesRows: ProjectRepository[] = [];\n sandboxesRows: ProjectRepositorySandbox[] = [];\n sandboxPoolRows: PooledSandbox[] = [];\n worktreesRows: SourceControlWorktree[] = [];\n sessionsRows: SourceControlSession[] = [];\n\n constructor(integrationId = 'github') {\n this.integrationId = integrationId;\n }\n\n readonly installations = {\n list: async ({ orgId }: { orgId: string }): Promise<SourceControlInstallation[]> =>\n this.installationsRows.filter(row => row.orgId === orgId),\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<SourceControlInstallation | null> =>\n this.installationsRows.find(row => row.orgId === orgId && row.id === id) ?? null,\n findByExternalId: async ({\n orgId,\n externalId,\n }: {\n orgId: string;\n externalId: string;\n }): Promise<SourceControlInstallation | null> =>\n this.installationsRows.find(row => row.orgId === orgId && row.externalId === externalId) ?? null,\n upsert: async (input: UpsertSourceControlInstallationInput): Promise<SourceControlInstallation> => {\n const existing = this.installationsRows.find(\n row => row.orgId === input.orgId && row.externalId === input.externalId,\n );\n if (existing) {\n Object.assign(existing, {\n connectedByUserId: input.connectedByUserId,\n accountName: input.accountName ?? null,\n accountType: input.accountType ?? null,\n providerMetadata: input.providerMetadata ?? {},\n });\n return existing;\n }\n const created: SourceControlInstallation = {\n id: randomUUID(),\n integrationId: this.integrationId,\n orgId: input.orgId,\n connectedByUserId: input.connectedByUserId,\n externalId: input.externalId,\n accountName: input.accountName ?? null,\n accountType: input.accountType ?? null,\n providerMetadata: input.providerMetadata ?? {},\n createdAt: new Date(),\n };\n this.installationsRows.push(created);\n return created;\n },\n delete: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n const index = this.installationsRows.findIndex(row => row.orgId === orgId && row.id === id);\n if (index < 0) return false;\n this.installationsRows.splice(index, 1);\n return true;\n },\n };\n\n readonly repositories = {\n list: async ({ orgId, installationId }: { orgId: string; installationId: string }) => {\n const installation = await this.installations.get({ orgId, id: installationId });\n return installation ? this.repositoriesRows.filter(row => row.installationId === installationId) : [];\n },\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<SourceControlRepository | null> => {\n const row = this.repositoriesRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.installations.get({ orgId, id: row.installationId })) ? row : null;\n },\n findByExternalId: async ({\n orgId,\n installationId,\n externalId,\n }: {\n orgId: string;\n installationId: string;\n externalId: string;\n }) => {\n const rows = await this.repositories.list({ orgId, installationId });\n return rows.find(row => row.externalId === externalId) ?? null;\n },\n findBySlug: async ({ orgId, installationId, slug }: { orgId: string; installationId: string; slug: string }) => {\n const rows = await this.repositories.list({ orgId, installationId });\n return rows.find(row => row.slug === slug) ?? null;\n },\n upsert: async ({\n orgId,\n input,\n }: {\n orgId: string;\n input: UpsertSourceControlRepositoryInput;\n }): Promise<SourceControlRepository> => {\n if (!(await this.installations.get({ orgId, id: input.installationId }))) {\n throw new Error('Source-control installation not found');\n }\n const existing = this.repositoriesRows.find(\n row => row.installationId === input.installationId && row.externalId === input.externalId,\n );\n const now = new Date();\n if (existing) {\n Object.assign(existing, {\n slug: input.slug,\n defaultBranch: input.defaultBranch,\n providerMetadata: input.providerMetadata ?? {},\n updatedAt: now,\n });\n return existing;\n }\n const created: SourceControlRepository = {\n id: randomUUID(),\n installationId: input.installationId,\n externalId: input.externalId,\n slug: input.slug,\n defaultBranch: input.defaultBranch,\n providerMetadata: input.providerMetadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n this.repositoriesRows.push(created);\n return created;\n },\n migrateInstallation: async ({\n orgId,\n id,\n newInstallationId,\n }: {\n orgId: string;\n id: string;\n newInstallationId: string;\n }) => {\n const existing = await this.repositories.get({ orgId, id });\n if (!existing) {\n throw new Error(`Repository ${id} not found in organization ${orgId}`);\n }\n if (!(await this.installations.get({ orgId, id: newInstallationId }))) {\n throw new Error('Source-control installation not found');\n }\n // Check if a repository with the same external_id exists under the new installation\n const conflict = this.repositoriesRows.find(\n row => row.installationId === newInstallationId && row.externalId === existing.externalId,\n );\n if (conflict) {\n // Return the existing repository under the new installation\n return conflict;\n }\n // Update the repository's installation\n existing.installationId = newInstallationId;\n existing.updatedAt = new Date();\n // Migrate dependent connections to the new installation\n for (const conn of this.connectionsRows) {\n if (conn.installationId === existing.installationId) {\n conn.installationId = newInstallationId;\n }\n }\n return existing;\n },\n };\n\n readonly connections = {\n list: async ({ factoryProjectId }: { orgId: string; factoryProjectId: string }) =>\n this.connectionsRows.filter(row => row.factoryProjectId === factoryProjectId),\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<ProjectSourceControlConnection | null> => {\n const row = this.connectionsRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.installations.get({ orgId, id: row.installationId })) ? row : null;\n },\n create: async (input: CreateProjectSourceControlConnectionInput): Promise<ProjectSourceControlConnection> => {\n if (!(await this.installations.get({ orgId: input.orgId, id: input.installationId }))) {\n throw new Error('Source-control installation not found');\n }\n const existing = this.connectionsRows.find(\n row =>\n row.factoryProjectId === input.factoryProjectId &&\n row.integrationId === this.integrationId &&\n row.installationId === input.installationId,\n );\n if (existing) return existing;\n const created: ProjectSourceControlConnection = {\n id: randomUUID(),\n factoryProjectId: input.factoryProjectId,\n integrationId: this.integrationId,\n installationId: input.installationId,\n createdByUserId: input.createdByUserId,\n createdAt: new Date(),\n };\n this.connectionsRows.push(created);\n return created;\n },\n delete: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n if (!(await this.connections.get({ orgId, id }))) return false;\n this.connectionsRows.splice(0, this.connectionsRows.length, ...this.connectionsRows.filter(row => row.id !== id));\n return true;\n },\n };\n\n readonly projectRepositories = {\n list: async ({ orgId, connectionId }: { orgId: string; connectionId: string }) =>\n (await this.connections.get({ orgId, id: connectionId }))\n ? this.projectRepositoriesRows.filter(row => row.connectionId === connectionId)\n : [],\n listConfiguredExternalKeys: async (): Promise<ConfiguredExternalRepositoryKey[]> => {\n const keys = new Map<string, ConfiguredExternalRepositoryKey>();\n for (const connection of this.connectionsRows.filter(row => row.integrationId === this.integrationId)) {\n const installation = this.installationsRows.find(row => row.id === connection.installationId);\n if (!installation) continue;\n for (const link of this.projectRepositoriesRows.filter(row => row.connectionId === connection.id)) {\n const repository = this.repositoriesRows.find(row => row.id === link.repositoryId);\n if (!repository) continue;\n keys.set(`${installation.externalId}\\u0000${repository.externalId}`, {\n installationExternalId: installation.externalId,\n repositoryExternalId: repository.externalId,\n });\n }\n }\n return [...keys.values()];\n },\n listByExternalRepository: async ({\n installationExternalId,\n repositoryExternalId,\n }: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]> => {\n const targets: ExternalRepositoryProjectTarget[] = [];\n for (const installation of this.installationsRows.filter(row => row.externalId === installationExternalId)) {\n const repository = this.repositoriesRows.find(\n row => row.installationId === installation.id && row.externalId === repositoryExternalId,\n );\n if (!repository) continue;\n for (const projectRepository of this.projectRepositoriesRows.filter(\n row => row.repositoryId === repository.id,\n )) {\n const connection = this.connectionsRows.find(\n row =>\n row.id === projectRepository.connectionId &&\n row.installationId === installation.id &&\n row.integrationId === this.integrationId,\n );\n if (!connection) continue;\n targets.push({\n orgId: installation.orgId,\n factoryProjectId: connection.factoryProjectId,\n projectRepository,\n });\n }\n }\n return targets;\n },\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<ProjectRepository | null> => {\n const row = this.projectRepositoriesRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.connections.get({ orgId, id: row.connectionId })) ? row : null;\n },\n link: async (input: LinkProjectRepositoryInput): Promise<ProjectRepository> => {\n const connection = await this.connections.get({ orgId: input.orgId, id: input.connectionId });\n const repository = await this.repositories.get({ orgId: input.orgId, id: input.repositoryId });\n if (!connection || !repository || repository.installationId !== connection.installationId) {\n throw new Error('Source-control connection or repository not found');\n }\n const existing = this.projectRepositoriesRows.find(\n row => row.connectionId === input.connectionId && row.repositoryId === input.repositoryId,\n );\n if (existing) return existing;\n const now = new Date();\n const created: ProjectRepository = {\n id: randomUUID(),\n connectionId: input.connectionId,\n repositoryId: input.repositoryId,\n createdByUserId: input.createdByUserId,\n branch: input.branch ?? null,\n sandboxProvider: input.sandboxProvider,\n sandboxWorkdir: input.sandboxWorkdir,\n setupCommand: input.setupCommand ?? null,\n createdAt: now,\n updatedAt: now,\n };\n this.projectRepositoriesRows.push(created);\n return created;\n },\n update: async ({\n orgId,\n id,\n input,\n }: {\n orgId: string;\n id: string;\n input: UpdateProjectRepositoryInput;\n }): Promise<ProjectRepository | null> => {\n const row = await this.projectRepositories.get({ orgId, id });\n if (!row) return null;\n Object.assign(row, input, { updatedAt: new Date() });\n return row;\n },\n unlink: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n if (!(await this.projectRepositories.get({ orgId, id }))) return false;\n this.projectRepositoriesRows.splice(\n 0,\n this.projectRepositoriesRows.length,\n ...this.projectRepositoriesRows.filter(row => row.id !== id),\n );\n return true;\n },\n };\n\n readonly sandboxes = {\n getOrCreate: async ({\n projectRepository,\n userId,\n }: {\n projectRepository: ProjectRepository;\n userId: string;\n }): Promise<ProjectRepositorySandbox> => {\n const existing = this.sandboxesRows.find(\n row => row.projectRepositoryId === projectRepository.id && row.userId === userId,\n );\n if (existing) return existing;\n const created: ProjectRepositorySandbox = {\n id: randomUUID(),\n projectRepositoryId: projectRepository.id,\n userId,\n sandboxId: null,\n sandboxWorkdir: projectRepository.sandboxWorkdir,\n materializedAt: null,\n createdAt: new Date(),\n };\n this.sandboxesRows.push(created);\n return created;\n },\n getById: async ({ id }: { id: string }): Promise<ProjectRepositorySandbox | null> =>\n this.sandboxesRows.find(row => row.id === id) ?? null,\n setWorkdir: async ({ id, sandboxWorkdir }: { id: string; sandboxWorkdir: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxWorkdir, materializedAt: null });\n },\n setSandboxId: async ({ id, sandboxId }: { id: string; sandboxId: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) row.sandboxId = sandboxId;\n },\n clearBinding: async ({ id }: { id: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxId: null, materializedAt: null });\n },\n markMaterialized: async ({ id }: { id: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) row.materializedAt = new Date();\n },\n };\n\n readonly sandboxPool = {\n release: async (input: ReleasePooledSandboxInput): Promise<void> => {\n // Mirror the SQL implementation: a missing project-repository link\n // makes the release a silent no-op.\n if (!this.projectRepositoriesRows.some(row => row.id === input.projectRepositoryId)) return;\n if (this.sandboxPoolRows.some(row => row.sandboxId === input.sandboxId)) return;\n this.sandboxPoolRows.push({ id: randomUUID(), releasedAt: new Date(), ...input });\n },\n claim: async ({ projectRepositoryId }: { projectRepositoryId: string }): Promise<PooledSandbox | null> => {\n const candidates = this.sandboxPoolRows\n .filter(row => row.projectRepositoryId === projectRepositoryId)\n .sort((left, right) => right.releasedAt.getTime() - left.releasedAt.getTime());\n const claimed = candidates[0];\n if (!claimed) return null;\n this.sandboxPoolRows.splice(this.sandboxPoolRows.indexOf(claimed), 1);\n return claimed;\n },\n };\n\n readonly worktrees = {\n upsert: async (input: UpsertSourceControlWorktreeInput): Promise<void> => {\n const existing = this.worktreesRows.find(\n row =>\n row.projectRepositoryId === input.projectRepositoryId &&\n row.userId === input.userId &&\n row.branch === input.branch,\n );\n if (existing) {\n existing.baseBranch = input.baseBranch;\n existing.worktreePath = input.worktreePath;\n return;\n }\n this.worktreesRows.push({ id: randomUUID(), createdAt: new Date(), ...input });\n },\n list: async ({\n projectRepositoryId,\n userId,\n }: {\n projectRepositoryId: string;\n userId: string;\n }): Promise<SourceControlWorktree[]> =>\n this.worktreesRows.filter(row => row.projectRepositoryId === projectRepositoryId && row.userId === userId),\n get: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<SourceControlWorktree | null> =>\n this.worktreesRows.find(\n row => row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch,\n ) ?? null,\n findByPath: async ({\n projectRepositoryId,\n userId,\n worktreePath,\n }: {\n projectRepositoryId: string;\n userId: string;\n worktreePath: string;\n }): Promise<SourceControlWorktree | null> =>\n this.worktreesRows.find(\n row =>\n row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.worktreePath === worktreePath,\n ) ?? null,\n delete: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<void> => {\n this.worktreesRows.splice(\n 0,\n this.worktreesRows.length,\n ...this.worktreesRows.filter(\n row => !(row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch),\n ),\n );\n },\n };\n\n readonly sessions = {\n list: async ({ projectRepositoryId, userId }: { projectRepositoryId: string; userId: string }) =>\n this.sessionsRows.filter(row => row.projectRepositoryId === projectRepositoryId && row.userId === userId),\n getBySessionId: async (sessionId: string): Promise<SourceControlSession | null> =>\n this.sessionsRows.find(row => row.sessionId === sessionId) ?? null,\n getForBranch: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<SourceControlSession | null> =>\n this.sessionsRows.find(\n row => row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch,\n ) ?? null,\n create: async (input: CreateSourceControlSessionInput): Promise<SourceControlSession> => {\n const existing = await this.sessions.getForBranch(input);\n if (existing) return existing;\n if (this.sessionsRows.some(row => row.sessionId === input.sessionId)) {\n throw new UniqueViolationError('Source-control session ID already exists');\n }\n const now = new Date();\n const session: SourceControlSession = {\n id: randomUUID(),\n ...input,\n title: input.title ?? null,\n sandboxId: null,\n sandboxWorkdir: null,\n materializedAt: null,\n firstMessageAt: null,\n firstMeaningfulExecAt: null,\n createdAt: now,\n updatedAt: now,\n };\n this.sessionsRows.push(session);\n return session;\n },\n setSandbox: async ({\n id,\n sandboxId,\n sandboxWorkdir,\n }: {\n id: string;\n sandboxId: string | null;\n sandboxWorkdir: string;\n }) => {\n const row = this.sessionsRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxId, sandboxWorkdir, updatedAt: new Date() });\n },\n markMaterialized: async ({ id }: { id: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.id === id);\n if (row && row.materializedAt === null) Object.assign(row, { materializedAt: new Date(), updatedAt: new Date() });\n },\n markFirstMessage: async ({ sessionId }: { sessionId: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.sessionId === sessionId);\n if (row && row.firstMessageAt === null) Object.assign(row, { firstMessageAt: new Date(), updatedAt: new Date() });\n },\n markFirstMeaningfulExec: async ({ sessionId }: { sessionId: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.sessionId === sessionId);\n if (row && row.firstMeaningfulExecAt === null) {\n Object.assign(row, { firstMeaningfulExecAt: new Date(), updatedAt: new Date() });\n }\n },\n delete: async (id: string) => {\n this.sessionsRows.splice(0, this.sessionsRows.length, ...this.sessionsRows.filter(row => row.id !== id));\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inmemory.js","names":[],"sources":["../../../../src/storage/domains/source-control/inmemory.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { UniqueViolationError } from '@mastra/core/storage';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n CreateProjectSourceControlConnectionInput,\n CreateSourceControlSessionInput,\n ExternalRepositoryProjectTarget,\n LinkProjectRepositoryInput,\n PooledSandbox,\n ProjectRepository,\n ProjectRepositorySandbox,\n ProjectSourceControlConnection,\n ReleasePooledSandboxInput,\n SourceControlInstallation,\n SourceControlRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n SourceControlWorktree,\n UpdateProjectRepositoryInput,\n UpsertSourceControlInstallationInput,\n UpsertSourceControlRepositoryInput,\n UpsertSourceControlWorktreeInput,\n} from './base.js';\n\n/** In-memory provider-scoped source-control handle for route tests. */\nexport class SourceControlStorageInMemory implements SourceControlStorageHandle {\n readonly integrationId: string;\n installationsRows: SourceControlInstallation[] = [];\n repositoriesRows: SourceControlRepository[] = [];\n connectionsRows: ProjectSourceControlConnection[] = [];\n projectRepositoriesRows: ProjectRepository[] = [];\n sandboxesRows: ProjectRepositorySandbox[] = [];\n sandboxPoolRows: PooledSandbox[] = [];\n worktreesRows: SourceControlWorktree[] = [];\n sessionsRows: SourceControlSession[] = [];\n\n constructor(integrationId = 'github') {\n this.integrationId = integrationId;\n }\n\n readonly installations = {\n list: async ({ orgId }: { orgId: string }): Promise<SourceControlInstallation[]> =>\n this.installationsRows.filter(row => row.orgId === orgId),\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<SourceControlInstallation | null> =>\n this.installationsRows.find(row => row.orgId === orgId && row.id === id) ?? null,\n findByExternalId: async ({\n orgId,\n externalId,\n }: {\n orgId: string;\n externalId: string;\n }): Promise<SourceControlInstallation | null> =>\n this.installationsRows.find(row => row.orgId === orgId && row.externalId === externalId) ?? null,\n upsert: async (input: UpsertSourceControlInstallationInput): Promise<SourceControlInstallation> => {\n const existing = this.installationsRows.find(\n row => row.orgId === input.orgId && row.externalId === input.externalId,\n );\n if (existing) {\n Object.assign(existing, {\n connectedByUserId: input.connectedByUserId,\n accountName: input.accountName ?? null,\n accountType: input.accountType ?? null,\n providerMetadata: input.providerMetadata ?? {},\n });\n return existing;\n }\n const created: SourceControlInstallation = {\n id: randomUUID(),\n integrationId: this.integrationId,\n orgId: input.orgId,\n connectedByUserId: input.connectedByUserId,\n externalId: input.externalId,\n accountName: input.accountName ?? null,\n accountType: input.accountType ?? null,\n providerMetadata: input.providerMetadata ?? {},\n createdAt: new Date(),\n };\n this.installationsRows.push(created);\n return created;\n },\n delete: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n const index = this.installationsRows.findIndex(row => row.orgId === orgId && row.id === id);\n if (index < 0) return false;\n this.installationsRows.splice(index, 1);\n return true;\n },\n };\n\n readonly repositories = {\n list: async ({ orgId, installationId }: { orgId: string; installationId: string }) => {\n const installation = await this.installations.get({ orgId, id: installationId });\n return installation ? this.repositoriesRows.filter(row => row.installationId === installationId) : [];\n },\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<SourceControlRepository | null> => {\n const row = this.repositoriesRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.installations.get({ orgId, id: row.installationId })) ? row : null;\n },\n findByExternalId: async ({\n orgId,\n installationId,\n externalId,\n }: {\n orgId: string;\n installationId: string;\n externalId: string;\n }) => {\n const rows = await this.repositories.list({ orgId, installationId });\n return rows.find(row => row.externalId === externalId) ?? null;\n },\n findBySlug: async ({ orgId, installationId, slug }: { orgId: string; installationId: string; slug: string }) => {\n const rows = await this.repositories.list({ orgId, installationId });\n return rows.find(row => row.slug === slug) ?? null;\n },\n upsert: async ({\n orgId,\n input,\n }: {\n orgId: string;\n input: UpsertSourceControlRepositoryInput;\n }): Promise<SourceControlRepository> => {\n if (!(await this.installations.get({ orgId, id: input.installationId }))) {\n throw new Error('Source-control installation not found');\n }\n const existing = this.repositoriesRows.find(\n row => row.installationId === input.installationId && row.externalId === input.externalId,\n );\n const now = new Date();\n if (existing) {\n Object.assign(existing, {\n slug: input.slug,\n defaultBranch: input.defaultBranch,\n providerMetadata: input.providerMetadata ?? {},\n updatedAt: now,\n });\n return existing;\n }\n const created: SourceControlRepository = {\n id: randomUUID(),\n installationId: input.installationId,\n externalId: input.externalId,\n slug: input.slug,\n defaultBranch: input.defaultBranch,\n providerMetadata: input.providerMetadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n this.repositoriesRows.push(created);\n return created;\n },\n migrateInstallation: async ({\n orgId,\n id,\n newInstallationId,\n }: {\n orgId: string;\n id: string;\n newInstallationId: string;\n }) => {\n const existing = await this.repositories.get({ orgId, id });\n if (!existing) {\n throw new Error(`Repository ${id} not found in organization ${orgId}`);\n }\n if (!(await this.installations.get({ orgId, id: newInstallationId }))) {\n throw new Error('Source-control installation not found');\n }\n // Check if a repository with the same external_id exists under the new installation\n const conflict = this.repositoriesRows.find(\n row => row.installationId === newInstallationId && row.externalId === existing.externalId,\n );\n if (conflict) {\n // Return the existing repository under the new installation\n return conflict;\n }\n // Update the repository's installation\n existing.installationId = newInstallationId;\n existing.updatedAt = new Date();\n // Migrate dependent connections to the new installation\n for (const conn of this.connectionsRows) {\n if (conn.installationId === existing.installationId) {\n conn.installationId = newInstallationId;\n }\n }\n return existing;\n },\n };\n\n readonly connections = {\n list: async ({ factoryProjectId }: { orgId: string; factoryProjectId: string }) =>\n this.connectionsRows.filter(row => row.factoryProjectId === factoryProjectId),\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<ProjectSourceControlConnection | null> => {\n const row = this.connectionsRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.installations.get({ orgId, id: row.installationId })) ? row : null;\n },\n create: async (input: CreateProjectSourceControlConnectionInput): Promise<ProjectSourceControlConnection> => {\n if (!(await this.installations.get({ orgId: input.orgId, id: input.installationId }))) {\n throw new Error('Source-control installation not found');\n }\n const existing = this.connectionsRows.find(\n row =>\n row.factoryProjectId === input.factoryProjectId &&\n row.integrationId === this.integrationId &&\n row.installationId === input.installationId,\n );\n if (existing) return existing;\n const created: ProjectSourceControlConnection = {\n id: randomUUID(),\n factoryProjectId: input.factoryProjectId,\n integrationId: this.integrationId,\n installationId: input.installationId,\n createdByUserId: input.createdByUserId,\n createdAt: new Date(),\n };\n this.connectionsRows.push(created);\n return created;\n },\n delete: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n if (!(await this.connections.get({ orgId, id }))) return false;\n this.connectionsRows.splice(0, this.connectionsRows.length, ...this.connectionsRows.filter(row => row.id !== id));\n return true;\n },\n };\n\n readonly projectRepositories = {\n list: async ({ orgId, connectionId }: { orgId: string; connectionId: string }) =>\n (await this.connections.get({ orgId, id: connectionId }))\n ? this.projectRepositoriesRows.filter(row => row.connectionId === connectionId)\n : [],\n listConfiguredExternalKeys: async (): Promise<ConfiguredExternalRepositoryKey[]> => {\n const keys = new Map<string, ConfiguredExternalRepositoryKey>();\n for (const connection of this.connectionsRows.filter(row => row.integrationId === this.integrationId)) {\n const installation = this.installationsRows.find(row => row.id === connection.installationId);\n if (!installation) continue;\n for (const link of this.projectRepositoriesRows.filter(row => row.connectionId === connection.id)) {\n const repository = this.repositoriesRows.find(row => row.id === link.repositoryId);\n if (!repository) continue;\n keys.set(`${installation.externalId}\\u0000${repository.externalId}`, {\n installationExternalId: installation.externalId,\n repositoryExternalId: repository.externalId,\n });\n }\n }\n return [...keys.values()];\n },\n listByExternalRepository: async ({\n installationExternalId,\n repositoryExternalId,\n }: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]> => {\n const targets: ExternalRepositoryProjectTarget[] = [];\n for (const installation of this.installationsRows.filter(row => row.externalId === installationExternalId)) {\n const repository = this.repositoriesRows.find(\n row => row.installationId === installation.id && row.externalId === repositoryExternalId,\n );\n if (!repository) continue;\n for (const projectRepository of this.projectRepositoriesRows.filter(\n row => row.repositoryId === repository.id,\n )) {\n const connection = this.connectionsRows.find(\n row =>\n row.id === projectRepository.connectionId &&\n row.installationId === installation.id &&\n row.integrationId === this.integrationId,\n );\n if (!connection) continue;\n targets.push({\n orgId: installation.orgId,\n factoryProjectId: connection.factoryProjectId,\n projectRepository,\n });\n }\n }\n return targets;\n },\n get: async ({ orgId, id }: { orgId: string; id: string }): Promise<ProjectRepository | null> => {\n const row = this.projectRepositoriesRows.find(candidate => candidate.id === id);\n if (!row) return null;\n return (await this.connections.get({ orgId, id: row.connectionId })) ? row : null;\n },\n link: async (input: LinkProjectRepositoryInput): Promise<ProjectRepository> => {\n const connection = await this.connections.get({ orgId: input.orgId, id: input.connectionId });\n const repository = await this.repositories.get({ orgId: input.orgId, id: input.repositoryId });\n if (!connection || !repository || repository.installationId !== connection.installationId) {\n throw new Error('Source-control connection or repository not found');\n }\n const existing = this.projectRepositoriesRows.find(\n row => row.connectionId === input.connectionId && row.repositoryId === input.repositoryId,\n );\n if (existing) return existing;\n const now = new Date();\n const created: ProjectRepository = {\n id: randomUUID(),\n connectionId: input.connectionId,\n repositoryId: input.repositoryId,\n createdByUserId: input.createdByUserId,\n branch: input.branch ?? null,\n sandboxProvider: input.sandboxProvider,\n sandboxWorkdir: input.sandboxWorkdir,\n setupCommand: input.setupCommand ?? null,\n teardownCommand: input.teardownCommand ?? null,\n createdAt: now,\n updatedAt: now,\n };\n this.projectRepositoriesRows.push(created);\n return created;\n },\n update: async ({\n orgId,\n id,\n input,\n }: {\n orgId: string;\n id: string;\n input: UpdateProjectRepositoryInput;\n }): Promise<ProjectRepository | null> => {\n const row = await this.projectRepositories.get({ orgId, id });\n if (!row) return null;\n Object.assign(row, input, { updatedAt: new Date() });\n return row;\n },\n unlink: async ({ orgId, id }: { orgId: string; id: string }): Promise<boolean> => {\n if (!(await this.projectRepositories.get({ orgId, id }))) return false;\n this.projectRepositoriesRows.splice(\n 0,\n this.projectRepositoriesRows.length,\n ...this.projectRepositoriesRows.filter(row => row.id !== id),\n );\n return true;\n },\n };\n\n readonly sandboxes = {\n getOrCreate: async ({\n projectRepository,\n userId,\n }: {\n projectRepository: ProjectRepository;\n userId: string;\n }): Promise<ProjectRepositorySandbox> => {\n const existing = this.sandboxesRows.find(\n row => row.projectRepositoryId === projectRepository.id && row.userId === userId,\n );\n if (existing) return existing;\n const created: ProjectRepositorySandbox = {\n id: randomUUID(),\n projectRepositoryId: projectRepository.id,\n userId,\n sandboxId: null,\n sandboxWorkdir: projectRepository.sandboxWorkdir,\n materializedAt: null,\n createdAt: new Date(),\n };\n this.sandboxesRows.push(created);\n return created;\n },\n getById: async ({ id }: { id: string }): Promise<ProjectRepositorySandbox | null> =>\n this.sandboxesRows.find(row => row.id === id) ?? null,\n setWorkdir: async ({ id, sandboxWorkdir }: { id: string; sandboxWorkdir: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxWorkdir, materializedAt: null });\n },\n setSandboxId: async ({ id, sandboxId }: { id: string; sandboxId: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) row.sandboxId = sandboxId;\n },\n clearBinding: async ({ id }: { id: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxId: null, materializedAt: null });\n },\n markMaterialized: async ({ id }: { id: string }): Promise<void> => {\n const row = this.sandboxesRows.find(candidate => candidate.id === id);\n if (row) row.materializedAt = new Date();\n },\n };\n\n readonly sandboxPool = {\n release: async (input: ReleasePooledSandboxInput): Promise<void> => {\n // Mirror the SQL implementation: a missing project-repository link\n // makes the release a silent no-op.\n if (!this.projectRepositoriesRows.some(row => row.id === input.projectRepositoryId)) return;\n if (this.sandboxPoolRows.some(row => row.sandboxId === input.sandboxId)) return;\n this.sandboxPoolRows.push({ id: randomUUID(), releasedAt: new Date(), ...input });\n },\n claim: async ({ projectRepositoryId }: { projectRepositoryId: string }): Promise<PooledSandbox | null> => {\n const candidates = this.sandboxPoolRows\n .filter(row => row.projectRepositoryId === projectRepositoryId)\n .sort((left, right) => right.releasedAt.getTime() - left.releasedAt.getTime());\n const claimed = candidates[0];\n if (!claimed) return null;\n this.sandboxPoolRows.splice(this.sandboxPoolRows.indexOf(claimed), 1);\n return claimed;\n },\n };\n\n readonly worktrees = {\n upsert: async (input: UpsertSourceControlWorktreeInput): Promise<void> => {\n const existing = this.worktreesRows.find(\n row =>\n row.projectRepositoryId === input.projectRepositoryId &&\n row.userId === input.userId &&\n row.branch === input.branch,\n );\n if (existing) {\n existing.baseBranch = input.baseBranch;\n existing.worktreePath = input.worktreePath;\n return;\n }\n this.worktreesRows.push({ id: randomUUID(), createdAt: new Date(), ...input });\n },\n list: async ({\n projectRepositoryId,\n userId,\n }: {\n projectRepositoryId: string;\n userId: string;\n }): Promise<SourceControlWorktree[]> =>\n this.worktreesRows.filter(row => row.projectRepositoryId === projectRepositoryId && row.userId === userId),\n get: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<SourceControlWorktree | null> =>\n this.worktreesRows.find(\n row => row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch,\n ) ?? null,\n findByPath: async ({\n projectRepositoryId,\n userId,\n worktreePath,\n }: {\n projectRepositoryId: string;\n userId: string;\n worktreePath: string;\n }): Promise<SourceControlWorktree | null> =>\n this.worktreesRows.find(\n row =>\n row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.worktreePath === worktreePath,\n ) ?? null,\n delete: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<void> => {\n this.worktreesRows.splice(\n 0,\n this.worktreesRows.length,\n ...this.worktreesRows.filter(\n row => !(row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch),\n ),\n );\n },\n };\n\n readonly sessions = {\n list: async ({ projectRepositoryId, userId }: { projectRepositoryId: string; userId: string }) =>\n this.sessionsRows.filter(row => row.projectRepositoryId === projectRepositoryId && row.userId === userId),\n listByProjectRepository: async ({ projectRepositoryId }: { projectRepositoryId: string }) =>\n this.sessionsRows.filter(row => row.projectRepositoryId === projectRepositoryId),\n getBySessionId: async (sessionId: string): Promise<SourceControlSession | null> =>\n this.sessionsRows.find(row => row.sessionId === sessionId) ?? null,\n getForBranch: async ({\n projectRepositoryId,\n userId,\n branch,\n }: {\n projectRepositoryId: string;\n userId: string;\n branch: string;\n }): Promise<SourceControlSession | null> =>\n this.sessionsRows.find(\n row => row.projectRepositoryId === projectRepositoryId && row.userId === userId && row.branch === branch,\n ) ?? null,\n create: async (input: CreateSourceControlSessionInput): Promise<SourceControlSession> => {\n const existing = await this.sessions.getForBranch(input);\n if (existing) return existing;\n if (this.sessionsRows.some(row => row.sessionId === input.sessionId)) {\n throw new UniqueViolationError('Source-control session ID already exists');\n }\n const now = new Date();\n const session: SourceControlSession = {\n id: randomUUID(),\n ...input,\n title: input.title ?? null,\n sandboxId: null,\n sandboxWorkdir: null,\n materializedAt: null,\n firstMessageAt: null,\n firstMeaningfulExecAt: null,\n createdAt: now,\n updatedAt: now,\n };\n this.sessionsRows.push(session);\n return session;\n },\n setSandbox: async ({\n id,\n sandboxId,\n sandboxWorkdir,\n }: {\n id: string;\n sandboxId: string | null;\n sandboxWorkdir: string;\n }) => {\n const row = this.sessionsRows.find(candidate => candidate.id === id);\n if (row) Object.assign(row, { sandboxId, sandboxWorkdir, updatedAt: new Date() });\n },\n markMaterialized: async ({ id }: { id: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.id === id);\n if (row && row.materializedAt === null) Object.assign(row, { materializedAt: new Date(), updatedAt: new Date() });\n },\n markFirstMessage: async ({ sessionId }: { sessionId: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.sessionId === sessionId);\n if (row && row.firstMessageAt === null) Object.assign(row, { firstMessageAt: new Date(), updatedAt: new Date() });\n },\n markFirstMeaningfulExec: async ({ sessionId }: { sessionId: string }) => {\n const row = this.sessionsRows.find(candidate => candidate.sessionId === sessionId);\n if (row && row.firstMeaningfulExecAt === null) {\n Object.assign(row, { firstMeaningfulExecAt: new Date(), updatedAt: new Date() });\n }\n },\n delete: async (id: string) => {\n this.sessionsRows.splice(0, this.sessionsRows.length, ...this.sessionsRows.filter(row => row.id !== id));\n },\n };\n}\n"],"mappings":"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"}
@@ -19,6 +19,16 @@ export interface CreateWorkspaceFactoryOptions {
19
19
  * review-board sessions get the reviewer PAT as `GH_TOKEN`. Optional —
20
20
  * without it every session uses the default (worker) PAT. */
21
21
  workItems?: Pick<WorkItemsStorage, 'findRunBindingBySession'>;
22
+ /** Runtime workspace/token registrations invalidated when a session retires. */
23
+ workspaceRegistry?: FactoryWorkspaceRegistry;
24
+ }
25
+ type WorkspaceUnregister = () => Promise<void> | void;
26
+ /** Tracks dynamic Factory workspaces by persisted session id for retirement. */
27
+ export declare class FactoryWorkspaceRegistry {
28
+ #private;
29
+ generation(sessionId: string): number;
30
+ register(sessionId: string, workspaceId: string, generation: number, unregister: WorkspaceUnregister): Promise<boolean>;
31
+ invalidateSession(sessionId: string): Promise<void>;
22
32
  }
23
33
  export declare function createWorkspaceFactory(options?: CreateWorkspaceFactoryOptions): ({ requestContext, mastra, skillExtension }: DynamicWorkspaceContext) => Promise<Workspace<import("@mastra/core/workspace").WorkspaceFilesystem | undefined, import("@mastra/core/workspace").WorkspaceSandbox | undefined, undefined> | Workspace<import("@mastra/core/workspace").LocalFilesystem, LocalSandbox, undefined> | undefined>;
24
34
  export declare const getFactoryWorkspace: ({ requestContext, mastra, skillExtension }: DynamicWorkspaceContext) => Promise<Workspace<import("@mastra/core/workspace").WorkspaceFilesystem | undefined, import("@mastra/core/workspace").WorkspaceSandbox | undefined, undefined> | Workspace<import("@mastra/core/workspace").LocalFilesystem, LocalSandbox, undefined> | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE,OAAO,EAAE,YAAY,EAAoB,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAY9E,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAK7E,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAElE;AAID,eAAO,MAAM,0BAA0B,QAUS,CAAC;AAEjD,eAAO,MAAM,mBAAmB,aAO9B,CAAC;AA+DH,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzE,MAAM,WAAW,6BAA6B;IAC5C,wEAAwE;IACxE,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,gFAAgF;IAChF,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;iEAE6D;IAC7D,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;CAC/D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,6BAAkC,IAiBlE,4CAA4C,uBAAuB,uQAyVlF;AAED,eAAO,MAAM,mBAAmB,+CA3V4B,uBAAuB,sQA2VxB,CAAC"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAKxE,OAAO,EAAE,YAAY,EAAoB,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAc9E,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAK7E,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAElE;AAID,eAAO,MAAM,0BAA0B,QAUS,CAAC;AAEjD,eAAO,MAAM,mBAAmB,aAO9B,CAAC;AA+DH,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzE,MAAM,WAAW,6BAA6B;IAC5C,wEAAwE;IACxE,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,gFAAgF;IAChF,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;iEAE6D;IAC7D,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;IAC9D,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;CAC9C;AAED,KAAK,mBAAmB,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEtD,gFAAgF;AAChF,qBAAa,wBAAwB;;IAInC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI/B,QAAQ,CACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,mBAAmB,GAC9B,OAAO,CAAC,OAAO,CAAC;IAWb,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS1D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,6BAAkC,IAkBlE,4CAA4C,uBAAuB,uQA0XlF;AAED,eAAO,MAAM,mBAAmB,+CA5X4B,uBAAuB,sQA4XxB,CAAC"}
package/dist/workspace.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { getFactoryAuthUserFromContext, getFactoryAuthUserId } from "./auth.js";
2
2
  import { getGithubPat } from "./integrations/github/pat.js";
3
3
  import { registerGithubPatKind, registerGithubTokenInjector } from "./integrations/github/token-refresh.js";
4
- import { MaterializeError, checkoutSessionBranch, materializeRepo, recycleClaimedWorkdir, runWorktreeSetup } from "./integrations/github/sandbox.js";
4
+ import { DEFAULT_COMMAND_TIMEOUT_MS, MaterializeError, checkoutSessionBranch, materializeRepo, recycleClaimedWorkdir, runWorktreeSetup, runWorktreeTeardown } from "./integrations/github/sandbox.js";
5
5
  import { getFactorySessionAddress } from "./rules/binding-context.js";
6
- import { LocalSandbox, LocalSkillSource, Workspace } from "@mastra/core/workspace";
7
6
  import path, { dirname, join } from "path";
7
+ import { LocalSandbox, LocalSkillSource, Workspace } from "@mastra/core/workspace";
8
8
  import { DEFAULT_CONFIG_DIR } from "@mastra/code-sdk/constants";
9
9
  import { SandboxFilesystem } from "@mastra/code-sdk/agents/sandbox-filesystem";
10
10
  import { existsSync } from "fs";
@@ -73,8 +73,35 @@ const factorySkillExtension = {
73
73
  paths: [FACTORY_SKILLS_MOUNT],
74
74
  createSource: (fallback, fallbackSkillRoots) => new FactorySkillSource(fallback, fallbackSkillRoots)
75
75
  };
76
+ /** Tracks dynamic Factory workspaces by persisted session id for retirement. */
77
+ var FactoryWorkspaceRegistry = class {
78
+ #entries = /* @__PURE__ */ new Map();
79
+ #generations = /* @__PURE__ */ new Map();
80
+ generation(sessionId) {
81
+ return this.#generations.get(sessionId) ?? 0;
82
+ }
83
+ async register(sessionId, workspaceId, generation, unregister) {
84
+ if (generation !== this.generation(sessionId)) {
85
+ await unregister();
86
+ return false;
87
+ }
88
+ const entries = this.#entries.get(sessionId) ?? /* @__PURE__ */ new Map();
89
+ entries.set(workspaceId, unregister);
90
+ this.#entries.set(sessionId, entries);
91
+ return true;
92
+ }
93
+ async invalidateSession(sessionId) {
94
+ this.#generations.set(sessionId, this.generation(sessionId) + 1);
95
+ const entries = this.#entries.get(sessionId);
96
+ if (!entries) return;
97
+ this.#entries.delete(sessionId);
98
+ const failure = (await Promise.allSettled([...entries.values()].map((unregister) => unregister()))).find((result) => result.status === "rejected");
99
+ if (failure?.status === "rejected") throw failure.reason;
100
+ }
101
+ };
76
102
  function createWorkspaceFactory(options = {}) {
77
103
  const { sandbox: sandboxConfig, github, fleet, workItems } = options;
104
+ const workspaceRegistry = options.workspaceRegistry ?? new FactoryWorkspaceRegistry();
78
105
  const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;
79
106
  const githubTokenInjectors = /* @__PURE__ */ new Map();
80
107
  const githubTokenReconciliations = /* @__PURE__ */ new Map();
@@ -146,6 +173,7 @@ function createWorkspaceFactory(options = {}) {
146
173
  };
147
174
  const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : "";
148
175
  const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;
176
+ const workspaceGeneration = workspaceRegistry.generation(session.sessionId);
149
177
  const configDir = sandboxConfig.workdir ?? DEFAULT_CONFIG_DIR;
150
178
  const getRepositoryToken = async () => {
151
179
  const token = (await github.versionControl.getRepositoryAccess({
@@ -292,20 +320,34 @@ function createWorkspaceFactory(options = {}) {
292
320
  token,
293
321
  repoFullName
294
322
  });
295
- if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
296
- const registered = {
323
+ if (projectRepository.setupCommand) try {
324
+ await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
325
+ } catch (setupError) {
326
+ if (projectRepository.teardownCommand) try {
327
+ await runWorktreeTeardown(sandbox, workdir, projectRepository.teardownCommand, { timeoutMs: DEFAULT_COMMAND_TIMEOUT_MS });
328
+ } catch (teardownError) {
329
+ console.warn("[Mastra Factory] Worktree teardown after setup failure failed", {
330
+ orgId: session.orgId,
331
+ sessionId: session.sessionId,
332
+ projectRepositoryId: session.projectRepositoryId,
333
+ error: teardownError instanceof Error ? teardownError.message.slice(-2e3) : String(teardownError)
334
+ });
335
+ }
336
+ throw setupError;
337
+ }
338
+ const tokenRegistration = {
297
339
  inject: (freshToken) => {
298
340
  if (!sandbox.setEnvironmentVariable) throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
299
341
  sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
300
- registered.ghToken = freshToken;
342
+ tokenRegistration.ghToken = freshToken;
301
343
  },
302
344
  patKind,
303
345
  ghToken: ghCliToken,
304
346
  generation: 0,
305
347
  tokenReplacementPending: false
306
348
  };
307
- githubTokenInjectors.set(workspaceId, registered);
308
- registerGithubTokenContext(registered);
349
+ githubTokenInjectors.set(workspaceId, tokenRegistration);
350
+ registerGithubTokenContext(tokenRegistration);
309
351
  const filesystem = new SandboxFilesystem({
310
352
  sandbox,
311
353
  workdir
@@ -326,6 +368,10 @@ function createWorkspaceFactory(options = {}) {
326
368
  skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
327
369
  });
328
370
  mastra?.addWorkspace(workspace, workspaceId, { source: "mastra" });
371
+ if (!await workspaceRegistry.register(session.sessionId, workspaceId, workspaceGeneration, async () => {
372
+ githubTokenInjectors.delete(workspaceId);
373
+ await mastra?.removeWorkspace?.(workspaceId);
374
+ })) throw new Error(`Factory session ${session.sessionId} was retired during workspace materialization`);
329
375
  return workspace;
330
376
  };
331
377
  const inflight = inflightMaterializations.get(workspaceId);
@@ -341,6 +387,6 @@ function createWorkspaceFactory(options = {}) {
341
387
  }
342
388
  const getFactoryWorkspace = createWorkspaceFactory();
343
389
  //#endregion
344
- export { FACTORY_SKILLS_SOURCE_PATH, FACTORY_SKILL_NAMES, checkpointNameForSession, createWorkspaceFactory, getFactoryWorkspace };
390
+ export { FACTORY_SKILLS_SOURCE_PATH, FACTORY_SKILL_NAMES, FactoryWorkspaceRegistry, checkpointNameForSession, createWorkspaceFactory, getFactoryWorkspace };
345
391
 
346
392
  //# sourceMappingURL=workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.js","names":["#factorySource","#fallbackSkillRoots","#isFactoryPath","#factoryPath"],"sources":["../src/workspace.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport path, { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { SandboxFilesystem } from '@mastra/code-sdk/agents/sandbox-filesystem';\nimport { MASTRACODE_WORKSPACE_TOOLS } from '@mastra/code-sdk/agents/tool-availability';\nimport { getDynamicWorkspace } from '@mastra/code-sdk/agents/workspace';\nimport type { WorkspaceSkillExtension } from '@mastra/code-sdk/agents/workspace';\nimport { DEFAULT_CONFIG_DIR } from '@mastra/code-sdk/constants';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { LocalSandbox, LocalSkillSource, Workspace } from '@mastra/core/workspace';\nimport type { SkillSource, SkillSourceEntry, SkillSourceStat } from '@mastra/core/workspace';\nimport { getFactoryAuthUserFromContext, getFactoryAuthUserId } from './auth.js';\nimport type { MastraFactorySandboxConfig } from './factory.js';\nimport type { GithubIntegration } from './integrations/github/integration.js';\nimport { getGithubPat } from './integrations/github/pat.js';\nimport type { GithubPatKind } from './integrations/github/pat.js';\nimport {\n checkoutSessionBranch,\n MaterializeError,\n materializeRepo,\n recycleClaimedWorkdir,\n runWorktreeSetup,\n} from './integrations/github/sandbox.js';\nimport { registerGithubPatKind, registerGithubTokenInjector } from './integrations/github/token-refresh.js';\nimport { getFactorySessionAddress } from './rules/binding-context.js';\nimport type { SandboxBindingStore, SandboxFleet } from './sandbox/fleet.js';\nimport type { WorkItemsStorage } from './storage/domains/work-items/base.js';\n\nconst WORKSPACE_ID_PREFIX = 'mfw';\nconst SESSION_CHECKPOINT_PREFIX = 'mastracode-session';\n\nexport function checkpointNameForSession(sessionId: string): string {\n return `${SESSION_CHECKPOINT_PREFIX}-${sessionId}`;\n}\n\nconst bundleDirectory = dirname(fileURLToPath(import.meta.url));\nconst bundledFactorySkillsPath = join(bundleDirectory, 'factory-skills');\nexport const FACTORY_SKILLS_SOURCE_PATH =\n [\n // Deploy bundle: the consumer copies `factory-skills/` next to the built\n // server module (e.g. via its public/ dir).\n bundledFactorySkillsPath,\n // Package layout: `dist/../factory-skills` (also `src/../factory-skills`\n // when running tests against sources).\n join(bundleDirectory, '..', 'factory-skills'),\n // Consumer repo running from its package root before a build.\n join(process.cwd(), 'src', 'mastra', 'public', 'factory-skills'),\n ].find(existsSync) ?? bundledFactorySkillsPath;\nconst FACTORY_SKILLS_MOUNT = path.resolve(path.parse(process.cwd()).root, '__mastracode_factory_skills__');\nexport const FACTORY_SKILL_NAMES = new Set([\n 'configure-factory-rules',\n 'factory-complete-issue',\n 'factory-plan',\n 'factory-rereview',\n 'factory-review',\n 'factory-triage',\n]);\n\nclass FactorySkillSource implements SkillSource {\n readonly #factorySource = new LocalSkillSource({ basePath: FACTORY_SKILLS_SOURCE_PATH });\n readonly #fallbackSkillRoots: Set<string>;\n\n constructor(\n readonly fallback: SkillSource,\n fallbackSkillRoots: string[],\n ) {\n this.#fallbackSkillRoots = new Set(fallbackSkillRoots.map(skillPath => path.normalize(skillPath)));\n }\n\n #isFactoryPath(skillPath: string): boolean {\n const normalized = path.normalize(skillPath);\n return normalized === FACTORY_SKILLS_MOUNT || normalized.startsWith(`${FACTORY_SKILLS_MOUNT}${path.sep}`);\n }\n\n #factoryPath(skillPath: string): string {\n return path.relative(FACTORY_SKILLS_MOUNT, path.normalize(skillPath));\n }\n\n exists(skillPath: string): Promise<boolean> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.exists(this.#factoryPath(skillPath))\n : this.fallback.exists(skillPath);\n }\n\n stat(skillPath: string): Promise<SkillSourceStat> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.stat(this.#factoryPath(skillPath))\n : this.fallback.stat(skillPath);\n }\n\n readFile(skillPath: string): Promise<string | Buffer> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.readFile(this.#factoryPath(skillPath))\n : this.fallback.readFile(skillPath);\n }\n\n async readdir(skillPath: string): Promise<SkillSourceEntry[]> {\n if (this.#isFactoryPath(skillPath)) {\n return this.#factorySource.readdir(this.#factoryPath(skillPath));\n }\n const entries = await this.fallback.readdir(skillPath);\n if (this.#fallbackSkillRoots.has(path.normalize(skillPath))) {\n return entries.filter(entry => !FACTORY_SKILL_NAMES.has(entry.name));\n }\n return entries;\n }\n\n realpath(skillPath: string): Promise<string> {\n if (this.#isFactoryPath(skillPath)) return Promise.resolve(path.normalize(skillPath));\n return this.fallback.realpath ? this.fallback.realpath(skillPath) : Promise.resolve(skillPath);\n }\n}\n\nconst factorySkillExtension: WorkspaceSkillExtension = {\n id: 'web-factory',\n paths: [FACTORY_SKILLS_MOUNT],\n createSource: (fallback, fallbackSkillRoots) => new FactorySkillSource(fallback, fallbackSkillRoots),\n};\n\ntype DynamicWorkspaceContext = Parameters<typeof getDynamicWorkspace>[0];\n\nexport interface CreateWorkspaceFactoryOptions {\n /** Factory sandbox runtime config (template machine + workdir base). */\n sandbox?: MastraFactorySandboxConfig;\n /** GitHub integration used to resolve Factory sessions and mint repo tokens. */\n github?: GithubIntegration;\n /** Fleet the per-session sandboxes are provisioned/reattached through. */\n fleet?: SandboxFleet;\n /** Work-items storage used to resolve the session's run-binding role, so\n * review-board sessions get the reviewer PAT as `GH_TOKEN`. Optional —\n * without it every session uses the default (worker) PAT. */\n workItems?: Pick<WorkItemsStorage, 'findRunBindingBySession'>;\n}\n\nexport function createWorkspaceFactory(options: CreateWorkspaceFactoryOptions = {}) {\n const { sandbox: sandboxConfig, github, fleet, workItems } = options;\n const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;\n type GithubTokenRegistration = {\n inject: (token: string) => void;\n patKind: GithubPatKind;\n ghToken: string;\n generation: number;\n tokenReplacementPending: boolean;\n };\n const githubTokenInjectors = new Map<string, GithubTokenRegistration>();\n const githubTokenReconciliations = new Map<string, Promise<void>>();\n // Concurrent requests for the same session (thread list + activity polling +\n // chat) must not each provision a sandbox and clone the repository. The\n // first caller materializes; followers await the same promise.\n const inflightMaterializations = new Map<string, Promise<Workspace>>();\n\n return async ({ requestContext, mastra, skillExtension }: DynamicWorkspaceContext) => {\n const effectiveSkillExtension = skillExtension ?? factorySkillExtension;\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeState> | undefined;\n const session =\n ctx?.resourceId && github ? await github.sourceControlStorage.sessions.getBySessionId(ctx.resourceId) : null;\n\n if (!session) {\n if (sandboxConfig && !isLocalSandbox) {\n // Chat-only session on a remote-sandbox deploy: there is no repository\n // to materialize, and the server host must never execute commands on a\n // shared deployment. Run the session without a workspace (chat works,\n // workspace tools are simply not registered) instead of erroring on\n // every message.\n return undefined;\n }\n return getDynamicWorkspace({ requestContext, mastra, skillExtension: effectiveSkillExtension });\n }\n\n const user = getFactoryAuthUserFromContext(requestContext);\n const userId = getFactoryAuthUserId(user);\n // No identity at all is a server-side caller that forgot to seed one\n // (webhook, cron), not someone reaching for another user's session.\n if (!user?.organizationId || !userId) {\n throw new Error(`Factory session ${session.sessionId} was resolved without a caller identity`);\n }\n if (user.organizationId !== session.orgId || userId !== session.userId) {\n throw new Error(`Factory session ${session.sessionId} is not available to the current user`);\n }\n if (!sandboxConfig || !github || !fleet) {\n throw new Error('GitHub and sandbox providers are required to create a Factory session workspace');\n }\n\n const storage = github.sourceControlStorage;\n const projectRepository = await storage.projectRepositories.get({\n orgId: session.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error(`Repository link ${session.projectRepositoryId} was not found`);\n const connection = await storage.connections.get({ orgId: session.orgId, id: projectRepository.connectionId });\n const repository = await storage.repositories.get({ orgId: session.orgId, id: projectRepository.repositoryId });\n if (!connection || !repository) throw new Error(`Repository link ${session.projectRepositoryId} is incomplete`);\n const installation = await storage.installations.get({ orgId: session.orgId, id: connection.installationId });\n if (!installation) throw new Error(`GitHub installation ${connection.installationId} was not found`);\n const repoFullName = repository.slug;\n\n let workdir = isLocalSandbox\n ? fleet.computeLocalSessionWorkdir(repoFullName, session.id)\n : (session.sandboxWorkdir ?? projectRepository.sandboxWorkdir);\n // The system prompt derives its working directory from `state.projectPath`\n // and falls back to the server's own process.cwd() when unset — which\n // points the agent at the host checkout (and lets it run `git checkout`\n // there instead of in its session workdir). Pin it to the session workdir.\n // During createSession this seeds the session's initial state (the\n // workspace resolves before the session is built); on later requests it\n // self-heals live state.\n if (ctx && workdir && ctx.getState()?.projectPath !== workdir) {\n await ctx.setState({ projectPath: workdir, projectName: repoFullName });\n }\n const binding: SandboxBindingStore = {\n // Read through to the session row so teardown after a fresh provision\n // sees the just-persisted id instead of a stale snapshot.\n get sandboxId() {\n return session.sandboxId;\n },\n checkpointName: checkpointNameForSession(session.id),\n setSandboxId: async id => {\n await storage.sessions.setSandbox({ id: session.id, sandboxId: id, sandboxWorkdir: workdir });\n session.sandboxId = id;\n session.sandboxWorkdir = workdir;\n },\n clear: async () => {\n await storage.sessions.setSandbox({ id: session.id, sandboxId: null, sandboxWorkdir: workdir });\n session.sandboxId = null;\n },\n };\n\n const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;\n const configDir = sandboxConfig.workdir ?? DEFAULT_CONFIG_DIR;\n\n const getRepositoryToken = async (): Promise<string> => {\n const access = await github.versionControl.getRepositoryAccess({\n orgId: session.orgId,\n repositoryId: repository.id,\n });\n const token = access.authorization?.token;\n if (!token) throw new Error('Repository access did not include a bearer token for the Factory session');\n return token;\n };\n const resolveGithubPatKind = async (fallback: GithubPatKind): Promise<GithubPatKind> => {\n if (!workItems) return 'default';\n try {\n const address = getFactorySessionAddress(requestContext);\n const runBinding = address ? await workItems.findRunBindingBySession(address) : null;\n return runBinding?.role === 'review' && runBinding.status === 'active' && runBinding.orgId === session.orgId\n ? 'reviewer'\n : 'default';\n } catch {\n // Preserve the installed role when binding storage is temporarily unavailable.\n return fallback;\n }\n };\n const registerGithubTokenContext = (registered: GithubTokenRegistration): void => {\n const generation = registered.generation;\n registerGithubTokenInjector(requestContext, token => {\n if (githubTokenInjectors.get(workspaceId) !== registered || registered.generation !== generation) {\n throw new Error('GitHub token refresh no longer matches the active Factory workspace role.');\n }\n registered.inject(token);\n });\n registerGithubPatKind(requestContext, registered.patKind);\n };\n const reconcileGithubToken = async (): Promise<void> => {\n const previous = githubTokenReconciliations.get(workspaceId) ?? Promise.resolve();\n const reconciliation = previous\n .catch(() => {})\n .then(async () => {\n const registered = githubTokenInjectors.get(workspaceId);\n if (!registered) return;\n\n const previousPatKind = registered.patKind;\n const patKind = await resolveGithubPatKind(previousPatKind);\n if (githubTokenInjectors.get(workspaceId) !== registered) return;\n\n if (patKind !== previousPatKind) {\n registered.patKind = patKind;\n registered.generation += 1;\n }\n if (patKind === 'reviewer') registered.tokenReplacementPending = false;\n if (previousPatKind === 'reviewer' && patKind === 'default') {\n // Invalidate reviewer refresh contexts before replacement I/O so\n // they cannot restore reviewer credentials after a failed downgrade.\n registered.tokenReplacementPending = true;\n }\n\n let token = await getGithubPat(() => github.integrationStorage, session.orgId, patKind);\n if (!token && registered.tokenReplacementPending) token = await getRepositoryToken();\n if (githubTokenInjectors.get(workspaceId) !== registered) return;\n\n if (token && token !== registered.ghToken) {\n try {\n registered.inject(token);\n } catch (error) {\n if (registered.tokenReplacementPending) throw error;\n // Same-role rotations and reviewer upgrades remain best-effort.\n }\n }\n if (token && token === registered.ghToken) registered.tokenReplacementPending = false;\n registerGithubTokenContext(registered);\n });\n githubTokenReconciliations.set(workspaceId, reconciliation);\n try {\n await reconciliation;\n } finally {\n if (githubTokenReconciliations.get(workspaceId) === reconciliation) {\n githubTokenReconciliations.delete(workspaceId);\n }\n }\n };\n const reconcileRegisteredWorkspace = async (workspace: Workspace): Promise<Workspace> => {\n const registered = githubTokenInjectors.get(workspaceId);\n try {\n await reconcileGithubToken();\n } catch (error) {\n if (registered?.tokenReplacementPending && githubTokenInjectors.get(workspaceId) === registered) {\n // The role generation already invalidated reviewer refresh contexts.\n // Keep the pending registration so failed eviction cannot make a\n // still-live reviewer workspace look safe on the next reuse.\n let evicted = false;\n try {\n evicted = (await mastra?.removeWorkspace?.(workspaceId)) === true;\n } catch {\n // Preserve the credential-replacement error and retry on the next reuse.\n }\n try {\n await workspace.destroy();\n evicted = true;\n } catch {\n // The pending registration keeps the workspace quarantined if cleanup also fails.\n }\n if (evicted && githubTokenInjectors.get(workspaceId) === registered) {\n githubTokenInjectors.delete(workspaceId);\n }\n }\n throw error;\n }\n if (registered && githubTokenInjectors.get(workspaceId) !== registered) {\n throw new Error('Factory workspace GitHub credential registration is no longer active.');\n }\n return workspace;\n };\n\n let existing: Workspace | undefined;\n try {\n existing = mastra?.getWorkspaceById(workspaceId) as Workspace | undefined;\n existing?.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);\n } catch {\n // Not registered yet.\n existing = undefined;\n }\n if (existing) {\n return reconcileRegisteredWorkspace(existing);\n }\n\n const materialize = async (): Promise<Workspace> => {\n // A terminal work item or a deleted session may have returned a\n // still-warm VM — with this repository already cloned — to the reuse\n // pool. Adopt it before provisioning a fresh sandbox. Pooled VMs carry\n // no credentials (tokens are injected per command, and the workdir is\n // scrubbed on release and again below), so any user's session for this\n // repository can claim one.\n let claimedPooledSandbox = false;\n if (!isLocalSandbox && !session.sandboxId) {\n const pooled = await storage.sandboxPool.claim({\n projectRepositoryId: session.projectRepositoryId,\n });\n if (pooled) {\n await storage.sessions.setSandbox({\n id: session.id,\n sandboxId: pooled.sandboxId,\n sandboxWorkdir: pooled.sandboxWorkdir,\n });\n session.sandboxId = pooled.sandboxId;\n session.sandboxWorkdir = pooled.sandboxWorkdir;\n workdir = pooled.sandboxWorkdir;\n claimedPooledSandbox = true;\n }\n }\n\n const token = await getRepositoryToken();\n\n // The `gh` CLI needs a PAT when the org configured one (installation\n // tokens 403 on integration-restricted endpoints); git clone/checkout\n // below keep using the minted installation token. Review-board sessions\n // (run-binding role `review`) authenticate `gh` as the reviewer account\n // when a reviewer token is configured; everything else — including\n // sessions with no resolvable run binding — uses the worker token.\n const patKind = await resolveGithubPatKind('default');\n const ghCliToken = (await getGithubPat(() => github.integrationStorage, session.orgId, patKind)) ?? token;\n\n const ensureSandbox = () =>\n fleet.ensureSandbox(binding, { GH_TOKEN: ghCliToken }, undefined, {\n ...(isLocalSandbox ? { workingDirectory: workdir } : {}),\n actingUserId: userId,\n });\n const runMaterialize = (target: Awaited<ReturnType<typeof ensureSandbox>>) =>\n materializeRepo({\n row: { id: session.id, sandboxWorkdir: workdir, materializedAt: session.materializedAt },\n repoInfo: { repoFullName: repoFullName, defaultBranch: repository.defaultBranch },\n sandbox: target,\n token,\n storage: storage.sessions,\n });\n const isGitMissing = (error: unknown) => error instanceof MaterializeError && error.code === 'git-missing';\n\n let sandbox = await ensureSandbox();\n // A claimed VM still has the previous session's branch checked out —\n // reset it to the default branch before materialize/checkout. When the\n // pooled VM was already reaped, `ensureSandbox` provisioned fresh and\n // the recycle is a no-op (no checkout on disk yet).\n if (claimedPooledSandbox) await recycleClaimedWorkdir(sandbox, workdir, repository.defaultBranch);\n try {\n await runMaterialize(sandbox);\n } catch (error) {\n if (!isGitMissing(error)) throw error;\n // A sandbox without git was booted from a bare base image (e.g. the\n // platform proxy falls back to a clean Debian base when its template\n // build fails). That VM can never materialize a repo, and its id is\n // already persisted on the binding — tear it down so re-opens stop\n // reattaching to the poisoned sandbox, then retry once on a fresh VM.\n await fleet.teardownSandbox(binding, sandbox);\n sandbox = await ensureSandbox();\n try {\n await runMaterialize(sandbox);\n } catch (retryError) {\n // Still bare — the provider's template is persistently broken.\n // Clear the binding so a later manual retry provisions fresh.\n if (isGitMissing(retryError)) await fleet.teardownSandbox(binding, sandbox);\n throw retryError;\n }\n }\n await checkoutSessionBranch(sandbox, workdir, {\n branch: session.branch,\n baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,\n token,\n repoFullName: repoFullName,\n });\n if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);\n\n const registered: GithubTokenRegistration = {\n inject: freshToken => {\n if (!sandbox.setEnvironmentVariable) {\n throw new Error('The active sandbox provider does not support runtime GitHub token refresh.');\n }\n sandbox.setEnvironmentVariable('GH_TOKEN', freshToken);\n registered.ghToken = freshToken;\n },\n patKind,\n ghToken: ghCliToken,\n generation: 0,\n tokenReplacementPending: false,\n };\n githubTokenInjectors.set(workspaceId, registered);\n registerGithubTokenContext(registered);\n\n const filesystem = new SandboxFilesystem({ sandbox, workdir });\n const projectSkillPaths = [path.join(configDir, 'skills'), '.claude/skills', '.agents/skills'];\n const skillPaths = [...(effectiveSkillExtension?.paths ?? []), ...projectSkillPaths];\n const workspace = new Workspace({\n id: workspaceId,\n name: 'Mastra Code Factory Session Workspace',\n filesystem,\n sandbox: sandbox as unknown as ConstructorParameters<typeof Workspace>[0]['sandbox'],\n tools: MASTRACODE_WORKSPACE_TOOLS,\n skills: skillPaths,\n skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem,\n });\n // Register with the Mastra instance so sync HTTP handlers that resolve\n // the workspace via `mastra.getWorkspaceById(id)` (file tree, permissions\n // probe, MCP/tool routes) find it instead of throwing\n // `MASTRA_GET_WORKSPACE_BY_ID_NOT_FOUND`. `addWorkspace` is idempotent on\n // key collision, so the inflight coalescing and reuse paths above stay\n // race-safe. Registration happens synchronously with the return so a\n // concurrent lookup on another request cannot observe an unregistered\n // workspace.\n mastra?.addWorkspace(workspace, workspaceId, { source: 'mastra' });\n return workspace;\n };\n\n // Dedupe concurrent materializations of the same workspace: followers\n // await the leader's promise instead of provisioning a second sandbox,\n // then bind the shared token injector into their own request context.\n const inflight = inflightMaterializations.get(workspaceId);\n if (inflight) {\n const workspace = await inflight;\n return reconcileRegisteredWorkspace(workspace);\n }\n const materialization = materialize();\n inflightMaterializations.set(workspaceId, materialization);\n try {\n return await materialization;\n } finally {\n inflightMaterializations.delete(workspaceId);\n }\n };\n}\n\nexport const getFactoryWorkspace = createWorkspaceFactory();\n"],"mappings":"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"}
1
+ {"version":3,"file":"workspace.js","names":["#factorySource","#fallbackSkillRoots","#isFactoryPath","#factoryPath","#entries","#generations"],"sources":["../src/workspace.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport path, { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { SandboxFilesystem } from '@mastra/code-sdk/agents/sandbox-filesystem';\nimport { MASTRACODE_WORKSPACE_TOOLS } from '@mastra/code-sdk/agents/tool-availability';\nimport { getDynamicWorkspace } from '@mastra/code-sdk/agents/workspace';\nimport type { WorkspaceSkillExtension } from '@mastra/code-sdk/agents/workspace';\nimport { DEFAULT_CONFIG_DIR } from '@mastra/code-sdk/constants';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { LocalSandbox, LocalSkillSource, Workspace } from '@mastra/core/workspace';\nimport type { SkillSource, SkillSourceEntry, SkillSourceStat } from '@mastra/core/workspace';\nimport { getFactoryAuthUserFromContext, getFactoryAuthUserId } from './auth.js';\nimport type { MastraFactorySandboxConfig } from './factory.js';\nimport type { GithubIntegration } from './integrations/github/integration.js';\nimport { getGithubPat } from './integrations/github/pat.js';\nimport type { GithubPatKind } from './integrations/github/pat.js';\nimport {\n checkoutSessionBranch,\n DEFAULT_COMMAND_TIMEOUT_MS,\n MaterializeError,\n materializeRepo,\n recycleClaimedWorkdir,\n runWorktreeSetup,\n runWorktreeTeardown,\n} from './integrations/github/sandbox.js';\nimport { registerGithubPatKind, registerGithubTokenInjector } from './integrations/github/token-refresh.js';\nimport { getFactorySessionAddress } from './rules/binding-context.js';\nimport type { SandboxBindingStore, SandboxFleet } from './sandbox/fleet.js';\nimport type { WorkItemsStorage } from './storage/domains/work-items/base.js';\n\nconst WORKSPACE_ID_PREFIX = 'mfw';\nconst SESSION_CHECKPOINT_PREFIX = 'mastracode-session';\n\nexport function checkpointNameForSession(sessionId: string): string {\n return `${SESSION_CHECKPOINT_PREFIX}-${sessionId}`;\n}\n\nconst bundleDirectory = dirname(fileURLToPath(import.meta.url));\nconst bundledFactorySkillsPath = join(bundleDirectory, 'factory-skills');\nexport const FACTORY_SKILLS_SOURCE_PATH =\n [\n // Deploy bundle: the consumer copies `factory-skills/` next to the built\n // server module (e.g. via its public/ dir).\n bundledFactorySkillsPath,\n // Package layout: `dist/../factory-skills` (also `src/../factory-skills`\n // when running tests against sources).\n join(bundleDirectory, '..', 'factory-skills'),\n // Consumer repo running from its package root before a build.\n join(process.cwd(), 'src', 'mastra', 'public', 'factory-skills'),\n ].find(existsSync) ?? bundledFactorySkillsPath;\nconst FACTORY_SKILLS_MOUNT = path.resolve(path.parse(process.cwd()).root, '__mastracode_factory_skills__');\nexport const FACTORY_SKILL_NAMES = new Set([\n 'configure-factory-rules',\n 'factory-complete-issue',\n 'factory-plan',\n 'factory-rereview',\n 'factory-review',\n 'factory-triage',\n]);\n\nclass FactorySkillSource implements SkillSource {\n readonly #factorySource = new LocalSkillSource({ basePath: FACTORY_SKILLS_SOURCE_PATH });\n readonly #fallbackSkillRoots: Set<string>;\n\n constructor(\n readonly fallback: SkillSource,\n fallbackSkillRoots: string[],\n ) {\n this.#fallbackSkillRoots = new Set(fallbackSkillRoots.map(skillPath => path.normalize(skillPath)));\n }\n\n #isFactoryPath(skillPath: string): boolean {\n const normalized = path.normalize(skillPath);\n return normalized === FACTORY_SKILLS_MOUNT || normalized.startsWith(`${FACTORY_SKILLS_MOUNT}${path.sep}`);\n }\n\n #factoryPath(skillPath: string): string {\n return path.relative(FACTORY_SKILLS_MOUNT, path.normalize(skillPath));\n }\n\n exists(skillPath: string): Promise<boolean> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.exists(this.#factoryPath(skillPath))\n : this.fallback.exists(skillPath);\n }\n\n stat(skillPath: string): Promise<SkillSourceStat> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.stat(this.#factoryPath(skillPath))\n : this.fallback.stat(skillPath);\n }\n\n readFile(skillPath: string): Promise<string | Buffer> {\n return this.#isFactoryPath(skillPath)\n ? this.#factorySource.readFile(this.#factoryPath(skillPath))\n : this.fallback.readFile(skillPath);\n }\n\n async readdir(skillPath: string): Promise<SkillSourceEntry[]> {\n if (this.#isFactoryPath(skillPath)) {\n return this.#factorySource.readdir(this.#factoryPath(skillPath));\n }\n const entries = await this.fallback.readdir(skillPath);\n if (this.#fallbackSkillRoots.has(path.normalize(skillPath))) {\n return entries.filter(entry => !FACTORY_SKILL_NAMES.has(entry.name));\n }\n return entries;\n }\n\n realpath(skillPath: string): Promise<string> {\n if (this.#isFactoryPath(skillPath)) return Promise.resolve(path.normalize(skillPath));\n return this.fallback.realpath ? this.fallback.realpath(skillPath) : Promise.resolve(skillPath);\n }\n}\n\nconst factorySkillExtension: WorkspaceSkillExtension = {\n id: 'web-factory',\n paths: [FACTORY_SKILLS_MOUNT],\n createSource: (fallback, fallbackSkillRoots) => new FactorySkillSource(fallback, fallbackSkillRoots),\n};\n\ntype DynamicWorkspaceContext = Parameters<typeof getDynamicWorkspace>[0];\n\nexport interface CreateWorkspaceFactoryOptions {\n /** Factory sandbox runtime config (template machine + workdir base). */\n sandbox?: MastraFactorySandboxConfig;\n /** GitHub integration used to resolve Factory sessions and mint repo tokens. */\n github?: GithubIntegration;\n /** Fleet the per-session sandboxes are provisioned/reattached through. */\n fleet?: SandboxFleet;\n /** Work-items storage used to resolve the session's run-binding role, so\n * review-board sessions get the reviewer PAT as `GH_TOKEN`. Optional —\n * without it every session uses the default (worker) PAT. */\n workItems?: Pick<WorkItemsStorage, 'findRunBindingBySession'>;\n /** Runtime workspace/token registrations invalidated when a session retires. */\n workspaceRegistry?: FactoryWorkspaceRegistry;\n}\n\ntype WorkspaceUnregister = () => Promise<void> | void;\n\n/** Tracks dynamic Factory workspaces by persisted session id for retirement. */\nexport class FactoryWorkspaceRegistry {\n readonly #entries = new Map<string, Map<string, WorkspaceUnregister>>();\n readonly #generations = new Map<string, number>();\n\n generation(sessionId: string): number {\n return this.#generations.get(sessionId) ?? 0;\n }\n\n async register(\n sessionId: string,\n workspaceId: string,\n generation: number,\n unregister: WorkspaceUnregister,\n ): Promise<boolean> {\n if (generation !== this.generation(sessionId)) {\n await unregister();\n return false;\n }\n const entries = this.#entries.get(sessionId) ?? new Map<string, WorkspaceUnregister>();\n entries.set(workspaceId, unregister);\n this.#entries.set(sessionId, entries);\n return true;\n }\n\n async invalidateSession(sessionId: string): Promise<void> {\n this.#generations.set(sessionId, this.generation(sessionId) + 1);\n const entries = this.#entries.get(sessionId);\n if (!entries) return;\n this.#entries.delete(sessionId);\n const results = await Promise.allSettled([...entries.values()].map(unregister => unregister()));\n const failure = results.find(result => result.status === 'rejected');\n if (failure?.status === 'rejected') throw failure.reason;\n }\n}\n\nexport function createWorkspaceFactory(options: CreateWorkspaceFactoryOptions = {}) {\n const { sandbox: sandboxConfig, github, fleet, workItems } = options;\n const workspaceRegistry = options.workspaceRegistry ?? new FactoryWorkspaceRegistry();\n const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;\n type GithubTokenRegistration = {\n inject: (token: string) => void;\n patKind: GithubPatKind;\n ghToken: string;\n generation: number;\n tokenReplacementPending: boolean;\n };\n const githubTokenInjectors = new Map<string, GithubTokenRegistration>();\n const githubTokenReconciliations = new Map<string, Promise<void>>();\n // Concurrent requests for the same session (thread list + activity polling +\n // chat) must not each provision a sandbox and clone the repository. The\n // first caller materializes; followers await the same promise.\n const inflightMaterializations = new Map<string, Promise<Workspace>>();\n\n return async ({ requestContext, mastra, skillExtension }: DynamicWorkspaceContext) => {\n const effectiveSkillExtension = skillExtension ?? factorySkillExtension;\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeState> | undefined;\n const session =\n ctx?.resourceId && github ? await github.sourceControlStorage.sessions.getBySessionId(ctx.resourceId) : null;\n\n if (!session) {\n if (sandboxConfig && !isLocalSandbox) {\n // Chat-only session on a remote-sandbox deploy: there is no repository\n // to materialize, and the server host must never execute commands on a\n // shared deployment. Run the session without a workspace (chat works,\n // workspace tools are simply not registered) instead of erroring on\n // every message.\n return undefined;\n }\n return getDynamicWorkspace({ requestContext, mastra, skillExtension: effectiveSkillExtension });\n }\n\n const user = getFactoryAuthUserFromContext(requestContext);\n const userId = getFactoryAuthUserId(user);\n // No identity at all is a server-side caller that forgot to seed one\n // (webhook, cron), not someone reaching for another user's session.\n if (!user?.organizationId || !userId) {\n throw new Error(`Factory session ${session.sessionId} was resolved without a caller identity`);\n }\n if (user.organizationId !== session.orgId || userId !== session.userId) {\n throw new Error(`Factory session ${session.sessionId} is not available to the current user`);\n }\n if (!sandboxConfig || !github || !fleet) {\n throw new Error('GitHub and sandbox providers are required to create a Factory session workspace');\n }\n\n const storage = github.sourceControlStorage;\n const projectRepository = await storage.projectRepositories.get({\n orgId: session.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error(`Repository link ${session.projectRepositoryId} was not found`);\n const connection = await storage.connections.get({ orgId: session.orgId, id: projectRepository.connectionId });\n const repository = await storage.repositories.get({ orgId: session.orgId, id: projectRepository.repositoryId });\n if (!connection || !repository) throw new Error(`Repository link ${session.projectRepositoryId} is incomplete`);\n const installation = await storage.installations.get({ orgId: session.orgId, id: connection.installationId });\n if (!installation) throw new Error(`GitHub installation ${connection.installationId} was not found`);\n const repoFullName = repository.slug;\n\n let workdir = isLocalSandbox\n ? fleet.computeLocalSessionWorkdir(repoFullName, session.id)\n : (session.sandboxWorkdir ?? projectRepository.sandboxWorkdir);\n // The system prompt derives its working directory from `state.projectPath`\n // and falls back to the server's own process.cwd() when unset — which\n // points the agent at the host checkout (and lets it run `git checkout`\n // there instead of in its session workdir). Pin it to the session workdir.\n // During createSession this seeds the session's initial state (the\n // workspace resolves before the session is built); on later requests it\n // self-heals live state.\n if (ctx && workdir && ctx.getState()?.projectPath !== workdir) {\n await ctx.setState({ projectPath: workdir, projectName: repoFullName });\n }\n const binding: SandboxBindingStore = {\n // Read through to the session row so teardown after a fresh provision\n // sees the just-persisted id instead of a stale snapshot.\n get sandboxId() {\n return session.sandboxId;\n },\n checkpointName: checkpointNameForSession(session.id),\n setSandboxId: async id => {\n await storage.sessions.setSandbox({ id: session.id, sandboxId: id, sandboxWorkdir: workdir });\n session.sandboxId = id;\n session.sandboxWorkdir = workdir;\n },\n clear: async () => {\n await storage.sessions.setSandbox({ id: session.id, sandboxId: null, sandboxWorkdir: workdir });\n session.sandboxId = null;\n },\n };\n\n const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;\n const workspaceGeneration = workspaceRegistry.generation(session.sessionId);\n const configDir = sandboxConfig.workdir ?? DEFAULT_CONFIG_DIR;\n\n const getRepositoryToken = async (): Promise<string> => {\n const access = await github.versionControl.getRepositoryAccess({\n orgId: session.orgId,\n repositoryId: repository.id,\n });\n const token = access.authorization?.token;\n if (!token) throw new Error('Repository access did not include a bearer token for the Factory session');\n return token;\n };\n const resolveGithubPatKind = async (fallback: GithubPatKind): Promise<GithubPatKind> => {\n if (!workItems) return 'default';\n try {\n const address = getFactorySessionAddress(requestContext);\n const runBinding = address ? await workItems.findRunBindingBySession(address) : null;\n return runBinding?.role === 'review' && runBinding.status === 'active' && runBinding.orgId === session.orgId\n ? 'reviewer'\n : 'default';\n } catch {\n // Preserve the installed role when binding storage is temporarily unavailable.\n return fallback;\n }\n };\n const registerGithubTokenContext = (registered: GithubTokenRegistration): void => {\n const generation = registered.generation;\n registerGithubTokenInjector(requestContext, token => {\n if (githubTokenInjectors.get(workspaceId) !== registered || registered.generation !== generation) {\n throw new Error('GitHub token refresh no longer matches the active Factory workspace role.');\n }\n registered.inject(token);\n });\n registerGithubPatKind(requestContext, registered.patKind);\n };\n const reconcileGithubToken = async (): Promise<void> => {\n const previous = githubTokenReconciliations.get(workspaceId) ?? Promise.resolve();\n const reconciliation = previous\n .catch(() => {})\n .then(async () => {\n const registered = githubTokenInjectors.get(workspaceId);\n if (!registered) return;\n\n const previousPatKind = registered.patKind;\n const patKind = await resolveGithubPatKind(previousPatKind);\n if (githubTokenInjectors.get(workspaceId) !== registered) return;\n\n if (patKind !== previousPatKind) {\n registered.patKind = patKind;\n registered.generation += 1;\n }\n if (patKind === 'reviewer') registered.tokenReplacementPending = false;\n if (previousPatKind === 'reviewer' && patKind === 'default') {\n // Invalidate reviewer refresh contexts before replacement I/O so\n // they cannot restore reviewer credentials after a failed downgrade.\n registered.tokenReplacementPending = true;\n }\n\n let token = await getGithubPat(() => github.integrationStorage, session.orgId, patKind);\n if (!token && registered.tokenReplacementPending) token = await getRepositoryToken();\n if (githubTokenInjectors.get(workspaceId) !== registered) return;\n\n if (token && token !== registered.ghToken) {\n try {\n registered.inject(token);\n } catch (error) {\n if (registered.tokenReplacementPending) throw error;\n // Same-role rotations and reviewer upgrades remain best-effort.\n }\n }\n if (token && token === registered.ghToken) registered.tokenReplacementPending = false;\n registerGithubTokenContext(registered);\n });\n githubTokenReconciliations.set(workspaceId, reconciliation);\n try {\n await reconciliation;\n } finally {\n if (githubTokenReconciliations.get(workspaceId) === reconciliation) {\n githubTokenReconciliations.delete(workspaceId);\n }\n }\n };\n const reconcileRegisteredWorkspace = async (workspace: Workspace): Promise<Workspace> => {\n const registered = githubTokenInjectors.get(workspaceId);\n try {\n await reconcileGithubToken();\n } catch (error) {\n if (registered?.tokenReplacementPending && githubTokenInjectors.get(workspaceId) === registered) {\n // The role generation already invalidated reviewer refresh contexts.\n // Keep the pending registration so failed eviction cannot make a\n // still-live reviewer workspace look safe on the next reuse.\n let evicted = false;\n try {\n evicted = (await mastra?.removeWorkspace?.(workspaceId)) === true;\n } catch {\n // Preserve the credential-replacement error and retry on the next reuse.\n }\n try {\n await workspace.destroy();\n evicted = true;\n } catch {\n // The pending registration keeps the workspace quarantined if cleanup also fails.\n }\n if (evicted && githubTokenInjectors.get(workspaceId) === registered) {\n githubTokenInjectors.delete(workspaceId);\n }\n }\n throw error;\n }\n if (registered && githubTokenInjectors.get(workspaceId) !== registered) {\n throw new Error('Factory workspace GitHub credential registration is no longer active.');\n }\n return workspace;\n };\n\n let existing: Workspace | undefined;\n try {\n existing = mastra?.getWorkspaceById(workspaceId) as Workspace | undefined;\n existing?.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);\n } catch {\n // Not registered yet.\n existing = undefined;\n }\n if (existing) {\n return reconcileRegisteredWorkspace(existing);\n }\n\n const materialize = async (): Promise<Workspace> => {\n // A terminal work item or a deleted session may have returned a\n // still-warm VM — with this repository already cloned — to the reuse\n // pool. Adopt it before provisioning a fresh sandbox. Pooled VMs carry\n // no credentials (tokens are injected per command, and the workdir is\n // scrubbed on release and again below), so any user's session for this\n // repository can claim one.\n let claimedPooledSandbox = false;\n if (!isLocalSandbox && !session.sandboxId) {\n const pooled = await storage.sandboxPool.claim({\n projectRepositoryId: session.projectRepositoryId,\n });\n if (pooled) {\n await storage.sessions.setSandbox({\n id: session.id,\n sandboxId: pooled.sandboxId,\n sandboxWorkdir: pooled.sandboxWorkdir,\n });\n session.sandboxId = pooled.sandboxId;\n session.sandboxWorkdir = pooled.sandboxWorkdir;\n workdir = pooled.sandboxWorkdir;\n claimedPooledSandbox = true;\n }\n }\n\n const token = await getRepositoryToken();\n\n // The `gh` CLI needs a PAT when the org configured one (installation\n // tokens 403 on integration-restricted endpoints); git clone/checkout\n // below keep using the minted installation token. Review-board sessions\n // (run-binding role `review`) authenticate `gh` as the reviewer account\n // when a reviewer token is configured; everything else — including\n // sessions with no resolvable run binding — uses the worker token.\n const patKind = await resolveGithubPatKind('default');\n const ghCliToken = (await getGithubPat(() => github.integrationStorage, session.orgId, patKind)) ?? token;\n\n const ensureSandbox = () =>\n fleet.ensureSandbox(binding, { GH_TOKEN: ghCliToken }, undefined, {\n ...(isLocalSandbox ? { workingDirectory: workdir } : {}),\n actingUserId: userId,\n });\n const runMaterialize = (target: Awaited<ReturnType<typeof ensureSandbox>>) =>\n materializeRepo({\n row: { id: session.id, sandboxWorkdir: workdir, materializedAt: session.materializedAt },\n repoInfo: { repoFullName: repoFullName, defaultBranch: repository.defaultBranch },\n sandbox: target,\n token,\n storage: storage.sessions,\n });\n const isGitMissing = (error: unknown) => error instanceof MaterializeError && error.code === 'git-missing';\n\n let sandbox = await ensureSandbox();\n // A claimed VM still has the previous session's branch checked out —\n // reset it to the default branch before materialize/checkout. When the\n // pooled VM was already reaped, `ensureSandbox` provisioned fresh and\n // the recycle is a no-op (no checkout on disk yet).\n if (claimedPooledSandbox) await recycleClaimedWorkdir(sandbox, workdir, repository.defaultBranch);\n try {\n await runMaterialize(sandbox);\n } catch (error) {\n if (!isGitMissing(error)) throw error;\n // A sandbox without git was booted from a bare base image (e.g. the\n // platform proxy falls back to a clean Debian base when its template\n // build fails). That VM can never materialize a repo, and its id is\n // already persisted on the binding — tear it down so re-opens stop\n // reattaching to the poisoned sandbox, then retry once on a fresh VM.\n await fleet.teardownSandbox(binding, sandbox);\n sandbox = await ensureSandbox();\n try {\n await runMaterialize(sandbox);\n } catch (retryError) {\n // Still bare — the provider's template is persistently broken.\n // Clear the binding so a later manual retry provisions fresh.\n if (isGitMissing(retryError)) await fleet.teardownSandbox(binding, sandbox);\n throw retryError;\n }\n }\n await checkoutSessionBranch(sandbox, workdir, {\n branch: session.branch,\n baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,\n token,\n repoFullName: repoFullName,\n });\n if (projectRepository.setupCommand) {\n try {\n await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);\n } catch (setupError) {\n if (projectRepository.teardownCommand) {\n try {\n await runWorktreeTeardown(sandbox, workdir, projectRepository.teardownCommand, {\n timeoutMs: DEFAULT_COMMAND_TIMEOUT_MS,\n });\n } catch (teardownError) {\n console.warn('[Mastra Factory] Worktree teardown after setup failure failed', {\n orgId: session.orgId,\n sessionId: session.sessionId,\n projectRepositoryId: session.projectRepositoryId,\n error: teardownError instanceof Error ? teardownError.message.slice(-2000) : String(teardownError),\n });\n }\n }\n throw setupError;\n }\n }\n\n const tokenRegistration: GithubTokenRegistration = {\n inject: freshToken => {\n if (!sandbox.setEnvironmentVariable) {\n throw new Error('The active sandbox provider does not support runtime GitHub token refresh.');\n }\n sandbox.setEnvironmentVariable('GH_TOKEN', freshToken);\n tokenRegistration.ghToken = freshToken;\n },\n patKind,\n ghToken: ghCliToken,\n generation: 0,\n tokenReplacementPending: false,\n };\n githubTokenInjectors.set(workspaceId, tokenRegistration);\n registerGithubTokenContext(tokenRegistration);\n\n const filesystem = new SandboxFilesystem({ sandbox, workdir });\n const projectSkillPaths = [path.join(configDir, 'skills'), '.claude/skills', '.agents/skills'];\n const skillPaths = [...(effectiveSkillExtension?.paths ?? []), ...projectSkillPaths];\n const workspace = new Workspace({\n id: workspaceId,\n name: 'Mastra Code Factory Session Workspace',\n filesystem,\n sandbox: sandbox as unknown as ConstructorParameters<typeof Workspace>[0]['sandbox'],\n tools: MASTRACODE_WORKSPACE_TOOLS,\n skills: skillPaths,\n skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem,\n });\n // Register with the Mastra instance so sync HTTP handlers that resolve\n // the workspace via `mastra.getWorkspaceById(id)` (file tree, permissions\n // probe, MCP/tool routes) find it instead of throwing\n // `MASTRA_GET_WORKSPACE_BY_ID_NOT_FOUND`. `addWorkspace` is idempotent on\n // key collision, so the inflight coalescing and reuse paths above stay\n // race-safe. Registration happens synchronously with the return so a\n // concurrent lookup on another request cannot observe an unregistered\n // workspace.\n mastra?.addWorkspace(workspace, workspaceId, { source: 'mastra' });\n const registered = await workspaceRegistry.register(\n session.sessionId,\n workspaceId,\n workspaceGeneration,\n async () => {\n githubTokenInjectors.delete(workspaceId);\n await mastra?.removeWorkspace?.(workspaceId);\n },\n );\n if (!registered) {\n throw new Error(`Factory session ${session.sessionId} was retired during workspace materialization`);\n }\n return workspace;\n };\n\n // Dedupe concurrent materializations of the same workspace: followers\n // await the leader's promise instead of provisioning a second sandbox,\n // then bind the shared token injector into their own request context.\n const inflight = inflightMaterializations.get(workspaceId);\n if (inflight) {\n const workspace = await inflight;\n return reconcileRegisteredWorkspace(workspace);\n }\n const materialization = materialize();\n inflightMaterializations.set(workspaceId, materialization);\n try {\n return await materialization;\n } finally {\n inflightMaterializations.delete(workspaceId);\n }\n };\n}\n\nexport const getFactoryWorkspace = createWorkspaceFactory();\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/factory",
3
- "version": "0.7.1-alpha.4",
3
+ "version": "0.8.0-alpha.6",
4
4
  "description": "Mastra Software Factory module: the server core behind the Mastra Software Factory — storage domains, integrations, and surfaces for agent-powered software delivery",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -51,11 +51,11 @@
51
51
  "@octokit/rest": "^22.0.1",
52
52
  "hono": "^4.12.8",
53
53
  "zod": "^4.3.6",
54
+ "@mastra/auth-studio": "1.3.4-alpha.0",
54
55
  "@mastra/auth-workos": "1.6.4",
55
- "@mastra/core": "1.60.0-alpha.4",
56
+ "@mastra/core": "1.60.0-alpha.5",
56
57
  "@mastra/slack": "1.6.1",
57
- "@mastra/auth-studio": "1.3.4-alpha.0",
58
- "@mastra/code-sdk": "1.2.2-alpha.4"
58
+ "@mastra/code-sdk": "1.2.2-alpha.5"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@types/node": "22.20.1",
@@ -65,9 +65,9 @@
65
65
  "typescript-eslint": "^8.57.0",
66
66
  "vitest": "4.1.10",
67
67
  "@internal/lint": "0.0.123",
68
- "@internal/types-builder": "0.0.98",
68
+ "@mastra/libsql": "1.20.0",
69
69
  "@mastra/pg": "1.20.1-alpha.0",
70
- "@mastra/libsql": "1.20.0"
70
+ "@internal/types-builder": "0.0.98"
71
71
  },
72
72
  "engines": {
73
73
  "node": ">=22.19.0"