@mastra/factory 0.2.1 → 0.2.2-alpha.1

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 (59) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/auth.d.ts +2 -2
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +22 -2
  5. package/dist/auth.js.map +1 -1
  6. package/dist/factory.d.ts.map +1 -1
  7. package/dist/factory.js +411 -244
  8. package/dist/factory.js.map +1 -1
  9. package/dist/index.js +411 -244
  10. package/dist/index.js.map +1 -1
  11. package/dist/integrations/github/integration.js +85 -37
  12. package/dist/integrations/github/integration.js.map +1 -1
  13. package/dist/integrations/github/routes.d.ts.map +1 -1
  14. package/dist/integrations/github/routes.js +85 -37
  15. package/dist/integrations/github/routes.js.map +1 -1
  16. package/dist/integrations/github/sandbox.d.ts +2 -0
  17. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  18. package/dist/integrations/github/sandbox.js +28 -8
  19. package/dist/integrations/github/sandbox.js.map +1 -1
  20. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  21. package/dist/integrations/platform/github/integration.js +119 -39
  22. package/dist/integrations/platform/github/integration.js.map +1 -1
  23. package/dist/routes/config.d.ts.map +1 -1
  24. package/dist/routes/config.js +1 -4
  25. package/dist/routes/config.js.map +1 -1
  26. package/dist/routes/surface.js +1 -4
  27. package/dist/routes/surface.js.map +1 -1
  28. package/dist/routes/work-items.js.map +1 -1
  29. package/dist/rules/binding-context.js.map +1 -1
  30. package/dist/rules/dispatcher.d.ts.map +1 -1
  31. package/dist/rules/dispatcher.js +7 -1
  32. package/dist/rules/dispatcher.js.map +1 -1
  33. package/dist/rules/processor.js.map +1 -1
  34. package/dist/rules/tools.js.map +1 -1
  35. package/dist/spa-static.d.ts.map +1 -1
  36. package/dist/spa-static.js +1 -0
  37. package/dist/spa-static.js.map +1 -1
  38. package/dist/storage/domains/source-control/base.d.ts +9 -0
  39. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  40. package/dist/storage/domains/source-control/base.js +4 -0
  41. package/dist/storage/domains/source-control/base.js.map +1 -1
  42. package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
  43. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  44. package/dist/storage/domains/source-control/inmemory.js +4 -0
  45. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  46. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  47. package/dist/storage/domains/work-items/base.js +20 -4
  48. package/dist/storage/domains/work-items/base.js.map +1 -1
  49. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  50. package/dist/timing.d.ts +15 -0
  51. package/dist/timing.d.ts.map +1 -0
  52. package/dist/timing.js +27 -0
  53. package/dist/timing.js.map +1 -0
  54. package/dist/workspace.d.ts +2 -3
  55. package/dist/workspace.d.ts.map +1 -1
  56. package/dist/workspace.js +104 -65
  57. package/dist/workspace.js.map +1 -1
  58. package/factory-skills/factory-review/SKILL.md +9 -2
  59. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAuD,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AASrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAwC1D,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAgB/G,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,iEAAiE;IACjE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC3F,6EAA6E;IAC7E,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAuPD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CA4oB/E"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAuD,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AASrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAwC1D,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAgB/G,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,UAAU,CAAC,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC7C,iEAAiE;IACjE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC3F,6EAA6E;IAC7E,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAuPD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CAkqB/E"}
