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

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 (163) hide show
  1. package/CHANGELOG.md +211 -0
  2. package/dist/auth.d.ts +17 -0
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +19 -1
  5. package/dist/auth.js.map +1 -1
  6. package/dist/capabilities/intake.d.ts +1 -0
  7. package/dist/capabilities/intake.d.ts.map +1 -1
  8. package/dist/capabilities/version-control.d.ts +3 -0
  9. package/dist/capabilities/version-control.d.ts.map +1 -1
  10. package/dist/factory.d.ts +10 -0
  11. package/dist/factory.d.ts.map +1 -1
  12. package/dist/factory.js +17 -4
  13. package/dist/factory.js.map +1 -1
  14. package/dist/integrations/base.d.ts +6 -0
  15. package/dist/integrations/base.d.ts.map +1 -1
  16. package/dist/integrations/github/integration.d.ts +14 -1
  17. package/dist/integrations/github/integration.d.ts.map +1 -1
  18. package/dist/integrations/github/integration.js +61 -3
  19. package/dist/integrations/github/integration.js.map +1 -1
  20. package/dist/integrations/github/issue-reconciler.d.ts +24 -0
  21. package/dist/integrations/github/issue-reconciler.d.ts.map +1 -0
  22. package/dist/integrations/github/issue-reconciler.js +104 -0
  23. package/dist/integrations/github/issue-reconciler.js.map +1 -0
  24. package/dist/integrations/github/reconcile-worker.d.ts +8 -0
  25. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  26. package/dist/integrations/github/reconcile-worker.js +38 -1
  27. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  28. package/dist/integrations/github/routes.d.ts.map +1 -1
  29. package/dist/integrations/github/routes.js +65 -52
  30. package/dist/integrations/github/routes.js.map +1 -1
  31. package/dist/integrations/github/rules.d.ts +37 -2
  32. package/dist/integrations/github/rules.d.ts.map +1 -1
  33. package/dist/integrations/github/rules.js +150 -14
  34. package/dist/integrations/github/rules.js.map +1 -1
  35. package/dist/integrations/github/sandbox-release.d.ts +16 -1
  36. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  37. package/dist/integrations/github/sandbox-release.js +42 -1
  38. package/dist/integrations/github/sandbox-release.js.map +1 -1
  39. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  40. package/dist/integrations/github/sandbox.js +74 -8
  41. package/dist/integrations/github/sandbox.js.map +1 -1
  42. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  43. package/dist/integrations/github/session-subscriptions.js +16 -12
  44. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  45. package/dist/integrations/issue-reconcile-worker.d.ts +19 -0
  46. package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -0
  47. package/dist/integrations/issue-reconcile-worker.js +98 -0
  48. package/dist/integrations/issue-reconcile-worker.js.map +1 -0
  49. package/dist/integrations/issue-reconciler.d.ts +47 -0
  50. package/dist/integrations/issue-reconciler.d.ts.map +1 -0
  51. package/dist/integrations/issue-reconciler.js +104 -0
  52. package/dist/integrations/issue-reconciler.js.map +1 -0
  53. package/dist/integrations/linear/integration.d.ts +4 -0
  54. package/dist/integrations/linear/integration.d.ts.map +1 -1
  55. package/dist/integrations/linear/integration.js +19 -2
  56. package/dist/integrations/linear/integration.js.map +1 -1
  57. package/dist/integrations/linear/issue-reconciler.d.ts +6 -0
  58. package/dist/integrations/linear/issue-reconciler.d.ts.map +1 -0
  59. package/dist/integrations/linear/issue-reconciler.js +64 -0
  60. package/dist/integrations/linear/issue-reconciler.js.map +1 -0
  61. package/dist/integrations/linear/routes.d.ts.map +1 -1
  62. package/dist/integrations/linear/routes.js +1 -0
  63. package/dist/integrations/linear/routes.js.map +1 -1
  64. package/dist/integrations/linear/rules.d.ts +2 -0
  65. package/dist/integrations/linear/rules.d.ts.map +1 -1
  66. package/dist/integrations/linear/rules.js +5 -2
  67. package/dist/integrations/linear/rules.js.map +1 -1
  68. package/dist/integrations/platform/github/event-worker.d.ts +7 -0
  69. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  70. package/dist/integrations/platform/github/event-worker.js +24 -0
  71. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  72. package/dist/integrations/platform/github/integration.d.ts +13 -3
  73. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  74. package/dist/integrations/platform/github/integration.js +42 -1
  75. package/dist/integrations/platform/github/integration.js.map +1 -1
  76. package/dist/integrations/platform/linear/event-worker.d.ts +105 -0
  77. package/dist/integrations/platform/linear/event-worker.d.ts.map +1 -0
  78. package/dist/integrations/platform/linear/event-worker.js +380 -0
  79. package/dist/integrations/platform/linear/event-worker.js.map +1 -0
  80. package/dist/integrations/platform/linear/integration.d.ts +9 -0
  81. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  82. package/dist/integrations/platform/linear/integration.js +37 -1
  83. package/dist/integrations/platform/linear/integration.js.map +1 -1
  84. package/dist/integrations/slack/integration.d.ts.map +1 -1
  85. package/dist/integrations/slack/integration.js +3 -2
  86. package/dist/integrations/slack/integration.js.map +1 -1
  87. package/dist/integrations/slack/slack.d.ts +37 -110
  88. package/dist/integrations/slack/slack.d.ts.map +1 -1
  89. package/dist/integrations/slack/slack.js +49 -44
  90. package/dist/integrations/slack/slack.js.map +1 -1
  91. package/dist/routes/config.d.ts +25 -0
  92. package/dist/routes/config.d.ts.map +1 -1
  93. package/dist/routes/config.js +63 -1
  94. package/dist/routes/config.js.map +1 -1
  95. package/dist/routes/fs.d.ts +16 -2
  96. package/dist/routes/fs.d.ts.map +1 -1
  97. package/dist/routes/fs.js +47 -5
  98. package/dist/routes/fs.js.map +1 -1
  99. package/dist/routes/intake.d.ts.map +1 -1
  100. package/dist/routes/intake.js +13 -5
  101. package/dist/routes/intake.js.map +1 -1
  102. package/dist/routes/surface.d.ts +13 -1
  103. package/dist/routes/surface.d.ts.map +1 -1
  104. package/dist/routes/surface.js +20 -9
  105. package/dist/routes/surface.js.map +1 -1
  106. package/dist/rules/binding-context.d.ts +28 -1
  107. package/dist/rules/binding-context.d.ts.map +1 -1
  108. package/dist/rules/binding-context.js +68 -3
  109. package/dist/rules/binding-context.js.map +1 -1
  110. package/dist/rules/defaults.d.ts.map +1 -1
  111. package/dist/rules/defaults.js +71 -5
  112. package/dist/rules/defaults.js.map +1 -1
  113. package/dist/rules/start-coordinator.d.ts.map +1 -1
  114. package/dist/rules/start-coordinator.js +8 -27
  115. package/dist/rules/start-coordinator.js.map +1 -1
  116. package/dist/rules/tools.d.ts +2 -0
  117. package/dist/rules/tools.d.ts.map +1 -1
  118. package/dist/rules/tools.js +15 -6
  119. package/dist/rules/tools.js.map +1 -1
  120. package/dist/rules/types.d.ts +17 -2
  121. package/dist/rules/types.d.ts.map +1 -1
  122. package/dist/rules/types.js +2 -1
  123. package/dist/rules/types.js.map +1 -1
  124. package/dist/session/factory-session.d.ts +116 -0
  125. package/dist/session/factory-session.d.ts.map +1 -0
  126. package/dist/session/factory-session.js +162 -0
  127. package/dist/session/factory-session.js.map +1 -0
  128. package/dist/session/filesystem-capture.d.ts +26 -0
  129. package/dist/session/filesystem-capture.d.ts.map +1 -0
  130. package/dist/session/filesystem-capture.js +75 -0
  131. package/dist/session/filesystem-capture.js.map +1 -0
  132. package/dist/storage/domains/audit/domain.d.ts +9 -2
  133. package/dist/storage/domains/audit/domain.d.ts.map +1 -1
  134. package/dist/storage/domains/audit/domain.js +106 -4
  135. package/dist/storage/domains/audit/domain.js.map +1 -1
  136. package/dist/storage/domains/filesystem/base.d.ts +26 -0
  137. package/dist/storage/domains/filesystem/base.d.ts.map +1 -0
  138. package/dist/storage/domains/filesystem/base.js +74 -0
  139. package/dist/storage/domains/filesystem/base.js.map +1 -0
  140. package/dist/storage/domains/projects/base.d.ts +1 -0
  141. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  142. package/dist/storage/domains/projects/base.js +3 -0
  143. package/dist/storage/domains/projects/base.js.map +1 -1
  144. package/dist/storage/domains/source-control/base.d.ts +2 -0
  145. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  146. package/dist/storage/domains/source-control/base.js +6 -0
  147. package/dist/storage/domains/source-control/base.js.map +1 -1
  148. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  149. package/dist/storage/domains/source-control/inmemory.js +3 -0
  150. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  151. package/dist/storage/domains/work-items/base.d.ts +11 -0
  152. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  153. package/dist/storage/domains/work-items/base.js +28 -0
  154. package/dist/storage/domains/work-items/base.js.map +1 -1
  155. package/dist/workspace.d.ts.map +1 -1
  156. package/dist/workspace.js +99 -45
  157. package/dist/workspace.js.map +1 -1
  158. package/factory-skills/factory-triage/SKILL.md +45 -12
  159. package/package.json +6 -6
  160. package/dist/integrations/github/factory-session.d.ts +0 -12
  161. package/dist/integrations/github/factory-session.d.ts.map +0 -1
  162. package/dist/integrations/github/factory-session.js +0 -37
  163. package/dist/integrations/github/factory-session.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-session.js","names":[],"sources":["../../src/session/factory-session.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\n\nimport type { MemorySettingsRecord, MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\n\ntype FactorySession = Awaited<ReturnType<AgentController<MastraCodeState>['createSession']>>;\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 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 a specific linked repository by slug. Defaults to the first linked repository. */\n repositorySlug?: string;\n}\n\nexport interface EnsuredFactorySourceSession {\n sessionId: string;\n userId: string;\n projectRepositoryId: string;\n branch: string;\n baseBranch: string;\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(args: {\n sourceControl: SourceControlStorageHandle;\n orgId: string;\n factoryProjectId: string;\n /** Pick a specific linked repository by slug. Defaults to the first linked repository. */\n repositorySlug?: string;\n}): Promise<FactorySourceRepositoryResult> {\n const { sourceControl, orgId, factoryProjectId, repositorySlug } = args;\n\n const connections = await sourceControl.connections.list({ orgId, factoryProjectId });\n const connection = connections.find(candidate => candidate.integrationId === sourceControl.integrationId);\n if (!connection) return { found: false, reason: 'connection' };\n\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 const resolved = resolvedRepositories.find(\n candidate => candidate.repository && (!repositorySlug || candidate.repository.slug === repositorySlug),\n );\n if (!resolved?.repository) return { found: false, reason: 'repository' };\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/**\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 whoever connected the repository\n * (`connection.createdByUserId`), because an autonomous run has no interactive\n * 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) {\n throw new Error(\n resolved.reason === 'connection'\n ? 'Factory source-control connection not found.'\n : 'Factory source-control repository not found.',\n );\n }\n\n const userId = 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 });\n return {\n sessionId: session.sessionId,\n userId,\n projectRepositoryId: resolved.projectRepositoryId,\n branch: session.branch,\n baseBranch: resolved.baseBranch,\n };\n}\n\nasync function applyMemorySettings(session: FactorySession, record: MemorySettingsRecord | null): Promise<void> {\n if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });\n if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });\n\n const state = {\n ...(record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {}),\n ...(record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {}),\n ...(record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}),\n };\n if (Object.keys(state).length > 0) await session.state.set(state);\n}\n\nexport interface HydrateFactorySessionArgs {\n orgId: string;\n userId: string;\n /** The factory project's default model. Without it the session keeps the SDK's built-in mode default. */\n defaultModelId?: string;\n /** Omitted when the storage domain is unavailable, in which case the session runs on memory defaults. */\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 if (args.memorySettings) {\n try {\n const record = await args.memorySettings.get({ orgId: args.orgId, userId: args.userId });\n await applyMemorySettings(session, record);\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 }\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"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { SessionBeforeAgentEndListener } from '@mastra/core/agent-controller';
2
+ import type { WorkspaceSandbox } from '@mastra/core/workspace';
3
+ import type { FilesystemFile, FilesystemStorage } from '../storage/domains/filesystem/base.js';
4
+ import type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';
5
+ export interface FilesystemCaptureSession {
6
+ readonly identity: {
7
+ getResourceId(): string;
8
+ };
9
+ readonly thread: {
10
+ requireId(): string;
11
+ };
12
+ getWorkspace(): {
13
+ sandbox?: Pick<WorkspaceSandbox, 'executeCommand'>;
14
+ };
15
+ onBeforeAgentEnd(listener: SessionBeforeAgentEndListener): () => void;
16
+ }
17
+ export interface FilesystemCaptureDependencies {
18
+ filesystem: Pick<FilesystemStorage, 'replaceFiles'>;
19
+ sourceControl: {
20
+ sessions: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;
21
+ };
22
+ }
23
+ export declare function parseFilesystemCaptureFiles(output: string): FilesystemFile[];
24
+ export declare function captureSessionFilesystem(session: FilesystemCaptureSession, { filesystem, sourceControl }: FilesystemCaptureDependencies): Promise<void>;
25
+ export declare function observeSessionFilesystem(session: FilesystemCaptureSession, dependencies: FilesystemCaptureDependencies): () => void;
26
+ //# sourceMappingURL=filesystem-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem-capture.d.ts","sourceRoot":"","sources":["../../src/session/filesystem-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC/F,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAK5F,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE;QAAE,aAAa,IAAI,MAAM,CAAA;KAAE,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE;QAAE,SAAS,IAAI,MAAM,CAAA;KAAE,CAAC;IACzC,YAAY,IAAI;QAAE,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAA;KAAE,CAAC;IACvE,gBAAgB,CAAC,QAAQ,EAAE,6BAA6B,GAAG,MAAM,IAAI,CAAC;CACvE;AAED,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;IACpD,aAAa,EAAE;QACb,QAAQ,EAAE,IAAI,CAAC,0BAA0B,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC,CAAC;KAC1E,CAAC;CACH;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CAmB5E;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,EACjC,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,6BAA6B,GAC3D,OAAO,CAAC,IAAI,CAAC,CA0Cf;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,wBAAwB,EACjC,YAAY,EAAE,6BAA6B,GAC1C,MAAM,IAAI,CAMZ"}
@@ -0,0 +1,75 @@
1
+ //#region src/session/filesystem-capture.ts
2
+ const GIT_STATUS_ARGS = [
3
+ "status",
4
+ "--porcelain=v1",
5
+ "-z",
6
+ "--untracked-files=all"
7
+ ];
8
+ const ARTIFACTS_LIST_COMMAND = "cd \"$1\" && test -d .artifacts && find .artifacts -type f -print0 || true";
9
+ function parseFilesystemCaptureFiles(output) {
10
+ const files = /* @__PURE__ */ new Map();
11
+ const records = output.split("\0");
12
+ for (let index = 0; index < records.length; index += 1) {
13
+ const record = records[index];
14
+ if (!record || record.length < 4) continue;
15
+ const code = record.slice(0, 2);
16
+ let path = record.slice(3);
17
+ const moved = code.includes("R") || code.includes("C");
18
+ if (moved) index += 1;
19
+ if (path.startsWith("./")) path = path.slice(2);
20
+ if (!path || !code.includes("U") && code.includes("D") && !moved) continue;
21
+ files.set(path, { path });
22
+ }
23
+ return [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path));
24
+ }
25
+ async function captureSessionFilesystem(session, { filesystem, sourceControl }) {
26
+ try {
27
+ const resourceId = session.identity.getResourceId();
28
+ const threadId = session.thread.requireId();
29
+ const sourceSession = await sourceControl.sessions.getBySessionId(resourceId);
30
+ const sandbox = session.getWorkspace().sandbox;
31
+ if (!sourceSession?.sandboxWorkdir || !sandbox?.executeCommand) return;
32
+ const result = await sandbox.executeCommand("git", [
33
+ "-C",
34
+ sourceSession.sandboxWorkdir,
35
+ ...GIT_STATUS_ARGS
36
+ ], { timeout: 3e4 });
37
+ if (result.exitCode !== 0) {
38
+ console.warn("[Factory filesystem capture] Unable to inspect Git status.", result.stderr);
39
+ return;
40
+ }
41
+ const artifacts = await sandbox.executeCommand("sh", [
42
+ "-c",
43
+ ARTIFACTS_LIST_COMMAND,
44
+ "sh",
45
+ sourceSession.sandboxWorkdir
46
+ ], { timeout: 3e4 });
47
+ if (artifacts.exitCode !== 0) {
48
+ console.warn("[Factory filesystem capture] Unable to list workspace artifacts.", artifacts.stderr);
49
+ return;
50
+ }
51
+ const files = new Map(parseFilesystemCaptureFiles(result.stdout).map((file) => [file.path, file]));
52
+ for (const path of artifacts.stdout.split("\0")) {
53
+ const normalizedPath = path.replace(/^\.\//, "");
54
+ if (normalizedPath) files.set(normalizedPath, { path: normalizedPath });
55
+ }
56
+ await filesystem.replaceFiles({
57
+ resourceId,
58
+ threadId,
59
+ files: [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path))
60
+ });
61
+ } catch (error) {
62
+ console.warn("[Factory filesystem capture] Unable to persist files.", error);
63
+ }
64
+ }
65
+ function observeSessionFilesystem(session, dependencies) {
66
+ let capture = Promise.resolve();
67
+ return session.onBeforeAgentEnd(() => {
68
+ capture = capture.then(() => captureSessionFilesystem(session, dependencies));
69
+ return capture;
70
+ });
71
+ }
72
+ //#endregion
73
+ export { captureSessionFilesystem, observeSessionFilesystem, parseFilesystemCaptureFiles };
74
+
75
+ //# sourceMappingURL=filesystem-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filesystem-capture.js","names":[],"sources":["../../src/session/filesystem-capture.ts"],"sourcesContent":["import type { SessionBeforeAgentEndListener } from '@mastra/core/agent-controller';\nimport type { WorkspaceSandbox } from '@mastra/core/workspace';\n\nimport type { FilesystemFile, FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\n\nconst GIT_STATUS_ARGS = ['status', '--porcelain=v1', '-z', '--untracked-files=all'];\nconst ARTIFACTS_LIST_COMMAND = 'cd \"$1\" && test -d .artifacts && find .artifacts -type f -print0 || true';\n\nexport interface FilesystemCaptureSession {\n readonly identity: { getResourceId(): string };\n readonly thread: { requireId(): string };\n getWorkspace(): { sandbox?: Pick<WorkspaceSandbox, 'executeCommand'> };\n onBeforeAgentEnd(listener: SessionBeforeAgentEndListener): () => void;\n}\n\nexport interface FilesystemCaptureDependencies {\n filesystem: Pick<FilesystemStorage, 'replaceFiles'>;\n sourceControl: {\n sessions: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;\n };\n}\n\nexport function parseFilesystemCaptureFiles(output: string): FilesystemFile[] {\n const files = new Map<string, FilesystemFile>();\n const records = output.split('\\0');\n\n for (let index = 0; index < records.length; index += 1) {\n const record = records[index];\n if (!record || record.length < 4) continue;\n\n const code = record.slice(0, 2);\n let path = record.slice(3);\n const moved = code.includes('R') || code.includes('C');\n if (moved) index += 1;\n if (path.startsWith('./')) path = path.slice(2);\n if (!path || (!code.includes('U') && code.includes('D') && !moved)) continue;\n\n files.set(path, { path });\n }\n\n return [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path));\n}\n\nexport async function captureSessionFilesystem(\n session: FilesystemCaptureSession,\n { filesystem, sourceControl }: FilesystemCaptureDependencies,\n): Promise<void> {\n try {\n const resourceId = session.identity.getResourceId();\n const threadId = session.thread.requireId();\n const sourceSession = await sourceControl.sessions.getBySessionId(resourceId);\n const sandbox = session.getWorkspace().sandbox;\n if (!sourceSession?.sandboxWorkdir || !sandbox?.executeCommand) return;\n\n const result = await sandbox.executeCommand('git', ['-C', sourceSession.sandboxWorkdir, ...GIT_STATUS_ARGS], {\n timeout: 30_000,\n });\n if (result.exitCode !== 0) {\n console.warn('[Factory filesystem capture] Unable to inspect Git status.', result.stderr);\n return;\n }\n\n const artifacts = await sandbox.executeCommand(\n 'sh',\n ['-c', ARTIFACTS_LIST_COMMAND, 'sh', sourceSession.sandboxWorkdir],\n { timeout: 30_000 },\n );\n if (artifacts.exitCode !== 0) {\n console.warn('[Factory filesystem capture] Unable to list workspace artifacts.', artifacts.stderr);\n return;\n }\n\n const files = new Map(parseFilesystemCaptureFiles(result.stdout).map(file => [file.path, file]));\n for (const path of artifacts.stdout.split('\\0')) {\n const normalizedPath = path.replace(/^\\.\\//, '');\n if (normalizedPath) {\n files.set(normalizedPath, { path: normalizedPath });\n }\n }\n\n await filesystem.replaceFiles({\n resourceId,\n threadId,\n files: [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path)),\n });\n } catch (error) {\n console.warn('[Factory filesystem capture] Unable to persist files.', error);\n }\n}\n\nexport function observeSessionFilesystem(\n session: FilesystemCaptureSession,\n dependencies: FilesystemCaptureDependencies,\n): () => void {\n let capture = Promise.resolve();\n return session.onBeforeAgentEnd(() => {\n capture = capture.then(() => captureSessionFilesystem(session, dependencies));\n return capture;\n });\n}\n"],"mappings":";AAMA,MAAM,kBAAkB;CAAC;CAAU;CAAkB;CAAM;AAAuB;AAClF,MAAM,yBAAyB;AAgB/B,SAAgB,4BAA4B,QAAkC;CAC5E,MAAM,wBAAQ,IAAI,IAA4B;CAC9C,MAAM,UAAU,OAAO,MAAM,IAAI;CAEjC,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;EACtD,MAAM,SAAS,QAAQ;EACvB,IAAI,CAAC,UAAU,OAAO,SAAS,GAAG;EAElC,MAAM,OAAO,OAAO,MAAM,GAAG,CAAC;EAC9B,IAAI,OAAO,OAAO,MAAM,CAAC;EACzB,MAAM,QAAQ,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG;EACrD,IAAI,OAAO,SAAS;EACpB,IAAI,KAAK,WAAW,IAAI,GAAG,OAAO,KAAK,MAAM,CAAC;EAC9C,IAAI,CAAC,QAAS,CAAC,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG,KAAK,CAAC,OAAQ;EAEpE,MAAM,IAAI,MAAM,EAAE,KAAK,CAAC;CAC1B;CAEA,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAC5E;AAEA,eAAsB,yBACpB,SACA,EAAE,YAAY,iBACC;CACf,IAAI;EACF,MAAM,aAAa,QAAQ,SAAS,cAAc;EAClD,MAAM,WAAW,QAAQ,OAAO,UAAU;EAC1C,MAAM,gBAAgB,MAAM,cAAc,SAAS,eAAe,UAAU;EAC5E,MAAM,UAAU,QAAQ,aAAa,CAAC,CAAC;EACvC,IAAI,CAAC,eAAe,kBAAkB,CAAC,SAAS,gBAAgB;EAEhE,MAAM,SAAS,MAAM,QAAQ,eAAe,OAAO;GAAC;GAAM,cAAc;GAAgB,GAAG;EAAe,GAAG,EAC3G,SAAS,IACX,CAAC;EACD,IAAI,OAAO,aAAa,GAAG;GACzB,QAAQ,KAAK,8DAA8D,OAAO,MAAM;GACxF;EACF;EAEA,MAAM,YAAY,MAAM,QAAQ,eAC9B,MACA;GAAC;GAAM;GAAwB;GAAM,cAAc;EAAc,GACjE,EAAE,SAAS,IAAO,CACpB;EACA,IAAI,UAAU,aAAa,GAAG;GAC5B,QAAQ,KAAK,oEAAoE,UAAU,MAAM;GACjG;EACF;EAEA,MAAM,QAAQ,IAAI,IAAI,4BAA4B,OAAO,MAAM,CAAC,CAAC,KAAI,SAAQ,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;EAC/F,KAAK,MAAM,QAAQ,UAAU,OAAO,MAAM,IAAI,GAAG;GAC/C,MAAM,iBAAiB,KAAK,QAAQ,SAAS,EAAE;GAC/C,IAAI,gBACF,MAAM,IAAI,gBAAgB,EAAE,MAAM,eAAe,CAAC;EAEtD;EAEA,MAAM,WAAW,aAAa;GAC5B;GACA;GACA,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;EAC5E,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,KAAK,yDAAyD,KAAK;CAC7E;AACF;AAEA,SAAgB,yBACd,SACA,cACY;CACZ,IAAI,UAAU,QAAQ,QAAQ;CAC9B,OAAO,QAAQ,uBAAuB;EACpC,UAAU,QAAQ,WAAW,yBAAyB,SAAS,YAAY,CAAC;EAC5E,OAAO;CACT,CAAC;AACH"}
@@ -1,5 +1,5 @@
1
1
  import type { RequestContext } from '@mastra/core/request-context';
2
- import type { ApiRoute } from '@mastra/core/server';
2
+ import type { ApiRoute, IUserProvider } from '@mastra/core/server';
3
3
  import type { Context } from 'hono';
4
4
  import type { RouteAuth } from '../../../routes/route.js';
5
5
  import type { FactoryProjectsStorage } from '../projects/base.js';
@@ -35,12 +35,19 @@ export interface AuditSink {
35
35
  event: AuditEventRow;
36
36
  }): Promise<void>;
37
37
  }
