@mastra/factory 0.8.0-alpha.8 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/CHANGELOG.md +660 -0
  2. package/dist/factory.d.ts.map +1 -1
  3. package/dist/factory.js +42 -4
  4. package/dist/factory.js.map +1 -1
  5. package/dist/integrations/base.d.ts +8 -0
  6. package/dist/integrations/base.d.ts.map +1 -1
  7. package/dist/integrations/github/app-identity.d.ts +43 -0
  8. package/dist/integrations/github/app-identity.d.ts.map +1 -0
  9. package/dist/integrations/github/app-identity.js +62 -0
  10. package/dist/integrations/github/app-identity.js.map +1 -0
  11. package/dist/integrations/github/integration.d.ts +9 -0
  12. package/dist/integrations/github/integration.d.ts.map +1 -1
  13. package/dist/integrations/github/integration.js +9 -1
  14. package/dist/integrations/github/integration.js.map +1 -1
  15. package/dist/integrations/github/reconcile-worker.d.ts +5 -0
  16. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  17. package/dist/integrations/github/reconcile-worker.js +7 -0
  18. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  19. package/dist/integrations/github/routes.d.ts.map +1 -1
  20. package/dist/integrations/github/routes.js +11 -6
  21. package/dist/integrations/github/routes.js.map +1 -1
  22. package/dist/integrations/github/rules.d.ts +8 -0
  23. package/dist/integrations/github/rules.d.ts.map +1 -1
  24. package/dist/integrations/github/rules.js +30 -8
  25. package/dist/integrations/github/rules.js.map +1 -1
  26. package/dist/integrations/github/sandbox.d.ts +39 -6
  27. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  28. package/dist/integrations/github/sandbox.js +48 -14
  29. package/dist/integrations/github/sandbox.js.map +1 -1
  30. package/dist/integrations/github/webhook.d.ts +39 -0
  31. package/dist/integrations/github/webhook.d.ts.map +1 -1
  32. package/dist/integrations/github/webhook.js +74 -13
  33. package/dist/integrations/github/webhook.js.map +1 -1
  34. package/dist/integrations/linear/integration.d.ts.map +1 -1
  35. package/dist/integrations/linear/integration.js +1 -0
  36. package/dist/integrations/linear/integration.js.map +1 -1
  37. package/dist/integrations/linear/routes.d.ts +10 -0
  38. package/dist/integrations/linear/routes.d.ts.map +1 -1
  39. package/dist/integrations/linear/routes.js +35 -1
  40. package/dist/integrations/linear/routes.js.map +1 -1
  41. package/dist/integrations/linear/rules.d.ts.map +1 -1
  42. package/dist/integrations/linear/rules.js +2 -1
  43. package/dist/integrations/linear/rules.js.map +1 -1
  44. package/dist/integrations/platform/github/event-worker.d.ts +11 -0
  45. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  46. package/dist/integrations/platform/github/event-worker.js +64 -16
  47. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  48. package/dist/integrations/platform/github/integration.d.ts +12 -0
  49. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  50. package/dist/integrations/platform/github/integration.js +47 -4
  51. package/dist/integrations/platform/github/integration.js.map +1 -1
  52. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  53. package/dist/integrations/platform/linear/integration.js +1 -0
  54. package/dist/integrations/platform/linear/integration.js.map +1 -1
  55. package/dist/integrations/slack/slack.d.ts.map +1 -1
  56. package/dist/integrations/slack/slack.js +2 -1
  57. package/dist/integrations/slack/slack.js.map +1 -1
  58. package/dist/routes/config.d.ts +12 -6
  59. package/dist/routes/config.d.ts.map +1 -1
  60. package/dist/routes/config.js +97 -56
  61. package/dist/routes/config.js.map +1 -1
  62. package/dist/routes/fs.d.ts.map +1 -1
  63. package/dist/routes/fs.js +2 -0
  64. package/dist/routes/fs.js.map +1 -1
  65. package/dist/routes/intake.d.ts +15 -0
  66. package/dist/routes/intake.d.ts.map +1 -1
  67. package/dist/routes/intake.js +65 -2
  68. package/dist/routes/intake.js.map +1 -1
  69. package/dist/routes/knowledge.d.ts +152 -0
  70. package/dist/routes/knowledge.d.ts.map +1 -0
  71. package/dist/routes/knowledge.js +442 -0
  72. package/dist/routes/knowledge.js.map +1 -0
  73. package/dist/routes/projects.d.ts +9 -1
  74. package/dist/routes/projects.d.ts.map +1 -1
  75. package/dist/routes/projects.js +8 -0
  76. package/dist/routes/projects.js.map +1 -1
  77. package/dist/routes/surface.d.ts +6 -0
  78. package/dist/routes/surface.d.ts.map +1 -1
  79. package/dist/routes/surface.js +10 -0
  80. package/dist/routes/surface.js.map +1 -1
  81. package/dist/routes/work-items.d.ts.map +1 -1
  82. package/dist/routes/work-items.js +3 -1
  83. package/dist/routes/work-items.js.map +1 -1
  84. package/dist/rules/binding-context.d.ts.map +1 -1
  85. package/dist/rules/binding-context.js +4 -1
  86. package/dist/rules/binding-context.js.map +1 -1
  87. package/dist/rules/defaults.d.ts.map +1 -1
  88. package/dist/rules/defaults.js +87 -4
  89. package/dist/rules/defaults.js.map +1 -1
  90. package/dist/rules/dispatcher.d.ts +6 -0
  91. package/dist/rules/dispatcher.d.ts.map +1 -1
  92. package/dist/rules/dispatcher.js +118 -16
  93. package/dist/rules/dispatcher.js.map +1 -1
  94. package/dist/rules/processor.d.ts.map +1 -1
  95. package/dist/rules/processor.js +20 -7
  96. package/dist/rules/processor.js.map +1 -1
  97. package/dist/rules/resolve.d.ts +1 -0
  98. package/dist/rules/resolve.d.ts.map +1 -1
  99. package/dist/rules/resolve.js +3 -2
  100. package/dist/rules/resolve.js.map +1 -1
  101. package/dist/rules/start-coordinator.d.ts +2 -0
  102. package/dist/rules/start-coordinator.d.ts.map +1 -1
  103. package/dist/rules/start-coordinator.js +3 -1
  104. package/dist/rules/start-coordinator.js.map +1 -1
  105. package/dist/rules/terminal-cleanup.d.ts +23 -0
  106. package/dist/rules/terminal-cleanup.d.ts.map +1 -0
  107. package/dist/rules/terminal-cleanup.js +43 -0
  108. package/dist/rules/terminal-cleanup.js.map +1 -0
  109. package/dist/rules/tools.d.ts.map +1 -1
  110. package/dist/rules/tools.js +24 -2
  111. package/dist/rules/tools.js.map +1 -1
  112. package/dist/rules/transition-service.d.ts +3 -0
  113. package/dist/rules/transition-service.d.ts.map +1 -1
  114. package/dist/rules/transition-service.js +10 -6
  115. package/dist/rules/transition-service.js.map +1 -1
  116. package/dist/rules/types.d.ts +32 -3
  117. package/dist/rules/types.d.ts.map +1 -1
  118. package/dist/rules/types.js +2 -0
  119. package/dist/rules/types.js.map +1 -1
  120. package/dist/rules/validation.d.ts.map +1 -1
  121. package/dist/rules/validation.js +8 -3
  122. package/dist/rules/validation.js.map +1 -1
  123. package/dist/sandbox/base-checkpoint-triggers.d.ts +77 -0
  124. package/dist/sandbox/base-checkpoint-triggers.d.ts.map +1 -0
  125. package/dist/sandbox/base-checkpoint-triggers.js +137 -0
  126. package/dist/sandbox/base-checkpoint-triggers.js.map +1 -0
  127. package/dist/sandbox/base-checkpoint.d.ts +59 -0
  128. package/dist/sandbox/base-checkpoint.d.ts.map +1 -0
  129. package/dist/sandbox/base-checkpoint.js +145 -0
  130. package/dist/sandbox/base-checkpoint.js.map +1 -0
  131. package/dist/sandbox/fleet.d.ts +32 -0
  132. package/dist/sandbox/fleet.d.ts.map +1 -1
  133. package/dist/sandbox/fleet.js +39 -10
  134. package/dist/sandbox/fleet.js.map +1 -1
  135. package/dist/session/checkpoint-capture.d.ts +3 -2
  136. package/dist/session/checkpoint-capture.d.ts.map +1 -1
  137. package/dist/session/checkpoint-capture.js +3 -3
  138. package/dist/session/checkpoint-capture.js.map +1 -1
  139. package/dist/session/factory-session.d.ts.map +1 -1
  140. package/dist/session/factory-session.js +2 -1
  141. package/dist/session/factory-session.js.map +1 -1
  142. package/dist/session/filesystem-capture.d.ts +7 -0
  143. package/dist/session/filesystem-capture.d.ts.map +1 -1
  144. package/dist/session/filesystem-capture.js +41 -4
  145. package/dist/session/filesystem-capture.js.map +1 -1
  146. package/dist/session/model-pack-hydration.d.ts +55 -0
  147. package/dist/session/model-pack-hydration.d.ts.map +1 -0
  148. package/dist/session/model-pack-hydration.js +56 -0
  149. package/dist/session/model-pack-hydration.js.map +1 -0
  150. package/dist/skills/service.d.ts +9 -0
  151. package/dist/skills/service.d.ts.map +1 -1
  152. package/dist/skills/service.js +10 -1
  153. package/dist/skills/service.js.map +1 -1
  154. package/dist/storage/domains/intake/base.d.ts +36 -0
  155. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  156. package/dist/storage/domains/intake/base.js +91 -2
  157. package/dist/storage/domains/intake/base.js.map +1 -1
  158. package/dist/storage/domains/model-packs/base.d.ts +26 -0
  159. package/dist/storage/domains/model-packs/base.d.ts.map +1 -1
  160. package/dist/storage/domains/model-packs/base.js +102 -13
  161. package/dist/storage/domains/model-packs/base.js.map +1 -1
  162. package/dist/storage/domains/source-control/base.d.ts +47 -1
  163. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  164. package/dist/storage/domains/source-control/base.js +78 -19
  165. package/dist/storage/domains/source-control/base.js.map +1 -1
  166. package/dist/storage/domains/source-control/inmemory.d.ts +11 -3
  167. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  168. package/dist/storage/domains/source-control/inmemory.js +10 -1
  169. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  170. package/dist/storage/domains/work-items/base.d.ts +67 -1
  171. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  172. package/dist/storage/domains/work-items/base.js +183 -12
  173. package/dist/storage/domains/work-items/base.js.map +1 -1
  174. package/dist/workspace.d.ts +31 -2
  175. package/dist/workspace.d.ts.map +1 -1
  176. package/dist/workspace.js +225 -54
  177. package/dist/workspace.js.map +1 -1
  178. package/factory-skills/factory-plan/SKILL.md +1 -1
  179. package/factory-skills/factory-rereview/SKILL.md +3 -3
  180. package/factory-skills/factory-review/SKILL.md +3 -3
  181. package/factory-skills/factory-triage/SKILL.md +2 -0
  182. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile-worker.js","names":["#reconcile","#reconcileIssues","#sourceControl","#intervalMs","#issueIntervalMs","#leaseTtlMs","#leaseOwner","#now","#leaseProvider","#running","#schedule","#timer","#inFlight","#tick","#nextDelay","#nextPullRequestReconcileAt","#nextIssueReconcileAt","#targets"],"sources":["../../../src/integrations/github/reconcile-worker.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { isLeaseProvider, NoopLeaseProvider } from '@mastra/core/events';\nimport type { LeaseProvider, PubSub } from '@mastra/core/events';\nimport { MastraWorker } from '@mastra/core/worker';\nimport type { WorkerDeps } from '@mastra/core/worker';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n ExternalRepositoryProjectTarget,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GithubIssueReconciler } from './issue-reconciler.js';\nimport type { GithubPullRequestReconciler, ReconcileRepository } from './rules.js';\n\nexport const DEFAULT_GITHUB_RECONCILE_INTERVAL_MS = 5 * 60_000;\nconst MIN_LEASE_TTL_MS = 30_000;\nconst LEASE_KEY = 'github:pull-request-reconcile';\n\n/** Storage slice the sweep needs to turn configured repositories into targets. */\nexport interface GithubReconcileRepositorySource {\n projectRepositories: {\n listConfiguredExternalKeys(): Promise<ConfiguredExternalRepositoryKey[]>;\n listByExternalRepository(args: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]>;\n };\n repositories: {\n findByExternalId(args: { orgId: string; externalId: string }): Promise<SourceControlRepository | null>;\n };\n}\n\nexport interface GithubReconcileWorkerConfig {\n reconcile?: GithubPullRequestReconciler;\n reconcileIssues?: GithubIssueReconciler;\n sourceControl: GithubReconcileRepositorySource;\n intervalMs?: number;\n issueIntervalMs?: number;\n now?: () => number;\n}\n\n/**\n * Periodic GitHub state sweeps for the self-hosted integration. Pull requests\n * drive review cards and issues drive work cards, but both share discovery and\n * a lease so replicas never sweep the same configured repositories together.\n */\nexport class GithubReconcileWorker extends MastraWorker {\n readonly name = 'github-pull-request-reconcile';\n\n readonly #reconcile: GithubPullRequestReconciler | undefined;\n readonly #reconcileIssues: GithubIssueReconciler | undefined;\n readonly #sourceControl: GithubReconcileRepositorySource;\n readonly #intervalMs: number;\n readonly #issueIntervalMs: number;\n readonly #leaseTtlMs: number;\n readonly #leaseOwner = randomUUID();\n readonly #now: () => number;\n\n #running = false;\n #timer: ReturnType<typeof setTimeout> | undefined;\n #inFlight: Promise<void> | undefined;\n #leaseProvider: LeaseProvider = NoopLeaseProvider;\n #nextPullRequestReconcileAt = 0;\n #nextIssueReconcileAt = 0;\n\n constructor(config: GithubReconcileWorkerConfig) {\n super();\n if (!config.reconcile && !config.reconcileIssues) {\n throw new Error('GitHub reconcile worker requires a pull request or issue reconciler.');\n }\n this.#reconcile = config.reconcile;\n this.#reconcileIssues = config.reconcileIssues;\n this.#sourceControl = config.sourceControl;\n this.#intervalMs = config.intervalMs ?? DEFAULT_GITHUB_RECONCILE_INTERVAL_MS;\n this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;\n if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n throw new Error('GitHub pull request reconcile interval must be a positive number.');\n }\n if (!Number.isFinite(this.#issueIntervalMs) || this.#issueIntervalMs <= 0) {\n throw new Error('GitHub issue reconcile interval must be a positive number.');\n }\n this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, Math.min(this.#intervalMs, this.#issueIntervalMs) * 3);\n this.#now = config.now ?? Date.now;\n }\n\n async init(deps: WorkerDeps): Promise<void> {\n await super.init(deps);\n this.#leaseProvider = getLeaseProvider(deps.pubsub);\n }\n\n async start(): Promise<void> {\n if (this.#running) return;\n if (!this.deps) throw new Error('GithubReconcileWorker: call init() before start()');\n this.#running = true;\n this.deps.logger.info('GitHub reconcile worker started', {\n pullRequestIntervalMs: this.#reconcile ? this.#intervalMs : undefined,\n issueIntervalMs: this.#reconcileIssues ? this.#issueIntervalMs : undefined,\n });\n // Sweep on boot: a restart is exactly when webhooks were most likely missed.\n this.#schedule(0);\n }\n\n async stop(): Promise<void> {\n if (!this.#running) return;\n this.#running = false;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n await this.#inFlight;\n }\n\n get isRunning(): boolean {\n return this.#running;\n }\n\n #schedule(delayMs: number): void {\n if (!this.#running) return;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n const run = this.#tick().finally(() => {\n this.#inFlight = undefined;\n this.#schedule(this.#nextDelay());\n });\n this.#inFlight = run;\n }, delayMs);\n this.#timer.unref?.();\n }\n\n #nextDelay(): number {\n const now = this.#now();\n const due = [\n this.#reconcile ? this.#nextPullRequestReconcileAt : undefined,\n this.#reconcileIssues ? this.#nextIssueReconcileAt : undefined,\n ].filter((at): at is number => at !== undefined);\n return Math.max(0, Math.min(...due) - now);\n }\n\n async #tick(): Promise<void> {\n const now = this.#now();\n const reconcilePullRequests = Boolean(this.#reconcile && now >= this.#nextPullRequestReconcileAt);\n const reconcileIssues = Boolean(this.#reconcileIssues && now >= this.#nextIssueReconcileAt);\n if (!reconcilePullRequests && !reconcileIssues) return;\n if (reconcilePullRequests) this.#nextPullRequestReconcileAt = now + this.#intervalMs;\n if (reconcileIssues) this.#nextIssueReconcileAt = now + this.#issueIntervalMs;\n\n // Replicas share one sweep: the ingress dedupes duplicate writes, but the\n // reads still burn the installation's rate limit.\n const lease = await this.#leaseProvider\n .acquireLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .catch(() => ({ acquired: false }));\n if (!lease.acquired) return;\n\n let hasLease = true;\n const renewalTimer = setInterval(\n () => {\n void this.#leaseProvider\n .renewLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .then(renewed => {\n if (!renewed) {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease was lost mid-sweep; aborting further writes');\n }\n })\n .catch(error => {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease renewal failed; aborting further writes', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n },\n Math.max(1_000, Math.floor(this.#leaseTtlMs / 3)),\n );\n renewalTimer.unref?.();\n\n try {\n const targets = await this.#targets();\n if (targets.length === 0) return;\n\n if (reconcilePullRequests && this.#reconcile) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcile(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.merged > 0 || counts.closed > 0) {\n this.deps?.logger.info('GitHub pull request reconcile replayed missed merges/closes', context);\n } else {\n this.deps?.logger.debug('GitHub pull request reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (reconcileIssues && this.#reconcileIssues && hasLease) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcileIssues(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub issue reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.closed > 0) {\n this.deps?.logger.info('GitHub issue reconcile replayed closed work items', context);\n } else if (counts.updated > 0) {\n this.deps?.logger.info('GitHub issue reconcile patched stale metadata', context);\n } else {\n this.deps?.logger.debug('GitHub issue reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub issue reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n } else if (reconcileIssues && this.#reconcileIssues && !hasLease) {\n this.deps?.logger.debug('GitHub issue reconcile skipped: lease lost during pull-request sweep');\n }\n } finally {\n clearInterval(renewalTimer);\n if (hasLease) {\n await this.#leaseProvider.releaseLease(LEASE_KEY, this.#leaseOwner).catch(() => undefined);\n }\n }\n }\n\n /**\n * Configured (installation, repository) pairs resolved to the numeric ids and\n * slug the sweep addresses GitHub with. A pair whose repository row is gone\n * is skipped rather than failing the sweep for the others.\n */\n async #targets(): Promise<ReconcileRepository[]> {\n const keys = await this.#sourceControl.projectRepositories.listConfiguredExternalKeys();\n const targets: ReconcileRepository[] = [];\n for (const key of keys) {\n const installationId = Number(key.installationExternalId);\n const repositoryId = Number(key.repositoryExternalId);\n if (!Number.isSafeInteger(installationId) || !Number.isSafeInteger(repositoryId)) continue;\n const projects = await this.#sourceControl.projectRepositories.listByExternalRepository(key);\n const orgId = projects[0]?.orgId;\n if (!orgId) continue;\n const repository = await this.#sourceControl.repositories.findByExternalId({\n orgId,\n externalId: key.repositoryExternalId,\n });\n if (!repository?.slug) continue;\n targets.push({ id: repositoryId, fullName: repository.slug, installationId });\n }\n return targets;\n }\n}\n\nfunction getLeaseProvider(pubsub: PubSub): LeaseProvider {\n const getProvider = (pubsub as PubSub & { getLeaseProvider?: () => LeaseProvider | undefined }).getLeaseProvider;\n if (typeof getProvider === 'function') return getProvider.call(pubsub) ?? NoopLeaseProvider;\n return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"reconcile-worker.js","names":["#reconcile","#reconcileIssues","#sourceControl","#sweepBaseCheckpoints","#intervalMs","#issueIntervalMs","#leaseTtlMs","#leaseOwner","#now","#leaseProvider","#running","#schedule","#timer","#inFlight","#tick","#nextDelay","#nextPullRequestReconcileAt","#nextIssueReconcileAt","#targets"],"sources":["../../../src/integrations/github/reconcile-worker.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { isLeaseProvider, NoopLeaseProvider } from '@mastra/core/events';\nimport type { LeaseProvider, PubSub } from '@mastra/core/events';\nimport { MastraWorker } from '@mastra/core/worker';\nimport type { WorkerDeps } from '@mastra/core/worker';\n\nimport type {\n ConfiguredExternalRepositoryKey,\n ExternalRepositoryProjectTarget,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GithubIssueReconciler } from './issue-reconciler.js';\nimport type { GithubPullRequestReconciler, ReconcileRepository } from './rules.js';\n\nexport const DEFAULT_GITHUB_RECONCILE_INTERVAL_MS = 5 * 60_000;\nconst MIN_LEASE_TTL_MS = 30_000;\nconst LEASE_KEY = 'github:pull-request-reconcile';\n\n/** Storage slice the sweep needs to turn configured repositories into targets. */\nexport interface GithubReconcileRepositorySource {\n projectRepositories: {\n listConfiguredExternalKeys(): Promise<ConfiguredExternalRepositoryKey[]>;\n listByExternalRepository(args: {\n installationExternalId: string;\n repositoryExternalId: string;\n }): Promise<ExternalRepositoryProjectTarget[]>;\n };\n repositories: {\n findByExternalId(args: { orgId: string; externalId: string }): Promise<SourceControlRepository | null>;\n };\n}\n\nexport interface GithubReconcileWorkerConfig {\n reconcile?: GithubPullRequestReconciler;\n reconcileIssues?: GithubIssueReconciler;\n sourceControl: GithubReconcileRepositorySource;\n /**\n * Base-checkpoint freshness sweep, run after the reconcilers within the same\n * lease. Rebuilds stale/missing base checkpoints for configured repos.\n */\n sweepBaseCheckpoints?: () => Promise<void>;\n intervalMs?: number;\n issueIntervalMs?: number;\n now?: () => number;\n}\n\n/**\n * Periodic GitHub state sweeps for the self-hosted integration. Pull requests\n * drive review cards and issues drive work cards, but both share discovery and\n * a lease so replicas never sweep the same configured repositories together.\n */\nexport class GithubReconcileWorker extends MastraWorker {\n readonly name = 'github-pull-request-reconcile';\n\n readonly #reconcile: GithubPullRequestReconciler | undefined;\n readonly #reconcileIssues: GithubIssueReconciler | undefined;\n readonly #sourceControl: GithubReconcileRepositorySource;\n readonly #sweepBaseCheckpoints: (() => Promise<void>) | undefined;\n readonly #intervalMs: number;\n readonly #issueIntervalMs: number;\n readonly #leaseTtlMs: number;\n readonly #leaseOwner = randomUUID();\n readonly #now: () => number;\n\n #running = false;\n #timer: ReturnType<typeof setTimeout> | undefined;\n #inFlight: Promise<void> | undefined;\n #leaseProvider: LeaseProvider = NoopLeaseProvider;\n #nextPullRequestReconcileAt = 0;\n #nextIssueReconcileAt = 0;\n\n constructor(config: GithubReconcileWorkerConfig) {\n super();\n if (!config.reconcile && !config.reconcileIssues) {\n throw new Error('GitHub reconcile worker requires a pull request or issue reconciler.');\n }\n this.#reconcile = config.reconcile;\n this.#reconcileIssues = config.reconcileIssues;\n this.#sourceControl = config.sourceControl;\n this.#sweepBaseCheckpoints = config.sweepBaseCheckpoints;\n this.#intervalMs = config.intervalMs ?? DEFAULT_GITHUB_RECONCILE_INTERVAL_MS;\n this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;\n if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n throw new Error('GitHub pull request reconcile interval must be a positive number.');\n }\n if (!Number.isFinite(this.#issueIntervalMs) || this.#issueIntervalMs <= 0) {\n throw new Error('GitHub issue reconcile interval must be a positive number.');\n }\n this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, Math.min(this.#intervalMs, this.#issueIntervalMs) * 3);\n this.#now = config.now ?? Date.now;\n }\n\n async init(deps: WorkerDeps): Promise<void> {\n await super.init(deps);\n this.#leaseProvider = getLeaseProvider(deps.pubsub);\n }\n\n async start(): Promise<void> {\n if (this.#running) return;\n if (!this.deps) throw new Error('GithubReconcileWorker: call init() before start()');\n this.#running = true;\n this.deps.logger.info('GitHub reconcile worker started', {\n pullRequestIntervalMs: this.#reconcile ? this.#intervalMs : undefined,\n issueIntervalMs: this.#reconcileIssues ? this.#issueIntervalMs : undefined,\n });\n // Sweep on boot: a restart is exactly when webhooks were most likely missed.\n this.#schedule(0);\n }\n\n async stop(): Promise<void> {\n if (!this.#running) return;\n this.#running = false;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n await this.#inFlight;\n }\n\n get isRunning(): boolean {\n return this.#running;\n }\n\n #schedule(delayMs: number): void {\n if (!this.#running) return;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n const run = this.#tick().finally(() => {\n this.#inFlight = undefined;\n this.#schedule(this.#nextDelay());\n });\n this.#inFlight = run;\n }, delayMs);\n this.#timer.unref?.();\n }\n\n #nextDelay(): number {\n const now = this.#now();\n const due = [\n this.#reconcile ? this.#nextPullRequestReconcileAt : undefined,\n this.#reconcileIssues ? this.#nextIssueReconcileAt : undefined,\n ].filter((at): at is number => at !== undefined);\n return Math.max(0, Math.min(...due) - now);\n }\n\n async #tick(): Promise<void> {\n const now = this.#now();\n const reconcilePullRequests = Boolean(this.#reconcile && now >= this.#nextPullRequestReconcileAt);\n const reconcileIssues = Boolean(this.#reconcileIssues && now >= this.#nextIssueReconcileAt);\n if (!reconcilePullRequests && !reconcileIssues) return;\n if (reconcilePullRequests) this.#nextPullRequestReconcileAt = now + this.#intervalMs;\n if (reconcileIssues) this.#nextIssueReconcileAt = now + this.#issueIntervalMs;\n\n // Replicas share one sweep: the ingress dedupes duplicate writes, but the\n // reads still burn the installation's rate limit.\n const lease = await this.#leaseProvider\n .acquireLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .catch(() => ({ acquired: false }));\n if (!lease.acquired) return;\n\n let hasLease = true;\n const renewalTimer = setInterval(\n () => {\n void this.#leaseProvider\n .renewLease(LEASE_KEY, this.#leaseOwner, this.#leaseTtlMs)\n .then(renewed => {\n if (!renewed) {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease was lost mid-sweep; aborting further writes');\n }\n })\n .catch(error => {\n hasLease = false;\n clearInterval(renewalTimer);\n this.deps?.logger.warn('GitHub reconcile lease renewal failed; aborting further writes', {\n error: error instanceof Error ? error.message : String(error),\n });\n });\n },\n Math.max(1_000, Math.floor(this.#leaseTtlMs / 3)),\n );\n renewalTimer.unref?.();\n\n try {\n const targets = await this.#targets();\n if (targets.length === 0) return;\n\n if (reconcilePullRequests && this.#reconcile) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcile(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.merged > 0 || counts.closed > 0) {\n this.deps?.logger.info('GitHub pull request reconcile replayed missed merges/closes', context);\n } else {\n this.deps?.logger.debug('GitHub pull request reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub pull request reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n if (reconcileIssues && this.#reconcileIssues && hasLease) {\n const startedAt = Date.now();\n try {\n const { errors, ...counts } = await this.#reconcileIssues(targets);\n const context = { ...counts, candidateRepositories: targets.length, durationMs: Date.now() - startedAt };\n if (counts.failed > 0) {\n this.deps?.logger.warn('GitHub issue reconcile sweep completed with failures', { ...context, errors });\n } else if (counts.closed > 0) {\n this.deps?.logger.info('GitHub issue reconcile replayed closed work items', context);\n } else if (counts.updated > 0) {\n this.deps?.logger.info('GitHub issue reconcile patched stale metadata', context);\n } else {\n this.deps?.logger.debug('GitHub issue reconcile sweep completed', context);\n }\n } catch (error) {\n this.deps?.logger.warn('GitHub issue reconcile sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n } else if (reconcileIssues && this.#reconcileIssues && !hasLease) {\n this.deps?.logger.debug('GitHub issue reconcile skipped: lease lost during pull-request sweep');\n }\n\n if (this.#sweepBaseCheckpoints && hasLease) {\n try {\n await this.#sweepBaseCheckpoints();\n } catch (error) {\n this.deps?.logger.warn('GitHub base-checkpoint freshness sweep failed', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n } finally {\n clearInterval(renewalTimer);\n if (hasLease) {\n await this.#leaseProvider.releaseLease(LEASE_KEY, this.#leaseOwner).catch(() => undefined);\n }\n }\n }\n\n /**\n * Configured (installation, repository) pairs resolved to the numeric ids and\n * slug the sweep addresses GitHub with. A pair whose repository row is gone\n * is skipped rather than failing the sweep for the others.\n */\n async #targets(): Promise<ReconcileRepository[]> {\n const keys = await this.#sourceControl.projectRepositories.listConfiguredExternalKeys();\n const targets: ReconcileRepository[] = [];\n for (const key of keys) {\n const installationId = Number(key.installationExternalId);\n const repositoryId = Number(key.repositoryExternalId);\n if (!Number.isSafeInteger(installationId) || !Number.isSafeInteger(repositoryId)) continue;\n const projects = await this.#sourceControl.projectRepositories.listByExternalRepository(key);\n const orgId = projects[0]?.orgId;\n if (!orgId) continue;\n const repository = await this.#sourceControl.repositories.findByExternalId({\n orgId,\n externalId: key.repositoryExternalId,\n });\n if (!repository?.slug) continue;\n targets.push({ id: repositoryId, fullName: repository.slug, installationId });\n }\n return targets;\n }\n}\n\nfunction getLeaseProvider(pubsub: PubSub): LeaseProvider {\n const getProvider = (pubsub as PubSub & { getLeaseProvider?: () => LeaseProvider | undefined }).getLeaseProvider;\n if (typeof getProvider === 'function') return getProvider.call(pubsub) ?? NoopLeaseProvider;\n return isLeaseProvider(pubsub) ? pubsub : NoopLeaseProvider;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAuD,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AASrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA4C1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAgBxD,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,qCAAqC,EAAE,4BAA4B,CAAC;IAC/F,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AA4ND;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CA+lB/E"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,KAAK,EAAuD,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AASrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA4C1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAgBxD,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,qCAAqC,EAAE,4BAA4B,CAAC;IAC/F,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AA4ND;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CA+lB/E"}
