@mastra/factory 0.9.0 → 0.10.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.
- package/CHANGELOG.md +179 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +1 -1
- package/dist/auth.js.map +1 -1
- package/dist/factory.d.ts +8 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +24 -8
- package/dist/factory.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +1 -0
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/provenance.d.ts +7 -2
- package/dist/integrations/github/provenance.d.ts.map +1 -1
- package/dist/integrations/github/provenance.js +16 -2
- package/dist/integrations/github/provenance.js.map +1 -1
- package/dist/integrations/github/routes.d.ts +3 -0
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +165 -6
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +193 -127
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/linear/routes.d.ts.map +1 -1
- package/dist/integrations/linear/routes.js +50 -0
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +1 -0
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/attention.d.ts +17 -0
- package/dist/routes/attention.d.ts.map +1 -0
- package/dist/routes/attention.js +305 -0
- package/dist/routes/attention.js.map +1 -0
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/intake.js +11 -2
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/surface.d.ts +2 -3
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +61 -43
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +35 -14
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/defaults.js +5 -5
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatch-errors.d.ts +13 -0
- package/dist/rules/dispatch-errors.d.ts.map +1 -0
- package/dist/rules/dispatch-errors.js +77 -0
- package/dist/rules/dispatch-errors.js.map +1 -0
- package/dist/rules/dispatcher.d.ts +9 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +118 -45
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +30 -14
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts +1 -1
- package/dist/rules/terminal-cleanup.d.ts.map +1 -1
- package/dist/rules/terminal-cleanup.js +2 -2
- package/dist/rules/terminal-cleanup.js.map +1 -1
- package/dist/rules/transition-service.d.ts +2 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +1 -1
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +2 -0
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +9 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/secret-encryption.d.ts +25 -0
- package/dist/secret-encryption.d.ts.map +1 -0
- package/dist/secret-encryption.js +96 -0
- package/dist/secret-encryption.js.map +1 -0
- package/dist/session/factory-session.d.ts +13 -3
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +15 -6
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/first-exec-capture.d.ts +16 -10
- package/dist/session/first-exec-capture.d.ts.map +1 -1
- package/dist/session/first-exec-capture.js +74 -14
- package/dist/session/first-exec-capture.js.map +1 -1
- package/dist/session/first-message-capture.d.ts +14 -10
- package/dist/session/first-message-capture.d.ts.map +1 -1
- package/dist/session/first-message-capture.js +17 -11
- package/dist/session/first-message-capture.js.map +1 -1
- package/dist/session/session-title.d.ts +7 -0
- package/dist/session/session-title.d.ts.map +1 -0
- package/dist/session/session-title.js +14 -0
- package/dist/session/session-title.js.map +1 -0
- package/dist/session/thread-title-mirror.d.ts +35 -0
- package/dist/session/thread-title-mirror.d.ts.map +1 -0
- package/dist/session/thread-title-mirror.js +51 -0
- package/dist/session/thread-title-mirror.js.map +1 -0
- package/dist/storage/domains/credentials/base.d.ts +3 -1
- package/dist/storage/domains/credentials/base.d.ts.map +1 -1
- package/dist/storage/domains/credentials/base.js +33 -15
- package/dist/storage/domains/credentials/base.js.map +1 -1
- package/dist/storage/domains/custom-providers/base.d.ts +3 -1
- package/dist/storage/domains/custom-providers/base.d.ts.map +1 -1
- package/dist/storage/domains/custom-providers/base.js +45 -25
- package/dist/storage/domains/custom-providers/base.js.map +1 -1
- package/dist/storage/domains/intake/base.d.ts +6 -5
- package/dist/storage/domains/intake/base.d.ts.map +1 -1
- package/dist/storage/domains/intake/base.js +21 -13
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts +3 -1
- package/dist/storage/domains/integrations/base.d.ts.map +1 -1
- package/dist/storage/domains/integrations/base.js +28 -12
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +8 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +14 -2
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +7 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +115 -12
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +497 -43
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/work-item-branch.d.ts +23 -0
- package/dist/work-item-branch.d.ts.map +1 -0
- package/dist/work-item-branch.js +39 -0
- package/dist/work-item-branch.js.map +1 -0
- package/factory-skills/factory-rereview/SKILL.md +2 -0
- package/factory-skills/factory-review/SKILL.md +2 -0
- package/package.json +7 -7
|
@@ -3,12 +3,15 @@ import { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from ".
|
|
|
3
3
|
import { SandboxBudgetError } from "../../sandbox/fleet.js";
|
|
4
4
|
import { MaterializeError, WorktreeError, commitAll, ensureProjectSandbox, isValidGitRef as isValidGitRef$1, materializeRepo, pushBranch, teardownProjectSandbox } from "./sandbox.js";
|
|
5
5
|
import { baseCheckpointIsStale } from "../../sandbox/base-checkpoint-triggers.js";
|
|
6
|
+
import { normalizeSessionTitle } from "../../session/session-title.js";
|
|
6
7
|
import { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from "./config.js";
|
|
7
8
|
import { reclaimDeletedSessionSandbox } from "./sandbox-release.js";
|
|
8
9
|
import { handleGithubWebhook } from "./webhook.js";
|
|
9
10
|
import { registerApiRoute } from "@mastra/core/server";
|
|
10
11
|
import { randomUUID } from "crypto";
|
|
11
12
|
import { UniqueViolationError } from "@mastra/core/storage";
|
|
13
|
+
import { resolveModel } from "@mastra/code-sdk/agents/model";
|
|
14
|
+
import { RequestContext } from "@mastra/core/request-context";
|
|
12
15
|
import { streamSSE } from "hono/streaming";
|
|
13
16
|
//#region src/integrations/github/routes.ts
|
|
14
17
|
/**
|
|
@@ -24,7 +27,6 @@ import { streamSSE } from "hono/streaming";
|
|
|
24
27
|
* so the SPA can cleanly hide all GitHub UI.
|
|
25
28
|
*/
|
|
26
29
|
const sessionOperationLocks = /* @__PURE__ */ new Map();
|
|
27
|
-
const MAX_SESSION_TITLE_LENGTH = 80;
|
|
28
30
|
const USER_SESSION_BRANCH_PREFIX = "user/session-";
|
|
29
31
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
30
32
|
/**
|
|
@@ -69,9 +71,6 @@ function isValidGitRef(value) {
|
|
|
69
71
|
function isJsonObject(value) {
|
|
70
72
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
71
73
|
}
|
|
72
|
-
function normalizeSessionTitle(title) {
|
|
73
|
-
return [...title.replace(/\s+/g, " ").trim()].slice(0, MAX_SESSION_TITLE_LENGTH).join("").trimEnd() || null;
|
|
74
|
-
}
|
|
75
74
|
/**
|
|
76
75
|
* Resolve the org-scoped tenant for a GitHub request. GitHub project features
|
|
77
76
|
* are org-owned, so they require both a signed-in user and a WorkOS
|
|
@@ -108,6 +107,11 @@ function parseListPage(raw) {
|
|
|
108
107
|
const page = Number(raw);
|
|
109
108
|
return page >= 1 ? page : null;
|
|
110
109
|
}
|
|
110
|
+
function parseResourceNumber(raw) {
|
|
111
|
+
if (raw === void 0 || !/^\d{1,10}$/.test(raw)) return null;
|
|
112
|
+
const parsed = Number(raw);
|
|
113
|
+
return parsed > 0 ? parsed : null;
|
|
114
|
+
}
|
|
111
115
|
const VALID_ISSUE_LABEL_FILTERS = /* @__PURE__ */ new Set(["status: auto-triaged", "status: needs approval"]);
|
|
112
116
|
function parseIssueLabelFilter(raw) {
|
|
113
117
|
if (raw === void 0 || raw === "") return void 0;
|
|
@@ -208,7 +212,7 @@ async function ingestPolledEvents(events, ingestFactoryEvent) {
|
|
|
208
212
|
*/
|
|
209
213
|
function buildGithubRoutes(options) {
|
|
210
214
|
const routes = [];
|
|
211
|
-
const { auth, fleet, storage, github, stateSigner, controller, emitAudit, sessionRetirement } = options;
|
|
215
|
+
const { auth, fleet, storage, github, stateSigner, controller, memorySettings, emitAudit, sessionRetirement } = options;
|
|
212
216
|
const diagnostics = () => getGithubFeatureDiagnostics({
|
|
213
217
|
github,
|
|
214
218
|
auth,
|
|
@@ -531,6 +535,48 @@ function buildGithubRoutes(options) {
|
|
|
531
535
|
}
|
|
532
536
|
}
|
|
533
537
|
}));
|
|
538
|
+
routes.push(registerApiRoute("/web/github/projects/:id/issues/:number", {
|
|
539
|
+
method: "GET",
|
|
540
|
+
requiresAuth: false,
|
|
541
|
+
handler: async (c) => {
|
|
542
|
+
const loaded = await loadOrgProject({
|
|
543
|
+
github,
|
|
544
|
+
auth,
|
|
545
|
+
c: loose(c)
|
|
546
|
+
});
|
|
547
|
+
if ("response" in loaded) return loaded.response;
|
|
548
|
+
const number = parseResourceNumber(c.req.param("number"));
|
|
549
|
+
if (number === null) return c.json({ error: "invalid_number" }, 400);
|
|
550
|
+
try {
|
|
551
|
+
const detail = await github.intake.getIssue({
|
|
552
|
+
connection: {
|
|
553
|
+
type: "app-installation",
|
|
554
|
+
installationId: Number(loaded.project.installation.externalId)
|
|
555
|
+
},
|
|
556
|
+
sourceId: loaded.project.repository.slug,
|
|
557
|
+
issueId: String(number)
|
|
558
|
+
});
|
|
559
|
+
if (detail === null) return c.json({ error: "issue_not_found" }, 404);
|
|
560
|
+
return c.json({
|
|
561
|
+
number: Number(detail.id),
|
|
562
|
+
title: detail.title,
|
|
563
|
+
url: detail.url,
|
|
564
|
+
author: detail.author,
|
|
565
|
+
assignee: detail.assignee,
|
|
566
|
+
labels: detail.labels,
|
|
567
|
+
comments: detail.commentCount ?? 0,
|
|
568
|
+
createdAt: detail.createdAt,
|
|
569
|
+
updatedAt: detail.updatedAt,
|
|
570
|
+
description: detail.description
|
|
571
|
+
});
|
|
572
|
+
} catch (err) {
|
|
573
|
+
return c.json({
|
|
574
|
+
error: "github_fetch_failed",
|
|
575
|
+
message: err instanceof Error ? err.message : String(err)
|
|
576
|
+
}, 502);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}));
|
|
534
580
|
routes.push(registerApiRoute("/web/github/projects/:id/prs", {
|
|
535
581
|
method: "GET",
|
|
536
582
|
requiresAuth: false,
|
|
@@ -578,6 +624,49 @@ function buildGithubRoutes(options) {
|
|
|
578
624
|
}
|
|
579
625
|
}
|
|
580
626
|
}));
|
|
627
|
+
routes.push(registerApiRoute("/web/github/projects/:id/prs/:number", {
|
|
628
|
+
method: "GET",
|
|
629
|
+
requiresAuth: false,
|
|
630
|
+
handler: async (c) => {
|
|
631
|
+
const loaded = await loadOrgProject({
|
|
632
|
+
github,
|
|
633
|
+
auth,
|
|
634
|
+
c: loose(c)
|
|
635
|
+
});
|
|
636
|
+
if ("response" in loaded) return loaded.response;
|
|
637
|
+
const number = parseResourceNumber(c.req.param("number"));
|
|
638
|
+
if (number === null) return c.json({ error: "invalid_number" }, 400);
|
|
639
|
+
try {
|
|
640
|
+
const pr = await github.versionControl.getPullRequest({
|
|
641
|
+
connection: {
|
|
642
|
+
type: "app-installation",
|
|
643
|
+
installationId: Number(loaded.project.installation.externalId)
|
|
644
|
+
},
|
|
645
|
+
sourceId: loaded.project.repository.slug,
|
|
646
|
+
pullRequestId: String(number)
|
|
647
|
+
});
|
|
648
|
+
if (pr === null) return c.json({ error: "pull_request_not_found" }, 404);
|
|
649
|
+
return c.json({
|
|
650
|
+
number: Number(pr.id),
|
|
651
|
+
title: pr.title,
|
|
652
|
+
url: pr.url,
|
|
653
|
+
author: pr.author,
|
|
654
|
+
assignees: pr.assignees ?? [],
|
|
655
|
+
requestedReviewers: pr.requestedReviewers ?? [],
|
|
656
|
+
baseBranch: pr.baseBranch,
|
|
657
|
+
headBranch: pr.headBranch,
|
|
658
|
+
createdAt: pr.createdAt,
|
|
659
|
+
updatedAt: pr.updatedAt,
|
|
660
|
+
description: pr.body
|
|
661
|
+
});
|
|
662
|
+
} catch (err) {
|
|
663
|
+
return c.json({
|
|
664
|
+
error: "github_fetch_failed",
|
|
665
|
+
message: err instanceof Error ? err.message : String(err)
|
|
666
|
+
}, 502);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}));
|
|
581
670
|
routes.push(registerApiRoute("/web/github/projects/:id/settings", {
|
|
582
671
|
method: "GET",
|
|
583
672
|
requiresAuth: false,
|
|
@@ -688,6 +777,7 @@ function buildGithubRoutes(options) {
|
|
|
688
777
|
auth,
|
|
689
778
|
fleet,
|
|
690
779
|
controller,
|
|
780
|
+
memorySettings,
|
|
691
781
|
emitAudit,
|
|
692
782
|
sessionRetirement
|
|
693
783
|
}));
|
|
@@ -894,7 +984,33 @@ async function loadOwnedProject(options) {
|
|
|
894
984
|
sandboxRow: await loadOrCreateSandboxRow(github, project, userId)
|
|
895
985
|
};
|
|
896
986
|
}
|
|
897
|
-
|
|
987
|
+
/**
|
|
988
|
+
* One naming per session at a time: a second caller joins the run already in
|
|
989
|
+
* flight instead of paying for another model call and racing its rename.
|
|
990
|
+
*/
|
|
991
|
+
function createSessionNaming() {
|
|
992
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
993
|
+
return (sessionId, run) => {
|
|
994
|
+
const pending = inFlight.get(sessionId);
|
|
995
|
+
if (pending) return pending;
|
|
996
|
+
const started = run().finally(() => inFlight.delete(sessionId));
|
|
997
|
+
inFlight.set(sessionId, started);
|
|
998
|
+
return started;
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Name a thread with a stored model id. Resolution has to go through
|
|
1003
|
+
* mastracode's gateway: a bare id handed to core's model router looks for a
|
|
1004
|
+
* process env key instead of the caller's stored provider credentials.
|
|
1005
|
+
*/
|
|
1006
|
+
function titleModel(modelId) {
|
|
1007
|
+
return ({ requestContext }) => resolveModel(modelId, {
|
|
1008
|
+
remapForCodexOAuth: true,
|
|
1009
|
+
requestContext
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
function buildProjectGitRoutes({ github, auth, fleet, controller, memorySettings, emitAudit, sessionRetirement }) {
|
|
1013
|
+
const nameSession = createSessionNaming();
|
|
898
1014
|
return [
|
|
899
1015
|
registerApiRoute("/web/github/projects/:id/sessions", {
|
|
900
1016
|
method: "GET",
|
|
@@ -1029,6 +1145,49 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, emitAudit, ses
|
|
|
1029
1145
|
return c.json({ removed: true });
|
|
1030
1146
|
}
|
|
1031
1147
|
}),
|
|
1148
|
+
registerApiRoute("/web/user-sessions/:sessionId/title", {
|
|
1149
|
+
method: "POST",
|
|
1150
|
+
requiresAuth: false,
|
|
1151
|
+
handler: async (c) => {
|
|
1152
|
+
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
1153
|
+
if ("response" in resolved) return resolved.response;
|
|
1154
|
+
const sessionId = c.req.param("sessionId");
|
|
1155
|
+
const row = await github.sourceControlStorage.sessions.getBySessionId(sessionId);
|
|
1156
|
+
if (!row || row.orgId !== resolved.tenant.orgId || row.userId !== resolved.tenant.userId) return c.json({ error: "Session not found" }, 404);
|
|
1157
|
+
if (!controller) return c.json({ error: "Sessions are not available on this server." }, 503);
|
|
1158
|
+
const thread = (await controller.queryThreads({ resourceId: sessionId })).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())[0];
|
|
1159
|
+
if (!thread) return c.json({ error: "This session has no conversation to name yet." }, 409);
|
|
1160
|
+
const stored = await memorySettings.get({
|
|
1161
|
+
orgId: row.orgId,
|
|
1162
|
+
userId: row.userId
|
|
1163
|
+
});
|
|
1164
|
+
const requestContext = new RequestContext();
|
|
1165
|
+
requestContext.set("user", {
|
|
1166
|
+
workosId: row.userId,
|
|
1167
|
+
organizationId: row.orgId
|
|
1168
|
+
});
|
|
1169
|
+
try {
|
|
1170
|
+
const title = await nameSession(sessionId, async () => {
|
|
1171
|
+
const generated = await controller.generateThreadTitle({
|
|
1172
|
+
threadId: thread.id,
|
|
1173
|
+
resourceId: sessionId,
|
|
1174
|
+
requestContext,
|
|
1175
|
+
...stored?.observerModelId ? { model: titleModel(stored.observerModelId) } : {}
|
|
1176
|
+
});
|
|
1177
|
+
const named = generated ? normalizeSessionTitle(generated) : null;
|
|
1178
|
+
if (named) await github.sourceControlStorage.sessions.rename({
|
|
1179
|
+
sessionId,
|
|
1180
|
+
title: named
|
|
1181
|
+
});
|
|
1182
|
+
return named;
|
|
1183
|
+
});
|
|
1184
|
+
if (!title) return c.json({ error: "The model returned an empty title. Try again." }, 502);
|
|
1185
|
+
return c.json({ title });
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}),
|
|
1032
1191
|
registerApiRoute("/web/github/projects/:id/commit", {
|
|
1033
1192
|
method: "POST",
|
|
1034
1193
|
requiresAuth: false,
|