@mastra/factory 0.2.2-alpha.0 → 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.
- package/CHANGELOG.md +26 -0
- package/dist/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +22 -2
- package/dist/auth.js.map +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +411 -244
- package/dist/factory.js.map +1 -1
- package/dist/index.js +411 -244
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/integration.js +85 -37
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +85 -37
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +2 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +28 -8
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +119 -39
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +1 -4
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/surface.js +1 -4
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +7 -1
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/tools.js.map +1 -1
- package/dist/spa-static.d.ts.map +1 -1
- package/dist/spa-static.js +1 -0
- package/dist/spa-static.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +9 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +4 -0
- 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 +4 -0
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +20 -4
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/metrics.js.map +1 -1
- package/dist/timing.d.ts +15 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +27 -0
- package/dist/timing.js.map +1 -0
- package/dist/workspace.d.ts +2 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +104 -65
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-review/SKILL.md +9 -2
- package/package.json +8 -8
|
@@ -192,8 +192,23 @@ async function teardownProjectSandbox(options) {
|
|
|
192
192
|
function shellQuote(value) {
|
|
193
193
|
return `'` + value.split(`'`).join(`'\\''`) + `'`;
|
|
194
194
|
}
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
var DEFAULT_COMMAND_TIMEOUT_MS = 15 * 6e4;
|
|
196
|
+
var CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 6e4;
|
|
197
|
+
async function sh(sandbox, script, options = {}) {
|
|
198
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
|
|
199
|
+
let timer;
|
|
200
|
+
const hangGuard = new Promise((_, reject) => {
|
|
201
|
+
timer = setTimeout(() => {
|
|
202
|
+
const phase = options.phase ? ` during ${options.phase}` : "";
|
|
203
|
+
reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1e3)}s${phase}.`));
|
|
204
|
+
}, timeoutMs);
|
|
205
|
+
timer.unref?.();
|
|
206
|
+
});
|
|
207
|
+
try {
|
|
208
|
+
return await Promise.race([sandbox.executeCommand("sh", ["-c", script], { timeout: timeoutMs }), hangGuard]);
|
|
209
|
+
} finally {
|
|
210
|
+
clearTimeout(timer);
|
|
211
|
+
}
|
|
197
212
|
}
|
|
198
213
|
var MaterializeError = class extends Error {
|
|
199
214
|
constructor(message, code) {
|
|
@@ -230,7 +245,8 @@ async function materializeRepo(options) {
|
|
|
230
245
|
);
|
|
231
246
|
}
|
|
232
247
|
const authUrl = tokenUrl(repo, token);
|
|
233
|
-
const alreadyMaterialized =
|
|
248
|
+
const alreadyMaterialized = await hasExistingCheckout(sandbox, workdir, repo);
|
|
249
|
+
let succeeded = false;
|
|
234
250
|
try {
|
|
235
251
|
if (!alreadyMaterialized) {
|
|
236
252
|
reportProgress(onProgress, {
|
|
@@ -239,7 +255,8 @@ async function materializeRepo(options) {
|
|
|
239
255
|
});
|
|
240
256
|
const clone = await sh(
|
|
241
257
|
sandbox,
|
|
242
|
-
`git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}
|
|
258
|
+
`git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`,
|
|
259
|
+
{ phase: "repository clone" }
|
|
243
260
|
);
|
|
244
261
|
if (clone.exitCode !== 0) {
|
|
245
262
|
throw classifyGitFailure(clone, "clone-failed");
|
|
@@ -250,13 +267,14 @@ async function materializeRepo(options) {
|
|
|
250
267
|
if (setUrl.exitCode !== 0) {
|
|
251
268
|
throw new MaterializeError(`Failed to set git remote: ${setUrl.stderr}`, "pull-failed");
|
|
252
269
|
}
|
|
253
|
-
const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only
|
|
270
|
+
const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`, { phase: "repository pull" });
|
|
254
271
|
if (pull.exitCode !== 0) {
|
|
255
272
|
throw classifyGitFailure(pull, "pull-failed");
|
|
256
273
|
}
|
|
257
274
|
}
|
|
275
|
+
succeeded = true;
|
|
258
276
|
} finally {
|
|
259
|
-
await scrubRemote(sandbox, workdir, repo,
|
|
277
|
+
await scrubRemote(sandbox, workdir, repo, succeeded);
|
|
260
278
|
}
|
|
261
279
|
reportProgress(onProgress, { phase: "finalizing", message: "Finalizing workspace\u2026" });
|
|
262
280
|
await storage.markMaterialized({ id: sandboxRow.id });
|
|
@@ -1155,43 +1173,56 @@ function buildGithubRoutes(options) {
|
|
|
1155
1173
|
handler: async (c) => {
|
|
1156
1174
|
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
1157
1175
|
if ("response" in resolved) return resolved.response;
|
|
1158
|
-
const
|
|
1176
|
+
const orgId = resolved.tenant.orgId;
|
|
1177
|
+
const installs = await github.sourceControlStorage.installations.list({ orgId });
|
|
1159
1178
|
const query = (c.req.query("q") ?? "").toLowerCase();
|
|
1160
|
-
const
|
|
1179
|
+
const listed = await Promise.all(
|
|
1180
|
+
installs.map(async (inst) => {
|
|
1181
|
+
try {
|
|
1182
|
+
return { inst, list: await github.listInstallationRepos(Number(inst.externalId)) };
|
|
1183
|
+
} catch (err) {
|
|
1184
|
+
if (err.status !== 404) throw err;
|
|
1185
|
+
console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
|
|
1186
|
+
await github.sourceControlStorage.installations.delete({ orgId, id: inst.id });
|
|
1187
|
+
return { inst, list: [] };
|
|
1188
|
+
}
|
|
1189
|
+
})
|
|
1190
|
+
);
|
|
1191
|
+
const matches = [];
|
|
1161
1192
|
const seenRepositoryIds = /* @__PURE__ */ new Set();
|
|
1162
|
-
for (const inst of
|
|
1163
|
-
let list;
|
|
1164
|
-
try {
|
|
1165
|
-
list = await github.listInstallationRepos(Number(inst.externalId));
|
|
1166
|
-
} catch (err) {
|
|
1167
|
-
if (err.status !== 404) throw err;
|
|
1168
|
-
console.error(`[Mastra Factory] pruning stale GitHub installation ${inst.externalId} (404 from GitHub)`);
|
|
1169
|
-
await github.sourceControlStorage.installations.delete({ orgId: resolved.tenant.orgId, id: inst.id });
|
|
1170
|
-
continue;
|
|
1171
|
-
}
|
|
1193
|
+
for (const { inst, list } of listed) {
|
|
1172
1194
|
for (const repo of list) {
|
|
1173
1195
|
if (query && !repo.fullName.toLowerCase().includes(query)) continue;
|
|
1174
1196
|
if (seenRepositoryIds.has(repo.id)) continue;
|
|
1175
1197
|
seenRepositoryIds.add(repo.id);
|
|
1176
|
-
|
|
1177
|
-
orgId: resolved.tenant.orgId,
|
|
1178
|
-
input: {
|
|
1179
|
-
installationId: inst.id,
|
|
1180
|
-
externalId: repo.id.toString(),
|
|
1181
|
-
slug: repo.fullName,
|
|
1182
|
-
defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
|
|
1183
|
-
providerMetadata: { private: repo.private, owner: repo.owner }
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
repos.push({
|
|
1187
|
-
...repo,
|
|
1188
|
-
installationStorageId: inst.id,
|
|
1189
|
-
repositoryStorageId: repository.id,
|
|
1190
|
-
sandboxProvider: fleet.provider,
|
|
1191
|
-
sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
|
|
1192
|
-
});
|
|
1198
|
+
matches.push({ inst, repo });
|
|
1193
1199
|
}
|
|
1194
1200
|
}
|
|
1201
|
+
const repos = new Array(matches.length);
|
|
1202
|
+
const upsertConcurrency = 10;
|
|
1203
|
+
for (let start = 0; start < matches.length; start += upsertConcurrency) {
|
|
1204
|
+
await Promise.all(
|
|
1205
|
+
matches.slice(start, start + upsertConcurrency).map(async ({ inst, repo }, offset) => {
|
|
1206
|
+
const repository = await github.sourceControlStorage.repositories.upsert({
|
|
1207
|
+
orgId,
|
|
1208
|
+
input: {
|
|
1209
|
+
installationId: inst.id,
|
|
1210
|
+
externalId: repo.id.toString(),
|
|
1211
|
+
slug: repo.fullName,
|
|
1212
|
+
defaultBranch: isValidGitRef2(repo.defaultBranch) ? repo.defaultBranch : "main",
|
|
1213
|
+
providerMetadata: { private: repo.private, owner: repo.owner }
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
repos[start + offset] = {
|
|
1217
|
+
...repo,
|
|
1218
|
+
installationStorageId: inst.id,
|
|
1219
|
+
repositoryStorageId: repository.id,
|
|
1220
|
+
sandboxProvider: fleet.provider,
|
|
1221
|
+
sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
|
|
1222
|
+
};
|
|
1223
|
+
})
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1195
1226
|
return c.json({ repos });
|
|
1196
1227
|
}
|
|
1197
1228
|
})
|
|
@@ -1522,8 +1553,25 @@ async function loadOrCreateSandboxRow(github, project, userId) {
|
|
|
1522
1553
|
return github.sourceControlStorage.sandboxes.getOrCreate({ projectRepository: project, userId });
|
|
1523
1554
|
}
|
|
1524
1555
|
async function prepareProject(options) {
|
|
1525
|
-
const { github, fleet,
|
|
1526
|
-
|
|
1556
|
+
const { github, fleet, userId, onProgress } = options;
|
|
1557
|
+
let project = options.project;
|
|
1558
|
+
if (project.sandboxProvider !== fleet.provider) {
|
|
1559
|
+
const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);
|
|
1560
|
+
await github.sourceControlStorage.projectRepositories.update({
|
|
1561
|
+
orgId: project.installation.orgId,
|
|
1562
|
+
id: project.id,
|
|
1563
|
+
input: { sandboxProvider: fleet.provider, sandboxWorkdir }
|
|
1564
|
+
});
|
|
1565
|
+
project = { ...project, sandboxProvider: fleet.provider, sandboxWorkdir };
|
|
1566
|
+
}
|
|
1567
|
+
let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
|
|
1568
|
+
if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {
|
|
1569
|
+
await github.sourceControlStorage.sandboxes.setWorkdir({
|
|
1570
|
+
id: sandboxRow.id,
|
|
1571
|
+
sandboxWorkdir: project.sandboxWorkdir
|
|
1572
|
+
});
|
|
1573
|
+
sandboxRow = { ...sandboxRow, sandboxWorkdir: project.sandboxWorkdir, materializedAt: null };
|
|
1574
|
+
}
|
|
1527
1575
|
const access = await github.versionControl.getRepositoryAccess({
|
|
1528
1576
|
orgId: project.installation.orgId,
|
|
1529
1577
|
repositoryId: project.repository.id
|