@mastra/factory 0.10.0-alpha.9 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +227 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +1 -0
- package/dist/auth.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +1 -0
- package/dist/factory.js.map +1 -1
- package/dist/integrations/base.d.ts +3 -1
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/github/integration.d.ts +14 -0
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +47 -1
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/routes.d.ts +5 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +155 -3
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.d.ts +9 -0
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +39 -1
- package/dist/integrations/github/session-subscriptions.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 +3 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +32 -0
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/intake.d.ts +5 -0
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/intake.js +70 -19
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/surface.d.ts +4 -2
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +1 -0
- package/dist/routes/surface.js.map +1 -1
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +9 -5
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +3 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +14 -1
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +4 -1
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +17 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +5 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +17 -1
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/factory-skills/factory-triage/SKILL.md +7 -17
- package/package.json +7 -7
|
@@ -107,6 +107,11 @@ function parseListPage(raw) {
|
|
|
107
107
|
const page = Number(raw);
|
|
108
108
|
return page >= 1 ? page : null;
|
|
109
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
|
+
}
|
|
110
115
|
const VALID_ISSUE_LABEL_FILTERS = /* @__PURE__ */ new Set(["status: auto-triaged", "status: needs approval"]);
|
|
111
116
|
function parseIssueLabelFilter(raw) {
|
|
112
117
|
if (raw === void 0 || raw === "") return void 0;
|
|
@@ -207,7 +212,7 @@ async function ingestPolledEvents(events, ingestFactoryEvent) {
|
|
|
207
212
|
*/
|
|
208
213
|
function buildGithubRoutes(options) {
|
|
209
214
|
const routes = [];
|
|
210
|
-
const { auth, fleet, storage, github, stateSigner, controller, memorySettings, emitAudit, sessionRetirement } = options;
|
|
215
|
+
const { auth, users, fleet, storage, github, stateSigner, controller, memorySettings, emitAudit, sessionRetirement } = options;
|
|
211
216
|
const diagnostics = () => getGithubFeatureDiagnostics({
|
|
212
217
|
github,
|
|
213
218
|
auth,
|
|
@@ -530,6 +535,48 @@ function buildGithubRoutes(options) {
|
|
|
530
535
|
}
|
|
531
536
|
}
|
|
532
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
|
+
}));
|
|
533
580
|
routes.push(registerApiRoute("/web/github/projects/:id/prs", {
|
|
534
581
|
method: "GET",
|
|
535
582
|
requiresAuth: false,
|
|
@@ -577,6 +624,49 @@ function buildGithubRoutes(options) {
|
|
|
577
624
|
}
|
|
578
625
|
}
|
|
579
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
|
+
}));
|
|
580
670
|
routes.push(registerApiRoute("/web/github/projects/:id/settings", {
|
|
581
671
|
method: "GET",
|
|
582
672
|
requiresAuth: false,
|
|
@@ -685,6 +775,7 @@ function buildGithubRoutes(options) {
|
|
|
685
775
|
routes.push(...buildProjectGitRoutes({
|
|
686
776
|
github,
|
|
687
777
|
auth,
|
|
778
|
+
users,
|
|
688
779
|
fleet,
|
|
689
780
|
controller,
|
|
690
781
|
memorySettings,
|
|
@@ -919,8 +1010,62 @@ function titleModel(modelId) {
|
|
|
919
1010
|
requestContext
|
|
920
1011
|
});
|
|
921
1012
|
}
|
|
922
|
-
|
|
1013
|
+
const MAX_SESSION_OWNER_PROFILES = 100;
|
|
1014
|
+
const MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES = 500;
|
|
1015
|
+
const SESSION_OWNER_PROFILE_TTL_MS = 5 * 6e4;
|
|
1016
|
+
function createSessionOwnerProfileResolver(users) {
|
|
1017
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1018
|
+
const cacheProfile = (userId, profile, expiresAt) => {
|
|
1019
|
+
cache.delete(userId);
|
|
1020
|
+
cache.set(userId, {
|
|
1021
|
+
profile,
|
|
1022
|
+
expiresAt
|
|
1023
|
+
});
|
|
1024
|
+
if (cache.size > MAX_SESSION_OWNER_PROFILE_CACHE_ENTRIES) {
|
|
1025
|
+
const oldestUserId = cache.keys().next().value;
|
|
1026
|
+
if (oldestUserId !== void 0) cache.delete(oldestUserId);
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
return async (userIds) => {
|
|
1030
|
+
if (!users) return /* @__PURE__ */ new Map();
|
|
1031
|
+
const requestedUserIds = [...new Set(userIds)].slice(0, MAX_SESSION_OWNER_PROFILES);
|
|
1032
|
+
const profiles = /* @__PURE__ */ new Map();
|
|
1033
|
+
const unresolvedUserIds = [];
|
|
1034
|
+
const now = Date.now();
|
|
1035
|
+
for (const userId of requestedUserIds) {
|
|
1036
|
+
const cached = cache.get(userId);
|
|
1037
|
+
if (!cached || cached.expiresAt <= now) {
|
|
1038
|
+
cache.delete(userId);
|
|
1039
|
+
unresolvedUserIds.push(userId);
|
|
1040
|
+
} else if (cached.profile) profiles.set(userId, cached.profile);
|
|
1041
|
+
}
|
|
1042
|
+
if (unresolvedUserIds.length === 0) return profiles;
|
|
1043
|
+
let resolvedUsers;
|
|
1044
|
+
if (users.getUsers) try {
|
|
1045
|
+
resolvedUsers = await users.getUsers(unresolvedUserIds);
|
|
1046
|
+
} catch (error) {
|
|
1047
|
+
console.warn("[GitHub Sessions] Bulk session owner profile lookup failed; falling back to individual lookups", { error: error instanceof Error ? error.message : String(error) });
|
|
1048
|
+
resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map((userId) => users.getUser(userId)))).filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
1049
|
+
}
|
|
1050
|
+
else resolvedUsers = (await Promise.allSettled(unresolvedUserIds.map((userId) => users.getUser(userId)))).filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
1051
|
+
for (const user of resolvedUsers) {
|
|
1052
|
+
if (!user) continue;
|
|
1053
|
+
const name = user.name?.trim() || user.email?.trim();
|
|
1054
|
+
if (!name) continue;
|
|
1055
|
+
profiles.set(user.id, {
|
|
1056
|
+
id: user.id,
|
|
1057
|
+
name,
|
|
1058
|
+
...user.avatarUrl ? { avatarUrl: user.avatarUrl } : {}
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
const expiresAt = now + SESSION_OWNER_PROFILE_TTL_MS;
|
|
1062
|
+
for (const userId of unresolvedUserIds) cacheProfile(userId, profiles.get(userId), expiresAt);
|
|
1063
|
+
return profiles;
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
function buildProjectGitRoutes({ github, auth, users, fleet, controller, memorySettings, emitAudit, sessionRetirement }) {
|
|
923
1067
|
const nameSession = createSessionNaming();
|
|
1068
|
+
const resolveSessionOwnerProfiles = createSessionOwnerProfileResolver(users);
|
|
924
1069
|
return [
|
|
925
1070
|
registerApiRoute("/web/github/projects/:id/sessions", {
|
|
926
1071
|
method: "GET",
|
|
@@ -940,7 +1085,14 @@ function buildProjectGitRoutes({ github, auth, fleet, controller, memorySettings
|
|
|
940
1085
|
projectRepositoryId: project.id,
|
|
941
1086
|
viewerUserId: userId
|
|
942
1087
|
});
|
|
943
|
-
|
|
1088
|
+
const owners = await resolveSessionOwnerProfiles(sessions.map((session) => session.userId));
|
|
1089
|
+
return c.json({ sessions: sessions.map((session) => {
|
|
1090
|
+
const owner = owners.get(session.userId);
|
|
1091
|
+
return {
|
|
1092
|
+
...session,
|
|
1093
|
+
...owner ? { owner } : {}
|
|
1094
|
+
};
|
|
1095
|
+
}) });
|
|
944
1096
|
}
|
|
945
1097
|
}),
|
|
946
1098
|
registerApiRoute("/web/github/projects/:id/sessions", {
|