@@ -1,8 +1,9 @@
1
1
  import { clearGithubPat, getGithubPat, getGithubPatStatus, setGithubPat } from "./pat.js";
2
2
  import { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from "./subscriptions.js";
3
3
  import { SandboxBudgetError } from "../../sandbox/fleet.js";
4
- import { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from "./config.js";
5
4
  import { MaterializeError, WorktreeError, commitAll, ensureProjectSandbox, isValidGitRef as isValidGitRef$1, materializeRepo, pushBranch, teardownProjectSandbox } from "./sandbox.js";
5
+ import { baseCheckpointIsStale } from "../../sandbox/base-checkpoint-triggers.js";
6
+ import { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from "./config.js";
6
7
  import { reclaimDeletedSessionSandbox } from "./sandbox-release.js";
7
8
  import { handleGithubWebhook } from "./webhook.js";
8
9
  import { registerApiRoute } from "@mastra/core/server";
@@ -788,12 +789,14 @@ async function prepareProject(options) {
788
789
  });
789
790
  if (!access.authorization) throw new MaterializeError("Repository access did not include a bearer token.", "clone-failed");
790
791
  const ghCliToken = await getGithubPat(() => github.integrationStorage, project.installation.orgId) ?? access.authorization.token;
792
+ const seedCheckpointName = project.baseCheckpoint && !baseCheckpointIsStale(project) ? project.baseCheckpoint.name : void 0;
791
793
  const sandbox = await ensureProjectSandbox({
792
794
  fleet,
793
795
  row: sandboxRow,
794
796
  storage: github.sourceControlStorage.sandboxes,
795
797
  token: ghCliToken,
796
- onProgress
798
+ onProgress,
799
+ ...seedCheckpointName ? { seedCheckpointName } : {}
797
800
  });
798
801
  const finalRow = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id }) ?? sandboxRow;