@@ -110,8 +110,23 @@ async function teardownProjectSandbox(options) {
110
110
  function shellQuote(value) {
111
111
  return `'` + value.split(`'`).join(`'\\''`) + `'`;
112
112
  }
113
- async function sh(sandbox, script) {
114
- return sandbox.executeCommand("sh", ["-c", script]);
113
+ var DEFAULT_COMMAND_TIMEOUT_MS = 15 * 6e4;
114
+ var CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 6e4;
115
+ async function sh(sandbox, script, options = {}) {
116
+ const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
117
+ let timer;
118
+ const hangGuard = new Promise((_, reject) => {
119
+ timer = setTimeout(() => {
120
+ const phase = options.phase ? ` during ${options.phase}` : "";
121
+ reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1e3)}s${phase}.`));
122
+ }, timeoutMs);
123
+ timer.unref?.();
124
+ });
125
+ try {
126
+ return await Promise.race([sandbox.executeCommand("sh", ["-c", script], { timeout: timeoutMs }), hangGuard]);
127
+ } finally {
128
+ clearTimeout(timer);
129
+ }
115
130
  }
116
131
  var MaterializeError = class extends Error {
117
132
  constructor(message, code) {
@@ -148,7 +163,8 @@ async function materializeRepo(options) {
148
163
  );
149
164
  }
150
165
  const authUrl = tokenUrl(repo, token);
151
- const alreadyMaterialized = Boolean(sandboxRow.materializedAt) || await hasExistingCheckout(sandbox, workdir, repo);
166
+ const alreadyMaterialized = await hasExistingCheckout(sandbox, workdir, repo);
167
+ let succeeded = false;
152
168
  try {
153
169
  if (!alreadyMaterialized) {
154
170
  reportProgress(onProgress, {
@@ -157,7 +173,8 @@ async function materializeRepo(options) {
157
173
  });
158
174
  const clone = await sh(
159
175
  sandbox,
160
- `git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`
176
+ `git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`,
177
+ { phase: "repository clone" }
161
178
  );
162
179
  if (clone.exitCode !== 0) {
163
180
  throw classifyGitFailure(clone, "clone-failed");
@@ -168,13 +185,14 @@ async function materializeRepo(options) {
168
185
  if (setUrl.exitCode !== 0) {
169
186
  throw new MaterializeError(`Failed to set git remote: ${setUrl.stderr}`, "pull-failed");
170
187
  }
171
- const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`);
188
+ const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`, { phase: "repository pull" });
172
189
  if (pull.exitCode !== 0) {
173
190
  throw classifyGitFailure(pull, "pull-failed");
174
191
  }
175
192
  }
193
+ succeeded = true;
176
194
  } finally {
177
- await scrubRemote(sandbox, workdir, repo, alreadyMaterialized);
195
+ await scrubRemote(sandbox, workdir, repo, succeeded);
178
196
  }
179
197
  reportProgress(onProgress, { phase: "finalizing", message: "Finalizing workspace\u2026" });
180
198
  await storage.markMaterialized({ id: sandboxRow.id });
@@ -1069,43 +1087,56 @@ function buildGithubRoutes(options) {
1069
1087
  handler: async (c) => {
1070
1088
  const resolved = await resolveOrgTenant(loose(c), auth);
1071
1089
  if ("response" in resolved) return resolved.response;
1072
- const installs = await github.sourceControlStorage.installations.list({ orgId: resolved.tenant.orgId });
1090
+ const orgId = resolved.tenant.orgId;
1091
+ const installs = await github.sourceControlStorage.installations.list({ orgId });
1073
1092
  const query = (c.req.query("q") ?? "").toLowerCase();
1074
- const repos = [];
1093
+ const listed = await Promise.all(
1094
+ installs.map(async (inst) => {
1095
+ try {
1096
+ return { inst, list: await github.listInstallationRepos(Number(inst.externalId)) };
1097
+ } catch (err) {
1098
+ if (err.status !== 404) throw err;
1099
+ console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
1100
+ await github.sourceControlStorage.installations.delete({ orgId, id: inst.id });
1101
+ return { inst, list: [] };
1102
+ }
1103
+ })
1104
+ );
1105
+ const matches = [];
1075
1106
  const seenRepositoryIds = /* @__PURE__ */ new Set();
1076
- for (const inst of installs) {
1077
- let list;
1078
- try {
1079
- list = await github.listInstallationRepos(Number(inst.externalId));
1080
- } catch (err) {
1081
- if (err.status !== 404) throw err;
1082
- console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
1083
- await github.sourceControlStorage.installations.delete({ orgId: resolved.tenant.orgId, id: inst.id });
1084
- continue;
1085
- }
1107
+ for (const { inst, list } of listed) {
1086
1108
  for (const repo of list) {
1087
1109
  if (query && !repo.fullName.toLowerCase().includes(query)) continue;
1088
1110
  if (seenRepositoryIds.has(repo.id)) continue;
1089
1111
  seenRepositoryIds.add(repo.id);
1090
- const repository = await github.sourceControlStorage.repositories.upsert({
1091
- orgId: resolved.tenant.orgId,
1092
- input: {
1093
- installationId: inst.id,
1094
- externalId: repo.id.toString(),
1095
- slug: repo.fullName,
1096
- defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
1097
- providerMetadata: { private: repo.private, owner: repo.owner }
1098
- }
1099
- });
1100
- repos.push({
1101
- ...repo,
1102
- installationStorageId: inst.id,
1103
- repositoryStorageId: repository.id,
1104
- sandboxProvider: fleet.provider,
1105
- sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
1106
- });
1112
+ matches.push({ inst, repo });
1107
1113
  }
1108
1114
  }
1115
+ const repos = new Array(matches.length);
1116
+ const upsertConcurrency = 10;
1117
+ for (let start = 0; start < matches.length; start += upsertConcurrency) {
1118
+ await Promise.all(
1119
+ matches.slice(start, start + upsertConcurrency).map(async ({ inst, repo }, offset) => {
1120
+ const repository = await github.sourceControlStorage.repositories.upsert({
1121
+ orgId,
1122
+ input: {
1123
+ installationId: inst.id,
1124
+ externalId: repo.id.toString(),
1125
+ slug: repo.fullName,
1126
+ defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
1127
+ providerMetadata: { private: repo.private, owner: repo.owner }
1128
+ }
1129
+ });
1130
+ repos[start + offset] = {
1131
+ ...repo,
1132
+ installationStorageId: inst.id,
1133
+ repositoryStorageId: repository.id,
1134
+ sandboxProvider: fleet.provider,
1135
+ sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
1136
+ };
1137
+ })
1138
+ );
1139
+ }
1109
1140
  return c.json({ repos });
1110
1141
  }
1111
1142
  })
@@ -1436,8 +1467,25 @@ async function loadOrCreateSandboxRow(github, project, userId) {
1436
1467
  return github.sourceControlStorage.sandboxes.getOrCreate({ projectRepository: project, userId });
1437
1468
  }
1438
1469
  async function prepareProject(options) {
1439
- const { github, fleet, project, userId, onProgress } = options;
1440
- const sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
1470
+ const { github, fleet, userId, onProgress } = options;
1471
+ let project = options.project;
1472
+ if (project.sandboxProvider !== fleet.provider) {
1473
+ const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);
1474
+ await github.sourceControlStorage.projectRepositories.update({
1475
+ orgId: project.installation.orgId,
1476
+ id: project.id,
1477
+ input: { sandboxProvider: fleet.provider, sandboxWorkdir }
1478
+ });
1479
+ project = { ...project, sandboxProvider: fleet.provider, sandboxWorkdir };
1480
+ }
1481
+ let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
1482
+ if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {
1483
+ await github.sourceControlStorage.sandboxes.setWorkdir({
1484
+ id: sandboxRow.id,
1485
+ sandboxWorkdir: project.sandboxWorkdir
1486
+ });
1487
+ sandboxRow = { ...sandboxRow, sandboxWorkdir: project.sandboxWorkdir, materializedAt: null };
1488
+ }
1441
1489
  const access = await github.versionControl.getRepositoryAccess({
1442
1490
  orgId: project.installation.orgId,
1443
1491
  repositoryId: project.repository.id