@mastra/factory 0.5.1-alpha.0 → 0.6.0-alpha.3

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 (154) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/dist/auth.d.ts +2 -0
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +2 -0
  5. package/dist/auth.js.map +1 -1
  6. package/dist/capabilities/intake.d.ts +1 -0
  7. package/dist/capabilities/intake.d.ts.map +1 -1
  8. package/dist/capabilities/version-control.d.ts +3 -0
  9. package/dist/capabilities/version-control.d.ts.map +1 -1
  10. package/dist/factory.d.ts +10 -0
  11. package/dist/factory.d.ts.map +1 -1
  12. package/dist/factory.js +15 -2
  13. package/dist/factory.js.map +1 -1
  14. package/dist/integrations/base.d.ts +6 -0
  15. package/dist/integrations/base.d.ts.map +1 -1
  16. package/dist/integrations/github/integration.d.ts +14 -1
  17. package/dist/integrations/github/integration.d.ts.map +1 -1
  18. package/dist/integrations/github/integration.js +61 -3
  19. package/dist/integrations/github/integration.js.map +1 -1
  20. package/dist/integrations/github/issue-reconciler.d.ts +24 -0
  21. package/dist/integrations/github/issue-reconciler.d.ts.map +1 -0
  22. package/dist/integrations/github/issue-reconciler.js +104 -0
  23. package/dist/integrations/github/issue-reconciler.js.map +1 -0
  24. package/dist/integrations/github/reconcile-worker.d.ts +8 -0
  25. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  26. package/dist/integrations/github/reconcile-worker.js +38 -1
  27. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  28. package/dist/integrations/github/routes.d.ts.map +1 -1
  29. package/dist/integrations/github/routes.js +65 -52
  30. package/dist/integrations/github/routes.js.map +1 -1
  31. package/dist/integrations/github/rules.d.ts +37 -2
  32. package/dist/integrations/github/rules.d.ts.map +1 -1
  33. package/dist/integrations/github/rules.js +150 -14
  34. package/dist/integrations/github/rules.js.map +1 -1
  35. package/dist/integrations/github/sandbox-release.d.ts +16 -1
  36. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  37. package/dist/integrations/github/sandbox-release.js +42 -1
  38. package/dist/integrations/github/sandbox-release.js.map +1 -1
  39. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  40. package/dist/integrations/github/sandbox.js +74 -8
  41. package/dist/integrations/github/sandbox.js.map +1 -1
  42. package/dist/integrations/issue-reconcile-worker.d.ts +19 -0
  43. package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -0
  44. package/dist/integrations/issue-reconcile-worker.js +98 -0
  45. package/dist/integrations/issue-reconcile-worker.js.map +1 -0
  46. package/dist/integrations/issue-reconciler.d.ts +47 -0
  47. package/dist/integrations/issue-reconciler.d.ts.map +1 -0
  48. package/dist/integrations/issue-reconciler.js +104 -0
  49. package/dist/integrations/issue-reconciler.js.map +1 -0
  50. package/dist/integrations/linear/integration.d.ts +4 -0
  51. package/dist/integrations/linear/integration.d.ts.map +1 -1
  52. package/dist/integrations/linear/integration.js +19 -2
  53. package/dist/integrations/linear/integration.js.map +1 -1
  54. package/dist/integrations/linear/issue-reconciler.d.ts +6 -0
  55. package/dist/integrations/linear/issue-reconciler.d.ts.map +1 -0
  56. package/dist/integrations/linear/issue-reconciler.js +64 -0
  57. package/dist/integrations/linear/issue-reconciler.js.map +1 -0
  58. package/dist/integrations/linear/routes.d.ts.map +1 -1
  59. package/dist/integrations/linear/routes.js +1 -0
  60. package/dist/integrations/linear/routes.js.map +1 -1
  61. package/dist/integrations/linear/rules.d.ts +2 -0
  62. package/dist/integrations/linear/rules.d.ts.map +1 -1
  63. package/dist/integrations/linear/rules.js +5 -2
  64. package/dist/integrations/linear/rules.js.map +1 -1
  65. package/dist/integrations/platform/github/event-worker.d.ts +7 -0
  66. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  67. package/dist/integrations/platform/github/event-worker.js +24 -0
  68. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  69. package/dist/integrations/platform/github/integration.d.ts +13 -3
  70. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  71. package/dist/integrations/platform/github/integration.js +42 -1
  72. package/dist/integrations/platform/github/integration.js.map +1 -1
  73. package/dist/integrations/platform/linear/event-worker.d.ts +105 -0
  74. package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -0
  75. package/dist/integrations/platform/linear/event-worker.js +380 -0
  76. package/dist/integrations/platform/linear/event-worker.js.map +1 -0
  77. package/dist/integrations/platform/linear/integration.d.ts +9 -0
  78. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  79. package/dist/integrations/platform/linear/integration.js +37 -1
  80. package/dist/integrations/platform/linear/integration.js.map +1 -1
  81. package/dist/integrations/slack/integration.d.ts.map +1 -1
  82. package/dist/integrations/slack/integration.js +3 -2
  83. package/dist/integrations/slack/integration.js.map +1 -1
  84. package/dist/integrations/slack/slack.d.ts +37 -110
  85. package/dist/integrations/slack/slack.d.ts.map +1 -1
  86. package/dist/integrations/slack/slack.js +49 -44
  87. package/dist/integrations/slack/slack.js.map +1 -1
  88. package/dist/routes/config.d.ts +25 -0
  89. package/dist/routes/config.d.ts.map +1 -1
  90. package/dist/routes/config.js +63 -1
  91. package/dist/routes/config.js.map +1 -1
  92. package/dist/routes/fs.d.ts +16 -2
  93. package/dist/routes/fs.d.ts.map +1 -1
  94. package/dist/routes/fs.js +47 -5
  95. package/dist/routes/fs.js.map +1 -1
  96. package/dist/routes/surface.d.ts +13 -1
  97. package/dist/routes/surface.d.ts.map +1 -1
  98. package/dist/routes/surface.js +20 -9
  99. package/dist/routes/surface.js.map +1 -1
  100. package/dist/rules/binding-context.d.ts +28 -1
  101. package/dist/rules/binding-context.d.ts.map +1 -1
  102. package/dist/rules/binding-context.js +66 -1
  103. package/dist/rules/binding-context.js.map +1 -1
  104. package/dist/rules/defaults.d.ts.map +1 -1
  105. package/dist/rules/defaults.js +71 -5
  106. package/dist/rules/defaults.js.map +1 -1
  107. package/dist/rules/start-coordinator.d.ts.map +1 -1
  108. package/dist/rules/start-coordinator.js +7 -26
  109. package/dist/rules/start-coordinator.js.map +1 -1
  110. package/dist/rules/tools.d.ts +2 -0
  111. package/dist/rules/tools.d.ts.map +1 -1
  112. package/dist/rules/tools.js +15 -6
  113. package/dist/rules/tools.js.map +1 -1
  114. package/dist/rules/types.d.ts +17 -2
  115. package/dist/rules/types.d.ts.map +1 -1
  116. package/dist/rules/types.js +2 -1
  117. package/dist/rules/types.js.map +1 -1
  118. package/dist/session/factory-session.d.ts +116 -0
  119. package/dist/session/factory-session.d.ts.map +1 -0
  120. package/dist/session/factory-session.js +162 -0
  121. package/dist/session/factory-session.js.map +1 -0
  122. package/dist/session/filesystem-capture.d.ts +26 -0
  123. package/dist/session/filesystem-capture.d.ts.map +1 -0
  124. package/dist/session/filesystem-capture.js +75 -0
  125. package/dist/session/filesystem-capture.js.map +1 -0
  126. package/dist/storage/domains/audit/domain.d.ts +9 -2
  127. package/dist/storage/domains/audit/domain.d.ts.map +1 -1
  128. package/dist/storage/domains/audit/domain.js +106 -4
  129. package/dist/storage/domains/audit/domain.js.map +1 -1
  130. package/dist/storage/domains/filesystem/base.d.ts +26 -0
  131. package/dist/storage/domains/filesystem/base.d.ts.map +1 -0
  132. package/dist/storage/domains/filesystem/base.js +74 -0
  133. package/dist/storage/domains/filesystem/base.js.map +1 -0
  134. package/dist/storage/domains/projects/base.d.ts +1 -0
  135. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  136. package/dist/storage/domains/projects/base.js +3 -0
  137. package/dist/storage/domains/projects/base.js.map +1 -1
  138. package/dist/storage/domains/source-control/base.d.ts +2 -0
  139. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  140. package/dist/storage/domains/source-control/base.js +6 -0
  141. package/dist/storage/domains/source-control/base.js.map +1 -1
  142. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  143. package/dist/storage/domains/source-control/inmemory.js +3 -0
  144. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  145. package/dist/storage/domains/work-items/base.d.ts +11 -0
  146. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  147. package/dist/storage/domains/work-items/base.js +28 -0
  148. package/dist/storage/domains/work-items/base.js.map +1 -1
  149. package/factory-skills/factory-triage/SKILL.md +45 -12
  150. package/package.json +5 -5
  151. package/dist/integrations/github/factory-session.d.ts +0 -12
  152. package/dist/integrations/github/factory-session.d.ts.map +0 -1
  153. package/dist/integrations/github/factory-session.js +0 -37
  154. package/dist/integrations/github/factory-session.js.map +0 -1
package/dist/factory.js CHANGED
@@ -20,6 +20,7 @@ import { FactoryPhaseStateProcessor } from "./rules/processor.js";
20
20
  import { createFactoryTransitionTools } from "./rules/tools.js";
21
21
  import { registerSandboxReattach } from "./sandbox/reattach.js";
22
22
  import { handleServerError } from "./server-error.js";
23
+ import { observeSessionFilesystem } from "./session/filesystem-capture.js";
23
24
  import { createSpaStaticMiddleware, resolveUiDistDir } from "./spa-static.js";
24
25
  import { createStateSigner } from "./state-signing.js";
25
26
  import { observeAgentGitAction } from "./storage/domains/audit/agent-audit.js";
@@ -27,6 +28,7 @@ import { AuditStorage } from "./storage/domains/audit/base.js";
27
28
  import { AuditDomain } from "./storage/domains/audit/domain.js";
28
29
  import { ChannelIdentityStorage } from "./storage/domains/channel-identity/base.js";
29
30
  import { CustomProvidersStorage } from "./storage/domains/custom-providers/base.js";
31
+ import { FilesystemStorage } from "./storage/domains/filesystem/base.js";
30
32
  import { IntakeStorage } from "./storage/domains/intake/base.js";
31
33
  import { IntegrationStorage } from "./storage/domains/integrations/base.js";
32
34
  import { MemorySettingsStorage } from "./storage/domains/memory-settings/base.js";
@@ -34,7 +36,7 @@ import { ModelPacksStorage } from "./storage/domains/model-packs/base.js";
34
36
  import { FactoryProjectsStorage } from "./storage/domains/projects/base.js";
35
37
  import { SourceControlStorage } from "./storage/domains/source-control/base.js";
36
38
  import { createWorkspaceFactory } from "./workspace.js";
37
- import { hasAuthInit } from "@mastra/core/server";
39
+ import { hasAuthInit, isUserProvider } from "@mastra/core/server";
38
40
  import { MastraAuthStudio } from "@mastra/auth-studio";
39
41
  import { prepareAgentControllerMount } from "@mastra/code-sdk";
40
42
  import { AgentControllerChannels } from "@mastra/core/channels";