799
802
  await materializeRepo({
@@ -805,7 +808,8 @@ async function prepareProject(options) {
805
808
  sandbox,
806
809
  token: access.authorization.token,
807
810
  storage: github.sourceControlStorage.sandboxes,
808
- onProgress
811
+ onProgress,
812
+ skipPullOnExistingCheckout: Boolean(seedCheckpointName && sandbox.seedCheckpointNameUsed === seedCheckpointName)
809
813
  });
810
814
  const result = {
811
815
  resourceId: project.factoryProjectId,
@@ -908,7 +912,7 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
908
912
  if (!project) return c.json({ error: "Project repository not found" }, 404);
909
913
  const sessions = await github.sourceControlStorage.sessions.list({
910
914
  projectRepositoryId: project.id,
911
- userId
915
+ viewerUserId: userId
912
916
  });
913
917
  return c.json({ sessions });
914
918
  }
@@ -963,7 +967,8 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
963
967
  userId,
964
968
  branch,
965
969
  baseBranch,
966
- title: normalizedTitle
970
+ title: normalizedTitle,
971
+ visibility: "org"
967
972
  }).catch(async (error) => {
968
973
  if (!(error instanceof UniqueViolationError) || requestedSessionId === void 0) throw error;
969
974
  const conflict = await github.sourceControlStorage.sessions.getBySessionId(sessionId);
@@ -981,7 +986,7 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
981
986
  const resolved = await resolveOrgTenant(loose(c), auth);
982
987
  if ("response" in resolved) return resolved.response;
983
988
  const session = await github.sourceControlStorage.sessions.getBySessionId(c.req.param("sessionId"));
984
- if (!session || session.orgId !== resolved.tenant.orgId || session.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
989
+ if (!session || session.orgId !== resolved.tenant.orgId || session.visibility === "private" && session.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
985
990
  return c.json({ session });
986
991
  }
987
992
  }),