@mastra/factory 0.18.0-alpha.9 → 0.18.1-alpha.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 (105) hide show
  1. package/dist/factory.d.ts.map +1 -1
  2. package/dist/factory.js +5 -2
  3. package/dist/factory.js.map +1 -1
  4. package/dist/integrations/github/default-rules.d.ts.map +1 -1
  5. package/dist/integrations/github/default-rules.js +3 -3
  6. package/dist/integrations/github/default-rules.js.map +1 -1
  7. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  8. package/dist/integrations/github/reconcile-worker.js +1 -2
  9. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  10. package/dist/integrations/github/routes.d.ts.map +1 -1
  11. package/dist/integrations/github/routes.js +1 -14
  12. package/dist/integrations/github/routes.js.map +1 -1
  13. package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
  14. package/dist/integrations/gitlab/version-control.js +4 -5
  15. package/dist/integrations/gitlab/version-control.js.map +1 -1
  16. package/dist/integrations/gitlab/webhook.d.ts.map +1 -1
  17. package/dist/integrations/gitlab/webhook.js +2 -2
  18. package/dist/integrations/gitlab/webhook.js.map +1 -1
  19. package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
  20. package/dist/integrations/issue-reconcile-worker.js +1 -2
  21. package/dist/integrations/issue-reconcile-worker.js.map +1 -1
  22. package/dist/integrations/linear/integration.d.ts.map +1 -1
  23. package/dist/integrations/linear/integration.js +10 -30
  24. package/dist/integrations/linear/integration.js.map +1 -1
  25. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  26. package/dist/integrations/platform/github/event-worker.js +1 -2
  27. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  28. package/dist/integrations/platform/gitlab/event-worker.d.ts.map +1 -1
  29. package/dist/integrations/platform/gitlab/event-worker.js +1 -2
  30. package/dist/integrations/platform/gitlab/event-worker.js.map +1 -1
  31. package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -1
  32. package/dist/integrations/platform/linear/event-worker.js +1 -2
  33. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  34. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  35. package/dist/integrations/platform/linear/integration.js +9 -9
  36. package/dist/integrations/platform/linear/integration.js.map +1 -1
  37. package/dist/integrations/slack/slack.d.ts.map +1 -1
  38. package/dist/integrations/slack/slack.js +137 -19
  39. package/dist/integrations/slack/slack.js.map +1 -1
  40. package/dist/integrations/subscription-session.d.ts +3 -1
  41. package/dist/integrations/subscription-session.d.ts.map +1 -1
  42. package/dist/integrations/subscription-session.js +4 -2
  43. package/dist/integrations/subscription-session.js.map +1 -1
  44. package/dist/review-verdict.d.ts +6 -0
  45. package/dist/review-verdict.d.ts.map +1 -0
  46. package/dist/review-verdict.js +14 -0
  47. package/dist/review-verdict.js.map +1 -0
  48. package/dist/routes/contracts.d.ts +23 -0
  49. package/dist/routes/contracts.d.ts.map +1 -1
  50. package/dist/routes/contracts.js +21 -0
  51. package/dist/routes/contracts.js.map +1 -1
  52. package/dist/routes/oauth.d.ts.map +1 -1
  53. package/dist/routes/oauth.js +3 -3
  54. package/dist/routes/oauth.js.map +1 -1
  55. package/dist/routes/projects.d.ts +22 -2
  56. package/dist/routes/projects.d.ts.map +1 -1
  57. package/dist/routes/projects.js +101 -0
  58. package/dist/routes/projects.js.map +1 -1
  59. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  60. package/dist/routes/source-control-sessions.js +1 -2
  61. package/dist/routes/source-control-sessions.js.map +1 -1
  62. package/dist/rules/dispatcher.d.ts.map +1 -1
  63. package/dist/rules/dispatcher.js +1 -2
  64. package/dist/rules/dispatcher.js.map +1 -1
  65. package/dist/rules/processor.d.ts.map +1 -1
  66. package/dist/rules/processor.js +5 -5
  67. package/dist/rules/processor.js.map +1 -1
  68. package/dist/rules/transition-service.d.ts.map +1 -1
  69. package/dist/rules/transition-service.js +1 -2
  70. package/dist/rules/transition-service.js.map +1 -1
  71. package/dist/sandbox/materialization.d.ts +5 -1
  72. package/dist/sandbox/materialization.d.ts.map +1 -1
  73. package/dist/sandbox/materialization.js.map +1 -1
  74. package/dist/sandbox/session-sandbox.d.ts +13 -1
  75. package/dist/sandbox/session-sandbox.d.ts.map +1 -1
  76. package/dist/sandbox/session-sandbox.js.map +1 -1
  77. package/dist/secret-encryption.js +2 -2
  78. package/dist/secret-encryption.js.map +1 -1
  79. package/dist/session/factory-session.d.ts.map +1 -1
  80. package/dist/session/factory-session.js +26 -9
  81. package/dist/session/factory-session.js.map +1 -1
  82. package/dist/session/source-control-tools.d.ts +9 -0
  83. package/dist/session/source-control-tools.d.ts.map +1 -1
  84. package/dist/session/source-control-tools.js +51 -2
  85. package/dist/session/source-control-tools.js.map +1 -1
  86. package/dist/state-signing.js +3 -3
  87. package/dist/state-signing.js.map +1 -1
  88. package/dist/storage/domains/audit/base.d.ts.map +1 -1
  89. package/dist/storage/domains/audit/base.js +2 -3
  90. package/dist/storage/domains/audit/base.js.map +1 -1
  91. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  92. package/dist/storage/domains/source-control/inmemory.js +5 -6
  93. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  94. package/dist/storage/domains/work-items/base.d.ts +2 -0
  95. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  96. package/dist/storage/domains/work-items/base.js +9 -1
  97. package/dist/storage/domains/work-items/base.js.map +1 -1
  98. package/dist/workspace.d.ts.map +1 -1
  99. package/dist/workspace.js +8 -7
  100. package/dist/workspace.js.map +1 -1
  101. package/factory-skills/factory-gitlab-rereview/SKILL.md +1 -1
  102. package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
  103. package/factory-skills/factory-rereview/SKILL.md +12 -3
  104. package/factory-skills/factory-review/SKILL.md +12 -3
  105. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"factory-session.d.ts","sourceRoot":"","sources":["../../src/session/factory-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"factory-session.d.ts","sourceRoot":"","sources":["../../src/session/factory-session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAChC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAGvG,KAAK,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAE7F,qBAAa,iCAAkC,SAAQ,KAAK;CAAG;AAE/D;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,sBAAsB,GAAG,SAAS,EAC5C,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAQ7B;AAED,MAAM,WAAW,0BAA0B;IACzC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IACxE,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAAC;IAC3F,MAAM,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,gBAAgB,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,uBAAuB,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,cAAc,EAAE,SAAS,0BAA0B,EAAE,GACpD,0BAA0B,CA2B5B;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,cAAc,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAwClD;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;;;OAKG;IACH,aAAa,EAAE,0BAA0B,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,mCAAoC,SAAQ,KAAK;IAChD,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY;gBAAnC,MAAM,EAAE,YAAY,GAAG,YAAY;CAQzD;AAED,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,GACrC,CAAC;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG,+BAA+B,CAAC,GACnD;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAAA;CAAE,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAClD,IAAI,EACA;IACE,aAAa,EAAE,0BAA0B,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,GACD;IACE,aAAa,EAAE,0BAA0B,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,IAAI,CAAC;CAC7B,GACJ,OAAO,CAAC,6BAA6B,CAAC,CA0CxC;AAED;;;;;;;;GAQG;AACH,wBAAsB,+BAA+B,CAAC,IAAI,EAAE;IAC1D,aAAa,EAAE,0BAA0B,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAc9E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,8BAA8B,GACnC,OAAO,CAAC,2BAA2B,CAAC,CAuBtC;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yGAAyG;IACzG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDnH;AAED,MAAM,WAAW,uCAAuC;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAC9C,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;CACpD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mCAAmC,CACvD,OAAO,EAAE,qBAAqB,EAC9B,IAAI,EAAE,uCAAuC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAiBf"}
@@ -2,7 +2,6 @@ import { seedSessionOrg } from "./org-seed.js";
2
2
  import { factoryMemorySettingsUserId } from "../storage/domains/memory-settings/base.js";
3
3
  import { SourceControlConnectionNotFoundError } from "../storage/domains/source-control/base.js";
4
4
  import { applyStoredMemorySettings } from "./memory-settings-hydration.js";
5
- import { randomUUID } from "crypto";
6
5
  import { resolveProviderOMDefault } from "@mastra/code-sdk/onboarding/packs";
7
6
  //#region src/session/factory-session.ts
8
7
  var FactorySourceControlConflictError = class extends Error {};
@@ -189,7 +188,7 @@ async function ensureFactorySourceSession(args) {
189
188
  if (!resolved.found) throw new FactorySourceSessionResolutionError(resolved.reason);
190
189
  const userId = args.attributeToUserId ?? resolved.connectedByUserId;
191
190
  const session = await sourceControl.sessions.create({
192
- sessionId: randomUUID(),
191
+ sessionId: globalThis.crypto.randomUUID(),
193
192
  projectRepositoryId: resolved.projectRepositoryId,
194
193
  orgId,
195
194
  userId,
@@ -226,13 +225,31 @@ async function hydrateFactorySession(session, args) {
226
225
  } catch (error) {
227
226
  console.warn("[Factory Start] Failed to apply observational-memory settings", { error: error instanceof Error ? error.message : String(error) });
228
227
  }
229
- if (args.defaultModelId) try {
230
- await session.model.switch({ modelId: args.defaultModelId });
231
- } catch (error) {
232
- console.warn("[Factory Start] Failed to apply factory default model", {
233
- modelId: args.defaultModelId,
234
- error: error instanceof Error ? error.message : String(error)
235
- });
228
+ if (args.defaultModelId) {
229
+ try {
230
+ await session.model.switch({ modelId: args.defaultModelId });
231
+ } catch (error) {
232
+ console.warn("[Factory Start] Failed to apply factory default model", {
233
+ modelId: args.defaultModelId,
234
+ error: error instanceof Error ? error.message : String(error)
235
+ });
236
+ }
237
+ for (const agentType of [
238
+ "explore",
239
+ "plan",
240
+ "execute"
241
+ ]) try {
242
+ await session.subagents.model.set({
243
+ modelId: args.defaultModelId,
244
+ agentType
245
+ });
246
+ } catch (error) {
247
+ console.warn("[Factory Start] Failed to apply factory default subagent model", {
248
+ agentType,
249
+ modelId: args.defaultModelId,
250
+ error: error instanceof Error ? error.message : String(error)
251
+ });
252
+ }
236
253
  }
237
254
  }
238
255
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"factory-session.js","names":[],"sources":["../../src/session/factory-session.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { resolveProviderOMDefault } from '@mastra/code-sdk/onboarding/packs';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\n\nimport { factoryMemorySettingsUserId } from '../storage/domains/memory-settings/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport {\n SourceControlConnectionNotFoundError,\n type SourceControlSession,\n type SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport { applyStoredMemorySettings, type OMConfigurableSession } from './memory-settings-hydration.js';\nimport { seedSessionOrg } from './org-seed.js';\n\ntype FactorySession = Awaited<ReturnType<AgentController<MastraCodeState>['createSession']>>;\n\nexport class FactorySourceControlConflictError extends Error {}\n\n/**\n * Read the factory project's default model. Best-effort: a missing project or an\n * uninitialized storage domain means \"no default\", never a failed run.\n */\nexport async function resolveFactoryDefaultModelId(\n projects: FactoryProjectsStorage | undefined,\n factoryProjectId: string | undefined,\n): Promise<string | undefined> {\n if (!projects || !factoryProjectId) return undefined;\n try {\n const project = await projects.getById({ id: factoryProjectId });\n return project?.defaultModelId ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SourceControlSessionLookup {\n getBySessionId(sessionId: string): Promise<SourceControlSession | null>;\n getSourceControlBySessionId(sessionId: string): Promise<SourceControlStorageHandle | null>;\n rename(args: { sessionId: string; title: string }): Promise<void>;\n markFirstMessage(args: { sessionId: string }): Promise<void>;\n markFirstMeaningfulExec(args: { sessionId: string }): Promise<void>;\n}\n\n/**\n * Read or update a session across every registered source-control partition.\n * Session ids are globally generated, so more than one match is invalid and\n * fails closed instead of mutating an arbitrary provider.\n */\nexport function createSourceControlSessionLookup(\n sourceControls: readonly SourceControlStorageHandle[],\n): SourceControlSessionLookup {\n const resolve = async (\n sessionId: string,\n ): Promise<{ sourceControl: SourceControlStorageHandle; session: SourceControlSession } | null> => {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(sessionId),\n })),\n )\n ).filter(\n (match): match is { sourceControl: SourceControlStorageHandle; session: SourceControlSession } =>\n match.session !== null,\n );\n if (matches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n return matches[0] ?? null;\n };\n\n return {\n getBySessionId: async sessionId => (await resolve(sessionId))?.session ?? null,\n getSourceControlBySessionId: async sessionId => (await resolve(sessionId))?.sourceControl ?? null,\n rename: async args => (await resolve(args.sessionId))?.sourceControl.sessions.rename(args),\n markFirstMessage: async args => (await resolve(args.sessionId))?.sourceControl.sessions.markFirstMessage(args),\n markFirstMeaningfulExec: async args =>\n (await resolve(args.sessionId))?.sourceControl.sessions.markFirstMeaningfulExec(args),\n };\n}\n\n/**\n * Resolve the source-control provider from durable Factory repository links,\n * never from the issue tracker that happened to create the work item.\n */\nexport async function resolveFactorySourceControl(args: {\n sourceControls: readonly SourceControlStorageHandle[];\n orgId: string;\n factoryProjectId: string;\n sessionId?: string;\n}): Promise<SourceControlStorageHandle | undefined> {\n if (args.sessionId) {\n const sessionMatches = (\n await Promise.all(\n args.sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(args.sessionId!),\n })),\n )\n ).filter(match => match.session !== null);\n if (sessionMatches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n if (sessionMatches[0]) return sessionMatches[0].sourceControl;\n }\n\n const linked = [];\n for (const sourceControl of args.sourceControls) {\n const connections = await sourceControl.connections.list({\n orgId: args.orgId,\n factoryProjectId: args.factoryProjectId,\n });\n let hasLinkedRepository = false;\n for (const connection of connections) {\n try {\n if (\n (await sourceControl.projectRepositories.list({ orgId: args.orgId, connectionId: connection.id })).length > 0\n ) {\n hasLinkedRepository = true;\n break;\n }\n } catch (error) {\n if (!(error instanceof SourceControlConnectionNotFoundError)) throw error;\n }\n }\n if (hasLinkedRepository) linked.push(sourceControl);\n }\n if (linked.length > 1)\n throw new FactorySourceControlConflictError(\n 'Factory project has repositories linked through multiple source-control providers.',\n );\n return linked[0];\n}\n\nexport interface EnsureFactorySourceSessionArgs {\n /**\n * Storage handle of the integration that owns source control. Nothing here is\n * provider-specific: the connection is matched by the handle's own\n * `integrationId`, so GitHub, Slack-on-behalf-of-GitHub, or any future owner\n * all resolve through the same traversal.\n */\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n branch: string;\n /** Pick the linked repository that the work item targets. */\n repositorySlug: string;\n /**\n * Attribute the run to this user instead of the repo connector. Set when the\n * run has an interactive user — e.g. the person who approved a proposed run.\n */\n attributeToUserId?: string;\n}\n\nexport interface EnsuredFactorySourceSession {\n sessionId: string;\n userId: string;\n projectRepositoryId: string;\n branch: string;\n baseBranch: string;\n}\n\nexport class FactorySourceSessionResolutionError extends Error {\n constructor(readonly reason: 'connection' | 'repository') {\n super(\n reason === 'connection'\n ? 'Factory source-control connection not found.'\n : 'Factory source-control repository not found.',\n );\n this.name = 'FactorySourceSessionResolutionError';\n }\n}\n\nexport interface ResolvedFactorySourceRepository {\n projectRepositoryId: string;\n /** The repository's pinned branch, else its default branch. */\n baseBranch: string;\n /** Who connected the repository. The attribution for runs with no interactive user. */\n connectedByUserId: string;\n}\n\n/**\n * Outcome of {@link resolveFactorySourceRepository}. A miss carries which step\n * failed: callers differ on whether that is an error (an autonomous run cannot\n * proceed) or a routine fallback (a chat integration drops to a chat-only\n * session), and the two steps fail for different reasons worth reporting apart.\n */\nexport type FactorySourceRepositoryResult =\n | ({ found: true } & ResolvedFactorySourceRepository)\n | { found: false; reason: 'connection' | 'repository' };\n\n/**\n * Resolve which repository a factory project's source-control runs act on: the\n * owner's connection on the project, then one of its linked repositories.\n *\n * The owner is whichever integration owns source control, matched by the\n * handle's own `integrationId` — nothing here is provider-specific.\n */\nexport async function resolveFactorySourceRepository(\n args:\n | {\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n repositorySlug: string;\n }\n | {\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n firstLinkedRepository: true;\n },\n): Promise<FactorySourceRepositoryResult> {\n const { sourceControl, orgId, factoryProjectId } = args;\n const repositorySlug = 'repositorySlug' in args ? args.repositorySlug : undefined;\n const firstLinkedRepository = 'firstLinkedRepository' in args;\n\n const connections = await sourceControl.connections.list({ orgId, factoryProjectId });\n const candidates = connections.filter(candidate => candidate.integrationId === sourceControl.integrationId);\n if (candidates.length === 0) return { found: false, reason: 'connection' };\n\n // A project can carry stale connections: a provider-app reinstall leaves the\n // old connection pointing at an installation that no longer exists, and that\n // row can sit ahead of the healthy one. Try every candidate and skip the ones\n // that no longer resolve rather than failing on the first.\n for (const connection of candidates) {\n let resolved;\n try {\n const projectRepositories = await sourceControl.projectRepositories.list({ orgId, connectionId: connection.id });\n const resolvedRepositories = await Promise.all(\n projectRepositories.map(async projectRepository => ({\n projectRepository,\n repository: await sourceControl.repositories.get({ orgId, id: projectRepository.repositoryId }),\n })),\n );\n resolved = resolvedRepositories.find(\n candidate => candidate.repository && (firstLinkedRepository || candidate.repository.slug === repositorySlug),\n );\n } catch (error) {\n // A deleted installation invalidates a stale connection; storage failures must propagate.\n if (!(error instanceof SourceControlConnectionNotFoundError)) throw error;\n continue;\n }\n if (!resolved?.repository) continue;\n\n return {\n found: true,\n projectRepositoryId: resolved.projectRepository.id,\n baseBranch: resolved.projectRepository.branch ?? resolved.repository.defaultBranch,\n connectedByUserId: connection.createdByUserId,\n };\n }\n\n return { found: false, reason: 'repository' };\n}\n\n/**\n * Walk a Factory user-session id back to the project it belongs to.\n *\n * Repo-backed channel threads are keyed by their Factory session id, which is\n * the only handle a session-start hook gets. This turns that id back into the\n * project whose configuration the session should adopt. Durable by\n * construction — it reads the same rows the session was created from, so it\n * survives restarts without any in-memory mapping.\n */\nexport async function resolveFactoryProjectForSession(args: {\n sourceControl: SourceControlStorageHandle;\n sessionId: string;\n}): Promise<{ factoryProjectId: string; orgId: string; userId: string } | null> {\n const { sourceControl, sessionId } = args;\n\n const session = await sourceControl.sessions.getBySessionId(sessionId);\n if (!session) return null;\n const projectRepository = await sourceControl.projectRepositories.get({\n orgId: session.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) return null;\n const connection = await sourceControl.connections.get({ orgId: session.orgId, id: projectRepository.connectionId });\n if (!connection) return null;\n\n return { factoryProjectId: connection.factoryProjectId, orgId: session.orgId, userId: session.userId };\n}\n\n/**\n * Create the source-control session a repo-backed factory run needs.\n *\n * `FactoryStartCoordinator.prepare` requires this record to already exist —\n * `resolveSourceSession` throws `Factory session not found` otherwise — so every\n * autonomous entry point has to produce one before it can start a run. This is\n * that step, in one place: the owner's connection on the factory project, one of\n * its linked repositories, and a session on the requested branch with the\n * repository's pinned or default branch as the base.\n *\n * The run is attributed to `attributeToUserId` when the caller has an\n * interactive user (e.g. the approver of a proposed run), and otherwise falls\n * back to whoever connected the repository (`connection.createdByUserId`),\n * because a genuinely autonomous run has no interactive user of its own.\n */\nexport async function ensureFactorySourceSession(\n args: EnsureFactorySourceSessionArgs,\n): Promise<EnsuredFactorySourceSession> {\n const { sourceControl, orgId, factoryProjectId, branch, repositorySlug } = args;\n\n const resolved = await resolveFactorySourceRepository({ sourceControl, orgId, factoryProjectId, repositorySlug });\n if (!resolved.found) throw new FactorySourceSessionResolutionError(resolved.reason);\n\n const userId = args.attributeToUserId ?? resolved.connectedByUserId;\n const session = await sourceControl.sessions.create({\n sessionId: randomUUID(),\n projectRepositoryId: resolved.projectRepositoryId,\n orgId,\n userId,\n branch,\n baseBranch: resolved.baseBranch,\n visibility: 'org',\n });\n return {\n sessionId: session.sessionId,\n userId,\n projectRepositoryId: resolved.projectRepositoryId,\n branch: session.branch,\n baseBranch: resolved.baseBranch,\n };\n}\n\nexport interface HydrateFactorySessionArgs {\n orgId: string;\n /**\n * The factory project whose shared memory settings apply. Factory sessions\n * never read an individual user's personal memory settings — the project's\n * own row (or the built-in defaults) is what they run with.\n */\n factoryProjectId?: string;\n /** The factory project's default model. Without it the session keeps the SDK's built-in mode default. */\n defaultModelId?: string;\n /**\n * Model whose provider supplies the observational-memory fallback. Defaults\n * to the factory model, but channel sessions can use the sender's model so OM\n * resolves against that sender's credentials.\n */\n observationalMemoryModelId?: string;\n /**\n * When provided, the factory project's stored memory-settings row is\n * applied. When omitted (or no row exists) the session is reset to the\n * built-in memory defaults.\n */\n memorySettings?: MemorySettingsStorage;\n}\n\n/**\n * Apply a factory project's configuration to a freshly created session:\n * observational-memory settings, then the project's default model.\n *\n * Both steps are best-effort. A retired model id or an unreachable settings row\n * must not sink a run that is otherwise ready — the session simply keeps the\n * default it was created with, and the reason is logged.\n */\nexport async function hydrateFactorySession(session: FactorySession, args: HydrateFactorySessionArgs): Promise<void> {\n // The org rung knowledge curation scopes on. Seeded first so it lands even if\n // a later best-effort step fails; an empty org marks the session unresolved.\n await seedSessionOrg(session, args.orgId);\n try {\n const record =\n args.memorySettings && args.factoryProjectId\n ? await args.memorySettings.get({\n orgId: args.orgId,\n userId: factoryMemorySettingsUserId(args.factoryProjectId),\n })\n : null;\n // Without a stored row, fall back to the low-cost OM model of the factory\n // default model's provider — a factory connected only to Anthropic should\n // not observe with the (uncredentialed) built-in Google default.\n const observationalMemoryModelId = args.observationalMemoryModelId ?? args.defaultModelId;\n const provider = observationalMemoryModelId?.split('/')[0];\n const fallbackOmModelId = provider\n ? resolveProviderOMDefault(provider, observationalMemoryModelId).modelId\n : undefined;\n await applyStoredMemorySettings(session, record, fallbackOmModelId);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (args.defaultModelId) {\n try {\n await session.model.switch({ modelId: args.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: args.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n\nexport interface RefreshFactorySessionMemorySettingsArgs {\n orgId: string;\n factoryProjectId: string;\n projects: Pick<FactoryProjectsStorage, 'get'>;\n memorySettings: Pick<MemorySettingsStorage, 'get'>;\n}\n\n/**\n * Re-apply a factory project's stored observational-memory settings to an\n * already-running session that automation is about to reuse. Session creation\n * hydrates these settings once (`hydrateFactorySession`), but a reused binding\n * keeps whatever observer/reflector models it was created with — so a project\n * whose OM models changed since would keep observing with the stale (and\n * possibly since-rejected) models. This reads the project's current row with the\n * same provider-aware fallback as initial hydration and applies it, mirroring\n * the `GET /web/config/om` refresh. Best-effort: a settings lookup failure must\n * never sink an otherwise-ready run, so it is logged and swallowed.\n */\nexport async function refreshFactorySessionMemorySettings(\n session: OMConfigurableSession,\n args: RefreshFactorySessionMemorySettingsArgs,\n): Promise<void> {\n try {\n const record = await args.memorySettings.get({\n orgId: args.orgId,\n userId: factoryMemorySettingsUserId(args.factoryProjectId),\n });\n const project = await args.projects.get({ orgId: args.orgId, id: args.factoryProjectId });\n const provider = project?.defaultModelId?.split('/')[0];\n const fallbackOmModelId = provider\n ? resolveProviderOMDefault(provider, project?.defaultModelId ?? undefined).modelId\n : undefined;\n await applyStoredMemorySettings(session, record, fallbackOmModelId);\n } catch (error) {\n console.warn('[Factory dispatch] Failed to reapply observational-memory settings on session reuse', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"factory-session.js","names":[],"sources":["../../src/session/factory-session.ts"],"sourcesContent":["import { resolveProviderOMDefault } from '@mastra/code-sdk/onboarding/packs';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\n\nimport { factoryMemorySettingsUserId } from '../storage/domains/memory-settings/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport {\n SourceControlConnectionNotFoundError,\n type SourceControlSession,\n type SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport { applyStoredMemorySettings, type OMConfigurableSession } from './memory-settings-hydration.js';\nimport { seedSessionOrg } from './org-seed.js';\n\ntype FactorySession = Awaited<ReturnType<AgentController<MastraCodeState>['createSession']>>;\n\nexport class FactorySourceControlConflictError extends Error {}\n\n/**\n * Read the factory project's default model. Best-effort: a missing project or an\n * uninitialized storage domain means \"no default\", never a failed run.\n */\nexport async function resolveFactoryDefaultModelId(\n projects: FactoryProjectsStorage | undefined,\n factoryProjectId: string | undefined,\n): Promise<string | undefined> {\n if (!projects || !factoryProjectId) return undefined;\n try {\n const project = await projects.getById({ id: factoryProjectId });\n return project?.defaultModelId ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface SourceControlSessionLookup {\n getBySessionId(sessionId: string): Promise<SourceControlSession | null>;\n getSourceControlBySessionId(sessionId: string): Promise<SourceControlStorageHandle | null>;\n rename(args: { sessionId: string; title: string }): Promise<void>;\n markFirstMessage(args: { sessionId: string }): Promise<void>;\n markFirstMeaningfulExec(args: { sessionId: string }): Promise<void>;\n}\n\n/**\n * Read or update a session across every registered source-control partition.\n * Session ids are globally generated, so more than one match is invalid and\n * fails closed instead of mutating an arbitrary provider.\n */\nexport function createSourceControlSessionLookup(\n sourceControls: readonly SourceControlStorageHandle[],\n): SourceControlSessionLookup {\n const resolve = async (\n sessionId: string,\n ): Promise<{ sourceControl: SourceControlStorageHandle; session: SourceControlSession } | null> => {\n const matches = (\n await Promise.all(\n sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(sessionId),\n })),\n )\n ).filter(\n (match): match is { sourceControl: SourceControlStorageHandle; session: SourceControlSession } =>\n match.session !== null,\n );\n if (matches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n return matches[0] ?? null;\n };\n\n return {\n getBySessionId: async sessionId => (await resolve(sessionId))?.session ?? null,\n getSourceControlBySessionId: async sessionId => (await resolve(sessionId))?.sourceControl ?? null,\n rename: async args => (await resolve(args.sessionId))?.sourceControl.sessions.rename(args),\n markFirstMessage: async args => (await resolve(args.sessionId))?.sourceControl.sessions.markFirstMessage(args),\n markFirstMeaningfulExec: async args =>\n (await resolve(args.sessionId))?.sourceControl.sessions.markFirstMeaningfulExec(args),\n };\n}\n\n/**\n * Resolve the source-control provider from durable Factory repository links,\n * never from the issue tracker that happened to create the work item.\n */\nexport async function resolveFactorySourceControl(args: {\n sourceControls: readonly SourceControlStorageHandle[];\n orgId: string;\n factoryProjectId: string;\n sessionId?: string;\n}): Promise<SourceControlStorageHandle | undefined> {\n if (args.sessionId) {\n const sessionMatches = (\n await Promise.all(\n args.sourceControls.map(async sourceControl => ({\n sourceControl,\n session: await sourceControl.sessions.getBySessionId(args.sessionId!),\n })),\n )\n ).filter(match => match.session !== null);\n if (sessionMatches.length > 1) throw new Error('Factory session exists in multiple source-control providers.');\n if (sessionMatches[0]) return sessionMatches[0].sourceControl;\n }\n\n const linked = [];\n for (const sourceControl of args.sourceControls) {\n const connections = await sourceControl.connections.list({\n orgId: args.orgId,\n factoryProjectId: args.factoryProjectId,\n });\n let hasLinkedRepository = false;\n for (const connection of connections) {\n try {\n if (\n (await sourceControl.projectRepositories.list({ orgId: args.orgId, connectionId: connection.id })).length > 0\n ) {\n hasLinkedRepository = true;\n break;\n }\n } catch (error) {\n if (!(error instanceof SourceControlConnectionNotFoundError)) throw error;\n }\n }\n if (hasLinkedRepository) linked.push(sourceControl);\n }\n if (linked.length > 1)\n throw new FactorySourceControlConflictError(\n 'Factory project has repositories linked through multiple source-control providers.',\n );\n return linked[0];\n}\n\nexport interface EnsureFactorySourceSessionArgs {\n /**\n * Storage handle of the integration that owns source control. Nothing here is\n * provider-specific: the connection is matched by the handle's own\n * `integrationId`, so GitHub, Slack-on-behalf-of-GitHub, or any future owner\n * all resolve through the same traversal.\n */\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n branch: string;\n /** Pick the linked repository that the work item targets. */\n repositorySlug: string;\n /**\n * Attribute the run to this user instead of the repo connector. Set when the\n * run has an interactive user — e.g. the person who approved a proposed run.\n */\n attributeToUserId?: string;\n}\n\nexport interface EnsuredFactorySourceSession {\n sessionId: string;\n userId: string;\n projectRepositoryId: string;\n branch: string;\n baseBranch: string;\n}\n\nexport class FactorySourceSessionResolutionError extends Error {\n constructor(readonly reason: 'connection' | 'repository') {\n super(\n reason === 'connection'\n ? 'Factory source-control connection not found.'\n : 'Factory source-control repository not found.',\n );\n this.name = 'FactorySourceSessionResolutionError';\n }\n}\n\nexport interface ResolvedFactorySourceRepository {\n projectRepositoryId: string;\n /** The repository's pinned branch, else its default branch. */\n baseBranch: string;\n /** Who connected the repository. The attribution for runs with no interactive user. */\n connectedByUserId: string;\n}\n\n/**\n * Outcome of {@link resolveFactorySourceRepository}. A miss carries which step\n * failed: callers differ on whether that is an error (an autonomous run cannot\n * proceed) or a routine fallback (a chat integration drops to a chat-only\n * session), and the two steps fail for different reasons worth reporting apart.\n */\nexport type FactorySourceRepositoryResult =\n | ({ found: true } & ResolvedFactorySourceRepository)\n | { found: false; reason: 'connection' | 'repository' };\n\n/**\n * Resolve which repository a factory project's source-control runs act on: the\n * owner's connection on the project, then one of its linked repositories.\n *\n * The owner is whichever integration owns source control, matched by the\n * handle's own `integrationId` — nothing here is provider-specific.\n */\nexport async function resolveFactorySourceRepository(\n args:\n | {\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n repositorySlug: string;\n }\n | {\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n firstLinkedRepository: true;\n },\n): Promise<FactorySourceRepositoryResult> {\n const { sourceControl, orgId, factoryProjectId } = args;\n const repositorySlug = 'repositorySlug' in args ? args.repositorySlug : undefined;\n const firstLinkedRepository = 'firstLinkedRepository' in args;\n\n const connections = await sourceControl.connections.list({ orgId, factoryProjectId });\n const candidates = connections.filter(candidate => candidate.integrationId === sourceControl.integrationId);\n if (candidates.length === 0) return { found: false, reason: 'connection' };\n\n // A project can carry stale connections: a provider-app reinstall leaves the\n // old connection pointing at an installation that no longer exists, and that\n // row can sit ahead of the healthy one. Try every candidate and skip the ones\n // that no longer resolve rather than failing on the first.\n for (const connection of candidates) {\n let resolved;\n try {\n const projectRepositories = await sourceControl.projectRepositories.list({ orgId, connectionId: connection.id });\n const resolvedRepositories = await Promise.all(\n projectRepositories.map(async projectRepository => ({\n projectRepository,\n repository: await sourceControl.repositories.get({ orgId, id: projectRepository.repositoryId }),\n })),\n );\n resolved = resolvedRepositories.find(\n candidate => candidate.repository && (firstLinkedRepository || candidate.repository.slug === repositorySlug),\n );\n } catch (error) {\n // A deleted installation invalidates a stale connection; storage failures must propagate.\n if (!(error instanceof SourceControlConnectionNotFoundError)) throw error;\n continue;\n }\n if (!resolved?.repository) continue;\n\n return {\n found: true,\n projectRepositoryId: resolved.projectRepository.id,\n baseBranch: resolved.projectRepository.branch ?? resolved.repository.defaultBranch,\n connectedByUserId: connection.createdByUserId,\n };\n }\n\n return { found: false, reason: 'repository' };\n}\n\n/**\n * Walk a Factory user-session id back to the project it belongs to.\n *\n * Repo-backed channel threads are keyed by their Factory session id, which is\n * the only handle a session-start hook gets. This turns that id back into the\n * project whose configuration the session should adopt. Durable by\n * construction — it reads the same rows the session was created from, so it\n * survives restarts without any in-memory mapping.\n */\nexport async function resolveFactoryProjectForSession(args: {\n sourceControl: SourceControlStorageHandle;\n sessionId: string;\n}): Promise<{ factoryProjectId: string; orgId: string; userId: string } | null> {\n const { sourceControl, sessionId } = args;\n\n const session = await sourceControl.sessions.getBySessionId(sessionId);\n if (!session) return null;\n const projectRepository = await sourceControl.projectRepositories.get({\n orgId: session.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) return null;\n const connection = await sourceControl.connections.get({ orgId: session.orgId, id: projectRepository.connectionId });\n if (!connection) return null;\n\n return { factoryProjectId: connection.factoryProjectId, orgId: session.orgId, userId: session.userId };\n}\n\n/**\n * Create the source-control session a repo-backed factory run needs.\n *\n * `FactoryStartCoordinator.prepare` requires this record to already exist —\n * `resolveSourceSession` throws `Factory session not found` otherwise — so every\n * autonomous entry point has to produce one before it can start a run. This is\n * that step, in one place: the owner's connection on the factory project, one of\n * its linked repositories, and a session on the requested branch with the\n * repository's pinned or default branch as the base.\n *\n * The run is attributed to `attributeToUserId` when the caller has an\n * interactive user (e.g. the approver of a proposed run), and otherwise falls\n * back to whoever connected the repository (`connection.createdByUserId`),\n * because a genuinely autonomous run has no interactive user of its own.\n */\nexport async function ensureFactorySourceSession(\n args: EnsureFactorySourceSessionArgs,\n): Promise<EnsuredFactorySourceSession> {\n const { sourceControl, orgId, factoryProjectId, branch, repositorySlug } = args;\n\n const resolved = await resolveFactorySourceRepository({ sourceControl, orgId, factoryProjectId, repositorySlug });\n if (!resolved.found) throw new FactorySourceSessionResolutionError(resolved.reason);\n\n const userId = args.attributeToUserId ?? resolved.connectedByUserId;\n const session = await sourceControl.sessions.create({\n sessionId: globalThis.crypto.randomUUID(),\n projectRepositoryId: resolved.projectRepositoryId,\n orgId,\n userId,\n branch,\n baseBranch: resolved.baseBranch,\n visibility: 'org',\n });\n return {\n sessionId: session.sessionId,\n userId,\n projectRepositoryId: resolved.projectRepositoryId,\n branch: session.branch,\n baseBranch: resolved.baseBranch,\n };\n}\n\nexport interface HydrateFactorySessionArgs {\n orgId: string;\n /**\n * The factory project whose shared memory settings apply. Factory sessions\n * never read an individual user's personal memory settings — the project's\n * own row (or the built-in defaults) is what they run with.\n */\n factoryProjectId?: string;\n /** The factory project's default model. Without it the session keeps the SDK's built-in mode default. */\n defaultModelId?: string;\n /**\n * Model whose provider supplies the observational-memory fallback. Defaults\n * to the factory model, but channel sessions can use the sender's model so OM\n * resolves against that sender's credentials.\n */\n observationalMemoryModelId?: string;\n /**\n * When provided, the factory project's stored memory-settings row is\n * applied. When omitted (or no row exists) the session is reset to the\n * built-in memory defaults.\n */\n memorySettings?: MemorySettingsStorage;\n}\n\n/**\n * Apply a factory project's configuration to a freshly created session:\n * observational-memory settings, then the project's default model.\n *\n * Both steps are best-effort. A retired model id or an unreachable settings row\n * must not sink a run that is otherwise ready — the session simply keeps the\n * default it was created with, and the reason is logged.\n */\nexport async function hydrateFactorySession(session: FactorySession, args: HydrateFactorySessionArgs): Promise<void> {\n // The org rung knowledge curation scopes on. Seeded first so it lands even if\n // a later best-effort step fails; an empty org marks the session unresolved.\n await seedSessionOrg(session, args.orgId);\n try {\n const record =\n args.memorySettings && args.factoryProjectId\n ? await args.memorySettings.get({\n orgId: args.orgId,\n userId: factoryMemorySettingsUserId(args.factoryProjectId),\n })\n : null;\n // Without a stored row, fall back to the low-cost OM model of the factory\n // default model's provider — a factory connected only to Anthropic should\n // not observe with the (uncredentialed) built-in Google default.\n const observationalMemoryModelId = args.observationalMemoryModelId ?? args.defaultModelId;\n const provider = observationalMemoryModelId?.split('/')[0];\n const fallbackOmModelId = provider\n ? resolveProviderOMDefault(provider, observationalMemoryModelId).modelId\n : undefined;\n await applyStoredMemorySettings(session, record, fallbackOmModelId);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (args.defaultModelId) {\n try {\n await session.model.switch({ modelId: args.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: args.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n // Subagents otherwise keep the server-wide settings (or the SDK's built-in\n // default), which may name a provider this factory has no credentials for.\n // Each role is independent, so one failure doesn't strand the others.\n for (const agentType of ['explore', 'plan', 'execute']) {\n try {\n await session.subagents.model.set({ modelId: args.defaultModelId, agentType });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default subagent model', {\n agentType,\n modelId: args.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n\nexport interface RefreshFactorySessionMemorySettingsArgs {\n orgId: string;\n factoryProjectId: string;\n projects: Pick<FactoryProjectsStorage, 'get'>;\n memorySettings: Pick<MemorySettingsStorage, 'get'>;\n}\n\n/**\n * Re-apply a factory project's stored observational-memory settings to an\n * already-running session that automation is about to reuse. Session creation\n * hydrates these settings once (`hydrateFactorySession`), but a reused binding\n * keeps whatever observer/reflector models it was created with — so a project\n * whose OM models changed since would keep observing with the stale (and\n * possibly since-rejected) models. This reads the project's current row with the\n * same provider-aware fallback as initial hydration and applies it, mirroring\n * the `GET /web/config/om` refresh. Best-effort: a settings lookup failure must\n * never sink an otherwise-ready run, so it is logged and swallowed.\n */\nexport async function refreshFactorySessionMemorySettings(\n session: OMConfigurableSession,\n args: RefreshFactorySessionMemorySettingsArgs,\n): Promise<void> {\n try {\n const record = await args.memorySettings.get({\n orgId: args.orgId,\n userId: factoryMemorySettingsUserId(args.factoryProjectId),\n });\n const project = await args.projects.get({ orgId: args.orgId, id: args.factoryProjectId });\n const provider = project?.defaultModelId?.split('/')[0];\n const fallbackOmModelId = provider\n ? resolveProviderOMDefault(provider, project?.defaultModelId ?? undefined).modelId\n : undefined;\n await applyStoredMemorySettings(session, record, fallbackOmModelId);\n } catch (error) {\n console.warn('[Factory dispatch] Failed to reapply observational-memory settings on session reuse', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n"],"mappings":"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"}
@@ -8,9 +8,18 @@ export interface SourceControlToolProvider {
8
8
  storage: SourceControlStorageHandle;
9
9
  versionControl: VersionControl;
10
10
  }
11
+ type ReviewEvent = 'approve' | 'request-changes' | 'comment';
12
+ /** Returns why a review's leading `Verdict:` line contradicts the submitted event, if it does. */
13
+ export declare function verdictEventMismatch(event: ReviewEvent, body: string | undefined): string | undefined;
14
+ /**
15
+ * Returns the full SHA named by the body's `Reviewed head:` lines, `null` when any line is malformed or the lines
16
+ * disagree, or `undefined` when absent.
17
+ */
18
+ export declare function reviewedHeadFromBody(body: string | undefined): string | null | undefined;
11
19
  export declare function createSourceControlTools({ requestContext, providers, audit, }: {
12
20
  requestContext: RequestContext;
13
21
  providers: readonly SourceControlToolProvider[];
14
22
  audit: AuditAgentEmitter;
15
23
  }): IntegrationTools;
24
+ export {};
16
25
  //# sourceMappingURL=source-control-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-control-tools.d.ts","sourceRoot":"","sources":["../../src/session/source-control-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAIhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,KAAK,EAIV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AAQnD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,cAAc,CAAC;CAChC;AAiGD,wBAAgB,wBAAwB,CAAC,EACvC,cAAc,EACd,SAAS,EACT,KAAK,GACN,EAAE;IACD,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,KAAK,EAAE,iBAAiB,CAAC;CAC1B,GAAG,gBAAgB,CA4YnB"}
1
+ {"version":3,"file":"source-control-tools.d.ts","sourceRoot":"","sources":["../../src/session/source-control-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,KAAK,EAIV,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AAQnD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,0BAA0B,CAAC;IACpC,cAAc,EAAE,cAAc,CAAC;CAChC;AAYD,KAAK,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAE7D,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAUrG;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CASxF;AAuFD,wBAAgB,wBAAwB,CAAC,EACvC,cAAc,EACd,SAAS,EACT,KAAK,GACN,EAAE;IACD,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,KAAK,EAAE,iBAAiB,CAAC;CAC1B,GAAG,gBAAgB,CAibnB"}
@@ -1,10 +1,32 @@
1
1
  import { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from "../auth.js";
2
2
  import { mergeRequestNumberFromBranch } from "../work-item-branch.js";
3
+ import { normalizedVerdictLine } from "../review-verdict.js";
3
4
  import { resolveSessionWorkdir } from "../sandbox/session-sandbox.js";
4
5
  import { pushRepositoryBranch, refreshMergeRequestCheckout } from "../integrations/github/sandbox.js";
5
6
  import { createTool } from "@mastra/core/tools";
6
7
  import { z } from "zod";
7
8
  //#region src/session/source-control-tools.ts
9
+ /** Returns why a review's leading `Verdict:` line contradicts the submitted event, if it does. */
10
+ function verdictEventMismatch(event, body) {
11
+ const match = /^verdict: ?(approve|request changes|changes requested)\b/.exec(normalizedVerdictLine(body) ?? "");
12
+ if (!match) return void 0;
13
+ const verdict = match[1] === "approve" ? "approve" : "request changes";
14
+ const allowed = verdict === "approve" ? ["approve"] : ["request-changes", "comment"];
15
+ if (allowed.includes(event)) return void 0;
16
+ return `Review body opens with "Verdict: ${verdict}" but event is "${event}". Nothing was posted. Use event ${allowed.map((e) => `"${e}"`).join(" or ")} for this body, or regenerate the body for the verdict you intend.`;
17
+ }
18
+ const REVIEWED_HEAD_LINE = /^[\s*_>-]*reviewed head[*_]*:[*_]*\s*(.*)$/gim;
19
+ const FULL_SHA = /^`?([0-9a-f]{40}|[0-9a-f]{64})`?(?:\s|$)/i;
20
+ /**
21
+ * Returns the full SHA named by the body's `Reviewed head:` lines, `null` when any line is malformed or the lines
22
+ * disagree, or `undefined` when absent.
23
+ */
24
+ function reviewedHeadFromBody(body) {
25
+ const shas = new Set([...(body ?? "").matchAll(REVIEWED_HEAD_LINE)].map((line) => FULL_SHA.exec(line[1].trim())?.[1]?.toLowerCase() ?? null));
26
+ if (shas.size === 0) return void 0;
27
+ if (shas.size > 1) return null;
28
+ return [...shas][0];
29
+ }
8
30
  function authIdentity(requestContext) {
9
31
  const user = getFactoryAuthUserFromContext(requestContext);
10
32
  return {
@@ -404,13 +426,40 @@ function createSourceControlTools({ requestContext, providers, audit }) {
404
426
  }).refine((input) => input.event === "approve" || Boolean(input.body?.trim()), {
405
427
  path: ["body"],
406
428
  message: "request-changes and comment reviews require a body."
429
+ }).superRefine((input, ctx) => {
430
+ const mismatch = verdictEventMismatch(input.event, input.body);
431
+ if (mismatch) ctx.addIssue({
432
+ code: "custom",
433
+ path: ["body"],
434
+ message: mismatch
435
+ });
436
+ const reviewedHead = reviewedHeadFromBody(input.body);
437
+ if (reviewedHead === null) ctx.addIssue({
438
+ code: "custom",
439
+ path: ["body"],
440
+ message: "Every \"Reviewed head:\" line must name the same full 40- or 64-character commit SHA."
441
+ });
442
+ else if (reviewedHead && input.commitId && input.commitId.toLowerCase() !== reviewedHead) ctx.addIssue({
443
+ code: "custom",
444
+ path: ["commitId"],
445
+ message: `Review body says "Reviewed head: ${reviewedHead}" but commitId is ${input.commitId}. Nothing was posted. Re-review the current head and regenerate the body before publishing.`
446
+ });
407
447
  }),
408
448
  execute: async (input) => {
409
449
  const target = await withTarget();
450
+ const reviewedHead = reviewedHeadFromBody(input.body);
451
+ if (reviewedHead) {
452
+ const pullRequest = await target.provider.versionControl.getPullRequest({
453
+ ...await reference(target),
454
+ pullRequestId: changeRequestId(input.changeRequestId)
455
+ });
456
+ if (!pullRequest) throw new Error(`Change request ${input.changeRequestId} was not found; nothing was posted.`);
457
+ if (pullRequest.headSha && pullRequest.headSha.toLowerCase() !== reviewedHead) throw new Error(`Review body says "Reviewed head: ${reviewedHead}" but the current change-request head is ${pullRequest.headSha}. Nothing was posted. Re-review the current head and regenerate the body before publishing.`);
458
+ }
410
459
  const base = {
411
460
  ...await reference(target),
412
461
  pullRequestId: changeRequestId(input.changeRequestId),
413
- ...input.commitId !== void 0 ? { commitId: input.commitId } : {}
462
+ ...input.commitId !== void 0 ? { commitId: input.commitId } : reviewedHead ? { commitId: reviewedHead } : {}
414
463
  };
415
464
  if (input.event === "approve") return target.provider.versionControl.createReview({
416
465
  ...base,
@@ -467,6 +516,6 @@ function createSourceControlTools({ requestContext, providers, audit }) {
467
516
  };
468
517
  }
469
518
  //#endregion
470
- export { createSourceControlTools };
519
+ export { createSourceControlTools, reviewedHeadFromBody, verdictEventMismatch };
471
520
 
472
521
  //# sourceMappingURL=source-control-tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-control-tools.js","names":[],"sources":["../../src/session/source-control-tools.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport type { WorkspaceSandbox } from '@mastra/core/workspace';\nimport { z } from 'zod';\n\nimport { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from '../auth.js';\nimport type { VersionControl } from '../capabilities/version-control.js';\nimport type { IntegrationTools } from '../integrations/base.js';\nimport { pushRepositoryBranch, refreshMergeRequestCheckout } from '../integrations/github/sandbox.js';\nimport type { ExecutableSandbox } from '../sandbox/materialization.js';\nimport { resolveSessionWorkdir } from '../sandbox/session-sandbox.js';\nimport type { AuditAgentEmitter } from '../storage/domains/audit/domain.js';\nimport type {\n ProjectRepository,\n SourceControlRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport { mergeRequestNumberFromBranch } from '../work-item-branch.js';\n\ntype RepositorySessionState = {\n factoryProjectId?: string;\n projectRepositoryId?: string;\n};\n\nexport interface SourceControlToolProvider {\n id: string;\n storage: SourceControlStorageHandle;\n versionControl: VersionControl;\n}\n\ninterface SessionTarget {\n context: AgentControllerRequestContext<RepositorySessionState>;\n provider: SourceControlToolProvider;\n session: SourceControlSession;\n projectRepository: ProjectRepository;\n repository: SourceControlRepository;\n orgId: string;\n userId: string;\n}\n\nfunction authIdentity(requestContext: RequestContext) {\n const user = getFactoryAuthUserFromContext(requestContext);\n return { orgId: getFactoryAuthOrgId(user), userId: getFactoryAuthUserId(user) };\n}\n\nasync function resolveSessionTarget(\n requestContext: RequestContext,\n providers: readonly SourceControlToolProvider[],\n): Promise<SessionTarget> {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n const { orgId, userId } = authIdentity(requestContext);\n if (!context?.resourceId || !orgId || !userId) {\n throw new Error('Source-control tools require an authenticated repository session.');\n }\n\n const matches = (\n await Promise.all(\n providers.map(async provider => ({\n provider,\n session: await provider.storage.sessions.getBySessionId(context.resourceId),\n })),\n )\n ).filter(\n (match): match is { provider: SourceControlToolProvider; session: SourceControlSession } => match.session !== null,\n );\n if (matches.length !== 1) {\n throw new Error(\n matches.length === 0\n ? 'The active session is not backed by a source-control repository.'\n : 'The active session is ambiguous across source-control providers.',\n );\n }\n\n const { provider, session } = matches[0]!;\n if (session.orgId !== orgId || (session.visibility === 'private' && session.userId !== userId)) {\n throw new Error('The active source-control session is not available to the authenticated user.');\n }\n const projectRepository = await provider.storage.projectRepositories.get({\n orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('The active project repository was not found.');\n const state = context.getState();\n if (state.projectRepositoryId && state.projectRepositoryId !== projectRepository.id) {\n throw new Error('The active source-control session does not match its controller repository.');\n }\n const connection = await provider.storage.connections.get({ orgId, id: projectRepository.connectionId });\n if (!connection) throw new Error('The active source-control connection was not found.');\n if (state.factoryProjectId && state.factoryProjectId !== connection.factoryProjectId) {\n throw new Error('The active source-control session does not match its Factory project.');\n }\n const repository = await provider.storage.repositories.get({ orgId, id: projectRepository.repositoryId });\n if (!repository) throw new Error('The active source-control repository was not found.');\n return { context, provider, session, projectRepository, repository, orgId, userId };\n}\n\nfunction changeRequestId(value: string | number): string {\n return String(value);\n}\n\nfunction executableSandbox(value: unknown): WorkspaceSandbox & ExecutableSandbox {\n const sandbox = value as Partial<ExecutableSandbox> | undefined;\n if (!sandbox?.executeCommand) throw new Error('The active Factory workspace has no executable sandbox.');\n return sandbox as WorkspaceSandbox & ExecutableSandbox;\n}\n\nasync function emitAgentAudit(\n audit: AuditAgentEmitter,\n requestContext: RequestContext,\n input: Parameters<AuditAgentEmitter['emitAgent']>[0]['input'],\n): Promise<void> {\n try {\n await audit.emitAgent({ requestContext, input });\n } catch (error) {\n console.warn('[Audit] Failed to record brokered source-control action', {\n action: input.action,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nconst changeRequestSchema = z.object({\n changeRequestId: z.union([z.string().trim().min(1), z.number().int().positive()]),\n});\n\nexport function createSourceControlTools({\n requestContext,\n providers,\n audit,\n}: {\n requestContext: RequestContext;\n providers: readonly SourceControlToolProvider[];\n audit: AuditAgentEmitter;\n}): IntegrationTools {\n if (!requestContext || typeof (requestContext as { get?: unknown }).get !== 'function') return {};\n const controller = requestContext.get('controller') as\n | AgentControllerRequestContext<RepositorySessionState>\n | undefined;\n const identity = authIdentity(requestContext);\n if (!controller?.resourceId || !identity.orgId || !identity.userId || providers.length === 0) return {};\n\n const withTarget = () => resolveSessionTarget(requestContext, providers);\n const reference = async (target: SessionTarget) => ({\n ...(await target.provider.versionControl.getRepositoryTarget({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n })),\n actingUserId: target.userId,\n });\n\n return {\n source_control_refresh_change_request_checkout: createTool({\n id: 'source_control_refresh_change_request_checkout',\n description:\n 'Refresh the active GitLab review session checkout to its current MR head. The MR, repository, branch, and credential are resolved server-side; no provider credentials enter the agent workspace.',\n inputSchema: z.object({}),\n execute: async (_input, { workspace }) => {\n const target = await withTarget();\n const mergeRequestNumber = mergeRequestNumberFromBranch(target.session.branch);\n if (target.provider.id !== 'gitlab' || mergeRequestNumber === undefined) {\n throw new Error('Checkout refresh is only available in a bound GitLab merge-request review session.');\n }\n const ref = await reference(target);\n const mergeRequest = await target.provider.versionControl.getPullRequest({\n ...ref,\n pullRequestId: String(mergeRequestNumber),\n });\n if (!mergeRequest || mergeRequest.state !== 'open' || mergeRequest.merged) {\n throw new Error('The bound GitLab merge request is no longer open.');\n }\n const sandbox = executableSandbox(workspace?.sandbox);\n const workdir = await resolveSessionWorkdir(target.session.id, sandbox, target.repository.slug);\n const access = await target.provider.versionControl.getRepositoryAccess({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n const result = await refreshMergeRequestCheckout(sandbox, workdir, {\n branch: target.session.branch,\n mergeRequestNumber,\n expectedHeadSha: mergeRequest.headSha,\n access,\n });\n return result;\n },\n }),\n source_control_push_branch: createTool({\n id: 'source_control_push_branch',\n description:\n 'Push the active Factory session branch to its connected source-control provider. Credentials are resolved and scrubbed server-side; this tool takes no token, repository, remote, or branch arguments.',\n inputSchema: z.object({}),\n execute: async (_input, { workspace }) => {\n const target = await withTarget();\n const sandbox = executableSandbox(workspace?.sandbox);\n const workdir = await resolveSessionWorkdir(target.session.id, sandbox, target.repository.slug);\n const access = await target.provider.versionControl.getRepositoryAccess({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n await pushRepositoryBranch(sandbox, workdir, target.session.branch, access, target.repository.slug);\n await emitAgentAudit(audit, requestContext, {\n action: 'factory.agent.push',\n targets: [{ type: 'repository', id: target.repository.slug }],\n metadata: { branch: target.session.branch, provider: target.provider.id },\n });\n return { pushed: true, branch: target.session.branch, repository: target.repository.slug };\n },\n }),\n source_control_get_change_request: createTool({\n id: 'source_control_get_change_request',\n description:\n 'Read a pull request or merge request in the active Factory repository by its numeric repository-local ID.',\n inputSchema: changeRequestSchema,\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.getPullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n });\n },\n }),\n source_control_list_change_request_reviews: createTool({\n id: 'source_control_list_change_request_reviews',\n description: 'List submitted reviews and approvals on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listReviews({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_create_change_request: createTool({\n id: 'source_control_create_change_request',\n description:\n 'Open a pull request or merge request from the active Factory session branch into its persisted base branch. Push the branch with source_control_push_branch first.',\n inputSchema: z.object({\n title: z.string().trim().min(1),\n body: z.string().optional(),\n draft: z.boolean().optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n const created = await target.provider.versionControl.createPullRequest({\n ...(await reference(target)),\n title: input.title,\n ...(input.body !== undefined ? { body: input.body } : {}),\n baseBranch: target.session.baseBranch,\n headBranch: target.session.branch,\n ...(input.draft !== undefined ? { draft: input.draft } : {}),\n });\n await emitAgentAudit(audit, requestContext, {\n action: 'factory.agent.pr_opened',\n targets: [\n { type: 'pull_request', id: created.url },\n { type: 'repository', id: target.repository.slug },\n ],\n metadata: { url: created.url, provider: target.provider.id },\n });\n return created;\n },\n }),\n source_control_update_change_request: createTool({\n id: 'source_control_update_change_request',\n description: 'Update the title, body, target branch, or open/closed state of a change request.',\n inputSchema: changeRequestSchema.extend({\n title: z.string().trim().min(1).optional(),\n body: z.string().nullable().optional(),\n baseBranch: z.string().trim().min(1).optional(),\n state: z.enum(['open', 'closed']).optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updatePullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.baseBranch !== undefined ? { baseBranch: input.baseBranch } : {}),\n ...(input.state !== undefined ? { state: input.state } : {}),\n });\n },\n }),\n source_control_comment_change_request: createTool({\n id: 'source_control_comment_change_request',\n description: 'Add a top-level comment to a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.createComment({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n body: input.body,\n });\n },\n }),\n source_control_list_change_request_comments: createTool({\n id: 'source_control_list_change_request_comments',\n description: 'List top-level comments on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listComments({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_update_change_request_comment: createTool({\n id: 'source_control_update_change_request_comment',\n description: 'Edit a top-level pull-request or merge-request comment in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1), body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updateComment({\n ...(await reference(target)),\n commentId: input.commentId,\n body: input.body,\n });\n },\n }),\n source_control_delete_change_request_comment: createTool({\n id: 'source_control_delete_change_request_comment',\n description: 'Delete a top-level pull-request or merge-request comment in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n await target.provider.versionControl.deleteComment({\n ...(await reference(target)),\n commentId: input.commentId,\n });\n return { deleted: true };\n },\n }),\n source_control_list_diff_comments: createTool({\n id: 'source_control_list_diff_comments',\n description:\n 'List line-anchored review comments and discussion replies on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listReviewComments({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_create_diff_comment: createTool({\n id: 'source_control_create_diff_comment',\n description:\n 'Create a line-anchored review comment or reply to an existing diff discussion. Use replyToId alone for a reply; otherwise provide commitId, path, line, and side.',\n // A root-level union is not representable as provider function parameters, which must be\n // an object schema, so both modes share one object shape and a refinement.\n inputSchema: changeRequestSchema\n .extend({\n body: z.string().trim().min(1),\n replyToId: z.string().trim().min(1).optional(),\n commitId: z.string().trim().min(1).optional(),\n path: z.string().trim().min(1).optional(),\n line: z.number().int().positive().optional(),\n side: z.enum(['left', 'right']).optional(),\n startLine: z.number().int().positive().optional(),\n startSide: z.enum(['left', 'right']).optional(),\n })\n .refine(\n input => {\n const anchorFields = [input.commitId, input.path, input.line, input.side];\n const anchor = anchorFields.every(field => field !== undefined);\n const reply = input.replyToId !== undefined;\n return (\n (reply ? anchorFields.every(field => field === undefined) : anchor) &&\n (input.startLine === undefined) === (input.startSide === undefined)\n );\n },\n {\n message:\n 'Provide replyToId alone to reply to a diff thread, or commitId, path, line, and side to start one. startLine and startSide must be provided together.',\n },\n ),\n execute: async input => {\n const target = await withTarget();\n const base = {\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n body: input.body,\n };\n if (input.replyToId !== undefined) {\n return target.provider.versionControl.createReviewComment({ ...base, replyToId: input.replyToId });\n }\n if (\n input.commitId === undefined ||\n input.path === undefined ||\n input.line === undefined ||\n input.side === undefined\n ) {\n throw new Error('commitId, path, line, and side are required to start a new diff thread.');\n }\n return target.provider.versionControl.createReviewComment({\n ...base,\n commitId: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side,\n ...(input.startLine !== undefined && input.startSide !== undefined\n ? { startLine: input.startLine, startSide: input.startSide }\n : {}),\n });\n },\n }),\n source_control_update_diff_comment: createTool({\n id: 'source_control_update_diff_comment',\n description: 'Edit a line-anchored review comment or discussion reply in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1), body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updateReviewComment({\n ...(await reference(target)),\n commentId: input.commentId,\n body: input.body,\n });\n },\n }),\n source_control_delete_diff_comment: createTool({\n id: 'source_control_delete_diff_comment',\n description: 'Delete a line-anchored review comment or discussion reply in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n await target.provider.versionControl.deleteReviewComment({\n ...(await reference(target)),\n commentId: input.commentId,\n });\n return { deleted: true };\n },\n }),\n source_control_resolve_diff_thread: createTool({\n id: 'source_control_resolve_diff_thread',\n description:\n 'Resolve or reopen the review thread containing a diff comment. Providers without resolvable threads return an explicit limitation.',\n inputSchema: z.object({\n commentId: z.string().trim().min(1),\n resolved: z.boolean().default(true),\n }),\n execute: async input => {\n const target = await withTarget();\n const resolveReviewThread = target.provider.versionControl.resolveReviewThread;\n if (!resolveReviewThread) {\n throw new Error(`${target.provider.id} does not support resolving review threads.`);\n }\n await resolveReviewThread({\n ...(await reference(target)),\n commentId: input.commentId,\n resolved: input.resolved,\n });\n return { resolved: input.resolved };\n },\n }),\n source_control_review_change_request: createTool({\n id: 'source_control_review_change_request',\n description:\n 'Submit an approve, request-changes, or comment review to a change request. Provider limitations are returned explicitly.',\n inputSchema: changeRequestSchema\n .extend({\n event: z.enum(['approve', 'request-changes', 'comment']),\n body: z.string().optional(),\n commitId: z.string().trim().min(1).optional(),\n })\n .refine(input => input.event === 'approve' || Boolean(input.body?.trim()), {\n path: ['body'],\n message: 'request-changes and comment reviews require a body.',\n }),\n execute: async input => {\n const target = await withTarget();\n const base = {\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.commitId !== undefined ? { commitId: input.commitId } : {}),\n };\n if (input.event === 'approve') {\n return target.provider.versionControl.createReview({\n ...base,\n event: 'approve',\n ...(input.body !== undefined ? { body: input.body } : {}),\n });\n }\n return target.provider.versionControl.createReview({ ...base, event: input.event, body: input.body! });\n },\n }),\n source_control_request_reviewers: createTool({\n id: 'source_control_request_reviewers',\n description:\n 'Request individual or team reviewers on a pull request or merge request. Provider limitations are returned explicitly.',\n inputSchema: changeRequestSchema.extend({\n users: z.array(z.string().trim().min(1)).default([]),\n teams: z.array(z.string().trim().min(1)).default([]),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.requestReviewers({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n users: input.users,\n teams: input.teams,\n });\n },\n }),\n source_control_merge_change_request: createTool({\n id: 'source_control_merge_change_request',\n description: 'Merge a pull request or merge request using the requested provider-supported merge method.',\n inputSchema: changeRequestSchema.extend({\n method: z.enum(['merge', 'squash', 'rebase']).optional(),\n commitTitle: z.string().optional(),\n commitMessage: z.string().optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.mergePullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.method !== undefined ? { method: input.method } : {}),\n ...(input.commitTitle !== undefined ? { commitTitle: input.commitTitle } : {}),\n ...(input.commitMessage !== undefined ? { commitMessage: input.commitMessage } : {}),\n });\n },\n }),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"source-control-tools.js","names":[],"sources":["../../src/session/source-control-tools.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport type { WorkspaceSandbox } from '@mastra/core/workspace';\nimport { z } from 'zod';\n\nimport { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from '../auth.js';\nimport type { VersionControl } from '../capabilities/version-control.js';\nimport type { IntegrationTools } from '../integrations/base.js';\nimport { pushRepositoryBranch, refreshMergeRequestCheckout } from '../integrations/github/sandbox.js';\nimport { normalizedVerdictLine } from '../review-verdict.js';\nimport type { ExecutableSandbox } from '../sandbox/materialization.js';\nimport { resolveSessionWorkdir } from '../sandbox/session-sandbox.js';\nimport type { AuditAgentEmitter } from '../storage/domains/audit/domain.js';\nimport type {\n ProjectRepository,\n SourceControlRepository,\n SourceControlSession,\n SourceControlStorageHandle,\n} from '../storage/domains/source-control/base.js';\nimport { mergeRequestNumberFromBranch } from '../work-item-branch.js';\n\ntype RepositorySessionState = {\n factoryProjectId?: string;\n projectRepositoryId?: string;\n};\n\nexport interface SourceControlToolProvider {\n id: string;\n storage: SourceControlStorageHandle;\n versionControl: VersionControl;\n}\n\ninterface SessionTarget {\n context: AgentControllerRequestContext<RepositorySessionState>;\n provider: SourceControlToolProvider;\n session: SourceControlSession;\n projectRepository: ProjectRepository;\n repository: SourceControlRepository;\n orgId: string;\n userId: string;\n}\n\ntype ReviewEvent = 'approve' | 'request-changes' | 'comment';\n\n/** Returns why a review's leading `Verdict:` line contradicts the submitted event, if it does. */\nexport function verdictEventMismatch(event: ReviewEvent, body: string | undefined): string | undefined {\n const match = /^verdict: ?(approve|request changes|changes requested)\\b/.exec(normalizedVerdictLine(body) ?? '');\n if (!match) return undefined;\n const verdict = match[1] === 'approve' ? 'approve' : 'request changes';\n // GitLab has no request-changes state, so a blocking verdict is published as a comment review.\n const allowed: ReviewEvent[] = verdict === 'approve' ? ['approve'] : ['request-changes', 'comment'];\n if (allowed.includes(event)) return undefined;\n return `Review body opens with \"Verdict: ${verdict}\" but event is \"${event}\". Nothing was posted. Use event ${allowed\n .map(e => `\"${e}\"`)\n .join(' or ')} for this body, or regenerate the body for the verdict you intend.`;\n}\n\nconst REVIEWED_HEAD_LINE = /^[\\s*_>-]*reviewed head[*_]*:[*_]*\\s*(.*)$/gim;\nconst FULL_SHA = /^`?([0-9a-f]{40}|[0-9a-f]{64})`?(?:\\s|$)/i;\n\n/**\n * Returns the full SHA named by the body's `Reviewed head:` lines, `null` when any line is malformed or the lines\n * disagree, or `undefined` when absent.\n */\nexport function reviewedHeadFromBody(body: string | undefined): string | null | undefined {\n const shas = new Set(\n [...(body ?? '').matchAll(REVIEWED_HEAD_LINE)].map(\n line => FULL_SHA.exec(line[1]!.trim())?.[1]?.toLowerCase() ?? null,\n ),\n );\n if (shas.size === 0) return undefined;\n if (shas.size > 1) return null;\n return [...shas][0];\n}\n\nfunction authIdentity(requestContext: RequestContext) {\n const user = getFactoryAuthUserFromContext(requestContext);\n return { orgId: getFactoryAuthOrgId(user), userId: getFactoryAuthUserId(user) };\n}\n\nasync function resolveSessionTarget(\n requestContext: RequestContext,\n providers: readonly SourceControlToolProvider[],\n): Promise<SessionTarget> {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n const { orgId, userId } = authIdentity(requestContext);\n if (!context?.resourceId || !orgId || !userId) {\n throw new Error('Source-control tools require an authenticated repository session.');\n }\n\n const matches = (\n await Promise.all(\n providers.map(async provider => ({\n provider,\n session: await provider.storage.sessions.getBySessionId(context.resourceId),\n })),\n )\n ).filter(\n (match): match is { provider: SourceControlToolProvider; session: SourceControlSession } => match.session !== null,\n );\n if (matches.length !== 1) {\n throw new Error(\n matches.length === 0\n ? 'The active session is not backed by a source-control repository.'\n : 'The active session is ambiguous across source-control providers.',\n );\n }\n\n const { provider, session } = matches[0]!;\n if (session.orgId !== orgId || (session.visibility === 'private' && session.userId !== userId)) {\n throw new Error('The active source-control session is not available to the authenticated user.');\n }\n const projectRepository = await provider.storage.projectRepositories.get({\n orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('The active project repository was not found.');\n const state = context.getState();\n if (state.projectRepositoryId && state.projectRepositoryId !== projectRepository.id) {\n throw new Error('The active source-control session does not match its controller repository.');\n }\n const connection = await provider.storage.connections.get({ orgId, id: projectRepository.connectionId });\n if (!connection) throw new Error('The active source-control connection was not found.');\n if (state.factoryProjectId && state.factoryProjectId !== connection.factoryProjectId) {\n throw new Error('The active source-control session does not match its Factory project.');\n }\n const repository = await provider.storage.repositories.get({ orgId, id: projectRepository.repositoryId });\n if (!repository) throw new Error('The active source-control repository was not found.');\n return { context, provider, session, projectRepository, repository, orgId, userId };\n}\n\nfunction changeRequestId(value: string | number): string {\n return String(value);\n}\n\nfunction executableSandbox(value: unknown): WorkspaceSandbox & ExecutableSandbox {\n const sandbox = value as Partial<ExecutableSandbox> | undefined;\n if (!sandbox?.executeCommand) throw new Error('The active Factory workspace has no executable sandbox.');\n return sandbox as WorkspaceSandbox & ExecutableSandbox;\n}\n\nasync function emitAgentAudit(\n audit: AuditAgentEmitter,\n requestContext: RequestContext,\n input: Parameters<AuditAgentEmitter['emitAgent']>[0]['input'],\n): Promise<void> {\n try {\n await audit.emitAgent({ requestContext, input });\n } catch (error) {\n console.warn('[Audit] Failed to record brokered source-control action', {\n action: input.action,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nconst changeRequestSchema = z.object({\n changeRequestId: z.union([z.string().trim().min(1), z.number().int().positive()]),\n});\n\nexport function createSourceControlTools({\n requestContext,\n providers,\n audit,\n}: {\n requestContext: RequestContext;\n providers: readonly SourceControlToolProvider[];\n audit: AuditAgentEmitter;\n}): IntegrationTools {\n if (!requestContext || typeof (requestContext as { get?: unknown }).get !== 'function') return {};\n const controller = requestContext.get('controller') as\n | AgentControllerRequestContext<RepositorySessionState>\n | undefined;\n const identity = authIdentity(requestContext);\n if (!controller?.resourceId || !identity.orgId || !identity.userId || providers.length === 0) return {};\n\n const withTarget = () => resolveSessionTarget(requestContext, providers);\n const reference = async (target: SessionTarget) => ({\n ...(await target.provider.versionControl.getRepositoryTarget({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n })),\n actingUserId: target.userId,\n });\n\n return {\n source_control_refresh_change_request_checkout: createTool({\n id: 'source_control_refresh_change_request_checkout',\n description:\n 'Refresh the active GitLab review session checkout to its current MR head. The MR, repository, branch, and credential are resolved server-side; no provider credentials enter the agent workspace.',\n inputSchema: z.object({}),\n execute: async (_input, { workspace }) => {\n const target = await withTarget();\n const mergeRequestNumber = mergeRequestNumberFromBranch(target.session.branch);\n if (target.provider.id !== 'gitlab' || mergeRequestNumber === undefined) {\n throw new Error('Checkout refresh is only available in a bound GitLab merge-request review session.');\n }\n const ref = await reference(target);\n const mergeRequest = await target.provider.versionControl.getPullRequest({\n ...ref,\n pullRequestId: String(mergeRequestNumber),\n });\n if (!mergeRequest || mergeRequest.state !== 'open' || mergeRequest.merged) {\n throw new Error('The bound GitLab merge request is no longer open.');\n }\n const sandbox = executableSandbox(workspace?.sandbox);\n const workdir = await resolveSessionWorkdir(target.session.id, sandbox, target.repository.slug);\n const access = await target.provider.versionControl.getRepositoryAccess({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n const result = await refreshMergeRequestCheckout(sandbox, workdir, {\n branch: target.session.branch,\n mergeRequestNumber,\n expectedHeadSha: mergeRequest.headSha,\n access,\n });\n return result;\n },\n }),\n source_control_push_branch: createTool({\n id: 'source_control_push_branch',\n description:\n 'Push the active Factory session branch to its connected source-control provider. Credentials are resolved and scrubbed server-side; this tool takes no token, repository, remote, or branch arguments.',\n inputSchema: z.object({}),\n execute: async (_input, { workspace }) => {\n const target = await withTarget();\n const sandbox = executableSandbox(workspace?.sandbox);\n const workdir = await resolveSessionWorkdir(target.session.id, sandbox, target.repository.slug);\n const access = await target.provider.versionControl.getRepositoryAccess({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n await pushRepositoryBranch(sandbox, workdir, target.session.branch, access, target.repository.slug);\n await emitAgentAudit(audit, requestContext, {\n action: 'factory.agent.push',\n targets: [{ type: 'repository', id: target.repository.slug }],\n metadata: { branch: target.session.branch, provider: target.provider.id },\n });\n return { pushed: true, branch: target.session.branch, repository: target.repository.slug };\n },\n }),\n source_control_get_change_request: createTool({\n id: 'source_control_get_change_request',\n description:\n 'Read a pull request or merge request in the active Factory repository by its numeric repository-local ID.',\n inputSchema: changeRequestSchema,\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.getPullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n });\n },\n }),\n source_control_list_change_request_reviews: createTool({\n id: 'source_control_list_change_request_reviews',\n description: 'List submitted reviews and approvals on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listReviews({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_create_change_request: createTool({\n id: 'source_control_create_change_request',\n description:\n 'Open a pull request or merge request from the active Factory session branch into its persisted base branch. Push the branch with source_control_push_branch first.',\n inputSchema: z.object({\n title: z.string().trim().min(1),\n body: z.string().optional(),\n draft: z.boolean().optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n const created = await target.provider.versionControl.createPullRequest({\n ...(await reference(target)),\n title: input.title,\n ...(input.body !== undefined ? { body: input.body } : {}),\n baseBranch: target.session.baseBranch,\n headBranch: target.session.branch,\n ...(input.draft !== undefined ? { draft: input.draft } : {}),\n });\n await emitAgentAudit(audit, requestContext, {\n action: 'factory.agent.pr_opened',\n targets: [\n { type: 'pull_request', id: created.url },\n { type: 'repository', id: target.repository.slug },\n ],\n metadata: { url: created.url, provider: target.provider.id },\n });\n return created;\n },\n }),\n source_control_update_change_request: createTool({\n id: 'source_control_update_change_request',\n description: 'Update the title, body, target branch, or open/closed state of a change request.',\n inputSchema: changeRequestSchema.extend({\n title: z.string().trim().min(1).optional(),\n body: z.string().nullable().optional(),\n baseBranch: z.string().trim().min(1).optional(),\n state: z.enum(['open', 'closed']).optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updatePullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.body !== undefined ? { body: input.body } : {}),\n ...(input.baseBranch !== undefined ? { baseBranch: input.baseBranch } : {}),\n ...(input.state !== undefined ? { state: input.state } : {}),\n });\n },\n }),\n source_control_comment_change_request: createTool({\n id: 'source_control_comment_change_request',\n description: 'Add a top-level comment to a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.createComment({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n body: input.body,\n });\n },\n }),\n source_control_list_change_request_comments: createTool({\n id: 'source_control_list_change_request_comments',\n description: 'List top-level comments on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listComments({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_update_change_request_comment: createTool({\n id: 'source_control_update_change_request_comment',\n description: 'Edit a top-level pull-request or merge-request comment in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1), body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updateComment({\n ...(await reference(target)),\n commentId: input.commentId,\n body: input.body,\n });\n },\n }),\n source_control_delete_change_request_comment: createTool({\n id: 'source_control_delete_change_request_comment',\n description: 'Delete a top-level pull-request or merge-request comment in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n await target.provider.versionControl.deleteComment({\n ...(await reference(target)),\n commentId: input.commentId,\n });\n return { deleted: true };\n },\n }),\n source_control_list_diff_comments: createTool({\n id: 'source_control_list_diff_comments',\n description:\n 'List line-anchored review comments and discussion replies on a pull request or merge request in the active repository.',\n inputSchema: changeRequestSchema.extend({ cursor: z.string().trim().min(1).optional() }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.listReviewComments({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.cursor !== undefined ? { cursor: input.cursor } : {}),\n });\n },\n }),\n source_control_create_diff_comment: createTool({\n id: 'source_control_create_diff_comment',\n description:\n 'Create a line-anchored review comment or reply to an existing diff discussion. Use replyToId alone for a reply; otherwise provide commitId, path, line, and side.',\n // A root-level union is not representable as provider function parameters, which must be\n // an object schema, so both modes share one object shape and a refinement.\n inputSchema: changeRequestSchema\n .extend({\n body: z.string().trim().min(1),\n replyToId: z.string().trim().min(1).optional(),\n commitId: z.string().trim().min(1).optional(),\n path: z.string().trim().min(1).optional(),\n line: z.number().int().positive().optional(),\n side: z.enum(['left', 'right']).optional(),\n startLine: z.number().int().positive().optional(),\n startSide: z.enum(['left', 'right']).optional(),\n })\n .refine(\n input => {\n const anchorFields = [input.commitId, input.path, input.line, input.side];\n const anchor = anchorFields.every(field => field !== undefined);\n const reply = input.replyToId !== undefined;\n return (\n (reply ? anchorFields.every(field => field === undefined) : anchor) &&\n (input.startLine === undefined) === (input.startSide === undefined)\n );\n },\n {\n message:\n 'Provide replyToId alone to reply to a diff thread, or commitId, path, line, and side to start one. startLine and startSide must be provided together.',\n },\n ),\n execute: async input => {\n const target = await withTarget();\n const base = {\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n body: input.body,\n };\n if (input.replyToId !== undefined) {\n return target.provider.versionControl.createReviewComment({ ...base, replyToId: input.replyToId });\n }\n if (\n input.commitId === undefined ||\n input.path === undefined ||\n input.line === undefined ||\n input.side === undefined\n ) {\n throw new Error('commitId, path, line, and side are required to start a new diff thread.');\n }\n return target.provider.versionControl.createReviewComment({\n ...base,\n commitId: input.commitId,\n path: input.path,\n line: input.line,\n side: input.side,\n ...(input.startLine !== undefined && input.startSide !== undefined\n ? { startLine: input.startLine, startSide: input.startSide }\n : {}),\n });\n },\n }),\n source_control_update_diff_comment: createTool({\n id: 'source_control_update_diff_comment',\n description: 'Edit a line-anchored review comment or discussion reply in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1), body: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.updateReviewComment({\n ...(await reference(target)),\n commentId: input.commentId,\n body: input.body,\n });\n },\n }),\n source_control_delete_diff_comment: createTool({\n id: 'source_control_delete_diff_comment',\n description: 'Delete a line-anchored review comment or discussion reply in the active repository.',\n inputSchema: z.object({ commentId: z.string().trim().min(1) }),\n execute: async input => {\n const target = await withTarget();\n await target.provider.versionControl.deleteReviewComment({\n ...(await reference(target)),\n commentId: input.commentId,\n });\n return { deleted: true };\n },\n }),\n source_control_resolve_diff_thread: createTool({\n id: 'source_control_resolve_diff_thread',\n description:\n 'Resolve or reopen the review thread containing a diff comment. Providers without resolvable threads return an explicit limitation.',\n inputSchema: z.object({\n commentId: z.string().trim().min(1),\n resolved: z.boolean().default(true),\n }),\n execute: async input => {\n const target = await withTarget();\n const resolveReviewThread = target.provider.versionControl.resolveReviewThread;\n if (!resolveReviewThread) {\n throw new Error(`${target.provider.id} does not support resolving review threads.`);\n }\n await resolveReviewThread({\n ...(await reference(target)),\n commentId: input.commentId,\n resolved: input.resolved,\n });\n return { resolved: input.resolved };\n },\n }),\n source_control_review_change_request: createTool({\n id: 'source_control_review_change_request',\n description:\n 'Submit an approve, request-changes, or comment review to a change request. Provider limitations are returned explicitly.',\n inputSchema: changeRequestSchema\n .extend({\n event: z.enum(['approve', 'request-changes', 'comment']),\n body: z.string().optional(),\n commitId: z.string().trim().min(1).optional(),\n })\n .refine(input => input.event === 'approve' || Boolean(input.body?.trim()), {\n path: ['body'],\n message: 'request-changes and comment reviews require a body.',\n })\n .superRefine((input, ctx) => {\n const mismatch = verdictEventMismatch(input.event, input.body);\n if (mismatch) ctx.addIssue({ code: 'custom', path: ['body'], message: mismatch });\n const reviewedHead = reviewedHeadFromBody(input.body);\n if (reviewedHead === null) {\n ctx.addIssue({\n code: 'custom',\n path: ['body'],\n message: 'Every \"Reviewed head:\" line must name the same full 40- or 64-character commit SHA.',\n });\n } else if (reviewedHead && input.commitId && input.commitId.toLowerCase() !== reviewedHead) {\n ctx.addIssue({\n code: 'custom',\n path: ['commitId'],\n message: `Review body says \"Reviewed head: ${reviewedHead}\" but commitId is ${input.commitId}. Nothing was posted. Re-review the current head and regenerate the body before publishing.`,\n });\n }\n }),\n execute: async input => {\n const target = await withTarget();\n const reviewedHead = reviewedHeadFromBody(input.body);\n if (reviewedHead) {\n const pullRequest = await target.provider.versionControl.getPullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n });\n if (!pullRequest) {\n throw new Error(`Change request ${input.changeRequestId} was not found; nothing was posted.`);\n }\n if (pullRequest.headSha && pullRequest.headSha.toLowerCase() !== reviewedHead) {\n throw new Error(\n `Review body says \"Reviewed head: ${reviewedHead}\" but the current change-request head is ${pullRequest.headSha}. Nothing was posted. Re-review the current head and regenerate the body before publishing.`,\n );\n }\n }\n const base = {\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.commitId !== undefined\n ? { commitId: input.commitId }\n : reviewedHead\n ? { commitId: reviewedHead }\n : {}),\n };\n if (input.event === 'approve') {\n return target.provider.versionControl.createReview({\n ...base,\n event: 'approve',\n ...(input.body !== undefined ? { body: input.body } : {}),\n });\n }\n return target.provider.versionControl.createReview({ ...base, event: input.event, body: input.body! });\n },\n }),\n source_control_request_reviewers: createTool({\n id: 'source_control_request_reviewers',\n description:\n 'Request individual or team reviewers on a pull request or merge request. Provider limitations are returned explicitly.',\n inputSchema: changeRequestSchema.extend({\n users: z.array(z.string().trim().min(1)).default([]),\n teams: z.array(z.string().trim().min(1)).default([]),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.requestReviewers({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n users: input.users,\n teams: input.teams,\n });\n },\n }),\n source_control_merge_change_request: createTool({\n id: 'source_control_merge_change_request',\n description: 'Merge a pull request or merge request using the requested provider-supported merge method.',\n inputSchema: changeRequestSchema.extend({\n method: z.enum(['merge', 'squash', 'rebase']).optional(),\n commitTitle: z.string().optional(),\n commitMessage: z.string().optional(),\n }),\n execute: async input => {\n const target = await withTarget();\n return target.provider.versionControl.mergePullRequest({\n ...(await reference(target)),\n pullRequestId: changeRequestId(input.changeRequestId),\n ...(input.method !== undefined ? { method: input.method } : {}),\n ...(input.commitTitle !== undefined ? { commitTitle: input.commitTitle } : {}),\n ...(input.commitMessage !== undefined ? { commitMessage: input.commitMessage } : {}),\n });\n },\n }),\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { createHmac, randomBytes, timingSafeEqual } from "crypto";
1
+ import { createHmac, timingSafeEqual } from "crypto";
2
2
  //#region src/state-signing.ts
3
3
  /**
4
4
  * Shared OAuth/install `state` signing for web integrations.
@@ -33,7 +33,7 @@ const STATE_MAX_AGE_MS = 600 * 1e3;
33
33
  */
34
34
  function createStateSigner(secret) {
35
35
  const stable = typeof secret === "string" && secret.length > 0;
36
- const key = stable ? secret : randomBytes(32).toString("hex");
36
+ const key = stable ? secret : Buffer.from(globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32))).toString("hex");
37
37
  return {
38
38
  stable,
39
39
  sign(orgId, userId, context) {
@@ -41,7 +41,7 @@ function createStateSigner(secret) {
41
41
  orgId,
42
42
  userId,
43
43
  ...context?.factoryProjectId ? { factoryProjectId: context.factoryProjectId } : {},
44
- nonce: randomBytes(8).toString("hex"),
44
+ nonce: Buffer.from(globalThis.crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(8))).toString("hex"),
45
45
  issuedAt: Date.now()
46
46
  };
47
47
  const body = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
@@ -1 +1 @@
1
- {"version":3,"file":"state-signing.js","names":[],"sources":["../src/state-signing.ts"],"sourcesContent":["/**\n * Shared OAuth/install `state` signing for web integrations.\n *\n * The GitHub, Linear, and Slack OAuth/OIDC flows each round-trip a signed `state`\n * value\n * through the third party to bind the callback to the `(orgId, userId)` tenant\n * that initiated it (CSRF protection + tenant routing). The signer is a system\n * facility: `MastraFactory` creates ONE signer at boot and hands it to every\n * registered integration through `IntegrationContext` (see\n * `./factory-integration.ts`), so all integrations sign and verify with the\n * same secret.\n *\n * Secret resolution happens in the factory, not here: explicit\n * `config.stateSecret` → the GitHub integration's webhook secret → a\n * per-process random secret. A random secret is NOT stable across replicas —\n * a `state` signed by one replica cannot be verified by another — which is\n * what the `stable` flag reports. The factory fails loud at boot when a\n * registered integration requires a stable signer but only a random one is\n * available.\n *\n * The wire format (base64url JSON payload + `.` + HMAC-SHA256 base64url\n * signature) is unchanged from the previous `github/config.ts` implementation\n * so in-flight OAuth states survive a deploy.\n */\n\nimport { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';\n\n/** Verified tenant and optional Factory context carried by a signed `state`. */\nexport interface StateTenant {\n orgId: string;\n userId: string;\n /** Factory that initiated the integration flow, when the caller supplied one. */\n factoryProjectId?: string;\n /**\n * Per-`state` random value. A signed `state` stays valid for its whole\n * lifetime, so a flow that must not run twice off one `state` (account\n * binding, for instance) can key single-use bookkeeping on this.\n */\n nonce: string;\n}\n\n/** Signs and verifies OAuth `state` values bound to a tenant and optional Factory. */\nexport interface StateSigner {\n /** Build a signed `state` bound to the tenant and optional initiating Factory. */\n sign(orgId: string, userId: string, context?: { factoryProjectId?: string }): string;\n /** Verify a signed `state`; returns the bound tenant, or `null` if invalid. */\n verify(state: string | undefined): StateTenant | null;\n /**\n * True when the signer was built from an explicit deployment-stable secret.\n * False means a per-process random secret: fine for single-process/local\n * dev, broken for multi-replica deploys (see module docs).\n */\n readonly stable: boolean;\n}\n\ninterface StatePayload {\n orgId: string;\n userId: string;\n factoryProjectId?: string;\n nonce: string;\n issuedAt: number;\n}\n\n/** Signed `state` values expire after this window to bound the CSRF token. */\nconst STATE_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * Create a state signer. With a `secret`, the signer is deployment-stable\n * (`stable: true`); without one it falls back to a per-process random secret\n * (`stable: false`).\n */\nexport function createStateSigner(secret?: string): StateSigner {\n const stable = typeof secret === 'string' && secret.length > 0;\n const key = stable ? secret : randomBytes(32).toString('hex');\n return {\n stable,\n sign(orgId: string, userId: string, context?: { factoryProjectId?: string }): string {\n const payload: StatePayload = {\n orgId,\n userId,\n ...(context?.factoryProjectId ? { factoryProjectId: context.factoryProjectId } : {}),\n nonce: randomBytes(8).toString('hex'),\n issuedAt: Date.now(),\n };\n const body = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');\n const sig = createHmac('sha256', key).update(body).digest('base64url');\n return `${body}.${sig}`;\n },\n verify(state: string | undefined): StateTenant | null {\n if (!state) return null;\n const dot = state.lastIndexOf('.');\n if (dot <= 0) return null;\n const body = state.slice(0, dot);\n const sig = state.slice(dot + 1);\n const expected = createHmac('sha256', key).update(body).digest('base64url');\n const sigBuf = Buffer.from(sig);\n const expectedBuf = Buffer.from(expected);\n if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {\n return null;\n }\n try {\n const parsed = JSON.parse(Buffer.from(body, 'base64url').toString('utf8')) as StatePayload;\n if (typeof parsed.orgId !== 'string' || typeof parsed.userId !== 'string') return null;\n if (typeof parsed.issuedAt !== 'number' || !Number.isFinite(parsed.issuedAt)) return null;\n if (typeof parsed.nonce !== 'string' || parsed.nonce.length === 0) return null;\n if (\n parsed.factoryProjectId !== undefined &&\n (typeof parsed.factoryProjectId !== 'string' || parsed.factoryProjectId.length === 0)\n ) {\n return null;\n }\n const age = Date.now() - parsed.issuedAt;\n if (age < 0 || age > STATE_MAX_AGE_MS) return null;\n return {\n orgId: parsed.orgId,\n userId: parsed.userId,\n ...(parsed.factoryProjectId ? { factoryProjectId: parsed.factoryProjectId } : {}),\n nonce: parsed.nonce,\n };\n } catch {\n return null;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,MAAM,mBAAmB,MAAU;;;;;;AAOnC,SAAgB,kBAAkB,QAA8B;CAC9D,MAAM,SAAS,OAAO,WAAW,YAAY,OAAO,SAAS;CAC7D,MAAM,MAAM,SAAS,SAAS,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK;CAC5D,OAAO;EACL;EACA,KAAK,OAAe,QAAgB,SAAiD;GACnF,MAAM,UAAwB;IAC5B;IACA;IACA,GAAI,SAAS,mBAAmB,EAAE,kBAAkB,QAAQ,iBAAiB,IAAI,CAAC;IAClF,OAAO,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;IACpC,UAAU,KAAK,IAAI;GACrB;GACA,MAAM,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,GAAG,MAAM,CAAC,CAAC,SAAS,WAAW;GAE9E,OAAO,GAAG,KAAK,GADH,WAAW,UAAU,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,WACtC;EACtB;EACA,OAAO,OAA+C;GACpD,IAAI,CAAC,OAAO,OAAO;GACnB,MAAM,MAAM,MAAM,YAAY,GAAG;GACjC,IAAI,OAAO,GAAG,OAAO;GACrB,MAAM,OAAO,MAAM,MAAM,GAAG,GAAG;GAC/B,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC;GAC/B,MAAM,WAAW,WAAW,UAAU,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,WAAW;GAC1E,MAAM,SAAS,OAAO,KAAK,GAAG;GAC9B,MAAM,cAAc,OAAO,KAAK,QAAQ;GACxC,IAAI,OAAO,WAAW,YAAY,UAAU,CAAC,gBAAgB,QAAQ,WAAW,GAC9E,OAAO;GAET,IAAI;IACF,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC;IACzE,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,WAAW,UAAU,OAAO;IAClF,IAAI,OAAO,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,OAAO,QAAQ,GAAG,OAAO;IACrF,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,WAAW,GAAG,OAAO;IAC1E,IACE,OAAO,qBAAqB,KAAA,MAC3B,OAAO,OAAO,qBAAqB,YAAY,OAAO,iBAAiB,WAAW,IAEnF,OAAO;IAET,MAAM,MAAM,KAAK,IAAI,IAAI,OAAO;IAChC,IAAI,MAAM,KAAK,MAAM,kBAAkB,OAAO;IAC9C,OAAO;KACL,OAAO,OAAO;KACd,QAAQ,OAAO;KACf,GAAI,OAAO,mBAAmB,EAAE,kBAAkB,OAAO,iBAAiB,IAAI,CAAC;KAC/E,OAAO,OAAO;IAChB;GACF,QAAQ;IACN,OAAO;GACT;EACF;CACF;AACF"}
1
+ {"version":3,"file":"state-signing.js","names":[],"sources":["../src/state-signing.ts"],"sourcesContent":["/**\n * Shared OAuth/install `state` signing for web integrations.\n *\n * The GitHub, Linear, and Slack OAuth/OIDC flows each round-trip a signed `state`\n * value\n * through the third party to bind the callback to the `(orgId, userId)` tenant\n * that initiated it (CSRF protection + tenant routing). The signer is a system\n * facility: `MastraFactory` creates ONE signer at boot and hands it to every\n * registered integration through `IntegrationContext` (see\n * `./factory-integration.ts`), so all integrations sign and verify with the\n * same secret.\n *\n * Secret resolution happens in the factory, not here: explicit\n * `config.stateSecret` → the GitHub integration's webhook secret → a\n * per-process random secret. A random secret is NOT stable across replicas —\n * a `state` signed by one replica cannot be verified by another — which is\n * what the `stable` flag reports. The factory fails loud at boot when a\n * registered integration requires a stable signer but only a random one is\n * available.\n *\n * The wire format (base64url JSON payload + `.` + HMAC-SHA256 base64url\n * signature) is unchanged from the previous `github/config.ts` implementation\n * so in-flight OAuth states survive a deploy.\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\n/** Verified tenant and optional Factory context carried by a signed `state`. */\nexport interface StateTenant {\n orgId: string;\n userId: string;\n /** Factory that initiated the integration flow, when the caller supplied one. */\n factoryProjectId?: string;\n /**\n * Per-`state` random value. A signed `state` stays valid for its whole\n * lifetime, so a flow that must not run twice off one `state` (account\n * binding, for instance) can key single-use bookkeeping on this.\n */\n nonce: string;\n}\n\n/** Signs and verifies OAuth `state` values bound to a tenant and optional Factory. */\nexport interface StateSigner {\n /** Build a signed `state` bound to the tenant and optional initiating Factory. */\n sign(orgId: string, userId: string, context?: { factoryProjectId?: string }): string;\n /** Verify a signed `state`; returns the bound tenant, or `null` if invalid. */\n verify(state: string | undefined): StateTenant | null;\n /**\n * True when the signer was built from an explicit deployment-stable secret.\n * False means a per-process random secret: fine for single-process/local\n * dev, broken for multi-replica deploys (see module docs).\n */\n readonly stable: boolean;\n}\n\ninterface StatePayload {\n orgId: string;\n userId: string;\n factoryProjectId?: string;\n nonce: string;\n issuedAt: number;\n}\n\n/** Signed `state` values expire after this window to bound the CSRF token. */\nconst STATE_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * Create a state signer. With a `secret`, the signer is deployment-stable\n * (`stable: true`); without one it falls back to a per-process random secret\n * (`stable: false`).\n */\nexport function createStateSigner(secret?: string): StateSigner {\n const stable = typeof secret === 'string' && secret.length > 0;\n const key = stable ? secret : Buffer.from(globalThis.crypto.getRandomValues(new Uint8Array(32))).toString('hex');\n return {\n stable,\n sign(orgId: string, userId: string, context?: { factoryProjectId?: string }): string {\n const payload: StatePayload = {\n orgId,\n userId,\n ...(context?.factoryProjectId ? { factoryProjectId: context.factoryProjectId } : {}),\n nonce: Buffer.from(globalThis.crypto.getRandomValues(new Uint8Array(8))).toString('hex'),\n issuedAt: Date.now(),\n };\n const body = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');\n const sig = createHmac('sha256', key).update(body).digest('base64url');\n return `${body}.${sig}`;\n },\n verify(state: string | undefined): StateTenant | null {\n if (!state) return null;\n const dot = state.lastIndexOf('.');\n if (dot <= 0) return null;\n const body = state.slice(0, dot);\n const sig = state.slice(dot + 1);\n const expected = createHmac('sha256', key).update(body).digest('base64url');\n const sigBuf = Buffer.from(sig);\n const expectedBuf = Buffer.from(expected);\n if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {\n return null;\n }\n try {\n const parsed = JSON.parse(Buffer.from(body, 'base64url').toString('utf8')) as StatePayload;\n if (typeof parsed.orgId !== 'string' || typeof parsed.userId !== 'string') return null;\n if (typeof parsed.issuedAt !== 'number' || !Number.isFinite(parsed.issuedAt)) return null;\n if (typeof parsed.nonce !== 'string' || parsed.nonce.length === 0) return null;\n if (\n parsed.factoryProjectId !== undefined &&\n (typeof parsed.factoryProjectId !== 'string' || parsed.factoryProjectId.length === 0)\n ) {\n return null;\n }\n const age = Date.now() - parsed.issuedAt;\n if (age < 0 || age > STATE_MAX_AGE_MS) return null;\n return {\n orgId: parsed.orgId,\n userId: parsed.userId,\n ...(parsed.factoryProjectId ? { factoryProjectId: parsed.factoryProjectId } : {}),\n nonce: parsed.nonce,\n };\n } catch {\n return null;\n }\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,MAAM,mBAAmB,MAAU;;;;;;AAOnC,SAAgB,kBAAkB,QAA8B;CAC9D,MAAM,SAAS,OAAO,WAAW,YAAY,OAAO,SAAS;CAC7D,MAAM,MAAM,SAAS,SAAS,OAAO,KAAK,WAAW,OAAO,gCAAgB,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK;CAC/G,OAAO;EACL;EACA,KAAK,OAAe,QAAgB,SAAiD;GACnF,MAAM,UAAwB;IAC5B;IACA;IACA,GAAI,SAAS,mBAAmB,EAAE,kBAAkB,QAAQ,iBAAiB,IAAI,CAAC;IAClF,OAAO,OAAO,KAAK,WAAW,OAAO,gCAAgB,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK;IACvF,UAAU,KAAK,IAAI;GACrB;GACA,MAAM,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,GAAG,MAAM,CAAC,CAAC,SAAS,WAAW;GAE9E,OAAO,GAAG,KAAK,GADH,WAAW,UAAU,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,WACtC;EACtB;EACA,OAAO,OAA+C;GACpD,IAAI,CAAC,OAAO,OAAO;GACnB,MAAM,MAAM,MAAM,YAAY,GAAG;GACjC,IAAI,OAAO,GAAG,OAAO;GACrB,MAAM,OAAO,MAAM,MAAM,GAAG,GAAG;GAC/B,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC;GAC/B,MAAM,WAAW,WAAW,UAAU,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,WAAW;GAC1E,MAAM,SAAS,OAAO,KAAK,GAAG;GAC9B,MAAM,cAAc,OAAO,KAAK,QAAQ;GACxC,IAAI,OAAO,WAAW,YAAY,UAAU,CAAC,gBAAgB,QAAQ,WAAW,GAC9E,OAAO;GAET,IAAI;IACF,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC;IACzE,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,WAAW,UAAU,OAAO;IAClF,IAAI,OAAO,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,OAAO,QAAQ,GAAG,OAAO;IACrF,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,WAAW,GAAG,OAAO;IAC1E,IACE,OAAO,qBAAqB,KAAA,MAC3B,OAAO,OAAO,qBAAqB,YAAY,OAAO,iBAAiB,WAAW,IAEnF,OAAO;IAET,MAAM,MAAM,KAAK,IAAI,IAAI,OAAO;IAChC,IAAI,MAAM,KAAK,MAAM,kBAAkB,OAAO;IAC9C,OAAO;KACL,OAAO,OAAO;KACd,QAAQ,OAAO;KACf,GAAI,OAAO,mBAAmB,EAAE,kBAAkB,OAAO,iBAAiB,IAAI,CAAC;KAC/E,OAAO,OAAO;IAChB;GACF,QAAQ;IACN,OAAO;GACT;EACF;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/base.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { createHash } from "crypto";
2
1
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
3
2
  //#region src/storage/domains/audit/base.ts
4
3
  /**
@@ -139,12 +138,12 @@ var AuditStorage = class extends FactoryStorageDomain {
139
138
  }
140
139
  async recordOnce(input) {
141
140
  if (!input.idempotencyKey) throw new Error("An audit idempotency key is required");
142
- const hash = createHash("sha256").update(JSON.stringify([
141
+ const hash = Buffer.from(await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify([
143
142
  input.orgId,
144
143
  input.factoryProjectId ?? null,
145
144
  input.action,
146
145
  input.idempotencyKey
147
- ])).digest("hex");
146
+ ])))).toString("hex");
148
147
  const id = `${hash.slice(0, 8)}-${hash.slice(8, 12)}-8${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
149
148
  try {
150
149
  return {