@mastra/factory 0.10.0-alpha.8 → 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.
Files changed (53) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/dist/auth.d.ts.map +1 -1
  3. package/dist/auth.js +1 -0
  4. package/dist/auth.js.map +1 -1
  5. package/dist/factory.d.ts.map +1 -1
  6. package/dist/factory.js +1 -0
  7. package/dist/factory.js.map +1 -1
  8. package/dist/integrations/base.d.ts +3 -1
  9. package/dist/integrations/base.d.ts.map +1 -1
  10. package/dist/integrations/github/integration.d.ts +14 -0
  11. package/dist/integrations/github/integration.d.ts.map +1 -1
  12. package/dist/integrations/github/integration.js +47 -1
  13. package/dist/integrations/github/integration.js.map +1 -1
  14. package/dist/integrations/github/routes.d.ts +5 -1
  15. package/dist/integrations/github/routes.d.ts.map +1 -1
  16. package/dist/integrations/github/routes.js +155 -3
  17. package/dist/integrations/github/routes.js.map +1 -1
  18. package/dist/integrations/github/session-subscriptions.d.ts +9 -0
  19. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  20. package/dist/integrations/github/session-subscriptions.js +39 -1
  21. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  22. package/dist/integrations/linear/routes.d.ts.map +1 -1
  23. package/dist/integrations/linear/routes.js +50 -0
  24. package/dist/integrations/linear/routes.js.map +1 -1
  25. package/dist/integrations/platform/github/integration.d.ts +3 -1
  26. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  27. package/dist/integrations/platform/github/integration.js +32 -0
  28. package/dist/integrations/platform/github/integration.js.map +1 -1
  29. package/dist/routes/intake.d.ts +5 -0
  30. package/dist/routes/intake.d.ts.map +1 -1
  31. package/dist/routes/intake.js +70 -19
  32. package/dist/routes/intake.js.map +1 -1
  33. package/dist/routes/surface.d.ts +4 -2
  34. package/dist/routes/surface.d.ts.map +1 -1
  35. package/dist/routes/surface.js +1 -0
  36. package/dist/routes/surface.js.map +1 -1
  37. package/dist/rules/tools.d.ts.map +1 -1
  38. package/dist/rules/tools.js +9 -5
  39. package/dist/rules/tools.js.map +1 -1
  40. package/dist/rules/transition-service.d.ts +3 -1
  41. package/dist/rules/transition-service.d.ts.map +1 -1
  42. package/dist/rules/transition-service.js +14 -1
  43. package/dist/rules/transition-service.js.map +1 -1
  44. package/dist/rules/types.d.ts +4 -1
  45. package/dist/rules/types.d.ts.map +1 -1
  46. package/dist/rules/types.js +17 -1
  47. package/dist/rules/types.js.map +1 -1
  48. package/dist/storage/domains/work-items/base.d.ts +5 -0
  49. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  50. package/dist/storage/domains/work-items/base.js +17 -1
  51. package/dist/storage/domains/work-items/base.js.map +1 -1
  52. package/factory-skills/factory-triage/SKILL.md +7 -17
  53. package/package.json +9 -9
@@ -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
- function buildProjectGitRoutes({ github, auth, fleet, controller, memorySettings, emitAudit, sessionRetirement }) {
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
- return c.json({ sessions });
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", {