@mastra/factory 0.0.0-fix-thread-subscription-multi-instance-redis-streams-20260730204150
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.
- package/CHANGELOG.md +695 -0
- package/LICENSE.md +30 -0
- package/README.md +27 -0
- package/dist/auth.d.ts +181 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +505 -0
- package/dist/auth.js.map +1 -0
- package/dist/capabilities/connection.d.ts +9 -0
- package/dist/capabilities/connection.d.ts.map +1 -0
- package/dist/capabilities/connection.js +1 -0
- package/dist/capabilities/intake.d.ts +140 -0
- package/dist/capabilities/intake.d.ts.map +1 -0
- package/dist/capabilities/intake.js +1 -0
- package/dist/capabilities/version-control.d.ts +245 -0
- package/dist/capabilities/version-control.d.ts.map +1 -0
- package/dist/capabilities/version-control.js +1 -0
- package/dist/factory.d.ts +156 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +483 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/integrations/base.d.ts +210 -0
- package/dist/integrations/base.d.ts.map +1 -0
- package/dist/integrations/base.js +1 -0
- package/dist/integrations/github/config.d.ts +60 -0
- package/dist/integrations/github/config.d.ts.map +1 -0
- package/dist/integrations/github/config.js +42 -0
- package/dist/integrations/github/config.js.map +1 -0
- package/dist/integrations/github/factory-session.d.ts +12 -0
- package/dist/integrations/github/factory-session.d.ts.map +1 -0
- package/dist/integrations/github/factory-session.js +37 -0
- package/dist/integrations/github/factory-session.js.map +1 -0
- package/dist/integrations/github/integration.d.ts +191 -0
- package/dist/integrations/github/integration.d.ts.map +1 -0
- package/dist/integrations/github/integration.js +1077 -0
- package/dist/integrations/github/integration.js.map +1 -0
- package/dist/integrations/github/issue-triage.d.ts +27 -0
- package/dist/integrations/github/issue-triage.d.ts.map +1 -0
- package/dist/integrations/github/issue-triage.js +82 -0
- package/dist/integrations/github/issue-triage.js.map +1 -0
- package/dist/integrations/github/pat.d.ts +38 -0
- package/dist/integrations/github/pat.d.ts.map +1 -0
- package/dist/integrations/github/pat.js +59 -0
- package/dist/integrations/github/pat.js.map +1 -0
- package/dist/integrations/github/provenance.d.ts +27 -0
- package/dist/integrations/github/provenance.d.ts.map +1 -0
- package/dist/integrations/github/provenance.js +75 -0
- package/dist/integrations/github/provenance.js.map +1 -0
- package/dist/integrations/github/routes.d.ts +69 -0
- package/dist/integrations/github/routes.d.ts.map +1 -0
- package/dist/integrations/github/routes.js +1324 -0
- package/dist/integrations/github/routes.js.map +1 -0
- package/dist/integrations/github/rules.d.ts +78 -0
- package/dist/integrations/github/rules.d.ts.map +1 -0
- package/dist/integrations/github/rules.js +362 -0
- package/dist/integrations/github/rules.js.map +1 -0
- package/dist/integrations/github/sandbox-release.d.ts +38 -0
- package/dist/integrations/github/sandbox-release.d.ts.map +1 -0
- package/dist/integrations/github/sandbox-release.js +74 -0
- package/dist/integrations/github/sandbox-release.js.map +1 -0
- package/dist/integrations/github/sandbox.d.ts +281 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -0
- package/dist/integrations/github/sandbox.js +547 -0
- package/dist/integrations/github/sandbox.js.map +1 -0
- package/dist/integrations/github/session-subscriptions.d.ts +26 -0
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -0
- package/dist/integrations/github/session-subscriptions.js +192 -0
- package/dist/integrations/github/session-subscriptions.js.map +1 -0
- package/dist/integrations/github/subscriptions.d.ts +54 -0
- package/dist/integrations/github/subscriptions.d.ts.map +1 -0
- package/dist/integrations/github/subscriptions.js +62 -0
- package/dist/integrations/github/subscriptions.js.map +1 -0
- package/dist/integrations/github/token-refresh.d.ts +12 -0
- package/dist/integrations/github/token-refresh.d.ts.map +1 -0
- package/dist/integrations/github/token-refresh.js +24 -0
- package/dist/integrations/github/token-refresh.js.map +1 -0
- package/dist/integrations/github/webhook.d.ts +87 -0
- package/dist/integrations/github/webhook.d.ts.map +1 -0
- package/dist/integrations/github/webhook.js +397 -0
- package/dist/integrations/github/webhook.js.map +1 -0
- package/dist/integrations/linear/agent-tools.d.ts +34 -0
- package/dist/integrations/linear/agent-tools.d.ts.map +1 -0
- package/dist/integrations/linear/agent-tools.js +85 -0
- package/dist/integrations/linear/agent-tools.js.map +1 -0
- package/dist/integrations/linear/integration.d.ts +233 -0
- package/dist/integrations/linear/integration.d.ts.map +1 -0
- package/dist/integrations/linear/integration.js +672 -0
- package/dist/integrations/linear/integration.js.map +1 -0
- package/dist/integrations/linear/routes.d.ts +61 -0
- package/dist/integrations/linear/routes.d.ts.map +1 -0
- package/dist/integrations/linear/routes.js +239 -0
- package/dist/integrations/linear/routes.js.map +1 -0
- package/dist/integrations/linear/rules.d.ts +42 -0
- package/dist/integrations/linear/rules.d.ts.map +1 -0
- package/dist/integrations/linear/rules.js +133 -0
- package/dist/integrations/linear/rules.js.map +1 -0
- package/dist/integrations/linear/storage.d.ts +65 -0
- package/dist/integrations/linear/storage.d.ts.map +1 -0
- package/dist/integrations/linear/storage.js +1 -0
- package/dist/integrations/platform/api-client.d.ts +26 -0
- package/dist/integrations/platform/api-client.d.ts.map +1 -0
- package/dist/integrations/platform/api-client.js +156 -0
- package/dist/integrations/platform/api-client.js.map +1 -0
- package/dist/integrations/platform/github/event-worker.d.ts +49 -0
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -0
- package/dist/integrations/platform/github/event-worker.js +348 -0
- package/dist/integrations/platform/github/event-worker.js.map +1 -0
- package/dist/integrations/platform/github/integration.d.ts +50 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -0
- package/dist/integrations/platform/github/integration.js +961 -0
- package/dist/integrations/platform/github/integration.js.map +1 -0
- package/dist/integrations/platform/linear/integration.d.ts +46 -0
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -0
- package/dist/integrations/platform/linear/integration.js +483 -0
- package/dist/integrations/platform/linear/integration.js.map +1 -0
- package/dist/integrations/workos/integration.d.ts +39 -0
- package/dist/integrations/workos/integration.d.ts.map +1 -0
- package/dist/integrations/workos/integration.js +91 -0
- package/dist/integrations/workos/integration.js.map +1 -0
- package/dist/routes/config.d.ts +235 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +972 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/custom-provider-source.d.ts +52 -0
- package/dist/routes/custom-provider-source.d.ts.map +1 -0
- package/dist/routes/custom-provider-source.js +124 -0
- package/dist/routes/custom-provider-source.js.map +1 -0
- package/dist/routes/fs.d.ts +151 -0
- package/dist/routes/fs.d.ts.map +1 -0
- package/dist/routes/fs.js +708 -0
- package/dist/routes/fs.js.map +1 -0
- package/dist/routes/intake.d.ts +23 -0
- package/dist/routes/intake.d.ts.map +1 -0
- package/dist/routes/intake.js +179 -0
- package/dist/routes/intake.js.map +1 -0
- package/dist/routes/oauth.d.ts +43 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +463 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/projects.d.ts +19 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +461 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/provider-credentials.d.ts +81 -0
- package/dist/routes/provider-credentials.d.ts.map +1 -0
- package/dist/routes/provider-credentials.js +86 -0
- package/dist/routes/provider-credentials.js.map +1 -0
- package/dist/routes/route.d.ts +48 -0
- package/dist/routes/route.d.ts.map +1 -0
- package/dist/routes/route.js +15 -0
- package/dist/routes/route.js.map +1 -0
- package/dist/routes/skills.d.ts +30 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +168 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/routes/surface.d.ts +91 -0
- package/dist/routes/surface.d.ts.map +1 -0
- package/dist/routes/surface.js +260 -0
- package/dist/routes/surface.js.map +1 -0
- package/dist/routes/tenant-credentials.d.ts +74 -0
- package/dist/routes/tenant-credentials.d.ts.map +1 -0
- package/dist/routes/tenant-credentials.js +156 -0
- package/dist/routes/tenant-credentials.js.map +1 -0
- package/dist/routes/work-items.d.ts +40 -0
- package/dist/routes/work-items.d.ts.map +1 -0
- package/dist/routes/work-items.js +695 -0
- package/dist/routes/work-items.js.map +1 -0
- package/dist/rules/binding-context.d.ts +5 -0
- package/dist/rules/binding-context.d.ts.map +1 -0
- package/dist/rules/binding-context.js +28 -0
- package/dist/rules/binding-context.js.map +1 -0
- package/dist/rules/defaults.d.ts +9 -0
- package/dist/rules/defaults.d.ts.map +1 -0
- package/dist/rules/defaults.js +260 -0
- package/dist/rules/defaults.js.map +1 -0
- package/dist/rules/dispatcher.d.ts +42 -0
- package/dist/rules/dispatcher.d.ts.map +1 -0
- package/dist/rules/dispatcher.js +518 -0
- package/dist/rules/dispatcher.js.map +1 -0
- package/dist/rules/index.d.ts +7 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +5 -0
- package/dist/rules/processor.d.ts +54 -0
- package/dist/rules/processor.d.ts.map +1 -0
- package/dist/rules/processor.js +378 -0
- package/dist/rules/processor.js.map +1 -0
- package/dist/rules/resolve.d.ts +17 -0
- package/dist/rules/resolve.d.ts.map +1 -0
- package/dist/rules/resolve.js +30 -0
- package/dist/rules/resolve.js.map +1 -0
- package/dist/rules/start-coordinator.d.ts +60 -0
- package/dist/rules/start-coordinator.d.ts.map +1 -0
- package/dist/rules/start-coordinator.js +194 -0
- package/dist/rules/start-coordinator.js.map +1 -0
- package/dist/rules/tools.d.ts +10 -0
- package/dist/rules/tools.d.ts.map +1 -0
- package/dist/rules/tools.js +58 -0
- package/dist/rules/tools.js.map +1 -0
- package/dist/rules/transition-service.d.ts +49 -0
- package/dist/rules/transition-service.d.ts.map +1 -0
- package/dist/rules/transition-service.js +232 -0
- package/dist/rules/transition-service.js.map +1 -0
- package/dist/rules/types.d.ts +234 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +38 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/validation.d.ts +11 -0
- package/dist/rules/validation.d.ts.map +1 -0
- package/dist/rules/validation.js +308 -0
- package/dist/rules/validation.js.map +1 -0
- package/dist/sandbox/fleet.d.ts +222 -0
- package/dist/sandbox/fleet.d.ts.map +1 -0
- package/dist/sandbox/fleet.js +322 -0
- package/dist/sandbox/fleet.js.map +1 -0
- package/dist/sandbox/reattach.d.ts +3 -0
- package/dist/sandbox/reattach.d.ts.map +1 -0
- package/dist/sandbox/reattach.js +16 -0
- package/dist/sandbox/reattach.js.map +1 -0
- package/dist/server-error.d.ts +12 -0
- package/dist/server-error.d.ts.map +1 -0
- package/dist/server-error.js +16 -0
- package/dist/server-error.js.map +1 -0
- package/dist/skills/service.d.ts +48 -0
- package/dist/skills/service.d.ts.map +1 -0
- package/dist/skills/service.js +40 -0
- package/dist/skills/service.js.map +1 -0
- package/dist/spa-static.d.ts +33 -0
- package/dist/spa-static.d.ts.map +1 -0
- package/dist/spa-static.js +104 -0
- package/dist/spa-static.js.map +1 -0
- package/dist/state-signing.d.ts +59 -0
- package/dist/state-signing.d.ts.map +1 -0
- package/dist/state-signing.js +83 -0
- package/dist/state-signing.js.map +1 -0
- package/dist/storage/domains/audit/agent-audit.d.ts +27 -0
- package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -0
- package/dist/storage/domains/audit/agent-audit.js +66 -0
- package/dist/storage/domains/audit/agent-audit.js.map +1 -0
- package/dist/storage/domains/audit/base.d.ts +140 -0
- package/dist/storage/domains/audit/base.d.ts.map +1 -0
- package/dist/storage/domains/audit/base.js +184 -0
- package/dist/storage/domains/audit/base.js.map +1 -0
- package/dist/storage/domains/audit/domain.d.ts +69 -0
- package/dist/storage/domains/audit/domain.d.ts.map +1 -0
- package/dist/storage/domains/audit/domain.js +167 -0
- package/dist/storage/domains/audit/domain.js.map +1 -0
- package/dist/storage/domains/channel-identity/base.d.ts +96 -0
- package/dist/storage/domains/channel-identity/base.d.ts.map +1 -0
- package/dist/storage/domains/channel-identity/base.js +149 -0
- package/dist/storage/domains/channel-identity/base.js.map +1 -0
- package/dist/storage/domains/credentials/base.d.ts +134 -0
- package/dist/storage/domains/credentials/base.d.ts.map +1 -0
- package/dist/storage/domains/credentials/base.js +273 -0
- package/dist/storage/domains/credentials/base.js.map +1 -0
- package/dist/storage/domains/custom-providers/base.d.ts +57 -0
- package/dist/storage/domains/custom-providers/base.d.ts.map +1 -0
- package/dist/storage/domains/custom-providers/base.js +145 -0
- package/dist/storage/domains/custom-providers/base.js.map +1 -0
- package/dist/storage/domains/intake/base.d.ts +38 -0
- package/dist/storage/domains/intake/base.d.ts.map +1 -0
- package/dist/storage/domains/intake/base.js +80 -0
- package/dist/storage/domains/intake/base.js.map +1 -0
- package/dist/storage/domains/integrations/base.d.ts +126 -0
- package/dist/storage/domains/integrations/base.d.ts.map +1 -0
- package/dist/storage/domains/integrations/base.js +317 -0
- package/dist/storage/domains/integrations/base.js.map +1 -0
- package/dist/storage/domains/memory-settings/base.d.ts +62 -0
- package/dist/storage/domains/memory-settings/base.d.ts.map +1 -0
- package/dist/storage/domains/memory-settings/base.js +126 -0
- package/dist/storage/domains/memory-settings/base.js.map +1 -0
- package/dist/storage/domains/model-packs/base.d.ts +49 -0
- package/dist/storage/domains/model-packs/base.d.ts.map +1 -0
- package/dist/storage/domains/model-packs/base.js +96 -0
- package/dist/storage/domains/model-packs/base.js.map +1 -0
- package/dist/storage/domains/projects/base.d.ts +58 -0
- package/dist/storage/domains/projects/base.d.ts.map +1 -0
- package/dist/storage/domains/projects/base.js +111 -0
- package/dist/storage/domains/projects/base.js.map +1 -0
- package/dist/storage/domains/queue-health/base.d.ts +52 -0
- package/dist/storage/domains/queue-health/base.d.ts.map +1 -0
- package/dist/storage/domains/queue-health/base.js +122 -0
- package/dist/storage/domains/queue-health/base.js.map +1 -0
- package/dist/storage/domains/source-control/base.d.ts +358 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -0
- package/dist/storage/domains/source-control/base.js +908 -0
- package/dist/storage/domains/source-control/base.js.map +1 -0
- package/dist/storage/domains/source-control/inmemory.d.ts +175 -0
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -0
- package/dist/storage/domains/source-control/inmemory.js +377 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -0
- package/dist/storage/domains/work-items/base.d.ts +412 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -0
- package/dist/storage/domains/work-items/base.js +1309 -0
- package/dist/storage/domains/work-items/base.js.map +1 -0
- package/dist/storage/domains/work-items/metrics.d.ts +101 -0
- package/dist/storage/domains/work-items/metrics.d.ts.map +1 -0
- package/dist/storage/domains/work-items/metrics.js +221 -0
- package/dist/storage/domains/work-items/metrics.js.map +1 -0
- package/dist/timing.d.ts +15 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +34 -0
- package/dist/timing.js.map +1 -0
- package/dist/workspace.d.ts +24 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +286 -0
- package/dist/workspace.js.map +1 -0
- package/factory-skills/configure-factory-rules/SKILL.md +67 -0
- package/factory-skills/factory-plan/SKILL.md +61 -0
- package/factory-skills/factory-review/SKILL.md +155 -0
- package/factory-skills/factory-triage/SKILL.md +77 -0
- package/package.json +81 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/storage/domains/audit/agent-audit.ts
|
|
2
|
+
/** Match command-start positions while ignoring command text embedded in heredoc bodies. */
|
|
3
|
+
const GIT_COMMIT_RE = /(?:^|\n|;|&&|\|\|)\s*git\s+commit(?:\s|$)/;
|
|
4
|
+
const GIT_PUSH_RE = /(?:^|\n|;|&&|\|\|)\s*git\s+push(?:\s|$)/;
|
|
5
|
+
function stripHeredocBodies(command) {
|
|
6
|
+
const lines = command.split("\n");
|
|
7
|
+
const executableLines = [];
|
|
8
|
+
let delimiter;
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
if (delimiter) {
|
|
11
|
+
if (line.trim() === delimiter) delimiter = void 0;
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
executableLines.push(line);
|
|
15
|
+
delimiter = line.match(/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/)?.[2];
|
|
16
|
+
}
|
|
17
|
+
return executableLines.join("\n");
|
|
18
|
+
}
|
|
19
|
+
/** Parse the branch from a plain `git push <remote> <branch>` invocation. */
|
|
20
|
+
function parsePushedBranch(command) {
|
|
21
|
+
return command.match(/(?:^|\n|;|&&|\|\|)\s*git\s+push\s+(?:-[^\s]+\s+)*([^\s;&|-][^\s;&|]*)\s+([^\s;&|-][^\s;&|]*)/)?.[2];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Detect externally-visible git side effects in a completed tool call and
|
|
25
|
+
* record `factory.agent.*` audit events for them. One command can emit
|
|
26
|
+
* multiple events (`git commit && git push` emits both). Never throws.
|
|
27
|
+
*/
|
|
28
|
+
async function observeAgentGitAction({ audit, toolContext }) {
|
|
29
|
+
try {
|
|
30
|
+
if (toolContext.toolName !== "execute_command" || toolContext.error) return;
|
|
31
|
+
const rawCommand = toolContext.input?.command;
|
|
32
|
+
if (typeof rawCommand !== "string") return;
|
|
33
|
+
const command = stripHeredocBodies(rawCommand);
|
|
34
|
+
const worktreePath = toolContext.context.get("controller")?.scope;
|
|
35
|
+
if (GIT_COMMIT_RE.test(command)) await audit.emitAgent({
|
|
36
|
+
requestContext: toolContext.context,
|
|
37
|
+
input: {
|
|
38
|
+
action: "factory.agent.commit",
|
|
39
|
+
targets: worktreePath ? [{
|
|
40
|
+
type: "worktree",
|
|
41
|
+
id: worktreePath
|
|
42
|
+
}] : []
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
if (GIT_PUSH_RE.test(command)) {
|
|
46
|
+
const branch = parsePushedBranch(command);
|
|
47
|
+
await audit.emitAgent({
|
|
48
|
+
requestContext: toolContext.context,
|
|
49
|
+
input: {
|
|
50
|
+
action: "factory.agent.push",
|
|
51
|
+
targets: worktreePath ? [{
|
|
52
|
+
type: "worktree",
|
|
53
|
+
id: worktreePath
|
|
54
|
+
}] : [],
|
|
55
|
+
...branch ? { metadata: { branch } } : {}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.warn("[Audit] Failed to observe agent git action", { error: err instanceof Error ? err.message : String(err) });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { observeAgentGitAction };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=agent-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-audit.js","names":[],"sources":["../../../../src/storage/domains/audit/agent-audit.ts"],"sourcesContent":["/**\n * Agent-level audit event detection (Audit v1.1).\n *\n * Git actions performed by agents inside runs never touch web routes, so this\n * observer detects externally-visible git side effects and delegates recording\n * to the factory-owned audit domain.\n */\n\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\n\nimport type { AuditAgentEmitter } from './domain.js';\n\ntype FactorySessionState = { factoryProjectId?: string; projectRepositoryId?: string };\n\ninterface ToolObserverContext {\n toolName: string;\n input: unknown;\n output?: unknown;\n error?: unknown;\n context: RequestContext;\n}\n\n/** Match command-start positions while ignoring command text embedded in heredoc bodies. */\nconst GIT_COMMIT_RE = /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+commit(?:\\s|$)/;\nconst GIT_PUSH_RE = /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+push(?:\\s|$)/;\n\nfunction stripHeredocBodies(command: string): string {\n const lines = command.split('\\n');\n const executableLines: string[] = [];\n let delimiter: string | undefined;\n\n for (const line of lines) {\n if (delimiter) {\n if (line.trim() === delimiter) delimiter = undefined;\n continue;\n }\n executableLines.push(line);\n const heredoc = line.match(/<<-?\\s*(['\"]?)([A-Za-z_][A-Za-z0-9_]*)\\1/);\n delimiter = heredoc?.[2];\n }\n\n return executableLines.join('\\n');\n}\n\n/** Parse the branch from a plain `git push <remote> <branch>` invocation. */\nfunction parsePushedBranch(command: string): string | undefined {\n const match = command.match(\n /(?:^|\\n|;|&&|\\|\\|)\\s*git\\s+push\\s+(?:-[^\\s]+\\s+)*([^\\s;&|-][^\\s;&|]*)\\s+([^\\s;&|-][^\\s;&|]*)/,\n );\n return match?.[2];\n}\n\n/**\n * Detect externally-visible git side effects in a completed tool call and\n * record `factory.agent.*` audit events for them. One command can emit\n * multiple events (`git commit && git push` emits both). Never throws.\n */\nexport async function observeAgentGitAction({\n audit,\n toolContext,\n}: {\n audit: AuditAgentEmitter;\n toolContext: ToolObserverContext;\n}): Promise<void> {\n try {\n if (toolContext.toolName !== 'execute_command' || toolContext.error) return;\n const rawCommand = (toolContext.input as { command?: unknown } | undefined)?.command;\n if (typeof rawCommand !== 'string') return;\n const command = stripHeredocBodies(rawCommand);\n\n const controller = toolContext.context.get('controller') as\n | AgentControllerRequestContext<FactorySessionState>\n | undefined;\n const worktreePath = controller?.scope;\n\n if (GIT_COMMIT_RE.test(command)) {\n await audit.emitAgent({\n requestContext: toolContext.context,\n input: {\n action: 'factory.agent.commit',\n targets: worktreePath ? [{ type: 'worktree', id: worktreePath }] : [],\n },\n });\n }\n\n if (GIT_PUSH_RE.test(command)) {\n const branch = parsePushedBranch(command);\n await audit.emitAgent({\n requestContext: toolContext.context,\n input: {\n action: 'factory.agent.push',\n targets: worktreePath ? [{ type: 'worktree', id: worktreePath }] : [],\n ...(branch ? { metadata: { branch } } : {}),\n },\n });\n }\n } catch (err) {\n console.warn('[Audit] Failed to observe agent git action', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n"],"mappings":";;AAwBA,MAAM,gBAAgB;AACtB,MAAM,cAAc;AAEpB,SAAS,mBAAmB,SAAyB;CACnD,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,MAAM,kBAA4B,CAAC;CACnC,IAAI;CAEJ,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,WAAW;GACb,IAAI,KAAK,KAAK,MAAM,WAAW,YAAY,KAAA;GAC3C;EACF;EACA,gBAAgB,KAAK,IAAI;EAEzB,YADgB,KAAK,MAAM,0CACT,CAAC,GAAG;CACxB;CAEA,OAAO,gBAAgB,KAAK,IAAI;AAClC;;AAGA,SAAS,kBAAkB,SAAqC;CAI9D,OAHc,QAAQ,MACpB,8FAES,CAAC,GAAG;AACjB;;;;;;AAOA,eAAsB,sBAAsB,EAC1C,OACA,eAIgB;CAChB,IAAI;EACF,IAAI,YAAY,aAAa,qBAAqB,YAAY,OAAO;EACrE,MAAM,aAAc,YAAY,OAA6C;EAC7E,IAAI,OAAO,eAAe,UAAU;EACpC,MAAM,UAAU,mBAAmB,UAAU;EAK7C,MAAM,eAHa,YAAY,QAAQ,IAAI,YAGb,CAAC,EAAE;EAEjC,IAAI,cAAc,KAAK,OAAO,GAC5B,MAAM,MAAM,UAAU;GACpB,gBAAgB,YAAY;GAC5B,OAAO;IACL,QAAQ;IACR,SAAS,eAAe,CAAC;KAAE,MAAM;KAAY,IAAI;IAAa,CAAC,IAAI,CAAC;GACtE;EACF,CAAC;EAGH,IAAI,YAAY,KAAK,OAAO,GAAG;GAC7B,MAAM,SAAS,kBAAkB,OAAO;GACxC,MAAM,MAAM,UAAU;IACpB,gBAAgB,YAAY;IAC5B,OAAO;KACL,QAAQ;KACR,SAAS,eAAe,CAAC;MAAE,MAAM;MAAY,IAAI;KAAa,CAAC,IAAI,CAAC;KACpE,GAAI,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;IAC3C;GACF,CAAC;EACH;CACF,SAAS,KAAK;EACZ,QAAQ,KAAK,8CAA8C,EACzD,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EACxD,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory audit events domain — the append-only "who did what, when" trail
|
|
3
|
+
* behind the software factory.
|
|
4
|
+
*
|
|
5
|
+
* One `audit_events` row records a single audited mutation (work-item change,
|
|
6
|
+
* stage move, run start, worktree create/delete, git action, intake config
|
|
7
|
+
* change). Rows are append-only: there is no update/delete API, and the table
|
|
8
|
+
* is the local source of truth even when the WorkOS Audit Logs mirror is
|
|
9
|
+
* unavailable.
|
|
10
|
+
*
|
|
11
|
+
* Tenancy is **org-first**, like `work_items`: events are scoped by `org_id`
|
|
12
|
+
* and (usually) `factory_project_id`; `actor_id` records who acted but never
|
|
13
|
+
* scopes reads.
|
|
14
|
+
*
|
|
15
|
+
* v1 action taxonomy (register these in the WorkOS dashboard under
|
|
16
|
+
* Audit Logs → Events for the export mirror to accept them):
|
|
17
|
+
* - factory.work_item.created
|
|
18
|
+
* - factory.work_item.updated
|
|
19
|
+
* - factory.work_item.stage_moved
|
|
20
|
+
* - factory.work_item.deleted
|
|
21
|
+
* - factory.run.started
|
|
22
|
+
* - factory.worktree.created
|
|
23
|
+
* - factory.worktree.deleted
|
|
24
|
+
* - factory.triage.started
|
|
25
|
+
* - factory.git.commit
|
|
26
|
+
* - factory.git.push
|
|
27
|
+
* - factory.git.pr_opened
|
|
28
|
+
* - factory.intake.config_updated
|
|
29
|
+
*
|
|
30
|
+
* v1.1 adds agent-level actions (also register these in WorkOS):
|
|
31
|
+
* - factory.agent.commit
|
|
32
|
+
* - factory.agent.push
|
|
33
|
+
* - factory.agent.pr_opened
|
|
34
|
+
*
|
|
35
|
+
* Agent events carry `actor_type = 'agent'` with `actor_id = 'agent:<threadId>'`
|
|
36
|
+
* and `metadata.startedBy = <userId>` chaining accountability back to the human
|
|
37
|
+
* whose message drove the run.
|
|
38
|
+
*/
|
|
39
|
+
import { FactoryStorageDomain } from '@mastra/core/storage';
|
|
40
|
+
import type { CollectionSchema } from '@mastra/core/storage';
|
|
41
|
+
/** What an audit event acted on (WorkOS Audit Logs target shape). */
|
|
42
|
+
export interface AuditTarget {
|
|
43
|
+
/** Target kind, e.g. 'work_item', 'worktree', 'issue', 'pull_request'. */
|
|
44
|
+
type: string;
|
|
45
|
+
/** Stable identifier of the target (row id, branch name, issue number...). */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Human-readable label (work-item title, branch name...). */
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Who performed the audited action. */
|
|
51
|
+
export type AuditActorType = 'human' | 'agent';
|
|
52
|
+
/** Request context captured alongside the event. */
|
|
53
|
+
export interface AuditContext {
|
|
54
|
+
/** Client IP (first hop of `x-forwarded-for`) when available. */
|
|
55
|
+
location?: string;
|
|
56
|
+
/** Request `user-agent` header when available. */
|
|
57
|
+
userAgent?: string;
|
|
58
|
+
}
|
|
59
|
+
/** One persisted audit event. */
|
|
60
|
+
export interface AuditEventRow {
|
|
61
|
+
id: string;
|
|
62
|
+
/** Owning WorkOS organization id — the trail is org-wide. */
|
|
63
|
+
orgId: string;
|
|
64
|
+
/** WorkOS user id of whoever performed the action, or `agent:<threadId>`. */
|
|
65
|
+
actorId: string;
|
|
66
|
+
/** Whether a human or an agent (inside a run) performed the action. */
|
|
67
|
+
actorType: AuditActorType;
|
|
68
|
+
/** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */
|
|
69
|
+
action: string;
|
|
70
|
+
/** What was acted on. */
|
|
71
|
+
targets: AuditTarget[];
|
|
72
|
+
/** Bounded event summary — never full payloads, never secrets. */
|
|
73
|
+
metadata: Record<string, unknown>;
|
|
74
|
+
/** Factory project the event is scoped to; null for org-level events. */
|
|
75
|
+
factoryProjectId: string | null;
|
|
76
|
+
/** Project-repository link affected by a repository-specific action. */
|
|
77
|
+
projectRepositoryId: string | null;
|
|
78
|
+
/** Request context (`x-forwarded-for` / `user-agent`). */
|
|
79
|
+
context: AuditContext;
|
|
80
|
+
occurredAt: Date;
|
|
81
|
+
}
|
|
82
|
+
export interface RecordAuditEventInput {
|
|
83
|
+
orgId: string;
|
|
84
|
+
actorId: string;
|
|
85
|
+
/** Who performed the action; defaults to 'human'. */
|
|
86
|
+
actorType?: AuditActorType;
|
|
87
|
+
/** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */
|
|
88
|
+
action: string;
|
|
89
|
+
targets: AuditTarget[];
|
|
90
|
+
metadata?: Record<string, unknown>;
|
|
91
|
+
factoryProjectId?: string;
|
|
92
|
+
projectRepositoryId?: string;
|
|
93
|
+
context?: AuditContext;
|
|
94
|
+
occurredAt?: Date;
|
|
95
|
+
}
|
|
96
|
+
/** A fully-normalized event ready to persist (id assigned on insert). */
|
|
97
|
+
export type AuditEventInsert = Omit<AuditEventRow, 'id'>;
|
|
98
|
+
export interface ListAuditEventsInput {
|
|
99
|
+
orgId: string;
|
|
100
|
+
factoryProjectId?: string;
|
|
101
|
+
/** Restrict to these actions (exact match). */
|
|
102
|
+
actions?: string[];
|
|
103
|
+
actorId?: string;
|
|
104
|
+
/** Opaque cursor from a previous page (`nextCursor`). */
|
|
105
|
+
before?: string;
|
|
106
|
+
limit?: number;
|
|
107
|
+
}
|
|
108
|
+
export interface AuditEventPage {
|
|
109
|
+
events: AuditEventRow[];
|
|
110
|
+
/** Pass back as `before` to fetch the next (older) page; absent at the end. */
|
|
111
|
+
nextCursor?: string;
|
|
112
|
+
}
|
|
113
|
+
/** Truncate oversized metadata rather than dropping the whole event. */
|
|
114
|
+
export declare function boundAuditMetadata(metadata: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
115
|
+
/** Normalize a requested page size to a finite integer in `[1, MAX_PAGE_SIZE]`. */
|
|
116
|
+
export declare function clampAuditLimit(limit: number | undefined): number;
|
|
117
|
+
/** Encode the `(occurredAt, id)` keyset cursor of a row. */
|
|
118
|
+
export declare function encodeAuditCursor(row: AuditEventRow): string;
|
|
119
|
+
/** Decode a cursor back into its `(occurredAt, id)` parts, or `undefined`. */
|
|
120
|
+
export declare function decodeAuditCursor(cursor: string): {
|
|
121
|
+
occurredAt: Date;
|
|
122
|
+
id: string;
|
|
123
|
+
} | undefined;
|
|
124
|
+
export declare const AUDIT_EVENTS_SCHEMA: CollectionSchema;
|
|
125
|
+
/**
|
|
126
|
+
* Audit event storage, written once against the generic `FactoryStorageOps`
|
|
127
|
+
* surface. `record()` normalizes inputs (defaults, metadata bounding);
|
|
128
|
+
* `list()` is keyset-paginated on `(occurred_at, id)` newest-first.
|
|
129
|
+
*/
|
|
130
|
+
export declare class AuditStorage extends FactoryStorageDomain {
|
|
131
|
+
#private;
|
|
132
|
+
constructor();
|
|
133
|
+
init(): Promise<void>;
|
|
134
|
+
dangerouslyClearAll(): Promise<void>;
|
|
135
|
+
/** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */
|
|
136
|
+
record(input: RecordAuditEventInput): Promise<AuditEventRow>;
|
|
137
|
+
/** List an org's audit events newest-first with keyset pagination. */
|
|
138
|
+
list(input: ListAuditEventsInput): Promise<AuditEventPage>;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { FactoryStorageDomain } from "@mastra/core/storage";
|
|
2
|
+
//#region src/storage/domains/audit/base.ts
|
|
3
|
+
/**
|
|
4
|
+
* Factory audit events domain — the append-only "who did what, when" trail
|
|
5
|
+
* behind the software factory.
|
|
6
|
+
*
|
|
7
|
+
* One `audit_events` row records a single audited mutation (work-item change,
|
|
8
|
+
* stage move, run start, worktree create/delete, git action, intake config
|
|
9
|
+
* change). Rows are append-only: there is no update/delete API, and the table
|
|
10
|
+
* is the local source of truth even when the WorkOS Audit Logs mirror is
|
|
11
|
+
* unavailable.
|
|
12
|
+
*
|
|
13
|
+
* Tenancy is **org-first**, like `work_items`: events are scoped by `org_id`
|
|
14
|
+
* and (usually) `factory_project_id`; `actor_id` records who acted but never
|
|
15
|
+
* scopes reads.
|
|
16
|
+
*
|
|
17
|
+
* v1 action taxonomy (register these in the WorkOS dashboard under
|
|
18
|
+
* Audit Logs → Events for the export mirror to accept them):
|
|
19
|
+
* - factory.work_item.created
|
|
20
|
+
* - factory.work_item.updated
|
|
21
|
+
* - factory.work_item.stage_moved
|
|
22
|
+
* - factory.work_item.deleted
|
|
23
|
+
* - factory.run.started
|
|
24
|
+
* - factory.worktree.created
|
|
25
|
+
* - factory.worktree.deleted
|
|
26
|
+
* - factory.triage.started
|
|
27
|
+
* - factory.git.commit
|
|
28
|
+
* - factory.git.push
|
|
29
|
+
* - factory.git.pr_opened
|
|
30
|
+
* - factory.intake.config_updated
|
|
31
|
+
*
|
|
32
|
+
* v1.1 adds agent-level actions (also register these in WorkOS):
|
|
33
|
+
* - factory.agent.commit
|
|
34
|
+
* - factory.agent.push
|
|
35
|
+
* - factory.agent.pr_opened
|
|
36
|
+
*
|
|
37
|
+
* Agent events carry `actor_type = 'agent'` with `actor_id = 'agent:<threadId>'`
|
|
38
|
+
* and `metadata.startedBy = <userId>` chaining accountability back to the human
|
|
39
|
+
* whose message drove the run.
|
|
40
|
+
*/
|
|
41
|
+
/** Metadata is a bounded summary — never full payloads, never secrets. */
|
|
42
|
+
const MAX_METADATA_JSON_LENGTH = 4096;
|
|
43
|
+
const DEFAULT_PAGE_SIZE = 50;
|
|
44
|
+
const MAX_PAGE_SIZE = 200;
|
|
45
|
+
/** Truncate oversized metadata rather than dropping the whole event. */
|
|
46
|
+
function boundAuditMetadata(metadata) {
|
|
47
|
+
if (!metadata) return {};
|
|
48
|
+
try {
|
|
49
|
+
if (JSON.stringify(metadata).length <= MAX_METADATA_JSON_LENGTH) return metadata;
|
|
50
|
+
} catch {
|
|
51
|
+
return { truncated: true };
|
|
52
|
+
}
|
|
53
|
+
return { truncated: true };
|
|
54
|
+
}
|
|
55
|
+
/** Normalize a requested page size to a finite integer in `[1, MAX_PAGE_SIZE]`. */
|
|
56
|
+
function clampAuditLimit(limit) {
|
|
57
|
+
return Math.min(Math.max(typeof limit === "number" && Number.isFinite(limit) ? Math.trunc(limit) : DEFAULT_PAGE_SIZE, 1), MAX_PAGE_SIZE);
|
|
58
|
+
}
|
|
59
|
+
/** Encode the `(occurredAt, id)` keyset cursor of a row. */
|
|
60
|
+
function encodeAuditCursor(row) {
|
|
61
|
+
return `${row.occurredAt.toISOString()}_${row.id}`;
|
|
62
|
+
}
|
|
63
|
+
/** Decode a cursor back into its `(occurredAt, id)` parts, or `undefined`. */
|
|
64
|
+
function decodeAuditCursor(cursor) {
|
|
65
|
+
const sep = cursor.lastIndexOf("_");
|
|
66
|
+
if (sep <= 0) return void 0;
|
|
67
|
+
const occurredAt = new Date(cursor.slice(0, sep));
|
|
68
|
+
const id = cursor.slice(sep + 1);
|
|
69
|
+
if (Number.isNaN(occurredAt.getTime()) || !id) return void 0;
|
|
70
|
+
return {
|
|
71
|
+
occurredAt,
|
|
72
|
+
id
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const AUDIT_EVENTS_SCHEMA = {
|
|
76
|
+
name: "audit_events",
|
|
77
|
+
columns: {
|
|
78
|
+
id: { type: "uuid-pk" },
|
|
79
|
+
org_id: { type: "text" },
|
|
80
|
+
actor_id: { type: "text" },
|
|
81
|
+
actor_type: {
|
|
82
|
+
type: "text",
|
|
83
|
+
default: "human"
|
|
84
|
+
},
|
|
85
|
+
action: { type: "text" },
|
|
86
|
+
targets: { type: "json" },
|
|
87
|
+
metadata: { type: "json" },
|
|
88
|
+
factory_project_id: {
|
|
89
|
+
type: "text",
|
|
90
|
+
nullable: true
|
|
91
|
+
},
|
|
92
|
+
project_repository_id: {
|
|
93
|
+
type: "text",
|
|
94
|
+
nullable: true
|
|
95
|
+
},
|
|
96
|
+
context: { type: "json" },
|
|
97
|
+
occurred_at: { type: "timestamp" }
|
|
98
|
+
},
|
|
99
|
+
indexes: [{
|
|
100
|
+
name: "audit_events_org_occurred_idx",
|
|
101
|
+
columns: ["org_id", "occurred_at"]
|
|
102
|
+
}, {
|
|
103
|
+
name: "audit_events_org_project_occurred_idx",
|
|
104
|
+
columns: [
|
|
105
|
+
"org_id",
|
|
106
|
+
"factory_project_id",
|
|
107
|
+
"occurred_at"
|
|
108
|
+
]
|
|
109
|
+
}]
|
|
110
|
+
};
|
|
111
|
+
function toRow(db) {
|
|
112
|
+
return {
|
|
113
|
+
id: db.id,
|
|
114
|
+
orgId: db.org_id,
|
|
115
|
+
actorId: db.actor_id,
|
|
116
|
+
actorType: db.actor_type,
|
|
117
|
+
action: db.action,
|
|
118
|
+
targets: db.targets,
|
|
119
|
+
metadata: db.metadata,
|
|
120
|
+
factoryProjectId: db.factory_project_id,
|
|
121
|
+
projectRepositoryId: db.project_repository_id,
|
|
122
|
+
context: db.context,
|
|
123
|
+
occurredAt: db.occurred_at
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Audit event storage, written once against the generic `FactoryStorageOps`
|
|
128
|
+
* surface. `record()` normalizes inputs (defaults, metadata bounding);
|
|
129
|
+
* `list()` is keyset-paginated on `(occurred_at, id)` newest-first.
|
|
130
|
+
*/
|
|
131
|
+
var AuditStorage = class extends FactoryStorageDomain {
|
|
132
|
+
constructor() {
|
|
133
|
+
super("audit");
|
|
134
|
+
}
|
|
135
|
+
async init() {
|
|
136
|
+
await this.ensureCollections([AUDIT_EVENTS_SCHEMA]);
|
|
137
|
+
}
|
|
138
|
+
async dangerouslyClearAll() {
|
|
139
|
+
await this.ops.deleteMany("audit_events", {});
|
|
140
|
+
}
|
|
141
|
+
get #db() {
|
|
142
|
+
return this.ops;
|
|
143
|
+
}
|
|
144
|
+
/** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */
|
|
145
|
+
async record(input) {
|
|
146
|
+
return toRow(await this.#db.insertOne("audit_events", {
|
|
147
|
+
org_id: input.orgId,
|
|
148
|
+
actor_id: input.actorId,
|
|
149
|
+
actor_type: input.actorType ?? "human",
|
|
150
|
+
action: input.action,
|
|
151
|
+
targets: input.targets,
|
|
152
|
+
metadata: boundAuditMetadata(input.metadata),
|
|
153
|
+
factory_project_id: input.factoryProjectId ?? null,
|
|
154
|
+
project_repository_id: input.projectRepositoryId ?? null,
|
|
155
|
+
context: input.context ?? {},
|
|
156
|
+
occurred_at: input.occurredAt ?? /* @__PURE__ */ new Date()
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
/** List an org's audit events newest-first with keyset pagination. */
|
|
160
|
+
async list(input) {
|
|
161
|
+
const limit = clampAuditLimit(input.limit);
|
|
162
|
+
const where = { org_id: input.orgId };
|
|
163
|
+
if (input.factoryProjectId) where.factory_project_id = input.factoryProjectId;
|
|
164
|
+
if (input.actions && input.actions.length > 0) where.action = { in: input.actions };
|
|
165
|
+
if (input.actorId) where.actor_id = input.actorId;
|
|
166
|
+
const cursor = input.before ? decodeAuditCursor(input.before) : void 0;
|
|
167
|
+
const rows = await this.#db.findMany("audit_events", where, {
|
|
168
|
+
orderBy: [["occurred_at", "desc"], ["id", "desc"]],
|
|
169
|
+
limit: limit + 1,
|
|
170
|
+
...cursor ? { cursor: { values: [cursor.occurredAt, cursor.id] } } : {}
|
|
171
|
+
});
|
|
172
|
+
const events = rows.slice(0, limit).map(toRow);
|
|
173
|
+
const hasMore = rows.length > limit;
|
|
174
|
+
const last = events[events.length - 1];
|
|
175
|
+
return {
|
|
176
|
+
events,
|
|
177
|
+
...hasMore && last ? { nextCursor: encodeAuditCursor(last) } : {}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
//#endregion
|
|
182
|
+
export { AUDIT_EVENTS_SCHEMA, AuditStorage, boundAuditMetadata, clampAuditLimit, decodeAuditCursor, encodeAuditCursor };
|
|
183
|
+
|
|
184
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","names":["#db"],"sources":["../../../../src/storage/domains/audit/base.ts"],"sourcesContent":["/**\n * Factory audit events domain — the append-only \"who did what, when\" trail\n * behind the software factory.\n *\n * One `audit_events` row records a single audited mutation (work-item change,\n * stage move, run start, worktree create/delete, git action, intake config\n * change). Rows are append-only: there is no update/delete API, and the table\n * is the local source of truth even when the WorkOS Audit Logs mirror is\n * unavailable.\n *\n * Tenancy is **org-first**, like `work_items`: events are scoped by `org_id`\n * and (usually) `factory_project_id`; `actor_id` records who acted but never\n * scopes reads.\n *\n * v1 action taxonomy (register these in the WorkOS dashboard under\n * Audit Logs → Events for the export mirror to accept them):\n * - factory.work_item.created\n * - factory.work_item.updated\n * - factory.work_item.stage_moved\n * - factory.work_item.deleted\n * - factory.run.started\n * - factory.worktree.created\n * - factory.worktree.deleted\n * - factory.triage.started\n * - factory.git.commit\n * - factory.git.push\n * - factory.git.pr_opened\n * - factory.intake.config_updated\n *\n * v1.1 adds agent-level actions (also register these in WorkOS):\n * - factory.agent.commit\n * - factory.agent.push\n * - factory.agent.pr_opened\n *\n * Agent events carry `actor_type = 'agent'` with `actor_id = 'agent:<threadId>'`\n * and `metadata.startedBy = <userId>` chaining accountability back to the human\n * whose message drove the run.\n */\n\nimport { FactoryStorageDomain } from '@mastra/core/storage';\nimport type { CollectionSchema, CollectionWhere, FactoryStorageOps } from '@mastra/core/storage';\n\n/** What an audit event acted on (WorkOS Audit Logs target shape). */\nexport interface AuditTarget {\n /** Target kind, e.g. 'work_item', 'worktree', 'issue', 'pull_request'. */\n type: string;\n /** Stable identifier of the target (row id, branch name, issue number...). */\n id: string;\n /** Human-readable label (work-item title, branch name...). */\n name?: string;\n}\n\n/** Who performed the audited action. */\nexport type AuditActorType = 'human' | 'agent';\n\n/** Request context captured alongside the event. */\nexport interface AuditContext {\n /** Client IP (first hop of `x-forwarded-for`) when available. */\n location?: string;\n /** Request `user-agent` header when available. */\n userAgent?: string;\n}\n\n/** One persisted audit event. */\nexport interface AuditEventRow {\n id: string;\n /** Owning WorkOS organization id — the trail is org-wide. */\n orgId: string;\n /** WorkOS user id of whoever performed the action, or `agent:<threadId>`. */\n actorId: string;\n /** Whether a human or an agent (inside a run) performed the action. */\n actorType: AuditActorType;\n /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */\n action: string;\n /** What was acted on. */\n targets: AuditTarget[];\n /** Bounded event summary — never full payloads, never secrets. */\n metadata: Record<string, unknown>;\n /** Factory project the event is scoped to; null for org-level events. */\n factoryProjectId: string | null;\n /** Project-repository link affected by a repository-specific action. */\n projectRepositoryId: string | null;\n /** Request context (`x-forwarded-for` / `user-agent`). */\n context: AuditContext;\n occurredAt: Date;\n}\n\nexport interface RecordAuditEventInput {\n orgId: string;\n actorId: string;\n /** Who performed the action; defaults to 'human'. */\n actorType?: AuditActorType;\n /** Dot-namespaced action, e.g. 'factory.work_item.stage_moved'. */\n action: string;\n targets: AuditTarget[];\n metadata?: Record<string, unknown>;\n factoryProjectId?: string;\n projectRepositoryId?: string;\n context?: AuditContext;\n occurredAt?: Date;\n}\n\n/** A fully-normalized event ready to persist (id assigned on insert). */\nexport type AuditEventInsert = Omit<AuditEventRow, 'id'>;\n\nexport interface ListAuditEventsInput {\n orgId: string;\n factoryProjectId?: string;\n /** Restrict to these actions (exact match). */\n actions?: string[];\n actorId?: string;\n /** Opaque cursor from a previous page (`nextCursor`). */\n before?: string;\n limit?: number;\n}\n\nexport interface AuditEventPage {\n events: AuditEventRow[];\n /** Pass back as `before` to fetch the next (older) page; absent at the end. */\n nextCursor?: string;\n}\n\n/** Metadata is a bounded summary — never full payloads, never secrets. */\nconst MAX_METADATA_JSON_LENGTH = 4096;\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst MAX_PAGE_SIZE = 200;\n\n/** Truncate oversized metadata rather than dropping the whole event. */\nexport function boundAuditMetadata(metadata: Record<string, unknown> | undefined): Record<string, unknown> {\n if (!metadata) return {};\n try {\n if (JSON.stringify(metadata).length <= MAX_METADATA_JSON_LENGTH) return metadata;\n } catch {\n return { truncated: true };\n }\n return { truncated: true };\n}\n\n/** Normalize a requested page size to a finite integer in `[1, MAX_PAGE_SIZE]`. */\nexport function clampAuditLimit(limit: number | undefined): number {\n const normalized = typeof limit === 'number' && Number.isFinite(limit) ? Math.trunc(limit) : DEFAULT_PAGE_SIZE;\n return Math.min(Math.max(normalized, 1), MAX_PAGE_SIZE);\n}\n\n/** Encode the `(occurredAt, id)` keyset cursor of a row. */\nexport function encodeAuditCursor(row: AuditEventRow): string {\n return `${row.occurredAt.toISOString()}_${row.id}`;\n}\n\n/** Decode a cursor back into its `(occurredAt, id)` parts, or `undefined`. */\nexport function decodeAuditCursor(cursor: string): { occurredAt: Date; id: string } | undefined {\n const sep = cursor.lastIndexOf('_');\n if (sep <= 0) return undefined;\n const occurredAt = new Date(cursor.slice(0, sep));\n const id = cursor.slice(sep + 1);\n if (Number.isNaN(occurredAt.getTime()) || !id) return undefined;\n return { occurredAt, id };\n}\n\nexport const AUDIT_EVENTS_SCHEMA: CollectionSchema = {\n name: 'audit_events',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n actor_id: { type: 'text' },\n actor_type: { type: 'text', default: 'human' },\n action: { type: 'text' },\n targets: { type: 'json' },\n metadata: { type: 'json' },\n factory_project_id: { type: 'text', nullable: true },\n project_repository_id: { type: 'text', nullable: true },\n context: { type: 'json' },\n occurred_at: { type: 'timestamp' },\n },\n indexes: [\n { name: 'audit_events_org_occurred_idx', columns: ['org_id', 'occurred_at'] },\n { name: 'audit_events_org_project_occurred_idx', columns: ['org_id', 'factory_project_id', 'occurred_at'] },\n ],\n};\n\n/** Column shape of one `audit_events` row as returned by ops. */\ninterface AuditEventDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n actor_id: string;\n actor_type: AuditActorType;\n action: string;\n targets: AuditTarget[];\n metadata: Record<string, unknown>;\n factory_project_id: string | null;\n project_repository_id: string | null;\n context: AuditContext;\n occurred_at: Date;\n}\n\nfunction toRow(db: AuditEventDbRow): AuditEventRow {\n return {\n id: db.id,\n orgId: db.org_id,\n actorId: db.actor_id,\n actorType: db.actor_type,\n action: db.action,\n targets: db.targets,\n metadata: db.metadata,\n factoryProjectId: db.factory_project_id,\n projectRepositoryId: db.project_repository_id,\n context: db.context,\n occurredAt: db.occurred_at,\n };\n}\n\n/**\n * Audit event storage, written once against the generic `FactoryStorageOps`\n * surface. `record()` normalizes inputs (defaults, metadata bounding);\n * `list()` is keyset-paginated on `(occurred_at, id)` newest-first.\n */\nexport class AuditStorage extends FactoryStorageDomain {\n constructor() {\n super('audit');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([AUDIT_EVENTS_SCHEMA]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('audit_events', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n /** Append one audit event. Throws on failure — swallow-on-failure lives in the caller. */\n async record(input: RecordAuditEventInput): Promise<AuditEventRow> {\n const inserted = await this.#db.insertOne<AuditEventDbRow>('audit_events', {\n org_id: input.orgId,\n actor_id: input.actorId,\n actor_type: input.actorType ?? 'human',\n action: input.action,\n targets: input.targets,\n metadata: boundAuditMetadata(input.metadata),\n factory_project_id: input.factoryProjectId ?? null,\n project_repository_id: input.projectRepositoryId ?? null,\n context: input.context ?? {},\n occurred_at: input.occurredAt ?? new Date(),\n });\n return toRow(inserted);\n }\n\n /** List an org's audit events newest-first with keyset pagination. */\n async list(input: ListAuditEventsInput): Promise<AuditEventPage> {\n const limit = clampAuditLimit(input.limit);\n\n const where: CollectionWhere = { org_id: input.orgId };\n if (input.factoryProjectId) where.factory_project_id = input.factoryProjectId;\n if (input.actions && input.actions.length > 0) where.action = { in: input.actions };\n if (input.actorId) where.actor_id = input.actorId;\n\n const cursor = input.before ? decodeAuditCursor(input.before) : undefined;\n\n const rows = await this.#db.findMany<AuditEventDbRow>('audit_events', where, {\n orderBy: [\n ['occurred_at', 'desc'],\n ['id', 'desc'],\n ],\n limit: limit + 1,\n ...(cursor ? { cursor: { values: [cursor.occurredAt, cursor.id] } } : {}),\n });\n\n const events = rows.slice(0, limit).map(toRow);\n const hasMore = rows.length > limit;\n const last = events[events.length - 1];\n return {\n events,\n ...(hasMore && last ? { nextCursor: encodeAuditCursor(last) } : {}),\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { RequestContext } from '@mastra/core/request-context';
|
|
2
|
+
import type { ApiRoute } from '@mastra/core/server';
|
|
3
|
+
import type { Context } from 'hono';
|
|
4
|
+
import type { RouteAuth } from '../../../routes/route.js';
|
|
5
|
+
import type { FactoryProjectsStorage } from '../projects/base.js';
|
|
6
|
+
import type { AuditContext, AuditEventPage, AuditEventRow, AuditStorage, AuditTarget, ListAuditEventsInput, RecordAuditEventInput } from './base.js';
|
|
7
|
+
export interface EmitAuditInput {
|
|
8
|
+
action: string;
|
|
9
|
+
factoryProjectId?: string;
|
|
10
|
+
projectRepositoryId?: string;
|
|
11
|
+
targets: AuditTarget[];
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface EmitAgentAuditInput {
|
|
15
|
+
action: string;
|
|
16
|
+
targets: AuditTarget[];
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface AuditEmitter {
|
|
20
|
+
emit(args: {
|
|
21
|
+
context: Context;
|
|
22
|
+
input: EmitAuditInput;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export interface AuditAgentEmitter {
|
|
26
|
+
emitAgent(args: {
|
|
27
|
+
requestContext: RequestContext;
|
|
28
|
+
input: EmitAgentAuditInput;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/** Best-effort destination for locally persisted audit events (e.g. an integration's audit log). */
|
|
32
|
+
export interface AuditSink {
|
|
33
|
+
id: string;
|
|
34
|
+
audit?(args: {
|
|
35
|
+
event: AuditEventRow;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export interface AuditDomainOptions {
|
|
39
|
+
auth: RouteAuth;
|
|
40
|
+
/** Audit storage domain handle. */
|
|
41
|
+
audit: AuditStorage;
|
|
42
|
+
/** Projects domain handle, used to scope the audit trail route. */
|
|
43
|
+
projects: FactoryProjectsStorage;
|
|
44
|
+
/** Best-effort fan-out destinations notified after each recorded event. */
|
|
45
|
+
sinks?: AuditSink[];
|
|
46
|
+
/** Resolve the acting tenant for agent-emitted events from the request context. */
|
|
47
|
+
agentTenant?: (requestContext: RequestContext) => {
|
|
48
|
+
orgId?: string;
|
|
49
|
+
userId?: string;
|
|
50
|
+
} | undefined;
|
|
51
|
+
}
|
|
52
|
+
export declare function auditRequestContext(c: Context): AuditContext;
|
|
53
|
+
/** Factory-owned audit behavior backed by the audit storage domain. */
|
|
54
|
+
export declare class AuditDomain implements AuditEmitter, AuditAgentEmitter {
|
|
55
|
+
#private;
|
|
56
|
+
constructor({ auth, audit, projects, sinks, agentTenant }: AuditDomainOptions);
|
|
57
|
+
record(input: RecordAuditEventInput): Promise<AuditEventRow | null>;
|
|
58
|
+
list(input: ListAuditEventsInput): Promise<AuditEventPage>;
|
|
59
|
+
emit({ context, input }: {
|
|
60
|
+
context: Context;
|
|
61
|
+
input: EmitAuditInput;
|
|
62
|
+
}): Promise<void>;
|
|
63
|
+
emitAgent({ requestContext, input, }: {
|
|
64
|
+
requestContext: RequestContext;
|
|
65
|
+
input: EmitAgentAuditInput;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
routes(): ApiRoute[];
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/audit/domain.ts"],"names":[],"mappings":"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"}
|