38
+ export interface AuditActorProfile {
39
+ id: string;
40
+ name: string;
41
+ avatarUrl?: string;
42
+ }
38
43
  export interface AuditDomainOptions {
39
44
  auth: RouteAuth;
40
45
  /** Audit storage domain handle. */
41
46
  audit: AuditStorage;
42
47
  /** Projects domain handle, used to scope the audit trail route. */
43
48
  projects: FactoryProjectsStorage;
49
+ /** Resolve persisted human actor ids to display names and profile images. */
50
+ users?: Pick<IUserProvider, 'getUser' | 'getUsers'>;
44
51
  /** Best-effort fan-out destinations notified after each recorded event. */
45
52
  sinks?: AuditSink[];
46
53
  /** Resolve the acting tenant for agent-emitted events from the request context. */
@@ -53,7 +60,7 @@ export declare function auditRequestContext(c: Context): AuditContext;
53
60
  /** Factory-owned audit behavior backed by the audit storage domain. */
54
61
  export declare class AuditDomain implements AuditEmitter, AuditAgentEmitter {
55
62
  #private;
56
- constructor({ auth, audit, projects, sinks, agentTenant }: AuditDomainOptions);
63
+ constructor({ auth, audit, projects, users, sinks, agentTenant }: AuditDomainOptions);
57
64
  record(input: RecordAuditEventInput): Promise<AuditEventRow | null>;
58
65
  list(input: ListAuditEventsInput): Promise<AuditEventPage>;
59
66
  emit({ context, input }: {
@@ -1 +1 @@
1
- {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/domain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/domain.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,50 @@
1
1
  import { registerApiRoute } from "@mastra/core/server";
2
2
  //#region src/storage/domains/audit/domain.ts
3
+ /**
4
+ * Reserved metadata key on `AuditEventRow.metadata` that carries the acting
5
+ * human user's display name and avatar captured from the auth context at
6
+ * record time. Read back by `#resolveActorProfiles` so names/avatars work
7
+ * for every auth provider without requiring an `IUserProvider.getUser(id)`
8
+ * implementation — the Studio provider proxies through the shared API and
9
+ * cannot resolve arbitrary users by id.
10
+ */
11
+ const ACTOR_PROFILE_METADATA_KEY = "__actorProfile";
12
+ function readStoredActorProfile(metadata) {
13
+ if (!metadata) return void 0;
14
+ const raw = metadata[ACTOR_PROFILE_METADATA_KEY];
15
+ if (!raw || typeof raw !== "object") return void 0;
16
+ const profile = raw;
17
+ const name = typeof profile.name === "string" && profile.name.trim() ? profile.name.trim() : void 0;
18
+ const avatarUrl = typeof profile.avatarUrl === "string" && profile.avatarUrl.trim() ? profile.avatarUrl.trim() : void 0;
19
+ if (!name && !avatarUrl) return void 0;
20
+ return {
21
+ ...name ? { name } : {},
22
+ ...avatarUrl ? { avatarUrl } : {}
23
+ };
24
+ }
25
+ /** Read the auth gate's stashed user directly from the Hono context. */
26
+ function readFactoryAuthUserFromContext(context) {
27
+ return context.get("factoryAuthUser") ?? void 0;
28
+ }
29
+ function buildActorProfileMetadata(user) {
30
+ const name = user.name?.trim() || user.email?.trim();
31
+ const avatarUrl = user.avatarUrl?.trim();
32
+ if (!name && !avatarUrl) return void 0;
33
+ return {
34
+ ...name ? { name } : {},
35
+ ...avatarUrl ? { avatarUrl } : {}
36
+ };
37
+ }
3
38
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4
39
  const MAX_ACTION_FILTERS = 16;
40
+ const MAX_ACTOR_PROFILES = 100;
41
+ const AUTOMATION_ACTORS = /* @__PURE__ */ new Set([
42
+ "factory",
43
+ "system",
44
+ "automation",
45
+ "factory-rule-dispatcher",
46
+ "factory-tool-result-rule"
47
+ ]);
5
48
  function loose(c) {
6
49
  return c;
7
50
  }
@@ -10,6 +53,14 @@ function parseActionsParam(raw) {
10
53
  const actions = raw.split(",").map((action) => action.trim()).filter(Boolean).slice(0, MAX_ACTION_FILTERS);
11
54
  return actions.length > 0 ? actions : void 0;
12
55
  }
56
+ function isHumanActorId(actorId) {
57
+ if (!actorId) return false;
58
+ return !AUTOMATION_ACTORS.has(actorId) && !actorId.startsWith("agent:") && !actorId.startsWith("github:");
59
+ }
60
+ function parseActorIdsParam(raw) {
61
+ if (!raw) return [];
62
+ return [...new Set(raw.split(",").map((actorId) => actorId.trim()).filter(isHumanActorId))].slice(0, MAX_ACTOR_PROFILES);
63
+ }
13
64
  function parseLimitParam(raw) {
14
65
  if (!raw) return void 0;
15
66
  const limit = Number.parseInt(raw, 10);
@@ -28,12 +79,14 @@ var AuditDomain = class {
28
79
  #auth;
29
80
  #audit;
30
81
  #projects;
82
+ #users;
31
83
  #sinks;
32
84
  #agentTenant;
33
- constructor({ auth, audit, projects, sinks = [], agentTenant }) {
85
+ constructor({ auth, audit, projects, users, sinks = [], agentTenant }) {
34
86
  this.#auth = auth;
35
87
  this.#audit = audit;
36
88
  this.#projects = projects;
89
+ this.#users = users;
37
90
  this.#sinks = sinks;
38
91
  this.#agentTenant = agentTenant;
39
92
  const ids = /* @__PURE__ */ new Set();
@@ -74,12 +127,18 @@ var AuditDomain = class {
74
127
  try {
75
128
  const tenant = this.#auth.tenant(context);
76
129
  if (!tenant?.orgId) return;
130
+ const user = readFactoryAuthUserFromContext(context);
131
+ const actorProfile = user ? buildActorProfileMetadata(user) : void 0;
132
+ const metadata = actorProfile ? {
133
+ ...input.metadata,
134
+ [ACTOR_PROFILE_METADATA_KEY]: actorProfile
135
+ } : input.metadata;
77
136
  await this.record({
78
137
  orgId: tenant.orgId,
79
138
  actorId: tenant.userId,
80
139
  action: input.action,
81
140
  targets: input.targets,
82
- metadata: input.metadata,
141
+ metadata,
83
142
  factoryProjectId: input.factoryProjectId,
84
143
  projectRepositoryId: input.projectRepositoryId,
85
144
  context: auditRequestContext(context)
@@ -100,6 +159,8 @@ var AuditDomain = class {
100
159
  const threadId = context?.threadId;
101
160
  const state = context?.getState();
102
161
  if (!orgId || !userId || !threadId || !state?.factoryProjectId) return;
162
+ const modeId = context.session.modeId?.trim();
163
+ const modelId = context.session.modelId?.trim();
103
164
  await this.record({
104
165
  orgId,
105
166
  actorId: `agent:${threadId}`,
@@ -108,7 +169,9 @@ var AuditDomain = class {
108
169
  targets: input.targets,
109
170
  metadata: {
110
171
  ...input.metadata,
111
- startedBy: userId
172
+ startedBy: userId,
173
+ ...modeId ? { agentName: `${modeId} agent` } : {},
174
+ ...modelId ? { modelId } : {}
112
175
  },
113
176
  factoryProjectId: state.factoryProjectId,
114
177
  projectRepositoryId: state.projectRepositoryId,
@@ -121,6 +184,41 @@ var AuditDomain = class {
121
184
  });
122
185
  }
123
186
  }
187
+ async #resolveActorProfiles(events, requestedActorIds = []) {
188
+ const humanActorIds = [...new Set([...requestedActorIds, ...events.filter((event) => event.actorType === "human").map((event) => event.actorId)].filter(isHumanActorId))].slice(0, MAX_ACTOR_PROFILES);
189
+ if (humanActorIds.length === 0) return {};
190
+ const profiles = {};
191
+ for (const event of events) {
192
+ if (event.actorType !== "human") continue;
193
+ if (!isHumanActorId(event.actorId)) continue;
194
+ if (profiles[event.actorId]) continue;
195
+ const stored = readStoredActorProfile(event.metadata);
196
+ if (!stored?.name) continue;
197
+ profiles[event.actorId] = {
198
+ id: event.actorId,
199
+ name: stored.name,
200
+ ...stored.avatarUrl ? { avatarUrl: stored.avatarUrl } : {}
201
+ };
202
+ }
203
+ const unresolved = humanActorIds.filter((actorId) => !profiles[actorId]);
204
+ if (unresolved.length === 0 || !this.#users) return profiles;
205
+ try {
206
+ const users = this.#users.getUsers ? await this.#users.getUsers(unresolved) : await Promise.all(unresolved.map((actorId) => this.#users?.getUser(actorId) ?? null));
207
+ for (const [index, user] of users.entries()) {
208
+ if (!user) continue;
209
+ const name = user.name?.trim() || user.email?.trim() || user.id;
210
+ const actorId = unresolved[index] ?? user.id;
211
+ profiles[actorId] = {
212
+ id: user.id,
213
+ name,
214
+ ...user.avatarUrl ? { avatarUrl: user.avatarUrl } : {}
215
+ };
216
+ }
217
+ } catch (err) {
218
+ console.warn("[Audit] Failed to resolve audit actor profiles", { error: err instanceof Error ? err.message : String(err) });
219
+ }
220
+ return profiles;
221
+ }
124
222
  routes() {
125
223
  return [registerApiRoute("/web/factory/projects/:id/audit", {
126
224
  method: "GET",
@@ -143,7 +241,11 @@ var AuditDomain = class {
143
241
  before: c.req.query("before") || void 0,
144
242
  limit: parseLimitParam(c.req.query("limit"))
145
243
  });
146
- return c.json(page);
244
+ const actors = await this.#resolveActorProfiles(page.events, parseActorIdsParam(c.req.query("actorIds")));
245
+ return c.json({
246
+ ...page,
247
+ actors
248
+ });
147
249
  }
148
250
  })];
149
251
  }
@@ -1 +1 @@
1
- {"version":3,"file":"domain.js","names":["#auth","#audit","#projects","#sinks","#agentTenant","#resolveTenant"],"sources":["../../../../src/storage/domains/audit/domain.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../projects/base.js';\nimport type {\n AuditContext,\n AuditEventPage,\n AuditEventRow,\n AuditStorage,\n AuditTarget,\n ListAuditEventsInput,\n RecordAuditEventInput,\n} from './base.js';\n\nexport interface EmitAuditInput {\n action: string;\n factoryProjectId?: string;\n projectRepositoryId?: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface EmitAgentAuditInput {\n action: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface AuditEmitter {\n emit(args: { context: Context; input: EmitAuditInput }): Promise<void>;\n}\n\nexport interface AuditAgentEmitter {\n emitAgent(args: { requestContext: RequestContext; input: EmitAgentAuditInput }): Promise<void>;\n}\n\n/** Best-effort destination for locally persisted audit events (e.g. an integration's audit log). */\nexport interface AuditSink {\n id: string;\n audit?(args: { event: AuditEventRow }): Promise<void>;\n}\n\ninterface FactorySessionState {\n factoryProjectId?: string;\n projectRepositoryId?: string;\n}\n\nexport interface AuditDomainOptions {\n auth: RouteAuth;\n /** Audit storage domain handle. */\n audit: AuditStorage;\n /** Projects domain handle, used to scope the audit trail route. */\n projects: FactoryProjectsStorage;\n /** Best-effort fan-out destinations notified after each recorded event. */\n sinks?: AuditSink[];\n /** Resolve the acting tenant for agent-emitted events from the request context. */\n agentTenant?: (requestContext: RequestContext) => { orgId?: string; userId?: string } | undefined;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst MAX_ACTION_FILTERS = 16;\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction parseActionsParam(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined;\n const actions = raw\n .split(',')\n .map(action => action.trim())\n .filter(Boolean)\n .slice(0, MAX_ACTION_FILTERS);\n return actions.length > 0 ? actions : undefined;\n}\n\nfunction parseLimitParam(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const limit = Number.parseInt(raw, 10);\n return Number.isFinite(limit) ? limit : undefined;\n}\n\nexport function auditRequestContext(c: Context): AuditContext {\n const location = c.req.header('x-forwarded-for')?.split(',')[0]?.trim();\n const userAgent = c.req.header('user-agent');\n return {\n ...(location ? { location } : {}),\n ...(userAgent ? { userAgent } : {}),\n };\n}\n\n/** Factory-owned audit behavior backed by the audit storage domain. */\nexport class AuditDomain implements AuditEmitter, AuditAgentEmitter {\n readonly #auth: RouteAuth;\n readonly #audit: AuditStorage;\n readonly #projects: FactoryProjectsStorage;\n readonly #sinks: AuditSink[];\n readonly #agentTenant: AuditDomainOptions['agentTenant'];\n\n constructor({ auth, audit, projects, sinks = [], agentTenant }: AuditDomainOptions) {\n this.#auth = auth;\n this.#audit = audit;\n this.#projects = projects;\n this.#sinks = sinks;\n this.#agentTenant = agentTenant;\n\n const ids = new Set<string>();\n for (const sink of this.#sinks) {\n if (!sink.id) throw new Error('Audit integration id must not be empty');\n if (ids.has(sink.id)) throw new Error(`Duplicate audit integration id '${sink.id}'`);\n ids.add(sink.id);\n }\n }\n\n async record(input: RecordAuditEventInput): Promise<AuditEventRow | null> {\n try {\n await this.#audit.ensureReady();\n const row = await this.#audit.record(input);\n for (const sink of this.#sinks) {\n if (!sink.audit) continue;\n void Promise.resolve()\n .then(() => sink.audit?.({ event: row }))\n .catch(err => {\n console.warn('[Audit] Audit integration failed', {\n integration: sink.id,\n action: row.action,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n return row;\n } catch (err) {\n console.warn('[Audit] Failed to record audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async list(input: ListAuditEventsInput): Promise<AuditEventPage> {\n await this.#audit.ensureReady();\n return this.#audit.list(input);\n }\n\n async emit({ context, input }: { context: Context; input: EmitAuditInput }): Promise<void> {\n try {\n const tenant = this.#auth.tenant(context);\n if (!tenant?.orgId) return;\n await this.record({\n orgId: tenant.orgId,\n actorId: tenant.userId,\n action: input.action,\n targets: input.targets,\n metadata: input.metadata,\n factoryProjectId: input.factoryProjectId,\n projectRepositoryId: input.projectRepositoryId,\n context: auditRequestContext(context),\n });\n } catch (err) {\n console.warn('[Audit] Failed to emit audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n async emitAgent({\n requestContext,\n input,\n }: {\n requestContext: RequestContext;\n input: EmitAgentAuditInput;\n }): Promise<void> {\n try {\n const context = requestContext.get('controller') as\n | AgentControllerRequestContext<FactorySessionState>\n | undefined;\n const tenant = this.#agentTenant?.(requestContext);\n const orgId = tenant?.orgId;\n const userId = tenant?.userId;\n const threadId = context?.threadId;\n const state = context?.getState();\n if (!orgId || !userId || !threadId || !state?.factoryProjectId) return;\n\n await this.record({\n orgId,\n actorId: `agent:${threadId}`,\n actorType: 'agent',\n action: input.action,\n targets: input.targets,\n metadata: { ...input.metadata, startedBy: userId },\n factoryProjectId: state.factoryProjectId,\n projectRepositoryId: state.projectRepositoryId,\n context: {},\n });\n } catch (err) {\n console.warn('[Audit] Failed to emit agent audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n routes(): ApiRoute[] {\n return [\n registerApiRoute('/web/factory/projects/:id/audit', {\n method: 'GET',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) return c.json({ error: 'Project not found' }, 404);\n await this.#projects.ensureReady();\n const project = await this.#projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) return c.json({ error: 'Project not found' }, 404);\n\n const page = await this.list({\n orgId: tenant.orgId,\n factoryProjectId: projectId,\n actions: parseActionsParam(c.req.query('actions')),\n actorId: c.req.query('actor') || undefined,\n before: c.req.query('before') || undefined,\n limit: parseLimitParam(c.req.query('limit')),\n });\n return c.json(page);\n },\n }),\n ];\n }\n\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.#auth.ensureUser(c);\n const tenant = this.#auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json({ error: 'organization_required', message: 'The audit trail requires an organization.' }, 403),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"domain.js","names":["#auth","#audit","#projects","#users","#sinks","#agentTenant","#resolveActorProfiles","#resolveTenant"],"sources":["../../../../src/storage/domains/audit/domain.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute, IUserProvider } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../projects/base.js';\nimport type {\n AuditContext,\n AuditEventPage,\n AuditEventRow,\n AuditStorage,\n AuditTarget,\n ListAuditEventsInput,\n RecordAuditEventInput,\n} from './base.js';\n\nexport interface EmitAuditInput {\n action: string;\n factoryProjectId?: string;\n projectRepositoryId?: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface EmitAgentAuditInput {\n action: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface AuditEmitter {\n emit(args: { context: Context; input: EmitAuditInput }): Promise<void>;\n}\n\nexport interface AuditAgentEmitter {\n emitAgent(args: { requestContext: RequestContext; input: EmitAgentAuditInput }): Promise<void>;\n}\n\n/** Best-effort destination for locally persisted audit events (e.g. an integration's audit log). */\nexport interface AuditSink {\n id: string;\n audit?(args: { event: AuditEventRow }): Promise<void>;\n}\n\ninterface FactorySessionState {\n factoryProjectId?: string;\n projectRepositoryId?: string;\n}\n\nexport interface AuditActorProfile {\n id: string;\n name: string;\n avatarUrl?: string;\n}\n\n/**\n * Reserved metadata key on `AuditEventRow.metadata` that carries the acting\n * human user's display name and avatar captured from the auth context at\n * record time. Read back by `#resolveActorProfiles` so names/avatars work\n * for every auth provider without requiring an `IUserProvider.getUser(id)`\n * implementation — the Studio provider proxies through the shared API and\n * cannot resolve arbitrary users by id.\n */\nconst ACTOR_PROFILE_METADATA_KEY = '__actorProfile';\n\ninterface StoredActorProfile {\n name?: string;\n avatarUrl?: string;\n}\n\nfunction readStoredActorProfile(metadata: Record<string, unknown> | undefined): StoredActorProfile | undefined {\n if (!metadata) return undefined;\n const raw = metadata[ACTOR_PROFILE_METADATA_KEY];\n if (!raw || typeof raw !== 'object') return undefined;\n const profile = raw as Record<string, unknown>;\n const name = typeof profile.name === 'string' && profile.name.trim() ? profile.name.trim() : undefined;\n const avatarUrl =\n typeof profile.avatarUrl === 'string' && profile.avatarUrl.trim() ? profile.avatarUrl.trim() : undefined;\n if (!name && !avatarUrl) return undefined;\n return { ...(name ? { name } : {}), ...(avatarUrl ? { avatarUrl } : {}) };\n}\n\n/** Read the auth gate's stashed user directly from the Hono context. */\nfunction readFactoryAuthUserFromContext(\n context: Context,\n): { name?: string; email?: string; avatarUrl?: string } | undefined {\n const user = context.get('factoryAuthUser') as { name?: string; email?: string; avatarUrl?: string } | undefined;\n return user ?? undefined;\n}\n\nfunction buildActorProfileMetadata(user: {\n name?: string;\n email?: string;\n avatarUrl?: string;\n}): StoredActorProfile | undefined {\n const name = user.name?.trim() || user.email?.trim();\n const avatarUrl = user.avatarUrl?.trim();\n if (!name && !avatarUrl) return undefined;\n return { ...(name ? { name } : {}), ...(avatarUrl ? { avatarUrl } : {}) };\n}\n\nexport interface AuditDomainOptions {\n auth: RouteAuth;\n /** Audit storage domain handle. */\n audit: AuditStorage;\n /** Projects domain handle, used to scope the audit trail route. */\n projects: FactoryProjectsStorage;\n /** Resolve persisted human actor ids to display names and profile images. */\n users?: Pick<IUserProvider, 'getUser' | 'getUsers'>;\n /** Best-effort fan-out destinations notified after each recorded event. */\n sinks?: AuditSink[];\n /** Resolve the acting tenant for agent-emitted events from the request context. */\n agentTenant?: (requestContext: RequestContext) => { orgId?: string; userId?: string } | undefined;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst MAX_ACTION_FILTERS = 16;\nconst MAX_ACTOR_PROFILES = 100;\nconst AUTOMATION_ACTORS = new Set([\n 'factory',\n 'system',\n 'automation',\n 'factory-rule-dispatcher',\n 'factory-tool-result-rule',\n]);\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction parseActionsParam(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined;\n const actions = raw\n .split(',')\n .map(action => action.trim())\n .filter(Boolean)\n .slice(0, MAX_ACTION_FILTERS);\n return actions.length > 0 ? actions : undefined;\n}\n\nfunction isHumanActorId(actorId: string | undefined): actorId is string {\n if (!actorId) return false;\n return !AUTOMATION_ACTORS.has(actorId) && !actorId.startsWith('agent:') && !actorId.startsWith('github:');\n}\n\nfunction parseActorIdsParam(raw: string | undefined): string[] {\n if (!raw) return [];\n return [\n ...new Set(\n raw\n .split(',')\n .map(actorId => actorId.trim())\n .filter(isHumanActorId),\n ),\n ].slice(0, MAX_ACTOR_PROFILES);\n}\n\nfunction parseLimitParam(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const limit = Number.parseInt(raw, 10);\n return Number.isFinite(limit) ? limit : undefined;\n}\n\nexport function auditRequestContext(c: Context): AuditContext {\n const location = c.req.header('x-forwarded-for')?.split(',')[0]?.trim();\n const userAgent = c.req.header('user-agent');\n return {\n ...(location ? { location } : {}),\n ...(userAgent ? { userAgent } : {}),\n };\n}\n\n/** Factory-owned audit behavior backed by the audit storage domain. */\nexport class AuditDomain implements AuditEmitter, AuditAgentEmitter {\n readonly #auth: RouteAuth;\n readonly #audit: AuditStorage;\n readonly #projects: FactoryProjectsStorage;\n readonly #users: AuditDomainOptions['users'];\n readonly #sinks: AuditSink[];\n readonly #agentTenant: AuditDomainOptions['agentTenant'];\n\n constructor({ auth, audit, projects, users, sinks = [], agentTenant }: AuditDomainOptions) {\n this.#auth = auth;\n this.#audit = audit;\n this.#projects = projects;\n this.#users = users;\n this.#sinks = sinks;\n this.#agentTenant = agentTenant;\n\n const ids = new Set<string>();\n for (const sink of this.#sinks) {\n if (!sink.id) throw new Error('Audit integration id must not be empty');\n if (ids.has(sink.id)) throw new Error(`Duplicate audit integration id '${sink.id}'`);\n ids.add(sink.id);\n }\n }\n\n async record(input: RecordAuditEventInput): Promise<AuditEventRow | null> {\n try {\n await this.#audit.ensureReady();\n const row = await this.#audit.record(input);\n for (const sink of this.#sinks) {\n if (!sink.audit) continue;\n void Promise.resolve()\n .then(() => sink.audit?.({ event: row }))\n .catch(err => {\n console.warn('[Audit] Audit integration failed', {\n integration: sink.id,\n action: row.action,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n return row;\n } catch (err) {\n console.warn('[Audit] Failed to record audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n }\n\n async list(input: ListAuditEventsInput): Promise<AuditEventPage> {\n await this.#audit.ensureReady();\n return this.#audit.list(input);\n }\n\n async emit({ context, input }: { context: Context; input: EmitAuditInput }): Promise<void> {\n try {\n const tenant = this.#auth.tenant(context);\n if (!tenant?.orgId) return;\n const user = readFactoryAuthUserFromContext(context);\n const actorProfile = user ? buildActorProfileMetadata(user) : undefined;\n const metadata = actorProfile\n ? { ...input.metadata, [ACTOR_PROFILE_METADATA_KEY]: actorProfile }\n : input.metadata;\n await this.record({\n orgId: tenant.orgId,\n actorId: tenant.userId,\n action: input.action,\n targets: input.targets,\n metadata,\n factoryProjectId: input.factoryProjectId,\n projectRepositoryId: input.projectRepositoryId,\n context: auditRequestContext(context),\n });\n } catch (err) {\n console.warn('[Audit] Failed to emit audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n async emitAgent({\n requestContext,\n input,\n }: {\n requestContext: RequestContext;\n input: EmitAgentAuditInput;\n }): Promise<void> {\n try {\n const context = requestContext.get('controller') as\n | AgentControllerRequestContext<FactorySessionState>\n | undefined;\n const tenant = this.#agentTenant?.(requestContext);\n const orgId = tenant?.orgId;\n const userId = tenant?.userId;\n const threadId = context?.threadId;\n const state = context?.getState();\n if (!orgId || !userId || !threadId || !state?.factoryProjectId) return;\n\n const modeId = context.session.modeId?.trim();\n const modelId = context.session.modelId?.trim();\n await this.record({\n orgId,\n actorId: `agent:${threadId}`,\n actorType: 'agent',\n action: input.action,\n targets: input.targets,\n metadata: {\n ...input.metadata,\n startedBy: userId,\n ...(modeId ? { agentName: `${modeId} agent` } : {}),\n ...(modelId ? { modelId } : {}),\n },\n factoryProjectId: state.factoryProjectId,\n projectRepositoryId: state.projectRepositoryId,\n context: {},\n });\n } catch (err) {\n console.warn('[Audit] Failed to emit agent audit event', {\n action: input.action,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n async #resolveActorProfiles(\n events: AuditEventRow[],\n requestedActorIds: string[] = [],\n ): Promise<Record<string, AuditActorProfile>> {\n const humanActorIds = [\n ...new Set(\n [\n ...requestedActorIds,\n ...events.filter(event => event.actorType === 'human').map(event => event.actorId),\n ].filter(isHumanActorId),\n ),\n ].slice(0, MAX_ACTOR_PROFILES);\n if (humanActorIds.length === 0) return {};\n\n // Prefer the profile stamped into event metadata at record time: it works\n // regardless of the auth provider's ability to resolve a user by id\n // (MastraAuthStudio's getUser() always returns null, WorkOS looks up by\n // id but every provider stamps here uniformly).\n const profiles: Record<string, AuditActorProfile> = {};\n for (const event of events) {\n if (event.actorType !== 'human') continue;\n if (!isHumanActorId(event.actorId)) continue;\n if (profiles[event.actorId]) continue;\n const stored = readStoredActorProfile(event.metadata);\n if (!stored?.name) continue;\n profiles[event.actorId] = {\n id: event.actorId,\n name: stored.name,\n ...(stored.avatarUrl ? { avatarUrl: stored.avatarUrl } : {}),\n };\n }\n\n const unresolved = humanActorIds.filter(actorId => !profiles[actorId]);\n if (unresolved.length === 0 || !this.#users) return profiles;\n\n try {\n const users = this.#users.getUsers\n ? await this.#users.getUsers(unresolved)\n : await Promise.all(unresolved.map(actorId => this.#users?.getUser(actorId) ?? null));\n for (const [index, user] of users.entries()) {\n if (!user) continue;\n const name = user.name?.trim() || user.email?.trim() || user.id;\n const actorId = unresolved[index] ?? user.id;\n profiles[actorId] = {\n id: user.id,\n name,\n ...(user.avatarUrl ? { avatarUrl: user.avatarUrl } : {}),\n };\n }\n } catch (err) {\n console.warn('[Audit] Failed to resolve audit actor profiles', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n return profiles;\n }\n\n routes(): ApiRoute[] {\n return [\n registerApiRoute('/web/factory/projects/:id/audit', {\n method: 'GET',\n handler: async cc => {\n const c = loose(cc);\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant.response;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) return c.json({ error: 'Project not found' }, 404);\n await this.#projects.ensureReady();\n const project = await this.#projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) return c.json({ error: 'Project not found' }, 404);\n\n const page = await this.list({\n orgId: tenant.orgId,\n factoryProjectId: projectId,\n actions: parseActionsParam(c.req.query('actions')),\n actorId: c.req.query('actor') || undefined,\n before: c.req.query('before') || undefined,\n limit: parseLimitParam(c.req.query('limit')),\n });\n const actors = await this.#resolveActorProfiles(page.events, parseActorIdsParam(c.req.query('actorIds')));\n return c.json({ ...page, actors });\n },\n }),\n ];\n }\n\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.#auth.ensureUser(c);\n const tenant = this.#auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json({ error: 'organization_required', message: 'The audit trail requires an organization.' }, 403),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { FactoryStorageDomain } from '@mastra/core/storage';
2
+ import type { CollectionSchema } from '@mastra/core/storage';
3
+ export interface FilesystemFile {
4
+ path: string;
5
+ }
6
+ export interface ReplaceFilesystemFilesInput {
7
+ resourceId: string;
8
+ threadId: string;
9
+ files: FilesystemFile[];
10
+ }
11
+ export declare const FILESYSTEM_SCHEMAS: CollectionSchema[];
12
+ export declare class FilesystemStorage extends FactoryStorageDomain {
13
+ constructor();
14
+ init(): Promise<void>;
15
+ dangerouslyClearAll(): Promise<void>;
16
+ replaceFiles(input: ReplaceFilesystemFilesInput): Promise<void>;
17
+ listFiles(args: {
18
+ resourceId: string;
19
+ threadId: string;
20
+ }): Promise<FilesystemFile[]>;
21
+ deleteFiles(args: {
22
+ resourceId: string;
23
+ threadId: string;
24
+ }): Promise<number>;
25
+ }
26
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/filesystem/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EAiBhD,CAAC;AAuCF,qBAAa,iBAAkB,SAAQ,oBAAoB;;IAKnD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,YAAY,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/D,SAAS,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IASpF,WAAW,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAInF"}
@@ -0,0 +1,74 @@
1
+ import { FactoryStorageDomain } from "@mastra/core/storage";
2
+ //#region src/storage/domains/filesystem/base.ts
3
+ const SNAPSHOTS = "filesystem_snapshots";
4
+ const FILESYSTEM_SCHEMAS = [{
5
+ name: SNAPSHOTS,
6
+ columns: {
7
+ id: { type: "uuid-pk" },
8
+ resource_id: { type: "text" },
9
+ thread_id: { type: "text" },
10
+ files: { type: "json" },
11
+ captured_at: { type: "timestamp" }
12
+ },
13
+ uniqueIndexes: [{
14
+ name: "filesystem_snapshots_resource_thread_unique",
15
+ columns: ["resource_id", "thread_id"]
16
+ }]
17
+ }];
18
+ function assertIdentifier(value, label) {
19
+ if (!value.trim()) throw new Error(`[FilesystemStorage] ${label} must not be empty.`);
20
+ }
21
+ function assertRelativePath(value) {
22
+ if (!value || value.startsWith("/") || value.split("/").some((segment) => !segment || segment === "." || segment === "..")) throw new Error("[FilesystemStorage] path must be a non-empty relative path.");
23
+ }
24
+ function assertScope(args) {
25
+ assertIdentifier(args.resourceId, "resourceId");
26
+ assertIdentifier(args.threadId, "threadId");
27
+ }
28
+ function validateFiles(files) {
29
+ const paths = /* @__PURE__ */ new Set();
30
+ for (const file of files) {
31
+ assertRelativePath(file.path);
32
+ if (paths.has(file.path)) throw new Error(`[FilesystemStorage] duplicate file path: ${file.path}`);
33
+ paths.add(file.path);
34
+ }
35
+ }
36
+ var FilesystemStorage = class extends FactoryStorageDomain {
37
+ constructor() {
38
+ super("filesystem");
39
+ }
40
+ async init() {
41
+ await this.ensureCollections(FILESYSTEM_SCHEMAS);
42
+ }
43
+ async dangerouslyClearAll() {
44
+ await this.ops.deleteMany(SNAPSHOTS, {});
45
+ }
46
+ async replaceFiles(input) {
47
+ assertScope(input);
48
+ validateFiles(input.files);
49
+ await this.ops.upsertOne(SNAPSHOTS, ["resource_id", "thread_id"], {
50
+ resource_id: input.resourceId,
51
+ thread_id: input.threadId,
52
+ files: input.files.toSorted((a, b) => a.path.localeCompare(b.path)),
53
+ captured_at: /* @__PURE__ */ new Date()
54
+ });
55
+ }
56
+ async listFiles(args) {
57
+ assertScope(args);
58
+ return (await this.ops.findOne(SNAPSHOTS, {
59
+ resource_id: args.resourceId,
60
+ thread_id: args.threadId
61
+ }))?.files ?? [];
62
+ }
63
+ async deleteFiles(args) {
64
+ assertScope(args);
65
+ return this.ops.deleteMany(SNAPSHOTS, {
66
+ resource_id: args.resourceId,
67
+ thread_id: args.threadId
68
+ });
69
+ }
70
+ };
71
+ //#endregion
72
+ export { FILESYSTEM_SCHEMAS, FilesystemStorage };
73
+
74
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../../../src/storage/domains/filesystem/base.ts"],"sourcesContent":["import { FactoryStorageDomain } from '@mastra/core/storage';\nimport type { CollectionSchema } from '@mastra/core/storage';\n\nconst SNAPSHOTS = 'filesystem_snapshots';\n\nexport interface FilesystemFile {\n path: string;\n}\n\nexport interface ReplaceFilesystemFilesInput {\n resourceId: string;\n threadId: string;\n files: FilesystemFile[];\n}\n\nexport const FILESYSTEM_SCHEMAS: CollectionSchema[] = [\n {\n name: SNAPSHOTS,\n columns: {\n id: { type: 'uuid-pk' },\n resource_id: { type: 'text' },\n thread_id: { type: 'text' },\n files: { type: 'json' },\n captured_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'filesystem_snapshots_resource_thread_unique',\n columns: ['resource_id', 'thread_id'],\n },\n ],\n },\n];\n\ninterface FilesystemSnapshotDbRow extends Record<string, unknown> {\n id: string;\n resource_id: string;\n thread_id: string;\n files: FilesystemFile[];\n captured_at: Date;\n}\n\nfunction assertIdentifier(value: string, label: string): void {\n if (!value.trim()) throw new Error(`[FilesystemStorage] ${label} must not be empty.`);\n}\n\nfunction assertRelativePath(value: string): void {\n if (\n !value ||\n value.startsWith('/') ||\n value.split('/').some(segment => !segment || segment === '.' || segment === '..')\n ) {\n throw new Error('[FilesystemStorage] path must be a non-empty relative path.');\n }\n}\n\nfunction assertScope(args: { resourceId: string; threadId: string }): void {\n assertIdentifier(args.resourceId, 'resourceId');\n assertIdentifier(args.threadId, 'threadId');\n}\n\nfunction validateFiles(files: FilesystemFile[]): void {\n const paths = new Set<string>();\n\n for (const file of files) {\n assertRelativePath(file.path);\n if (paths.has(file.path)) throw new Error(`[FilesystemStorage] duplicate file path: ${file.path}`);\n paths.add(file.path);\n }\n}\n\nexport class FilesystemStorage extends FactoryStorageDomain {\n constructor() {\n super('filesystem');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections(FILESYSTEM_SCHEMAS);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany(SNAPSHOTS, {});\n }\n\n async replaceFiles(input: ReplaceFilesystemFilesInput): Promise<void> {\n assertScope(input);\n validateFiles(input.files);\n\n await this.ops.upsertOne<FilesystemSnapshotDbRow>(SNAPSHOTS, ['resource_id', 'thread_id'], {\n resource_id: input.resourceId,\n thread_id: input.threadId,\n files: input.files.toSorted((a, b) => a.path.localeCompare(b.path)),\n captured_at: new Date(),\n });\n }\n\n async listFiles(args: { resourceId: string; threadId: string }): Promise<FilesystemFile[]> {\n assertScope(args);\n const snapshot = await this.ops.findOne<FilesystemSnapshotDbRow>(SNAPSHOTS, {\n resource_id: args.resourceId,\n thread_id: args.threadId,\n });\n return snapshot?.files ?? [];\n }\n\n async deleteFiles(args: { resourceId: string; threadId: string }): Promise<number> {\n assertScope(args);\n return this.ops.deleteMany(SNAPSHOTS, { resource_id: args.resourceId, thread_id: args.threadId });\n }\n}\n"],"mappings":";;AAGA,MAAM,YAAY;AAYlB,MAAa,qBAAyC,CACpD;CACE,MAAM;CACN,SAAS;EACP,IAAI,EAAE,MAAM,UAAU;EACtB,aAAa,EAAE,MAAM,OAAO;EAC5B,WAAW,EAAE,MAAM,OAAO;EAC1B,OAAO,EAAE,MAAM,OAAO;EACtB,aAAa,EAAE,MAAM,YAAY;CACnC;CACA,eAAe,CACb;EACE,MAAM;EACN,SAAS,CAAC,eAAe,WAAW;CACtC,CACF;AACF,CACF;AAUA,SAAS,iBAAiB,OAAe,OAAqB;CAC5D,IAAI,CAAC,MAAM,KAAK,GAAG,MAAM,IAAI,MAAM,uBAAuB,MAAM,oBAAoB;AACtF;AAEA,SAAS,mBAAmB,OAAqB;CAC/C,IACE,CAAC,SACD,MAAM,WAAW,GAAG,KACpB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAK,YAAW,CAAC,WAAW,YAAY,OAAO,YAAY,IAAI,GAEhF,MAAM,IAAI,MAAM,6DAA6D;AAEjF;AAEA,SAAS,YAAY,MAAsD;CACzE,iBAAiB,KAAK,YAAY,YAAY;CAC9C,iBAAiB,KAAK,UAAU,UAAU;AAC5C;AAEA,SAAS,cAAc,OAA+B;CACpD,MAAM,wBAAQ,IAAI,IAAY;CAE9B,KAAK,MAAM,QAAQ,OAAO;EACxB,mBAAmB,KAAK,IAAI;EAC5B,IAAI,MAAM,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM;EACjG,MAAM,IAAI,KAAK,IAAI;CACrB;AACF;AAEA,IAAa,oBAAb,cAAuC,qBAAqB;CAC1D,cAAc;EACZ,MAAM,YAAY;CACpB;CAEA,MAAM,OAAsB;EAC1B,MAAM,KAAK,kBAAkB,kBAAkB;CACjD;CAEA,MAAM,sBAAqC;EACzC,MAAM,KAAK,IAAI,WAAW,WAAW,CAAC,CAAC;CACzC;CAEA,MAAM,aAAa,OAAmD;EACpE,YAAY,KAAK;EACjB,cAAc,MAAM,KAAK;EAEzB,MAAM,KAAK,IAAI,UAAmC,WAAW,CAAC,eAAe,WAAW,GAAG;GACzF,aAAa,MAAM;GACnB,WAAW,MAAM;GACjB,OAAO,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;GAClE,6BAAa,IAAI,KAAK;EACxB,CAAC;CACH;CAEA,MAAM,UAAU,MAA2E;EACzF,YAAY,IAAI;EAKhB,QAAO,MAJgB,KAAK,IAAI,QAAiC,WAAW;GAC1E,aAAa,KAAK;GAClB,WAAW,KAAK;EAClB,CAAC,EAAA,EACgB,SAAS,CAAC;CAC7B;CAEA,MAAM,YAAY,MAAiE;EACjF,YAAY,IAAI;EAChB,OAAO,KAAK,IAAI,WAAW,WAAW;GAAE,aAAa,KAAK;GAAY,WAAW,KAAK;EAAS,CAAC;CAClG;AACF"}
@@ -38,6 +38,7 @@ export declare class FactoryProjectsStorage extends FactoryStorageDomain {
38
38
  list({ orgId }: {
39
39
  orgId: string;
40
40
  }): Promise<FactoryProject[]>;
41
+ listAll(): Promise<FactoryProject[]>;
41
42
  get({ orgId, id }: {
42
43
  orgId: string;
43
44
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/projects/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAqB,MAAM,sBAAsB,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2FAA2F;IAC3F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,eAAO,MAAM,uBAAuB,EAAE,gBAcrC,CAAC;AA4BF,qBAAa,sBAAuB,SAAQ,oBAAoB;;;IAKxD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC,MAAM,CAAC,EACX,KAAK,EACL,MAAM,EACN,KAAK,GACN,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,yBAAyB,CAAC;KAClC,GAAG,OAAO,CAAC,cAAc,CAAC;IAerB,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAS7D,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKjF,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAK/D,MAAM,CAAC,EACX,KAAK,EACL,EAAE,EACF,KAAK,GACN,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,yBAAyB,CAAC;KAClC,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAW5B,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAM3F"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/projects/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAqB,MAAM,sBAAsB,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2FAA2F;IAC3F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,eAAO,MAAM,uBAAuB,EAAE,gBAcrC,CAAC;AA4BF,qBAAa,sBAAuB,SAAQ,oBAAoB;;;IAKxD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC,MAAM,CAAC,EACX,KAAK,EACL,MAAM,EACN,KAAK,GACN,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,yBAAyB,CAAC;KAClC,GAAG,OAAO,CAAC,cAAc,CAAC;IAerB,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAS7D,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IASpC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKjF,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAK/D,MAAM,CAAC,EACX,KAAK,EACL,EAAE,EACF,KAAK,GACN,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,yBAAyB,CAAC;KAClC,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAW5B,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAM3F"}
@@ -69,6 +69,9 @@ var FactoryProjectsStorage = class extends FactoryStorageDomain {
69
69
  async list({ orgId }) {
70
70
  return (await this.#db.findMany("factory_projects", { org_id: orgId }, { orderBy: [["updated_at", "desc"]] })).map(toFactoryProject);
71
71
  }
72
+ async listAll() {
73
+ return (await this.#db.findMany("factory_projects", {}, { orderBy: [["updated_at", "desc"]] })).map(toFactoryProject);
74
+ }
72
75
  async get({ orgId, id }) {
73
76
  const row = await this.#db.findOne("factory_projects", {
74
77
  org_id: orgId,