@@ -178,6 +180,7 @@ var MastraFactory = class {
178
180
  const queueHealthStorage = storage.registerDomain(new QueueHealthStorage());
179
181
  const integrationStorage = storage.registerDomain(new IntegrationStorage());
180
182
  const factoryProjectsStorage = storage.registerDomain(new FactoryProjectsStorage());
183
+ const filesystemStorage = storage.registerDomain(new FilesystemStorage());
181
184
  const sourceControlStorage = storage.registerDomain(new SourceControlStorage());
182
185
  const domains = {
183
186
  intake: intakeStorage,
@@ -185,6 +188,7 @@ var MastraFactory = class {
185
188
  modelPacks: modelPacksStorage,
186
189
  memorySettings: memorySettingsStorage,
187
190
  customProviders: customProvidersStorage,
191
+ filesystem: filesystemStorage,
188
192
  projects: factoryProjectsStorage,
189
193
  queueHealth: queueHealthStorage,
190
194
  workItems: workItemsStorage,
@@ -200,6 +204,7 @@ var MastraFactory = class {
200
204
  auth: routeAuth,
201
205
  audit: auditStorage,
202
206
  projects: factoryProjectsStorage,
207
+ users: auth && isUserProvider(auth) ? auth : void 0,
203
208
  sinks: integrations,
204
209
  agentTenant: (requestContext) => {
205
210
  const user = requestContext.get("user");
@@ -318,7 +323,8 @@ var MastraFactory = class {
318
323
  if (workItemsStorage && transitionService) mergeTools("factory", await createFactoryTransitionTools({
319
324
  requestContext,
320
325
  storage: workItemsStorage,
321
- transitionService
326
+ transitionService,
327
+ ...storage.isDomainReady("source-control") ? { sessions: sourceControlStorage.forIntegration("github").sessions } : {}
322
328
  }));
323
329
  for (const { integration, ready, ensureReady } of toolIntegrations) {
324
330
  if (!ready && ensureReady) try {
@@ -381,6 +387,7 @@ var MastraFactory = class {
381
387
  controller,
382
388
  transitionService: runtimeTransitionService,
383
389
  storage: storage.getDomain("work-items"),
390
+ maxInFlight: this.#config.dispatcher?.maxInFlight,
384
391
  reconcileToolResults: () => factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),
385
392
  prepareBinding,
386
393
  primeCredentials: (tenant) => primeTenantCredentials({
@@ -430,6 +437,12 @@ var MastraFactory = class {
430
437
  };
431
438
  }
432
439
  }));
440
+ prepared.base.controller.onSessionCreated((session) => {
441
+ observeSessionFilesystem(session, {
442
+ filesystem: filesystemStorage,
443
+ sourceControl: sourceControlStorage.forIntegration("github")
444
+ });
445
+ });
433
446
  this.#prepared = prepared;
434
447
  this.#factoryProcessor = factoryProcessor;
435
448
  const channelRegistrations = integrationRegistrations.filter(({ integration, ready }) => ready && integration.channels);
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","names":["#config","#preparing","#dispatcher","#prepared","#factoryProcessor"],"sources":["../src/factory.ts"],"sourcesContent":["/**\n * `MastraFactory` — the single entry point to the whole Mastra Software Factory.\n *\n * The consumer's deploy entry constructs deployment-specific config instances\n * (auth adapter, pubsub) and passes them here explicitly. The only provider\n * defaults constructed here are Platform GitHub and Linear integrations when\n * Platform credentials exist and the caller did not provide those integrations.\n *\n * `prepare()` resolves feature readiness, threads every dependency explicitly,\n * assembles the web routes/middleware, and returns the constructor args for\n * `new Mastra(...)`. The literal `export const mastra = new Mastra(...)` must\n * stay in the entry file — the deployer's `checkConfigExport` Babel plugin\n * only marks the config valid when it finds that literal in the entry AST —\n * so the factory produces args instead of the instance. `finalize()` runs the\n * post-construct boot (controller init + workers).\n *\n * Integration readiness is derived from each instance's declared capabilities\n * and the storage domains those capabilities require.\n */\n\nimport { MastraAuthStudio } from '@mastra/auth-studio';\nimport { prepareAgentControllerMount } from '@mastra/code-sdk';\nimport { AgentControllerChannels } from '@mastra/core/channels';\nimport type { PubSub } from '@mastra/core/events';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { hasAuthInit } from '@mastra/core/server';\nimport type { IMastraAuthProvider } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\nimport type { MastraVector } from '@mastra/core/vector';\nimport { LocalSandbox } from '@mastra/core/workspace';\nimport type { WorkspaceSandbox } from '@mastra/core/workspace';\nimport type { FactoryAuthUser } from './auth.js';\nimport {\n buildAuthRoutes,\n createFactoryAuthGate,\n createFactoryRouteAuth,\n getFactoryAuthOrgId,\n getFactoryAuthUserId,\n} from './auth.js';\nimport type { FactoryIntegration, IntegrationPostToolContext, IntegrationTools } from './integrations/base.js';\nimport type { GithubIntegration } from './integrations/github/integration.js';\nimport type { GithubIssueTriageInput, GithubIssueTriageResult } from './integrations/github/issue-triage.js';\nimport { recordFactoryPullRequestProvenance } from './integrations/github/provenance.js';\nimport { releaseWorkItemSandboxes } from './integrations/github/sandbox-release.js';\nimport { PlatformGithubIntegration } from './integrations/platform/github/integration.js';\nimport { PlatformLinearIntegration } from './integrations/platform/linear/integration.js';\nimport { createCustomProvidersPrimer, registerCustomProvidersSource } from './routes/custom-provider-source.js';\nimport { ProjectRoutes } from './routes/projects.js';\nimport { assembleFactoryApiRoutes, buildIntegrationContext } from './routes/surface.js';\nimport type { FactoryApiRoutesDeps } from './routes/surface.js';\nimport {\n createTenantCredentialPrimer,\n primeTenantCredentials,\n registerTenantCredentialResolver,\n} from './routes/tenant-credentials.js';\nimport { builtInFactoryRules } from './rules/defaults.js';\nimport { FactoryDecisionDispatcher } from './rules/dispatcher.js';\nimport { FactoryPhaseStateProcessor } from './rules/processor.js';\nimport { createFactoryTransitionTools } from './rules/tools.js';\nimport { FactoryTransitionService } from './rules/transition-service.js';\nimport type { FactoryRules } from './rules/types.js';\nimport { assertFactoryRules } from './rules/validation.js';\nimport { SandboxFleet } from './sandbox/fleet.js';\nimport { registerSandboxReattach } from './sandbox/reattach.js';\nimport { handleServerError } from './server-error.js';\nimport { createSpaStaticMiddleware, resolveUiDistDir } from './spa-static.js';\nimport { createStateSigner } from './state-signing.js';\nimport { observeAgentGitAction } from './storage/domains/audit/agent-audit.js';\nimport { AuditStorage } from './storage/domains/audit/base.js';\nimport { AuditDomain } from './storage/domains/audit/domain.js';\nimport { ChannelIdentityStorage } from './storage/domains/channel-identity/base.js';\nimport { ModelCredentialsStorage } from './storage/domains/credentials/base.js';\nimport { CustomProvidersStorage } from './storage/domains/custom-providers/base.js';\nimport { IntakeStorage } from './storage/domains/intake/base.js';\nimport { IntegrationStorage } from './storage/domains/integrations/base.js';\nimport { MemorySettingsStorage } from './storage/domains/memory-settings/base.js';\nimport { ModelPacksStorage } from './storage/domains/model-packs/base.js';\nimport { FactoryProjectsStorage } from './storage/domains/projects/base.js';\nimport { QueueHealthStorage } from './storage/domains/queue-health/base.js';\nimport { SourceControlStorage } from './storage/domains/source-control/base.js';\nimport { WorkItemsStorage } from './storage/domains/work-items/base.js';\nimport { timedPhase } from './timing.js';\nimport { createWorkspaceFactory } from './workspace.js';\n\ntype BuildApiRoutesDeps = Pick<FactoryApiRoutesDeps, 'controller' | 'authStorage'>;\n\n/** Constructor args for the `new Mastra(...)` literal in the deploy entry. */\nexport type MastraArgs = NonNullable<ConstructorParameters<typeof Mastra>[0]>;\n\nexport interface MastraFactoryConfig {\n /**\n * Auth provider instance — `MastraAuthStudio` (`@mastra/auth-studio`),\n * `MastraAuthWorkos` (`@mastra/auth-workos`), `MastraAuthBetterAuth`\n * (`@mastra/auth-better-auth`), or any custom `MastraAuthProvider`. Whatever\n * instance is passed is the active provider; a passed instance is always\n * honored as-is.\n *\n * Omitted → the factory defaults to `MastraAuthStudio`, proxying auth\n * through the shared Mastra platform API. `MastraAuthStudio` resolves its\n * own env (`MASTRA_SHARED_API_URL`, `MASTRA_ORGANIZATION_ID`,\n * `MASTRA_COOKIE_DOMAIN`).\n *\n * Pass `null` to disable auth entirely (open server, local-dev behavior)\n * without falling back to the default.\n */\n auth?: IMastraAuthProvider | null;\n /**\n * REQUIRED. Factory storage backend powering BOTH agent storage (threads,\n * messages, memory, OM — via `getMastraStorage()`) and the app tables\n * (projects/source-control/audit/intake — via the generic ops surface). Pass a\n * `PgFactoryStorage` (`@mastra/pg`) for deployments or a\n * `LibSQLFactoryStorage` (`@mastra/libsql`) for local dev — one backend,\n * one connection, every feature on.\n */\n storage: FactoryStorage;\n /**\n * Vector store instance for recall search — `PgVector` (`@mastra/pg`) on\n * the same database as `storage`. Omitted → the SDK mount's default vector\n * store resolution applies.\n */\n vector?: MastraVector;\n /**\n * Distributed event bus instance (e.g. `new RedisStreamsPubSub({ url })`).\n * When set, streams/workflows/signals ride it across processes and the\n * controller drops file-based thread locks in favor of pubsub-coordinated\n * leases. Omitted → in-process default.\n */\n pubsub?: PubSub;\n /**\n * Browser-facing origin used to build integration OAuth/install callback\n * URLs and to derive the auth redirect URI. On the platform the SPA is\n * hosted separately, so this MUST be the public API origin.\n * Default: `http://localhost:4111` (the local Factory server, which also\n * serves the UI).\n */\n publicUrl?: string;\n /**\n * Allowed cross-origin SPA origins. The SPA may be served from a separate\n * static host, so credentialed requests must be explicitly allowed.\n */\n allowedOrigins?: string[];\n /** Sandbox configuration. Omitted → repository sandboxes are disabled. */\n sandbox?: MastraFactorySandboxConfig;\n /**\n * Deployment-stable secret for signing integration OAuth `state` values.\n * Omitted → a per-process random secret, which is fine for single-process\n * local development but rejected for integrations that declare\n * `requiresStableStateSigner`.\n */\n stateSecret?: string;\n /**\n * Registered capability providers. The factory registers the pieces each\n * `FactoryIntegration` instance provides — HTTP routes, storage domains,\n * agent/session tools, intake, source control, and diagnostics — into the\n * system. When Platform credentials are configured, missing `github` and\n * `linear` integrations default to their Platform-backed implementations.\n */\n integrations?: FactoryIntegration[];\n /**\n * Authoritative Factory board, tool-result, and GitHub-event rules. Construct\n * with `defaultFactoryRules({ version, overrides })` so deployment policy has\n * an explicit version and exact handler leaves replace rather than compose.\n * Omitted → conservative built-in rules for the current deployment.\n */\n rules?: FactoryRules;\n\n /**\n * Platform-specific overrides. When the Platform-backed GitHub integration\n * is active, it derives a `runIssueTriage` runner from the mounted\n * controller automatically. An explicit `runIssueTriage` here takes\n * precedence over the controller-derived default. `githubAppSlug` identifies\n * Factory's own GitHub App writes so their webhook deliveries do not retrigger\n * triage.\n */\n platform?: {\n runIssueTriage?: (input: GithubIssueTriageInput) => Promise<GithubIssueTriageResult>;\n githubAppSlug?: string;\n };\n}\n\nexport interface MastraFactorySandboxConfig {\n /**\n * Template machine — `RailwaySandbox` (`@mastra/railway`), core\n * `LocalSandbox` (`@mastra/core/workspace`), or any `WorkspaceSandbox` that\n * implements `clone()`. Each project-repository execution environment gets\n * its own sandbox cloned from this machine; the machine itself is never\n * started. `prepare()` fails fast when the instance lacks `clone()`.\n */\n machine: WorkspaceSandbox;\n /**\n * In-sandbox base directory repos check out under (nested `owner/name` per\n * repo). Default: the machine's own `workingDirectory` when it exposes one\n * (core `LocalSandbox` does), else `/workspace`.\n */\n workdir?: string;\n /**\n * Per-replica cap on concurrently provisioned sandboxes. `0`/omitted means\n * unlimited. A lightweight per-process budget, not a cross-replica scheduler.\n */\n maxSandboxes?: number;\n}\n\nconst CONTROLLER_ID = 'code';\n\nfunction hasPlatformSecretKey(): boolean {\n return Boolean(process.env.MASTRA_PLATFORM_SECRET_KEY?.trim());\n}\n\n/**\n * The template sandbox's own working directory, when it exposes one as a\n * string (core `LocalSandbox` does; remote providers generally don't).\n * Used as the default checkout base so a local template rooted at a host\n * directory checks repos out under that same root.\n */\nfunction templateWorkingDirectory(sandbox: WorkspaceSandbox): string | undefined {\n const wd = (sandbox as { workingDirectory?: unknown }).workingDirectory;\n return typeof wd === 'string' && wd.length > 0 ? wd : undefined;\n}\n\nfunction resolveSandboxWorkdirBase(machine: WorkspaceSandbox, configuredWorkdir?: string): string {\n const machineWorkdir = templateWorkingDirectory(machine);\n const workdir =\n configuredWorkdir === '/workspace' && machineWorkdir ? machineWorkdir : (configuredWorkdir ?? machineWorkdir);\n return (workdir ?? '/workspace').replace(/\\/+$/, '');\n}\n\n/**\n * Default auth provider — `MastraAuthStudio`, which proxies identity to the\n * shared Mastra platform API. `MastraAuthStudio` resolves `MASTRA_SHARED_API_URL`,\n * `MASTRA_ORGANIZATION_ID`, and `MASTRA_COOKIE_DOMAIN` from env on its own —\n * this helper only derives a cookie-domain fallback from the factory's\n * `publicUrl`.\n *\n * Cookie-domain resolution (Studio picks the first that wins):\n * 1. explicit `MASTRA_COOKIE_DOMAIN` env, if set;\n * 2. `.mastra.ai` when `sharedApiUrl` is on `.mastra.ai`;\n * 3. this parent-domain fallback derived from `publicUrl` — so a deploy on\n * `https://foo.mastra.cloud` mints cookies with `Domain=.mastra.cloud`\n * without the caller wiring the env var by hand.\n * 4. otherwise host-only (no `Domain=`), which is correct for `localhost`.\n */\nfunction buildDefaultStudioAuth(publicUrl: string): IMastraAuthProvider {\n return new MastraAuthStudio({\n cookieDomain: parentDomainFromPublicUrl(publicUrl),\n });\n}\n\n/**\n * Derive a parent cookie domain from `publicUrl` by stripping the leftmost\n * label — the same shape platform-API's env injection uses (see\n * `platform/servers/api/src/lib/studio-env-vars.ts`: `.${routingDomain.replace(/^[^.]+\\./, '')}`).\n *\n * Rather than a generic `strip-left-label` heuristic — which either emits\n * cookies scoped to a public suffix (`sub.example.co.uk` → `.example.co.uk`\n * requires PSL data to be safe) or misclassifies numeric hostnames like\n * `3scale.example.com` as IPv4 — we only derive a parent domain when the\n * host sits under one of the platform's known registrable domains. Anything\n * else (custom domains, arbitrary tenant hostnames, IPs, `localhost`)\n * falls through to host-only cookies. Callers that need a different scope\n * pass `MASTRA_COOKIE_DOMAIN` explicitly (Studio honors that first).\n */\nconst KNOWN_PLATFORM_COOKIE_PARENTS = ['mastra.cloud', 'mastra.ai'] as const;\n\nfunction isIpLiteral(hostname: string): boolean {\n // IPv6 addresses in URLs are bracketed; `URL.hostname` strips the brackets\n // but the address itself still contains `:`. IPv4 is four dot-separated\n // numeric octets — trust the parser to have already validated shape.\n if (hostname.includes(':')) return true;\n return /^\\d+(?:\\.\\d+){3}$/.test(hostname);\n}\n\nfunction parentDomainFromPublicUrl(publicUrl: string): string | undefined {\n let hostname: string;\n try {\n hostname = new URL(publicUrl).hostname.toLowerCase();\n } catch {\n return undefined;\n }\n if (hostname === 'localhost' || isIpLiteral(hostname)) return undefined;\n for (const parent of KNOWN_PLATFORM_COOKIE_PARENTS) {\n // Exact match → we're already on the parent, host-only is correct.\n // Subdomain match → mint the parent-scoped cookie.\n if (hostname === parent) return undefined;\n if (hostname.endsWith(`.${parent}`)) return `.${parent}`;\n }\n return undefined;\n}\n\nexport class MastraFactory {\n readonly #config: MastraFactoryConfig;\n #prepared: Awaited<ReturnType<typeof prepareAgentControllerMount>> | undefined;\n #dispatcher: FactoryDecisionDispatcher | undefined;\n #factoryProcessor: FactoryPhaseStateProcessor | undefined;\n #preparing = false;\n\n constructor(config: MastraFactoryConfig) {\n if (!config?.storage) {\n throw new Error(\n \"MastraFactory: 'storage' is required. Pass a FactoryStorage backend — e.g. \" +\n \"new PgFactoryStorage({ connectionString }) from '@mastra/pg' for deployments, or \" +\n \"new LibSQLFactoryStorage({ url }) from '@mastra/libsql' for local dev.\",\n );\n }\n this.#config = config;\n }\n\n /**\n * Resolve feature readiness, wire every dependency explicitly, and assemble\n * everything needed to construct the server-owned Mastra. Returns the args\n * for the `new Mastra(...)` literal that must live in the entry file.\n */\n async prepare(): Promise<MastraArgs> {\n // Guard set synchronously (before the first await) so overlapping calls —\n // not just strictly sequential ones — can't double-seed the runtime\n // registry or double-run one-time adapter init.\n if (this.#preparing) throw new Error('MastraFactory.prepare() called twice');\n this.#preparing = true;\n\n const publicOrigin = (this.#config.publicUrl ?? 'http://localhost:4111').replace(/\\/+$/, '');\n const allowedOrigins = (this.#config.allowedOrigins ?? []).map(o => o.replace(/\\/+$/, '')).filter(Boolean);\n const storage = this.#config.storage;\n const vector = this.#config.vector;\n const pubsub = this.#config.pubsub;\n // Default auth: honor an explicitly-passed provider (including `null` to\n // disable auth) as-is; otherwise fall back to `MastraAuthStudio`\n // (platform-proxied identity). The default derives its cookie domain\n // from `publicUrl` — deploys on `<sub>.mastra.cloud` mint parent-domain\n // cookies without the caller wiring `MASTRA_COOKIE_DOMAIN` explicitly.\n const configuredAuth = this.#config.auth;\n const auth: IMastraAuthProvider | undefined =\n configuredAuth === null ? undefined : (configuredAuth ?? buildDefaultStudioAuth(publicOrigin));\n // One RouteAuth seam per boot, closed over the resolved provider. Every\n // factory route module receives this handle — no service locator.\n const routeAuth = createFactoryRouteAuth(auth);\n\n // Explicit integrations win. Platform credentials fill only missing GitHub\n // and Linear slots so callers can override either provider independently.\n const integrations = [...(this.#config.integrations ?? [])];\n if (hasPlatformSecretKey()) {\n if (!integrations.some(integration => integration.id === 'github')) {\n integrations.push(\n new PlatformGithubIntegration({\n runIssueTriage: this.#config.platform?.runIssueTriage,\n slug: this.#config.platform?.githubAppSlug,\n }),\n );\n }\n if (!integrations.some(integration => integration.id === 'linear')) {\n integrations.push(new PlatformLinearIntegration());\n }\n }\n\n // Validate ids up front so a copy-paste duplicate fails loud instead of one\n // instance silently shadowing the other.\n const integrationIds = new Set<string>();\n for (const integration of integrations) {\n if (integrationIds.has(integration.id)) {\n throw new Error(`MastraFactory: duplicate integration id '${integration.id}' in 'integrations'.`);\n }\n integrationIds.add(integration.id);\n }\n const rules = this.#config.rules ?? builtInFactoryRules();\n assertFactoryRules(rules);\n\n // FactoryStorage owns every app-table domain and initializes them through\n // the same lifecycle as the backend connection.\n const intakeStorage = storage.registerDomain(new IntakeStorage());\n const auditStorage = storage.registerDomain(new AuditStorage());\n const workItemsStorage = storage.registerDomain(new WorkItemsStorage());\n const modelCredentialsStorage = storage.registerDomain(new ModelCredentialsStorage());\n const modelPacksStorage = storage.registerDomain(new ModelPacksStorage());\n const memorySettingsStorage = storage.registerDomain(new MemorySettingsStorage());\n const customProvidersStorage = storage.registerDomain(new CustomProvidersStorage());\n const queueHealthStorage = storage.registerDomain(new QueueHealthStorage());\n // Generic integration storage (connections/subscriptions/settings) — the\n // default persistence surface for integrations without a bespoke domain.\n const integrationStorage = storage.registerDomain(new IntegrationStorage());\n const factoryProjectsStorage = storage.registerDomain(new FactoryProjectsStorage());\n const sourceControlStorage = storage.registerDomain(new SourceControlStorage());\n // Reverse index from a platform sender (Slack/Discord/...) to a Mastra\n // tenant, so inbound channel events can resolve the sender's model creds.\n const channelIdentityStorage = storage.registerDomain(new ChannelIdentityStorage());\n // Every app-table domain handle the route builders and integrations need,\n // threaded explicitly (no service locator).\n const domains = {\n intake: intakeStorage,\n modelCredentials: modelCredentialsStorage,\n modelPacks: modelPacksStorage,\n memorySettings: memorySettingsStorage,\n customProviders: customProvidersStorage,\n projects: factoryProjectsStorage,\n queueHealth: queueHealthStorage,\n workItems: workItemsStorage,\n channelIdentity: channelIdentityStorage,\n };\n const projectRoutes = new ProjectRoutes({\n auth: routeAuth,\n projects: factoryProjectsStorage,\n sourceControl: sourceControlStorage,\n versionControlIntegrationIds: integrations\n .filter(integration => integration.versionControl)\n .map(integration => integration.id),\n });\n const auditDomain = new AuditDomain({\n auth: routeAuth,\n audit: auditStorage,\n projects: factoryProjectsStorage,\n sinks: integrations,\n agentTenant: requestContext => {\n const user = requestContext.get('user') as FactoryAuthUser | undefined;\n return { orgId: getFactoryAuthOrgId(user), userId: getFactoryAuthUserId(user) };\n },\n });\n\n // Repository execution needs one sandbox per project-repository link,\n // cloned from the configured machine. A machine without `clone()` would\n // only fail on first use, so fail fast at boot instead.\n const sandboxConfig = this.#config.sandbox;\n const machine = sandboxConfig?.machine;\n if (machine && typeof machine.clone !== 'function') {\n throw new Error(\n `MastraFactory: the configured sandbox machine (provider '${machine.provider}') does not implement clone(). ` +\n `Project repositories each get their own sandbox cloned from the configured machine. ` +\n `Pass a machine that implements clone() — e.g. RailwaySandbox (@mastra/railway) or ` +\n `LocalSandbox (@mastra/core/workspace) — or omit 'sandbox' to disable sandboxes.`,\n );\n }\n\n // One sandbox fleet per boot: constructed with the machine config when\n // sandboxes are configured, disabled otherwise. Handed to integrations\n // through the IntegrationContext — no global registry.\n const fleet = new SandboxFleet(\n machine\n ? {\n machine,\n workdirBase: resolveSandboxWorkdirBase(machine, sandboxConfig?.workdir),\n maxSandboxes: sandboxConfig?.maxSandboxes,\n }\n : undefined,\n );\n // Core's `getDynamicWorkspace` reattaches project sandboxes through the\n // SDK seam; only this factory owns the fleet, so register it here.\n registerSandboxReattach(fleet);\n\n // One shared OAuth state signer per boot. The deploy entry supplies a\n // replica-stable secret when needed; otherwise local development gets a\n // per-process random signer (`stable: false`).\n const stateSigner = createStateSigner(this.#config.stateSecret);\n\n // One-time provider initialization with factory-level context (e.g.\n // better-auth builds its default instance on the backend's auth\n // database, WorkOS derives its redirect URI from the public URL).\n // Failures surface here, at prepare() — a misconfigured provider must\n // not boot.\n if (auth && hasAuthInit(auth)) {\n await timedPhase('prepare.auth.init', () =>\n auth.init({ database: storage.authDatabase?.(), publicUrl: publicOrigin, allowedOrigins }),\n );\n }\n\n // Single init path: backend connection failure is a hard boot error;\n // registered app domains initialize fail-soft inside FactoryStorage.\n await timedPhase('prepare.storage.init', () => storage.init());\n\n // Per-tenant model credentials: once the credentials domain is up, model\n // resolution goes through the caller's own store and the SDK stops\n // mirroring stored API keys into process.env.\n //\n // Only register when a real auth adapter gates callers. In local /\n // auth-disabled mode there is no authenticated tenant, so registering would\n // force every model call through an empty tenant store (fail-closed, no env\n // fallback) and break chat with \"Not logged in\". Leaving it unregistered\n // lets the SDK fall back to the file-backed AuthStorage (auth.json) — the\n // same store the local /login and Settings pages read and write.\n if (auth) {\n registerTenantCredentialResolver(modelCredentialsStorage);\n }\n\n // Custom providers: DB-backed in both modes (org rows in tenant mode, the\n // sentinel `local` org in no-auth mode). Once registered, model resolution\n // and the gateway catalog never read settings.json custom providers.\n registerCustomProvidersSource({ storage: customProvidersStorage, authEnabled: Boolean(auth) });\n\n for (const integration of integrations) {\n integration.initialize?.({\n storage: integrationStorage.forIntegration(integration.id),\n projects: factoryProjectsStorage,\n auth: routeAuth,\n });\n if (integration.versionControl) {\n integration.versionControl.initialize({\n storage: sourceControlStorage.forIntegration(integration.id),\n });\n }\n }\n\n // Every integration uses generic integration storage. Version-control\n // providers additionally require the source-control storage domain. Readiness\n // is derived solely from capability presence, never from provider ids.\n const integrationRegistrations = integrations.map(integration => {\n const requiredDomains = [\n 'integrations',\n ...(integration.versionControl ? ['source-control'] : []),\n // Channels resolve an inbound sender to a tenant through the reverse\n // index; without it every message would dispatch tenant-less.\n ...(integration.channels ? ['channel-identity'] : []),\n ];\n return {\n integration,\n ready: requiredDomains.every(domain => storage.isDomainReady(domain)),\n ensureReady: async () => {\n for (const domain of requiredDomains) await storage.ensureDomainReady(domain);\n },\n };\n });\n const intakeReady =\n integrations.some(integration => integration.intake !== undefined) && storage.isDomainReady('intake');\n const factoryReady = storage.isDomainReady('projects') && storage.isDomainReady('work-items');\n const githubIntegration = integrations.find(integration => integration.id === 'github') as\n | GithubIntegration\n | undefined;\n const workItemsReady = storage.isDomainReady('work-items');\n // Terminal work items release their session sandboxes back to the reuse\n // pool so the next session for the same repository/user claims a warm VM\n // instead of provisioning fresh. Remote providers only: local \"sandboxes\"\n // are the host machine with per-session workdirs — nothing to pool.\n const releaseTerminalSandboxes =\n machine && !(machine instanceof LocalSandbox) && workItemsReady && storage.isDomainReady('source-control')\n ? async ({ orgId, workItemId }: { orgId: string; workItemId: string }) =>\n releaseWorkItemSandboxes({\n workItems: workItemsStorage,\n sourceControl: sourceControlStorage.forIntegration('github'),\n fleet,\n orgId,\n workItemId,\n })\n : undefined;\n const transitionService = workItemsReady\n ? new FactoryTransitionService({\n rules,\n storage: workItemsStorage,\n ...(releaseTerminalSandboxes ? { onTerminalStage: releaseTerminalSandboxes } : {}),\n })\n : undefined;\n const factoryProcessor = workItemsReady\n ? new FactoryPhaseStateProcessor({\n rules,\n storage: workItemsStorage,\n ...(transitionService ? { transitionService } : {}),\n ...(githubIntegration\n ? {\n recordPullRequestProvenance: (input: Parameters<typeof recordFactoryPullRequestProvenance>[3]) =>\n recordFactoryPullRequestProvenance(\n githubIntegration,\n sourceControlStorage.forIntegration('github'),\n integrationStorage.forIntegration('github'),\n input,\n ),\n }\n : {}),\n messageReader: {\n listMessages: async input => {\n const memory = await storage.getMastraStorage().getStore('memory');\n return memory ? memory.listMessages(input) : { messages: [], hasMore: false };\n },\n },\n })\n : undefined;\n\n // Boot assertion: an active integration that signs OAuth `state` needs a\n // replica-stable signer — a per-process random secret silently breaks the\n // OAuth callback on any replica that didn't sign the state. Fail loud now\n // instead. (The built-ins also assert this inside their readiness gates.)\n for (const { integration } of integrationRegistrations) {\n if (integration.requiresStableStateSigner && !stateSigner.stable) {\n throw new Error(\n `MastraFactory: integration '${integration.id}' signs OAuth state and requires a ` +\n `replica-stable state secret, but none is configured. Set 'stateSecret' on the factory config.`,\n );\n }\n }\n\n // The SDK needs to know which backend the injected Mastra store uses\n // (its own `instanceof` detection breaks when the dependency graph holds\n // duplicate package copies). Resolve it by walking the FactoryStorage\n // prototype chain by class name — the factory can't import the concrete\n // classes since '@mastra/pg' / '@mastra/libsql' are the user's choice.\n const mastraStorageBackend = (() => {\n for (let proto = Object.getPrototypeOf(storage); proto; proto = Object.getPrototypeOf(proto)) {\n if (proto.constructor?.name === 'PgFactoryStorage') return 'pg' as const;\n if (proto.constructor?.name === 'LibSQLFactoryStorage') return 'libsql' as const;\n }\n return undefined;\n })();\n\n // Integrations contributing tools to agent sessions: org-scoped\n // `agentTools` (resolved per request) + session-scoped `sessionTools`.\n const toolIntegrations = integrationRegistrations.filter(\n ({ integration }) => integration.agentTools || integration.sessionTools,\n );\n\n // Build the real production controller (agents, modes, tools, memory, OM,\n // MCP, providers) — identical to the terminal app. Agent state lives in\n // the storage backend's Mastra store alongside the Factory app tables —\n // one shared database for all users, separated by `resourceId` scoping.\n const prepared = await timedPhase('prepare.controllerMount', () =>\n prepareAgentControllerMount({\n controllerId: CONTROLLER_ID,\n workspace: createWorkspaceFactory({\n ...(this.#config.sandbox ? { sandbox: this.#config.sandbox } : {}),\n ...(githubIntegration ? { github: githubIntegration } : {}),\n ...(workItemsStorage ? { workItems: workItemsStorage } : {}),\n fleet,\n }),\n disableGithubSignals: true,\n // Memory settings live in the factory's `memory-settings` app table (per\n // org/user), so the host machine's TUI settings.json must not seed them.\n disableSettingsOmSeed: true,\n // A factory reads the repository it works on and its skill, never the\n // ~/.claude instructions of whoever hosts the process. On the controller\n // rather than per session, so webhook-recreated sessions keep it too.\n initialState: { skipGlobalInstructions: true },\n storage: storage.getMastraStorage(),\n ...(mastraStorageBackend ? { storageBackend: mastraStorageBackend } : {}),\n ...(factoryProcessor ? { inputProcessors: [factoryProcessor] } : {}),\n ...(vector ? { vector } : {}),\n ...(toolIntegrations.length > 0 || (workItemsStorage && transitionService)\n ? {\n extraTools: async ({ requestContext }: { requestContext: RequestContext }) => {\n const tools: IntegrationTools = {};\n const toolOwners = new Map<string, string>();\n const mergeTools = (ownerId: string, contributed: IntegrationTools) => {\n for (const [name, tool] of Object.entries(contributed)) {\n const owner = toolOwners.get(name);\n if (owner) {\n throw new Error(\n `MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'.`,\n );\n }\n toolOwners.set(name, ownerId);\n tools[name] = tool;\n }\n };\n if (workItemsStorage && transitionService) {\n mergeTools(\n 'factory',\n await createFactoryTransitionTools({\n requestContext,\n storage: workItemsStorage,\n transitionService,\n }),\n );\n }\n for (const { integration, ready, ensureReady } of toolIntegrations) {\n if (!ready && ensureReady) {\n try {\n await ensureReady();\n } catch {\n continue;\n }\n }\n if (integration.agentTools) {\n mergeTools(integration.id, await integration.agentTools({ requestContext }));\n }\n if (integration.sessionTools) {\n mergeTools(integration.id, integration.sessionTools({ requestContext }));\n }\n }\n return tools;\n },\n }\n : {}),\n postToolObserver: async (toolContext: IntegrationPostToolContext) => {\n const requestContext = (toolContext.context as { requestContext?: RequestContext } | undefined)\n ?.requestContext;\n if (requestContext) {\n await observeAgentGitAction({\n audit: auditDomain,\n toolContext: { ...toolContext, context: requestContext },\n });\n }\n await Promise.all(\n integrations.map(async integration => {\n if (!integration.postToolObserver) return;\n try {\n await integration.postToolObserver({ toolContext, requestContext });\n } catch (error) {\n console.warn(`[factory] Integration '${integration.id}' post-tool observer failed:`, error);\n }\n }),\n );\n },\n ...(pubsub ? { pubsub, crossProcessPubSub: true } : {}),\n buildApiRoutes: ({ controller, authStorage }: BuildApiRoutesDeps) => [\n // Public `/auth/*` routes (login/callback/logout/me). Folded in as\n // `apiRoutes` (not plain Hono routes) because the entry can't touch the\n // Hono app the deployer generates. `requiresAuth: false`; the gate\n // skips `/auth/*`.\n ...(auth ? buildAuthRoutes(auth, { publicUrl: publicOrigin }) : []),\n // Custom `/web/*` routes (fs / config / integrations / factory / audit).\n ...assembleFactoryApiRoutes({\n controllerId: CONTROLLER_ID,\n controller,\n auth: routeAuth,\n authStorage,\n audit: auditDomain,\n publicOrigin,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n domains,\n integrations: integrationRegistrations,\n intakeReady,\n factoryReady,\n rules,\n factoryTransitionService: transitionService,\n onFactoryRuntime: ({ transitionService: runtimeTransitionService, prepareBinding }) => {\n this.#dispatcher ??= new FactoryDecisionDispatcher({\n controller,\n transitionService: runtimeTransitionService,\n storage: storage.getDomain<WorkItemsStorage>('work-items'),\n reconcileToolResults: () => factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),\n prepareBinding,\n primeCredentials: tenant => primeTenantCredentials({ tenant, credentials: modelCredentialsStorage }),\n });\n },\n }),\n ...projectRoutes.routes(),\n ...auditDomain.routes(),\n ],\n buildServerConfig: () => {\n const cors = allowedOrigins.length ? { cors: { origin: allowedOrigins, credentials: true } } : {};\n // Log route errors with method/path/stack and answer with structured\n // JSON instead of an opaque `Internal Server Error`. Applied by the\n // deployer to both the top-level app and the custom-route sub-app.\n const onError = { onError: handleServerError };\n // Same-origin SPA: when a vite build is present (see resolveUiDistDir),\n // serve it at `/` from this server. Mounted last so the auth gate (when\n // enabled) covers it; it always passes `/api`, `/web`, `/auth` through.\n const uiDist = resolveUiDistDir();\n const spa = uiDist ? [createSpaStaticMiddleware(uiDist)] : [];\n if (!auth) {\n // Auth disabled: no gate. Still prime the sentinel-local custom\n // provider snapshot so model calls see DB rows, then SPA + CORS.\n return {\n middleware: [\n createCustomProvidersPrimer({ auth: routeAuth, storage: customProvidersStorage, authEnabled: false }),\n ...spa,\n ],\n ...cors,\n ...onError,\n };\n }\n\n // Ordered middleware. The deployer applies these AFTER its context\n // middleware sets `c.set('mastra', mastra)` and BEFORE routes, so:\n // 1. gate — validates the auth session, stashes the user, and 401s /\n // redirects unauthenticated requests. Skips public `/auth/*`.\n // 2. primers — hydrate the caller's model-credential and custom\n // provider snapshots so the request's first model call\n // resolves tenant credentials and custom providers.\n // 3. spa — serves the built UI for everything the server doesn't own.\n // `auth` also lands on `server.auth` so the core auth middleware (and\n // Studio's dual-auth routing — see `studio.auth` on the returned args)\n // authenticates core `/api/*` routes with the same provider.\n return {\n auth,\n middleware: [\n createFactoryAuthGate(auth),\n createTenantCredentialPrimer({ auth: routeAuth, credentials: modelCredentialsStorage }),\n createCustomProvidersPrimer({\n auth: routeAuth,\n storage: customProvidersStorage,\n authEnabled: Boolean(auth),\n }),\n ...spa,\n ],\n ...cors,\n ...onError,\n };\n },\n }),\n );\n\n this.#prepared = prepared;\n this.#factoryProcessor = factoryProcessor;\n\n // Chat-platform channels (Slack, Discord, …) contributed by integrations,\n // attached to the mounted controller so inbound platform messages reach\n // the same agents the web UI drives. READY integrations only — readiness\n // means the `channel-identity` domain's `init()` succeeded, so its link\n // table is queryable. Without it a sender can't be resolved to a tenant,\n // and attaching anyway would dispatch runs on default credentials.\n const channelRegistrations = integrationRegistrations.filter(\n ({ integration, ready }) => ready && integration.channels,\n );\n // `setChannels` replaces rather than merges, so a second provider would\n // silently never receive a message. Fail loud instead.\n if (channelRegistrations.length > 1) {\n throw new Error(\n `MastraFactory: integrations [${channelRegistrations\n .map(({ integration }) => integration.id)\n .join(', ')}] all provide channels, but only one may. Remove all but one.`,\n );\n }\n for (const { integration } of channelRegistrations) {\n // Integrations return a channels CONFIG; the factory owns construction.\n prepared.base.controller.setChannels(\n new AgentControllerChannels(\n integration.channels!(\n buildIntegrationContext(\n {\n controller: prepared.base.controller,\n publicOrigin,\n auth: routeAuth,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n rules,\n factoryReady,\n domains,\n ...(githubIntegration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n ),\n ),\n ),\n );\n }\n\n // Integration lifecycle workers (e.g. polling an upstream without\n // webhooks): collected from READY integrations only, folded into the\n // constructor args so `new Mastra(...)` merges them with the default\n // workers and `finalize()`'s `startWorkers()` starts them alongside the\n // built-ins. Never passed for the disabled/not-ready case — a worker for\n // an unavailable integration must not run.\n const integrationWorkers = integrationRegistrations\n .filter(({ integration, ready }) => ready && integration.workers)\n .flatMap(({ integration }) =>\n integration.workers!(\n buildIntegrationContext(\n {\n controller: prepared.base.controller,\n publicOrigin,\n auth: routeAuth,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n rules,\n factoryReady,\n domains,\n ...(githubIntegration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n ),\n ),\n );\n\n return {\n ...prepared.mastraArgs,\n // Same provider on `studio.auth` as on `server.auth` (buildServerConfig):\n // deployed factories must authenticate BOTH plain API callers and Studio\n // requests (`x-mastra-client-type: studio` routes to `studio.auth`).\n ...(auth ? { studio: { auth } } : {}),\n ...(integrationWorkers.length > 0 ? { workers: integrationWorkers } : {}),\n };\n }\n\n /**\n * Post-construct boot: initialize the controller (which inherits the\n * constructed Mastra's storage) and start its workers. Call AFTER the entry\n * has run `new Mastra(prepare()'s args)`.\n */\n async finalize(): Promise<void> {\n if (!this.#prepared) {\n throw new Error('MastraFactory.finalize() called before prepare()');\n }\n await timedPhase('finalize.controller', () => this.#prepared!.finalize());\n await timedPhase(\n 'finalize.reconcileBoundThreads',\n () => this.#factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),\n );\n this.#dispatcher?.start();\n }\n\n /** Stop Factory-owned background dispatch before the host process shuts down. */\n async shutdown(): Promise<void> {\n await this.#dispatcher?.stop();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"factory.js","names":["#config","#preparing","#dispatcher","#prepared","#factoryProcessor"],"sources":["../src/factory.ts"],"sourcesContent":["/**\n * `MastraFactory` — the single entry point to the whole Mastra Software Factory.\n *\n * The consumer's deploy entry constructs deployment-specific config instances\n * (auth adapter, pubsub) and passes them here explicitly. The only provider\n * defaults constructed here are Platform GitHub and Linear integrations when\n * Platform credentials exist and the caller did not provide those integrations.\n *\n * `prepare()` resolves feature readiness, threads every dependency explicitly,\n * assembles the web routes/middleware, and returns the constructor args for\n * `new Mastra(...)`. The literal `export const mastra = new Mastra(...)` must\n * stay in the entry file — the deployer's `checkConfigExport` Babel plugin\n * only marks the config valid when it finds that literal in the entry AST —\n * so the factory produces args instead of the instance. `finalize()` runs the\n * post-construct boot (controller init + workers).\n *\n * Integration readiness is derived from each instance's declared capabilities\n * and the storage domains those capabilities require.\n */\n\nimport { MastraAuthStudio } from '@mastra/auth-studio';\nimport { prepareAgentControllerMount } from '@mastra/code-sdk';\nimport { AgentControllerChannels } from '@mastra/core/channels';\nimport type { PubSub } from '@mastra/core/events';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { hasAuthInit, isUserProvider } from '@mastra/core/server';\nimport type { IMastraAuthProvider } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\nimport type { MastraVector } from '@mastra/core/vector';\nimport { LocalSandbox } from '@mastra/core/workspace';\nimport type { WorkspaceSandbox } from '@mastra/core/workspace';\nimport type { FactoryAuthUser } from './auth.js';\nimport {\n buildAuthRoutes,\n createFactoryAuthGate,\n createFactoryRouteAuth,\n getFactoryAuthOrgId,\n getFactoryAuthUserId,\n} from './auth.js';\nimport type { FactoryIntegration, IntegrationPostToolContext, IntegrationTools } from './integrations/base.js';\nimport type { GithubIntegration } from './integrations/github/integration.js';\nimport type { GithubIssueTriageInput, GithubIssueTriageResult } from './integrations/github/issue-triage.js';\nimport { recordFactoryPullRequestProvenance } from './integrations/github/provenance.js';\nimport { releaseWorkItemSandboxes } from './integrations/github/sandbox-release.js';\nimport { PlatformGithubIntegration } from './integrations/platform/github/integration.js';\nimport { PlatformLinearIntegration } from './integrations/platform/linear/integration.js';\nimport { createCustomProvidersPrimer, registerCustomProvidersSource } from './routes/custom-provider-source.js';\nimport { ProjectRoutes } from './routes/projects.js';\nimport { assembleFactoryApiRoutes, buildIntegrationContext } from './routes/surface.js';\nimport type { FactoryApiRoutesDeps } from './routes/surface.js';\nimport {\n createTenantCredentialPrimer,\n primeTenantCredentials,\n registerTenantCredentialResolver,\n} from './routes/tenant-credentials.js';\nimport { builtInFactoryRules } from './rules/defaults.js';\nimport { FactoryDecisionDispatcher } from './rules/dispatcher.js';\nimport { FactoryPhaseStateProcessor } from './rules/processor.js';\nimport { createFactoryTransitionTools } from './rules/tools.js';\nimport { FactoryTransitionService } from './rules/transition-service.js';\nimport type { FactoryRules } from './rules/types.js';\nimport { assertFactoryRules } from './rules/validation.js';\nimport { SandboxFleet } from './sandbox/fleet.js';\nimport { registerSandboxReattach } from './sandbox/reattach.js';\nimport { handleServerError } from './server-error.js';\nimport { observeSessionFilesystem } from './session/filesystem-capture.js';\nimport { createSpaStaticMiddleware, resolveUiDistDir } from './spa-static.js';\nimport { createStateSigner } from './state-signing.js';\nimport { observeAgentGitAction } from './storage/domains/audit/agent-audit.js';\nimport { AuditStorage } from './storage/domains/audit/base.js';\nimport { AuditDomain } from './storage/domains/audit/domain.js';\nimport { ChannelIdentityStorage } from './storage/domains/channel-identity/base.js';\nimport { ModelCredentialsStorage } from './storage/domains/credentials/base.js';\nimport { CustomProvidersStorage } from './storage/domains/custom-providers/base.js';\nimport { FilesystemStorage } from './storage/domains/filesystem/base.js';\nimport { IntakeStorage } from './storage/domains/intake/base.js';\nimport { IntegrationStorage } from './storage/domains/integrations/base.js';\nimport { MemorySettingsStorage } from './storage/domains/memory-settings/base.js';\nimport { ModelPacksStorage } from './storage/domains/model-packs/base.js';\nimport { FactoryProjectsStorage } from './storage/domains/projects/base.js';\nimport { QueueHealthStorage } from './storage/domains/queue-health/base.js';\nimport { SourceControlStorage } from './storage/domains/source-control/base.js';\nimport { WorkItemsStorage } from './storage/domains/work-items/base.js';\nimport { timedPhase } from './timing.js';\nimport { createWorkspaceFactory } from './workspace.js';\n\ntype BuildApiRoutesDeps = Pick<FactoryApiRoutesDeps, 'controller' | 'authStorage'>;\n\n/** Constructor args for the `new Mastra(...)` literal in the deploy entry. */\nexport type MastraArgs = NonNullable<ConstructorParameters<typeof Mastra>[0]>;\n\nexport interface MastraFactoryConfig {\n /**\n * Auth provider instance — `MastraAuthStudio` (`@mastra/auth-studio`),\n * `MastraAuthWorkos` (`@mastra/auth-workos`), `MastraAuthBetterAuth`\n * (`@mastra/auth-better-auth`), or any custom `MastraAuthProvider`. Whatever\n * instance is passed is the active provider; a passed instance is always\n * honored as-is.\n *\n * Omitted → the factory defaults to `MastraAuthStudio`, proxying auth\n * through the shared Mastra platform API. `MastraAuthStudio` resolves its\n * own env (`MASTRA_SHARED_API_URL`, `MASTRA_ORGANIZATION_ID`,\n * `MASTRA_COOKIE_DOMAIN`).\n *\n * Pass `null` to disable auth entirely (open server, local-dev behavior)\n * without falling back to the default.\n */\n auth?: IMastraAuthProvider | null;\n /**\n * REQUIRED. Factory storage backend powering BOTH agent storage (threads,\n * messages, memory, OM — via `getMastraStorage()`) and the app tables\n * (projects/source-control/audit/intake — via the generic ops surface). Pass a\n * `PgFactoryStorage` (`@mastra/pg`) for deployments or a\n * `LibSQLFactoryStorage` (`@mastra/libsql`) for local dev — one backend,\n * one connection, every feature on.\n */\n storage: FactoryStorage;\n /**\n * Vector store instance for recall search — `PgVector` (`@mastra/pg`) on\n * the same database as `storage`. Omitted → the SDK mount's default vector\n * store resolution applies.\n */\n vector?: MastraVector;\n /**\n * Distributed event bus instance (e.g. `new RedisStreamsPubSub({ url })`).\n * When set, streams/workflows/signals ride it across processes and the\n * controller drops file-based thread locks in favor of pubsub-coordinated\n * leases. Omitted → in-process default.\n */\n pubsub?: PubSub;\n /**\n * Browser-facing origin used to build integration OAuth/install callback\n * URLs and to derive the auth redirect URI. On the platform the SPA is\n * hosted separately, so this MUST be the public API origin.\n * Default: `http://localhost:4111` (the local Factory server, which also\n * serves the UI).\n */\n publicUrl?: string;\n /**\n * Allowed cross-origin SPA origins. The SPA may be served from a separate\n * static host, so credentialed requests must be explicitly allowed.\n */\n allowedOrigins?: string[];\n /** Sandbox configuration. Omitted → repository sandboxes are disabled. */\n sandbox?: MastraFactorySandboxConfig;\n /** Background Factory dispatcher configuration. */\n dispatcher?: MastraFactoryDispatcherConfig;\n /**\n * Deployment-stable secret for signing integration OAuth `state` values.\n * Omitted → a per-process random secret, which is fine for single-process\n * local development but rejected for integrations that declare\n * `requiresStableStateSigner`.\n */\n stateSecret?: string;\n /**\n * Registered capability providers. The factory registers the pieces each\n * `FactoryIntegration` instance provides — HTTP routes, storage domains,\n * agent/session tools, intake, source control, and diagnostics — into the\n * system. When Platform credentials are configured, missing `github` and\n * `linear` integrations default to their Platform-backed implementations.\n */\n integrations?: FactoryIntegration[];\n /**\n * Authoritative Factory board, tool-result, and GitHub-event rules. Construct\n * with `defaultFactoryRules({ version, overrides })` so deployment policy has\n * an explicit version and exact handler leaves replace rather than compose.\n * Omitted → conservative built-in rules for the current deployment.\n */\n rules?: FactoryRules;\n\n /**\n * Platform-specific overrides. When the Platform-backed GitHub integration\n * is active, it derives a `runIssueTriage` runner from the mounted\n * controller automatically. An explicit `runIssueTriage` here takes\n * precedence over the controller-derived default. `githubAppSlug` identifies\n * Factory's own GitHub App writes so their webhook deliveries do not retrigger\n * triage.\n */\n platform?: {\n runIssueTriage?: (input: GithubIssueTriageInput) => Promise<GithubIssueTriageResult>;\n githubAppSlug?: string;\n };\n}\n\nexport interface MastraFactorySandboxConfig {\n /**\n * Template machine — `RailwaySandbox` (`@mastra/railway`), core\n * `LocalSandbox` (`@mastra/core/workspace`), or any `WorkspaceSandbox` that\n * implements `clone()`. Each project-repository execution environment gets\n * its own sandbox cloned from this machine; the machine itself is never\n * started. `prepare()` fails fast when the instance lacks `clone()`.\n */\n machine: WorkspaceSandbox;\n /**\n * In-sandbox base directory repos check out under (nested `owner/name` per\n * repo). Default: the machine's own `workingDirectory` when it exposes one\n * (core `LocalSandbox` does), else `/workspace`.\n */\n workdir?: string;\n /**\n * Per-replica cap on concurrently provisioned sandboxes. `0`/omitted means\n * unlimited. A lightweight per-process budget, not a cross-replica scheduler.\n */\n maxSandboxes?: number;\n}\n\n/**\n * Per-process cap on concurrent background Factory dispatches. Omitted means\n * the dispatcher default; this is a local replica budget, not a global queue\n * limit shared across deployments.\n */\nexport interface MastraFactoryDispatcherConfig {\n maxInFlight?: number;\n}\n\nconst CONTROLLER_ID = 'code';\n\nfunction hasPlatformSecretKey(): boolean {\n return Boolean(process.env.MASTRA_PLATFORM_SECRET_KEY?.trim());\n}\n\n/**\n * The template sandbox's own working directory, when it exposes one as a\n * string (core `LocalSandbox` does; remote providers generally don't).\n * Used as the default checkout base so a local template rooted at a host\n * directory checks repos out under that same root.\n */\nfunction templateWorkingDirectory(sandbox: WorkspaceSandbox): string | undefined {\n const wd = (sandbox as { workingDirectory?: unknown }).workingDirectory;\n return typeof wd === 'string' && wd.length > 0 ? wd : undefined;\n}\n\nfunction resolveSandboxWorkdirBase(machine: WorkspaceSandbox, configuredWorkdir?: string): string {\n const machineWorkdir = templateWorkingDirectory(machine);\n const workdir =\n configuredWorkdir === '/workspace' && machineWorkdir ? machineWorkdir : (configuredWorkdir ?? machineWorkdir);\n return (workdir ?? '/workspace').replace(/\\/+$/, '');\n}\n\n/**\n * Default auth provider — `MastraAuthStudio`, which proxies identity to the\n * shared Mastra platform API. `MastraAuthStudio` resolves `MASTRA_SHARED_API_URL`,\n * `MASTRA_ORGANIZATION_ID`, and `MASTRA_COOKIE_DOMAIN` from env on its own —\n * this helper only derives a cookie-domain fallback from the factory's\n * `publicUrl`.\n *\n * Cookie-domain resolution (Studio picks the first that wins):\n * 1. explicit `MASTRA_COOKIE_DOMAIN` env, if set;\n * 2. `.mastra.ai` when `sharedApiUrl` is on `.mastra.ai`;\n * 3. this parent-domain fallback derived from `publicUrl` — so a deploy on\n * `https://foo.mastra.cloud` mints cookies with `Domain=.mastra.cloud`\n * without the caller wiring the env var by hand.\n * 4. otherwise host-only (no `Domain=`), which is correct for `localhost`.\n */\nfunction buildDefaultStudioAuth(publicUrl: string): IMastraAuthProvider {\n return new MastraAuthStudio({\n cookieDomain: parentDomainFromPublicUrl(publicUrl),\n });\n}\n\n/**\n * Derive a parent cookie domain from `publicUrl` by stripping the leftmost\n * label — the same shape platform-API's env injection uses (see\n * `platform/servers/api/src/lib/studio-env-vars.ts`: `.${routingDomain.replace(/^[^.]+\\./, '')}`).\n *\n * Rather than a generic `strip-left-label` heuristic — which either emits\n * cookies scoped to a public suffix (`sub.example.co.uk` → `.example.co.uk`\n * requires PSL data to be safe) or misclassifies numeric hostnames like\n * `3scale.example.com` as IPv4 — we only derive a parent domain when the\n * host sits under one of the platform's known registrable domains. Anything\n * else (custom domains, arbitrary tenant hostnames, IPs, `localhost`)\n * falls through to host-only cookies. Callers that need a different scope\n * pass `MASTRA_COOKIE_DOMAIN` explicitly (Studio honors that first).\n */\nconst KNOWN_PLATFORM_COOKIE_PARENTS = ['mastra.cloud', 'mastra.ai'] as const;\n\nfunction isIpLiteral(hostname: string): boolean {\n // IPv6 addresses in URLs are bracketed; `URL.hostname` strips the brackets\n // but the address itself still contains `:`. IPv4 is four dot-separated\n // numeric octets — trust the parser to have already validated shape.\n if (hostname.includes(':')) return true;\n return /^\\d+(?:\\.\\d+){3}$/.test(hostname);\n}\n\nfunction parentDomainFromPublicUrl(publicUrl: string): string | undefined {\n let hostname: string;\n try {\n hostname = new URL(publicUrl).hostname.toLowerCase();\n } catch {\n return undefined;\n }\n if (hostname === 'localhost' || isIpLiteral(hostname)) return undefined;\n for (const parent of KNOWN_PLATFORM_COOKIE_PARENTS) {\n // Exact match → we're already on the parent, host-only is correct.\n // Subdomain match → mint the parent-scoped cookie.\n if (hostname === parent) return undefined;\n if (hostname.endsWith(`.${parent}`)) return `.${parent}`;\n }\n return undefined;\n}\n\nexport class MastraFactory {\n readonly #config: MastraFactoryConfig;\n #prepared: Awaited<ReturnType<typeof prepareAgentControllerMount>> | undefined;\n #dispatcher: FactoryDecisionDispatcher | undefined;\n #factoryProcessor: FactoryPhaseStateProcessor | undefined;\n #preparing = false;\n\n constructor(config: MastraFactoryConfig) {\n if (!config?.storage) {\n throw new Error(\n \"MastraFactory: 'storage' is required. Pass a FactoryStorage backend — e.g. \" +\n \"new PgFactoryStorage({ connectionString }) from '@mastra/pg' for deployments, or \" +\n \"new LibSQLFactoryStorage({ url }) from '@mastra/libsql' for local dev.\",\n );\n }\n this.#config = config;\n }\n\n /**\n * Resolve feature readiness, wire every dependency explicitly, and assemble\n * everything needed to construct the server-owned Mastra. Returns the args\n * for the `new Mastra(...)` literal that must live in the entry file.\n */\n async prepare(): Promise<MastraArgs> {\n // Guard set synchronously (before the first await) so overlapping calls —\n // not just strictly sequential ones — can't double-seed the runtime\n // registry or double-run one-time adapter init.\n if (this.#preparing) throw new Error('MastraFactory.prepare() called twice');\n this.#preparing = true;\n\n const publicOrigin = (this.#config.publicUrl ?? 'http://localhost:4111').replace(/\\/+$/, '');\n const allowedOrigins = (this.#config.allowedOrigins ?? []).map(o => o.replace(/\\/+$/, '')).filter(Boolean);\n const storage = this.#config.storage;\n const vector = this.#config.vector;\n const pubsub = this.#config.pubsub;\n // Default auth: honor an explicitly-passed provider (including `null` to\n // disable auth) as-is; otherwise fall back to `MastraAuthStudio`\n // (platform-proxied identity). The default derives its cookie domain\n // from `publicUrl` — deploys on `<sub>.mastra.cloud` mint parent-domain\n // cookies without the caller wiring `MASTRA_COOKIE_DOMAIN` explicitly.\n const configuredAuth = this.#config.auth;\n const auth: IMastraAuthProvider | undefined =\n configuredAuth === null ? undefined : (configuredAuth ?? buildDefaultStudioAuth(publicOrigin));\n // One RouteAuth seam per boot, closed over the resolved provider. Every\n // factory route module receives this handle — no service locator.\n const routeAuth = createFactoryRouteAuth(auth);\n\n // Explicit integrations win. Platform credentials fill only missing GitHub\n // and Linear slots so callers can override either provider independently.\n const integrations = [...(this.#config.integrations ?? [])];\n if (hasPlatformSecretKey()) {\n if (!integrations.some(integration => integration.id === 'github')) {\n integrations.push(\n new PlatformGithubIntegration({\n runIssueTriage: this.#config.platform?.runIssueTriage,\n slug: this.#config.platform?.githubAppSlug,\n }),\n );\n }\n if (!integrations.some(integration => integration.id === 'linear')) {\n integrations.push(new PlatformLinearIntegration());\n }\n }\n\n // Validate ids up front so a copy-paste duplicate fails loud instead of one\n // instance silently shadowing the other.\n const integrationIds = new Set<string>();\n for (const integration of integrations) {\n if (integrationIds.has(integration.id)) {\n throw new Error(`MastraFactory: duplicate integration id '${integration.id}' in 'integrations'.`);\n }\n integrationIds.add(integration.id);\n }\n const rules = this.#config.rules ?? builtInFactoryRules();\n assertFactoryRules(rules);\n\n // FactoryStorage owns every app-table domain and initializes them through\n // the same lifecycle as the backend connection.\n const intakeStorage = storage.registerDomain(new IntakeStorage());\n const auditStorage = storage.registerDomain(new AuditStorage());\n const workItemsStorage = storage.registerDomain(new WorkItemsStorage());\n const modelCredentialsStorage = storage.registerDomain(new ModelCredentialsStorage());\n const modelPacksStorage = storage.registerDomain(new ModelPacksStorage());\n const memorySettingsStorage = storage.registerDomain(new MemorySettingsStorage());\n const customProvidersStorage = storage.registerDomain(new CustomProvidersStorage());\n const queueHealthStorage = storage.registerDomain(new QueueHealthStorage());\n // Generic integration storage (connections/subscriptions/settings) — the\n // default persistence surface for integrations without a bespoke domain.\n const integrationStorage = storage.registerDomain(new IntegrationStorage());\n const factoryProjectsStorage = storage.registerDomain(new FactoryProjectsStorage());\n const filesystemStorage = storage.registerDomain(new FilesystemStorage());\n const sourceControlStorage = storage.registerDomain(new SourceControlStorage());\n // Reverse index from a platform sender (Slack/Discord/...) to a Mastra\n // tenant, so inbound channel events can resolve the sender's model creds.\n const channelIdentityStorage = storage.registerDomain(new ChannelIdentityStorage());\n // Every app-table domain handle the route builders and integrations need,\n // threaded explicitly (no service locator).\n const domains = {\n intake: intakeStorage,\n modelCredentials: modelCredentialsStorage,\n modelPacks: modelPacksStorage,\n memorySettings: memorySettingsStorage,\n customProviders: customProvidersStorage,\n filesystem: filesystemStorage,\n projects: factoryProjectsStorage,\n queueHealth: queueHealthStorage,\n workItems: workItemsStorage,\n channelIdentity: channelIdentityStorage,\n };\n const projectRoutes = new ProjectRoutes({\n auth: routeAuth,\n projects: factoryProjectsStorage,\n sourceControl: sourceControlStorage,\n versionControlIntegrationIds: integrations\n .filter(integration => integration.versionControl)\n .map(integration => integration.id),\n });\n const auditDomain = new AuditDomain({\n auth: routeAuth,\n audit: auditStorage,\n projects: factoryProjectsStorage,\n users: auth && isUserProvider(auth) ? auth : undefined,\n sinks: integrations,\n agentTenant: requestContext => {\n const user = requestContext.get('user') as FactoryAuthUser | undefined;\n return { orgId: getFactoryAuthOrgId(user), userId: getFactoryAuthUserId(user) };\n },\n });\n\n // Repository execution needs one sandbox per project-repository link,\n // cloned from the configured machine. A machine without `clone()` would\n // only fail on first use, so fail fast at boot instead.\n const sandboxConfig = this.#config.sandbox;\n const machine = sandboxConfig?.machine;\n if (machine && typeof machine.clone !== 'function') {\n throw new Error(\n `MastraFactory: the configured sandbox machine (provider '${machine.provider}') does not implement clone(). ` +\n `Project repositories each get their own sandbox cloned from the configured machine. ` +\n `Pass a machine that implements clone() — e.g. RailwaySandbox (@mastra/railway) or ` +\n `LocalSandbox (@mastra/core/workspace) — or omit 'sandbox' to disable sandboxes.`,\n );\n }\n\n // One sandbox fleet per boot: constructed with the machine config when\n // sandboxes are configured, disabled otherwise. Handed to integrations\n // through the IntegrationContext — no global registry.\n const fleet = new SandboxFleet(\n machine\n ? {\n machine,\n workdirBase: resolveSandboxWorkdirBase(machine, sandboxConfig?.workdir),\n maxSandboxes: sandboxConfig?.maxSandboxes,\n }\n : undefined,\n );\n // Core's `getDynamicWorkspace` reattaches project sandboxes through the\n // SDK seam; only this factory owns the fleet, so register it here.\n registerSandboxReattach(fleet);\n\n // One shared OAuth state signer per boot. The deploy entry supplies a\n // replica-stable secret when needed; otherwise local development gets a\n // per-process random signer (`stable: false`).\n const stateSigner = createStateSigner(this.#config.stateSecret);\n\n // One-time provider initialization with factory-level context (e.g.\n // better-auth builds its default instance on the backend's auth\n // database, WorkOS derives its redirect URI from the public URL).\n // Failures surface here, at prepare() — a misconfigured provider must\n // not boot.\n if (auth && hasAuthInit(auth)) {\n await timedPhase('prepare.auth.init', () =>\n auth.init({ database: storage.authDatabase?.(), publicUrl: publicOrigin, allowedOrigins }),\n );\n }\n\n // Single init path: backend connection failure is a hard boot error;\n // registered app domains initialize fail-soft inside FactoryStorage.\n await timedPhase('prepare.storage.init', () => storage.init());\n\n // Per-tenant model credentials: once the credentials domain is up, model\n // resolution goes through the caller's own store and the SDK stops\n // mirroring stored API keys into process.env.\n //\n // Only register when a real auth adapter gates callers. In local /\n // auth-disabled mode there is no authenticated tenant, so registering would\n // force every model call through an empty tenant store (fail-closed, no env\n // fallback) and break chat with \"Not logged in\". Leaving it unregistered\n // lets the SDK fall back to the file-backed AuthStorage (auth.json) — the\n // same store the local /login and Settings pages read and write.\n if (auth) {\n registerTenantCredentialResolver(modelCredentialsStorage);\n }\n\n // Custom providers: DB-backed in both modes (org rows in tenant mode, the\n // sentinel `local` org in no-auth mode). Once registered, model resolution\n // and the gateway catalog never read settings.json custom providers.\n registerCustomProvidersSource({ storage: customProvidersStorage, authEnabled: Boolean(auth) });\n\n for (const integration of integrations) {\n integration.initialize?.({\n storage: integrationStorage.forIntegration(integration.id),\n projects: factoryProjectsStorage,\n auth: routeAuth,\n });\n if (integration.versionControl) {\n integration.versionControl.initialize({\n storage: sourceControlStorage.forIntegration(integration.id),\n });\n }\n }\n\n // Every integration uses generic integration storage. Version-control\n // providers additionally require the source-control storage domain. Readiness\n // is derived solely from capability presence, never from provider ids.\n const integrationRegistrations = integrations.map(integration => {\n const requiredDomains = [\n 'integrations',\n ...(integration.versionControl ? ['source-control'] : []),\n // Channels resolve an inbound sender to a tenant through the reverse\n // index; without it every message would dispatch tenant-less.\n ...(integration.channels ? ['channel-identity'] : []),\n ];\n return {\n integration,\n ready: requiredDomains.every(domain => storage.isDomainReady(domain)),\n ensureReady: async () => {\n for (const domain of requiredDomains) await storage.ensureDomainReady(domain);\n },\n };\n });\n const intakeReady =\n integrations.some(integration => integration.intake !== undefined) && storage.isDomainReady('intake');\n const factoryReady = storage.isDomainReady('projects') && storage.isDomainReady('work-items');\n const githubIntegration = integrations.find(integration => integration.id === 'github') as\n | GithubIntegration\n | undefined;\n const workItemsReady = storage.isDomainReady('work-items');\n // Terminal work items release their session sandboxes back to the reuse\n // pool so the next session for the same repository/user claims a warm VM\n // instead of provisioning fresh. Remote providers only: local \"sandboxes\"\n // are the host machine with per-session workdirs — nothing to pool.\n const releaseTerminalSandboxes =\n machine && !(machine instanceof LocalSandbox) && workItemsReady && storage.isDomainReady('source-control')\n ? async ({ orgId, workItemId }: { orgId: string; workItemId: string }) =>\n releaseWorkItemSandboxes({\n workItems: workItemsStorage,\n sourceControl: sourceControlStorage.forIntegration('github'),\n fleet,\n orgId,\n workItemId,\n })\n : undefined;\n const transitionService = workItemsReady\n ? new FactoryTransitionService({\n rules,\n storage: workItemsStorage,\n ...(releaseTerminalSandboxes ? { onTerminalStage: releaseTerminalSandboxes } : {}),\n })\n : undefined;\n const factoryProcessor = workItemsReady\n ? new FactoryPhaseStateProcessor({\n rules,\n storage: workItemsStorage,\n ...(transitionService ? { transitionService } : {}),\n ...(githubIntegration\n ? {\n recordPullRequestProvenance: (input: Parameters<typeof recordFactoryPullRequestProvenance>[3]) =>\n recordFactoryPullRequestProvenance(\n githubIntegration,\n sourceControlStorage.forIntegration('github'),\n integrationStorage.forIntegration('github'),\n input,\n ),\n }\n : {}),\n messageReader: {\n listMessages: async input => {\n const memory = await storage.getMastraStorage().getStore('memory');\n return memory ? memory.listMessages(input) : { messages: [], hasMore: false };\n },\n },\n })\n : undefined;\n\n // Boot assertion: an active integration that signs OAuth `state` needs a\n // replica-stable signer — a per-process random secret silently breaks the\n // OAuth callback on any replica that didn't sign the state. Fail loud now\n // instead. (The built-ins also assert this inside their readiness gates.)\n for (const { integration } of integrationRegistrations) {\n if (integration.requiresStableStateSigner && !stateSigner.stable) {\n throw new Error(\n `MastraFactory: integration '${integration.id}' signs OAuth state and requires a ` +\n `replica-stable state secret, but none is configured. Set 'stateSecret' on the factory config.`,\n );\n }\n }\n\n // The SDK needs to know which backend the injected Mastra store uses\n // (its own `instanceof` detection breaks when the dependency graph holds\n // duplicate package copies). Resolve it by walking the FactoryStorage\n // prototype chain by class name — the factory can't import the concrete\n // classes since '@mastra/pg' / '@mastra/libsql' are the user's choice.\n const mastraStorageBackend = (() => {\n for (let proto = Object.getPrototypeOf(storage); proto; proto = Object.getPrototypeOf(proto)) {\n if (proto.constructor?.name === 'PgFactoryStorage') return 'pg' as const;\n if (proto.constructor?.name === 'LibSQLFactoryStorage') return 'libsql' as const;\n }\n return undefined;\n })();\n\n // Integrations contributing tools to agent sessions: org-scoped\n // `agentTools` (resolved per request) + session-scoped `sessionTools`.\n const toolIntegrations = integrationRegistrations.filter(\n ({ integration }) => integration.agentTools || integration.sessionTools,\n );\n\n // Build the real production controller (agents, modes, tools, memory, OM,\n // MCP, providers) — identical to the terminal app. Agent state lives in\n // the storage backend's Mastra store alongside the Factory app tables —\n // one shared database for all users, separated by `resourceId` scoping.\n const prepared = await timedPhase('prepare.controllerMount', () =>\n prepareAgentControllerMount({\n controllerId: CONTROLLER_ID,\n workspace: createWorkspaceFactory({\n ...(this.#config.sandbox ? { sandbox: this.#config.sandbox } : {}),\n ...(githubIntegration ? { github: githubIntegration } : {}),\n ...(workItemsStorage ? { workItems: workItemsStorage } : {}),\n fleet,\n }),\n disableGithubSignals: true,\n // Memory settings live in the factory's `memory-settings` app table (per\n // org/user), so the host machine's TUI settings.json must not seed them.\n disableSettingsOmSeed: true,\n // A factory reads the repository it works on and its skill, never the\n // ~/.claude instructions of whoever hosts the process. On the controller\n // rather than per session, so webhook-recreated sessions keep it too.\n initialState: { skipGlobalInstructions: true },\n storage: storage.getMastraStorage(),\n ...(mastraStorageBackend ? { storageBackend: mastraStorageBackend } : {}),\n ...(factoryProcessor ? { inputProcessors: [factoryProcessor] } : {}),\n ...(vector ? { vector } : {}),\n ...(toolIntegrations.length > 0 || (workItemsStorage && transitionService)\n ? {\n extraTools: async ({ requestContext }: { requestContext: RequestContext }) => {\n const tools: IntegrationTools = {};\n const toolOwners = new Map<string, string>();\n const mergeTools = (ownerId: string, contributed: IntegrationTools) => {\n for (const [name, tool] of Object.entries(contributed)) {\n const owner = toolOwners.get(name);\n if (owner) {\n throw new Error(\n `MastraFactory: integration tool '${name}' from '${ownerId}' conflicts with '${owner}'.`,\n );\n }\n toolOwners.set(name, ownerId);\n tools[name] = tool;\n }\n };\n if (workItemsStorage && transitionService) {\n mergeTools(\n 'factory',\n await createFactoryTransitionTools({\n requestContext,\n storage: workItemsStorage,\n transitionService,\n // Heals crash-resumed sessions: recovered addresses re-seed\n // projectRepositoryId/baseRef from the source session record.\n // Only offered while the source-control domain is ready — a\n // throwing lookup would abort recovery's catch block and also\n // skip the metadata baseRef fallback.\n ...(storage.isDomainReady('source-control')\n ? { sessions: sourceControlStorage.forIntegration('github').sessions }\n : {}),\n }),\n );\n }\n for (const { integration, ready, ensureReady } of toolIntegrations) {\n if (!ready && ensureReady) {\n try {\n await ensureReady();\n } catch {\n continue;\n }\n }\n if (integration.agentTools) {\n mergeTools(integration.id, await integration.agentTools({ requestContext }));\n }\n if (integration.sessionTools) {\n mergeTools(integration.id, integration.sessionTools({ requestContext }));\n }\n }\n return tools;\n },\n }\n : {}),\n postToolObserver: async (toolContext: IntegrationPostToolContext) => {\n const requestContext = (toolContext.context as { requestContext?: RequestContext } | undefined)\n ?.requestContext;\n if (requestContext) {\n await observeAgentGitAction({\n audit: auditDomain,\n toolContext: { ...toolContext, context: requestContext },\n });\n }\n await Promise.all(\n integrations.map(async integration => {\n if (!integration.postToolObserver) return;\n try {\n await integration.postToolObserver({ toolContext, requestContext });\n } catch (error) {\n console.warn(`[factory] Integration '${integration.id}' post-tool observer failed:`, error);\n }\n }),\n );\n },\n ...(pubsub ? { pubsub, crossProcessPubSub: true } : {}),\n buildApiRoutes: ({ controller, authStorage }: BuildApiRoutesDeps) => [\n // Public `/auth/*` routes (login/callback/logout/me). Folded in as\n // `apiRoutes` (not plain Hono routes) because the entry can't touch the\n // Hono app the deployer generates. `requiresAuth: false`; the gate\n // skips `/auth/*`.\n ...(auth ? buildAuthRoutes(auth, { publicUrl: publicOrigin }) : []),\n // Custom `/web/*` routes (fs / config / integrations / factory / audit).\n ...assembleFactoryApiRoutes({\n controllerId: CONTROLLER_ID,\n controller,\n auth: routeAuth,\n authStorage,\n audit: auditDomain,\n publicOrigin,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n domains,\n integrations: integrationRegistrations,\n intakeReady,\n factoryReady,\n rules,\n factoryTransitionService: transitionService,\n onFactoryRuntime: ({ transitionService: runtimeTransitionService, prepareBinding }) => {\n this.#dispatcher ??= new FactoryDecisionDispatcher({\n controller,\n transitionService: runtimeTransitionService,\n storage: storage.getDomain<WorkItemsStorage>('work-items'),\n maxInFlight: this.#config.dispatcher?.maxInFlight,\n reconcileToolResults: () => factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),\n prepareBinding,\n primeCredentials: tenant => primeTenantCredentials({ tenant, credentials: modelCredentialsStorage }),\n });\n },\n }),\n ...projectRoutes.routes(),\n ...auditDomain.routes(),\n ],\n buildServerConfig: () => {\n const cors = allowedOrigins.length ? { cors: { origin: allowedOrigins, credentials: true } } : {};\n // Log route errors with method/path/stack and answer with structured\n // JSON instead of an opaque `Internal Server Error`. Applied by the\n // deployer to both the top-level app and the custom-route sub-app.\n const onError = { onError: handleServerError };\n // Same-origin SPA: when a vite build is present (see resolveUiDistDir),\n // serve it at `/` from this server. Mounted last so the auth gate (when\n // enabled) covers it; it always passes `/api`, `/web`, `/auth` through.\n const uiDist = resolveUiDistDir();\n const spa = uiDist ? [createSpaStaticMiddleware(uiDist)] : [];\n if (!auth) {\n // Auth disabled: no gate. Still prime the sentinel-local custom\n // provider snapshot so model calls see DB rows, then SPA + CORS.\n return {\n middleware: [\n createCustomProvidersPrimer({ auth: routeAuth, storage: customProvidersStorage, authEnabled: false }),\n ...spa,\n ],\n ...cors,\n ...onError,\n };\n }\n\n // Ordered middleware. The deployer applies these AFTER its context\n // middleware sets `c.set('mastra', mastra)` and BEFORE routes, so:\n // 1. gate — validates the auth session, stashes the user, and 401s /\n // redirects unauthenticated requests. Skips public `/auth/*`.\n // 2. primers — hydrate the caller's model-credential and custom\n // provider snapshots so the request's first model call\n // resolves tenant credentials and custom providers.\n // 3. spa — serves the built UI for everything the server doesn't own.\n // `auth` also lands on `server.auth` so the core auth middleware (and\n // Studio's dual-auth routing — see `studio.auth` on the returned args)\n // authenticates core `/api/*` routes with the same provider.\n return {\n auth,\n middleware: [\n createFactoryAuthGate(auth),\n createTenantCredentialPrimer({ auth: routeAuth, credentials: modelCredentialsStorage }),\n createCustomProvidersPrimer({\n auth: routeAuth,\n storage: customProvidersStorage,\n authEnabled: Boolean(auth),\n }),\n ...spa,\n ],\n ...cors,\n ...onError,\n };\n },\n }),\n );\n\n prepared.base.controller.onSessionCreated(session => {\n observeSessionFilesystem(session, {\n filesystem: filesystemStorage,\n sourceControl: sourceControlStorage.forIntegration('github'),\n });\n });\n\n this.#prepared = prepared;\n this.#factoryProcessor = factoryProcessor;\n\n // Chat-platform channels (Slack, Discord, …) contributed by integrations,\n // attached to the mounted controller so inbound platform messages reach\n // the same agents the web UI drives. READY integrations only — readiness\n // means the `channel-identity` domain's `init()` succeeded, so its link\n // table is queryable. Without it a sender can't be resolved to a tenant,\n // and attaching anyway would dispatch runs on default credentials.\n const channelRegistrations = integrationRegistrations.filter(\n ({ integration, ready }) => ready && integration.channels,\n );\n // `setChannels` replaces rather than merges, so a second provider would\n // silently never receive a message. Fail loud instead.\n if (channelRegistrations.length > 1) {\n throw new Error(\n `MastraFactory: integrations [${channelRegistrations\n .map(({ integration }) => integration.id)\n .join(', ')}] all provide channels, but only one may. Remove all but one.`,\n );\n }\n for (const { integration } of channelRegistrations) {\n // Integrations return a channels CONFIG; the factory owns construction.\n prepared.base.controller.setChannels(\n new AgentControllerChannels(\n integration.channels!(\n buildIntegrationContext(\n {\n controller: prepared.base.controller,\n publicOrigin,\n auth: routeAuth,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n rules,\n factoryReady,\n domains,\n ...(githubIntegration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n ),\n ),\n ),\n );\n }\n\n // Integration lifecycle workers (e.g. polling an upstream without\n // webhooks): collected from READY integrations only, folded into the\n // constructor args so `new Mastra(...)` merges them with the default\n // workers and `finalize()`'s `startWorkers()` starts them alongside the\n // built-ins. Never passed for the disabled/not-ready case — a worker for\n // an unavailable integration must not run.\n const integrationWorkers = integrationRegistrations\n .filter(({ integration, ready }) => ready && integration.workers)\n .flatMap(({ integration }) =>\n integration.workers!(\n buildIntegrationContext(\n {\n controller: prepared.base.controller,\n publicOrigin,\n auth: routeAuth,\n stateSigner,\n fleet,\n factoryStorage: storage,\n integrationStorage,\n sourceControlStorage,\n rules,\n factoryReady,\n domains,\n ...(githubIntegration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n ),\n ),\n );\n\n return {\n ...prepared.mastraArgs,\n // Same provider on `studio.auth` as on `server.auth` (buildServerConfig):\n // deployed factories must authenticate BOTH plain API callers and Studio\n // requests (`x-mastra-client-type: studio` routes to `studio.auth`).\n ...(auth ? { studio: { auth } } : {}),\n ...(integrationWorkers.length > 0 ? { workers: integrationWorkers } : {}),\n };\n }\n\n /**\n * Post-construct boot: initialize the controller (which inherits the\n * constructed Mastra's storage) and start its workers. Call AFTER the entry\n * has run `new Mastra(prepare()'s args)`.\n */\n async finalize(): Promise<void> {\n if (!this.#prepared) {\n throw new Error('MastraFactory.finalize() called before prepare()');\n }\n await timedPhase('finalize.controller', () => this.#prepared!.finalize());\n await timedPhase(\n 'finalize.reconcileBoundThreads',\n () => this.#factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),\n );\n this.#dispatcher?.start();\n }\n\n /** Stop Factory-owned background dispatch before the host process shuts down. */\n async shutdown(): Promise<void> {\n await this.#dispatcher?.stop();\n }\n}\n"],"mappings":"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"}
@@ -33,6 +33,7 @@ import type { AuditEmitter } from '../storage/domains/audit/domain.js';
33
33
  import type { ChannelIdentityStorage } from '../storage/domains/channel-identity/base.js';
34
34
  import type { IntakeStorage } from '../storage/domains/intake/base.js';
35
35
  import type { IntegrationStorageHandle } from '../storage/domains/integrations/base.js';
36
+ import type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';
36
37
  import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
37
38
  import type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';
38
39
  import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
@@ -94,6 +95,11 @@ export interface IntegrationContext {
94
95
  sourceControlOwner?: SourceControlStorageHandle;
95
96
  /** Factory projects domain — e.g. resolving a project's default model. */
96
97
  projects: FactoryProjectsStorage;
98
+ /**
99
+ * Observational-memory settings domain, so a session an integration starts
100
+ * adopts the same memory configuration the web kickoff applies.
101
+ */
102
+ memorySettings: MemorySettingsStorage;
97
103
  /** Cross-integration intake selection (which sources are synced). */
98
104
  intake: IntakeStorage;
99
105
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/integrations/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/integrations/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,6BAA6B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE7G,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,sEAAsE;IACtE,OAAO,EAAE;QACP,OAAO,EAAE,wBAAwB,CAAC;QAClC,aAAa,EAAE,0BAA0B,CAAC;QAC1C;;;;;;WAMG;QACH,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;QAChD,0EAA0E;QAC1E,QAAQ,EAAE,sBAAsB,CAAC;QACjC;;;WAGG;QACH,cAAc,EAAE,qBAAqB,CAAC;QACtC,qEAAqE;QACrE,MAAM,EAAE,aAAa,CAAC;QACtB;;;;WAIG;QACH,eAAe,EAAE,sBAAsB,CAAC;KACzC,CAAC;IACF;;;;OAIG;IACH,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,YAAY,CAAC;QACrB,SAAS,EAAE,gBAAgB,CAAC;KAC7B,CAAC;IACF,4CAA4C;IAC5C,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AAE9D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,6BAA6B,EAAE,UAAU,CAAC;IAC5F,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;CACtD;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;;OAMG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,wBAAwB,CAAC;QAAC,QAAQ,EAAE,sBAAsB,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;IAClH;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE,CAAC;IAC5C;;;;OAIG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjF;;;OAGG;IACH,YAAY,CAAC,CAAC,IAAI,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,gBAAgB,CAAC;IAC1E;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,0BAA0B,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrH;;;;;;;;OAQG;IACH,OAAO,CAAC,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE,CAAC;IAClD;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,CAAC,GAAG,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IAC1D;;;OAGG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC;;;OAGG;IACH,KAAK,CAAC,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,aAAa,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD;;;;;OAKG;IACH,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAC9C"}
@@ -29,7 +29,7 @@ import { Octokit } from '@octokit/rest';
29
29
  import type { Intake } from '../../capabilities/intake.js';
30
30
  import type { VersionControl } from '../../capabilities/version-control.js';
31
31
  import type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../base.js';
32
- import type { ReconcilePullRequestState } from './rules.js';
32
+ import type { ReconcileIssueState, ReconcilePullRequestState } from './rules.js';
33
33
  import type { GithubSubscriptionStorage } from './subscriptions.js';
34
34
  /**
35
35
  * Normalize a PEM private key supplied via env. Env tooling tends to mangle
@@ -60,6 +60,7 @@ export interface IssueSummary {
60
60
  title: string;
61
61
  url: string;
62
62
  author: string | null;
63
+ assignees: string[];
63
64
  labels: string[];
64
65
  comments: number;
65
66
  createdAt: string;
@@ -153,6 +154,8 @@ export declare class GithubIntegration implements FactoryIntegration {
153
154
  getInstallationRepo(installationId: number, repoFullName: string): Promise<RepoSummary | null>;
154
155
  /** Add labels to an issue (deduplicated; no-op on empty/malformed input). */
155
156
  addIssueLabels(installationId: number, repoFullName: string, issueNumber: number, labels: string[]): Promise<void>;
157
+ /** Remove one label from an issue. */
158
+ removeIssueLabel(installationId: number, repoFullName: string, issueNumber: number, label: string): Promise<void>;
156
159
  /**
157
160
  * List one page of a repo's open issues through an installation token. The
158
161
  * issues API also returns pull requests, so those are filtered out (the
@@ -195,6 +198,16 @@ export declare class GithubIntegration implements FactoryIntegration {
195
198
  repository: string;
196
199
  number: number;
197
200
  }): Promise<ReconcilePullRequestState | undefined>;
201
+ /**
202
+ * Reads live issue state for the reconciler. Returns undefined when the
203
+ * issue cannot be resolved (missing, is actually a PR, API error) so a
204
+ * sweep never fabricates a close.
205
+ */
206
+ fetchIssueState(input: {
207
+ installationId: number;
208
+ repository: string;
209
+ number: number;
210
+ }): Promise<ReconcileIssueState | undefined>;
198
211
  /**
199
212
  * Session-scoped agent tools for token refresh and PR subscriptions in
200
213
  * sessions bound to a GitHub-backed project. Empty elsewhere.
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/integration.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { createGithubSubscriptionTools, parseCreatedPullRequest, subscribeCurrentSessionToPullRequest } from "./session-subscriptions.js";
2
+ import { attachGithubReconciler, attachGithubRules } from "./rules.js";
3
+ import { attachGithubIssueReconciler } from "./issue-reconciler.js";
2
4
  import { runGithubIssueTriage } from "./issue-triage.js";
3
5
  import { buildGithubRoutes } from "./routes.js";
4
- import { attachGithubReconciler, attachGithubRules } from "./rules.js";
5
6
  import { GithubReconcileWorker } from "./reconcile-worker.js";
6
7
  import { createAppAuth } from "@octokit/auth-app";
7
8
  import { Octokit } from "@octokit/rest";
@@ -399,7 +400,8 @@ var GithubIntegration = class {
399
400
  state: "open",
400
401
  stateType: "open",
401
402
  priority: null,
402
- assignee: null,
403
+ assignee: issue.assignees[0] ?? null,
404
+ assignees: issue.assignees,
403
405
  source: repoFullName,
404
406
  labels: issue.labels,
405
407
  commentCount: issue.comments,
@@ -438,6 +440,7 @@ var GithubIntegration = class {
438
440
  stateType: issue.state,
439
441
  priority: null,
440
442
  assignee: issue.assignee?.login ?? null,
443
+ assignees: (issue.assignees ?? []).map((user) => user.login).filter((login) => Boolean(login)),
441
444
  source: repoFullName,
442
445
  labels: issue.labels.map((label) => typeof label === "string" ? label : label.name ?? "").filter(Boolean),
443
446
  commentCount: issue.comments,
@@ -495,6 +498,7 @@ var GithubIntegration = class {
495
498
  stateType: issue.state,
496
499
  priority: null,
497
500
  assignee: issue.assignee?.login ?? null,
501
+ assignees: (issue.assignees ?? []).map((user) => user.login).filter((login) => Boolean(login)),
498
502
  source: repoFullName,
499
503
  labels: issue.labels.map((label) => typeof label === "string" ? label : label.name ?? "").filter(Boolean),
500
504
  commentCount: issue.comments,
@@ -825,6 +829,18 @@ var GithubIntegration = class {
825
829
  labels: uniqueLabels
826
830
  });
827
831
  }
832
+ /** Remove one label from an issue. */
833
+ async removeIssueLabel(installationId, repoFullName, issueNumber, label) {
834
+ const parts = splitRepoFullName(repoFullName);
835
+ const labelName = label.trim();
836
+ if (!parts || !labelName) return;
837
+ await this.getInstallationOctokit(installationId).issues.removeLabel({
838
+ owner: parts.owner,
839
+ repo: parts.repo,
840
+ issue_number: issueNumber,
841
+ name: labelName
842
+ });
843
+ }
828
844
  /**
829
845
  * List one page of a repo's open issues through an installation token. The
830
846
  * issues API also returns pull requests, so those are filtered out (the
@@ -851,6 +867,7 @@ var GithubIntegration = class {
851
867
  title: issue.title,
852
868
  url: issue.html_url,
853
869
  author: issue.user?.login ?? null,
870
+ assignees: issue.assignees?.flatMap((assignee) => assignee.login ? [assignee.login] : []) ?? [],
854
871
  labels: issue.labels.map((label) => typeof label === "string" ? label : label.name ?? "").filter(Boolean),
855
872
  comments: issue.comments,
856
873
  createdAt: issue.created_at,
@@ -936,11 +953,14 @@ var GithubIntegration = class {
936
953
  if (process.env.MASTRACODE_GITHUB_RECONCILE_ENABLED?.trim().toLowerCase() === "false") return [];
937
954
  const reconcile = attachGithubReconciler(this, ctx, (input) => this.fetchPullRequestState(input));
938
955
  if (!reconcile) return [];
956
+ const issues = attachGithubIssueReconciler(this, ctx, (input) => this.fetchIssueState(input));
939
957
  const intervalMs = Number(process.env.MASTRACODE_GITHUB_RECONCILE_INTERVAL_MS);
958
+ const interval = Number.isSafeInteger(intervalMs) && intervalMs > 0 ? { intervalMs } : {};
940
959
  return [new GithubReconcileWorker({
941
960
  reconcile,
961
+ ...issues ? { reconcileIssues: issues } : {},
942
962
  sourceControl: ctx.storage.sourceControl,
943
- ...Number.isSafeInteger(intervalMs) && intervalMs > 0 ? { intervalMs } : {}
963
+ ...interval
944
964
  })];
945
965
  }
946
966
  /**
@@ -962,9 +982,14 @@ var GithubIntegration = class {
962
982
  title: pullRequest.title,
963
983
  url: pullRequest.url,
964
984
  state: pullRequest.state === "closed" ? "closed" : "open",
985
+ draft: pullRequest.draft,
965
986
  merged: pullRequest.merged,
987
+ assignees: pullRequest.assignees ?? [],
988
+ requestedReviewers: pullRequest.requestedReviewers ?? [],
989
+ labels: pullRequest.labels ?? [],
966
990
  headBranch: pullRequest.headBranch,
967
991
  baseBranch: pullRequest.baseBranch,
992
+ ...pullRequest.author ? { author: pullRequest.author } : {},
968
993
  ...pullRequest.createdAt ? { createdAt: pullRequest.createdAt } : {}
969
994
  };
970
995
  } catch {
@@ -972,6 +997,36 @@ var GithubIntegration = class {
972
997
  }
973
998
  }
974
999
  /**
1000
+ * Reads live issue state for the reconciler. Returns undefined when the
1001
+ * issue cannot be resolved (missing, is actually a PR, API error) so a
1002
+ * sweep never fabricates a close.
1003
+ */
1004
+ async fetchIssueState(input) {
1005
+ const parts = splitRepoFullName(input.repository);
1006
+ if (!parts) return void 0;
1007
+ try {
1008
+ const { data: issue } = await this.getInstallationOctokit(input.installationId).issues.get({
1009
+ owner: parts.owner,
1010
+ repo: parts.repo,
1011
+ issue_number: input.number
1012
+ });
1013
+ if (issue.pull_request) return void 0;
1014
+ return {
1015
+ title: issue.title,
1016
+ url: issue.html_url,
1017
+ state: issue.state === "closed" ? "closed" : "open",
1018
+ ...issue.state_reason ? { stateReason: issue.state_reason } : {},
1019
+ assignees: (issue.assignees ?? []).map((user) => user.login).filter((login) => Boolean(login)),
1020
+ labels: (issue.labels ?? []).map((label) => typeof label === "string" ? label : label.name).filter((name) => Boolean(name)),
1021
+ ...issue.user?.login ? { author: issue.user.login } : {},
1022
+ createdAt: issue.created_at,
1023
+ updatedAt: issue.updated_at
1024
+ };
1025
+ } catch {
1026
+ return;
1027
+ }
1028
+ }
1029
+ /**
975
1030
  * Session-scoped agent tools for token refresh and PR subscriptions in
976
1031
  * sessions bound to a GitHub-backed project. Empty elsewhere.
977
1032
  */
@@ -997,6 +1052,9 @@ function parsePullRequest(pr) {
997
1052
  title: pr.title,
998
1053
  url: pr.html_url,
999
1054
  author: pr.user?.login ?? null,
1055
+ assignees: (pr.assignees ?? []).flatMap((assignee) => assignee.login ? [assignee.login] : []),
1056
+ requestedReviewers: (pr.requested_reviewers ?? []).flatMap((reviewer) => reviewer.login ? [reviewer.login] : []),
1057
+ labels: (pr.labels ?? []).flatMap((label) => typeof label === "string" ? [label] : label.name ? [label.name] : []),
1000
1058
  body: pr.body?.trim() ? pr.body : null,
1001
1059
  state: pr.state === "closed" ? "closed" : "open",
1002
1060
  draft: pr.draft ?? false,