@mastra/factory 0.11.1 → 0.12.0-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 +59 -0
- package/dist/factory.d.ts +2 -22
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +21 -59
- package/dist/factory.js.map +1 -1
- package/dist/feed-events.d.ts +13 -0
- package/dist/feed-events.d.ts.map +1 -0
- package/dist/feed-events.js +25 -0
- package/dist/feed-events.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/integrations/base.d.ts +5 -13
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/github/config.d.ts +4 -4
- package/dist/integrations/github/config.d.ts.map +1 -1
- package/dist/integrations/github/config.js +3 -3
- package/dist/integrations/github/config.js.map +1 -1
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +2 -4
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/reconcile-worker.d.ts +0 -5
- package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
- package/dist/integrations/github/reconcile-worker.js +1 -8
- package/dist/integrations/github/reconcile-worker.js.map +1 -1
- package/dist/integrations/github/routes.d.ts +6 -5
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +36 -263
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/sandbox-release.d.ts +17 -47
- package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
- package/dist/integrations/github/sandbox-release.js +24 -103
- package/dist/integrations/github/sandbox-release.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +25 -139
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +24 -212
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/webhook.d.ts.map +1 -1
- package/dist/integrations/github/webhook.js +1 -2
- package/dist/integrations/github/webhook.js.map +1 -1
- package/dist/integrations/issue-reconcile-worker.js +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts +0 -2
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +1 -8
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +5 -7
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/linear/event-worker.js +1 -1
- package/dist/routes/attention-activity.d.ts +24 -0
- package/dist/routes/attention-activity.d.ts.map +1 -0
- package/dist/routes/attention-activity.js +143 -0
- package/dist/routes/attention-activity.js.map +1 -0
- package/dist/routes/attention-providers.d.ts +31 -1
- package/dist/routes/attention-providers.d.ts.map +1 -1
- package/dist/routes/attention-providers.js +4 -4
- package/dist/routes/attention-providers.js.map +1 -1
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js +39 -11
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +3 -1
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/fs.d.ts +4 -6
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +28 -34
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/skills.d.ts.map +1 -1
- package/dist/routes/skills.js +6 -3
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/surface.d.ts +4 -9
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +3 -5
- package/dist/routes/surface.js.map +1 -1
- package/dist/sandbox/materialization.d.ts +36 -0
- package/dist/sandbox/materialization.d.ts.map +1 -0
- package/dist/sandbox/materialization.js +18 -0
- package/dist/sandbox/materialization.js.map +1 -0
- package/dist/sandbox/session-retirement.d.ts +8 -6
- package/dist/sandbox/session-retirement.d.ts.map +1 -1
- package/dist/sandbox/session-retirement.js +28 -123
- package/dist/sandbox/session-retirement.js.map +1 -1
- package/dist/sandbox/session-sandbox.d.ts +117 -0
- package/dist/sandbox/session-sandbox.d.ts.map +1 -0
- package/dist/sandbox/session-sandbox.js +132 -0
- package/dist/sandbox/session-sandbox.js.map +1 -0
- package/dist/sandbox/workdir.d.ts +30 -0
- package/dist/sandbox/workdir.d.ts.map +1 -0
- package/dist/sandbox/workdir.js +48 -0
- package/dist/sandbox/workdir.js.map +1 -0
- package/dist/session/filesystem-capture.d.ts +2 -1
- package/dist/session/filesystem-capture.d.ts.map +1 -1
- package/dist/session/filesystem-capture.js +45 -4
- package/dist/session/filesystem-capture.js.map +1 -1
- package/dist/session/first-exec-capture.d.ts +1 -0
- package/dist/session/first-exec-capture.d.ts.map +1 -1
- package/dist/session/first-exec-capture.js +1 -1
- package/dist/session/first-exec-capture.js.map +1 -1
- package/dist/storage/domains/comments/activity.d.ts +40 -0
- package/dist/storage/domains/comments/activity.d.ts.map +1 -0
- package/dist/storage/domains/comments/activity.js +94 -0
- package/dist/storage/domains/comments/activity.js.map +1 -0
- package/dist/storage/domains/comments/base.d.ts +13 -1
- package/dist/storage/domains/comments/base.d.ts.map +1 -1
- package/dist/storage/domains/comments/base.js +41 -3
- package/dist/storage/domains/comments/base.js.map +1 -1
- package/dist/storage/domains/comments/domain.d.ts +4 -1
- package/dist/storage/domains/comments/domain.d.ts.map +1 -1
- package/dist/storage/domains/comments/domain.js +17 -5
- package/dist/storage/domains/comments/domain.js.map +1 -1
- package/dist/storage/domains/comments/parse.d.ts +1 -0
- package/dist/storage/domains/comments/parse.d.ts.map +1 -1
- package/dist/storage/domains/comments/parse.js +2 -2
- package/dist/storage/domains/comments/parse.js.map +1 -1
- package/dist/storage/domains/comments/routes.d.ts +2 -0
- package/dist/storage/domains/comments/routes.d.ts.map +1 -1
- package/dist/storage/domains/comments/routes.js +49 -3
- package/dist/storage/domains/comments/routes.js.map +1 -1
- package/dist/storage/domains/comments/schema.d.ts +1 -0
- package/dist/storage/domains/comments/schema.d.ts.map +1 -1
- package/dist/storage/domains/comments/schema.js +45 -1
- package/dist/storage/domains/comments/schema.js.map +1 -1
- package/dist/storage/domains/integrations/base.d.ts +1 -1
- package/dist/storage/domains/integrations/base.js +1 -1
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +0 -144
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +3 -290
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +1 -63
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +0 -89
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +14 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +60 -11
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/workspace.d.ts +5 -37
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +107 -245
- package/dist/workspace.js.map +1 -1
- package/package.json +6 -6
- package/dist/sandbox/base-checkpoint-triggers.d.ts +0 -77
- package/dist/sandbox/base-checkpoint-triggers.d.ts.map +0 -1
- package/dist/sandbox/base-checkpoint-triggers.js +0 -137
- package/dist/sandbox/base-checkpoint-triggers.js.map +0 -1
- package/dist/sandbox/base-checkpoint.d.ts +0 -59
- package/dist/sandbox/base-checkpoint.d.ts.map +0 -1
- package/dist/sandbox/base-checkpoint.js +0 -145
- package/dist/sandbox/base-checkpoint.js.map +0 -1
- package/dist/sandbox/fleet.d.ts +0 -258
- package/dist/sandbox/fleet.d.ts.map +0 -1
- package/dist/sandbox/fleet.js +0 -356
- package/dist/sandbox/fleet.js.map +0 -1
- package/dist/sandbox/reattach.d.ts +0 -3
- package/dist/sandbox/reattach.d.ts.map +0 -1
- package/dist/sandbox/reattach.js +0 -16
- package/dist/sandbox/reattach.js.map +0 -1
|
@@ -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;AAG1D,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
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;AAG1D,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAInF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAC3F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAQrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAgBxD,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,SAAS,CAAC;IAChB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,wBAAwB,CAAC;IACjC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,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,gGAAgG;IAChG,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IACnD,6EAA6E;IAC7E,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,qCAAqC,EAAE,4BAA4B,CAAC;IAC/F,kFAAkF;IAClF,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO,0CAA0C,EAAE,gBAAgB,EAAE,wBAAwB,CAAC,CAAC;IAChH,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AA4ND;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CAypB/E;AAiHD,KAAK,wBAAwB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC"}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { clearGithubPat,
|
|
1
|
+
import { clearGithubPat, getGithubPatStatus, setGithubPat } from "./pat.js";
|
|
2
2
|
import { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from "./subscriptions.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { requireExec } from "../../sandbox/materialization.js";
|
|
4
|
+
import { sanitizeSegment } from "../../sandbox/workdir.js";
|
|
5
|
+
import { peekSessionSandbox } from "../../sandbox/session-sandbox.js";
|
|
6
6
|
import { normalizeSessionTitle } from "../../session/session-title.js";
|
|
7
7
|
import { getGithubFeatureDiagnostics, isGithubFeatureEnabled } from "./config.js";
|
|
8
8
|
import { reclaimDeletedSessionSandbox } from "./sandbox-release.js";
|
|
9
|
+
import { MaterializeError, SetupCommandError, commitAll, isValidGitRef as isValidGitRef$1, pushBranch } from "./sandbox.js";
|
|
9
10
|
import { handleGithubWebhook } from "./webhook.js";
|
|
10
11
|
import { registerApiRoute } from "@mastra/core/server";
|
|
11
12
|
import { randomUUID } from "crypto";
|
|
12
13
|
import { UniqueViolationError } from "@mastra/core/storage";
|
|
13
14
|
import { resolveModel } from "@mastra/code-sdk/agents/model";
|
|
14
15
|
import { RequestContext } from "@mastra/core/request-context";
|
|
15
|
-
import { streamSSE } from "hono/streaming";
|
|
16
16
|
//#region src/integrations/github/routes.ts
|
|
17
17
|
/**
|
|
18
18
|
* Mastra `apiRoutes` for the GitHub App project feature.
|
|
@@ -212,13 +212,13 @@ async function ingestPolledEvents(events, ingestFactoryEvent) {
|
|
|
212
212
|
*/
|
|
213
213
|
function buildGithubRoutes(options) {
|
|
214
214
|
const routes = [];
|
|
215
|
-
const { auth,
|
|
215
|
+
const { auth, sandbox, users, storage, github, stateSigner, controller, memorySettings, emitAudit, sessionRetirement, workItems } = options;
|
|
216
216
|
const diagnostics = () => getGithubFeatureDiagnostics({
|
|
217
217
|
github,
|
|
218
218
|
auth,
|
|
219
219
|
appDbConfigured: storage !== void 0,
|
|
220
220
|
stateSigner,
|
|
221
|
-
|
|
221
|
+
sandbox
|
|
222
222
|
});
|
|
223
223
|
routes.push(registerApiRoute("/web/github/status", {
|
|
224
224
|
method: "GET",
|
|
@@ -242,7 +242,7 @@ function buildGithubRoutes(options) {
|
|
|
242
242
|
}, 401);
|
|
243
243
|
if (!tenant.orgId) return c.json({
|
|
244
244
|
enabled: true,
|
|
245
|
-
sandboxEnabled:
|
|
245
|
+
sandboxEnabled: !!sandbox,
|
|
246
246
|
organizationRequired: true,
|
|
247
247
|
connected: false,
|
|
248
248
|
installations: [],
|
|
@@ -253,7 +253,7 @@ function buildGithubRoutes(options) {
|
|
|
253
253
|
const connected = rows.length > 0;
|
|
254
254
|
return c.json({
|
|
255
255
|
enabled: true,
|
|
256
|
-
sandboxEnabled:
|
|
256
|
+
sandboxEnabled: !!sandbox,
|
|
257
257
|
connected,
|
|
258
258
|
installations: rows.map((r) => ({
|
|
259
259
|
installationId: Number(r.externalId),
|
|
@@ -423,69 +423,13 @@ function buildGithubRoutes(options) {
|
|
|
423
423
|
...repo,
|
|
424
424
|
installationStorageId: inst.id,
|
|
425
425
|
repositoryStorageId: repository.id,
|
|
426
|
-
sandboxProvider:
|
|
427
|
-
sandboxWorkdir:
|
|
426
|
+
sandboxProvider: sandbox ? "custom" : "none",
|
|
427
|
+
sandboxWorkdir: `~/${sanitizeSegment(repo.fullName.split("/", 2)[1] || "repo")}`
|
|
428
428
|
};
|
|
429
429
|
}));
|
|
430
430
|
return c.json({ repos });
|
|
431
431
|
}
|
|
432
432
|
}));
|
|
433
|
-
routes.push(registerApiRoute("/web/github/projects/:id/ensure", {
|
|
434
|
-
method: "POST",
|
|
435
|
-
requiresAuth: false,
|
|
436
|
-
handler: async (c) => {
|
|
437
|
-
const resolved = await resolveOrgTenant(loose(c), auth);
|
|
438
|
-
if ("response" in resolved) return resolved.response;
|
|
439
|
-
const { orgId, userId } = resolved.tenant;
|
|
440
|
-
if (!fleet.enabled) return c.json({
|
|
441
|
-
error: "sandbox_not_configured",
|
|
442
|
-
message: "No sandbox provider is configured."
|
|
443
|
-
}, 503);
|
|
444
|
-
const projectRepositoryId = c.req.param("id");
|
|
445
|
-
if (!projectRepositoryId) return c.json({ error: "Project repository not found" }, 404);
|
|
446
|
-
const project = await resolveProjectRepository({
|
|
447
|
-
github,
|
|
448
|
-
orgId,
|
|
449
|
-
projectRepositoryId
|
|
450
|
-
});
|
|
451
|
-
if (!project) return c.json({ error: "Project repository not found" }, 404);
|
|
452
|
-
if ((c.req.header("accept") ?? "").includes("text/event-stream")) return streamSSE(loose(c), async (stream) => {
|
|
453
|
-
try {
|
|
454
|
-
const result = await prepareProject({
|
|
455
|
-
github,
|
|
456
|
-
fleet,
|
|
457
|
-
project,
|
|
458
|
-
userId,
|
|
459
|
-
onProgress: (ev) => void stream.writeSSE({
|
|
460
|
-
event: "progress",
|
|
461
|
-
data: JSON.stringify(ev)
|
|
462
|
-
})
|
|
463
|
-
});
|
|
464
|
-
await stream.writeSSE({
|
|
465
|
-
event: "done",
|
|
466
|
-
data: JSON.stringify(result)
|
|
467
|
-
});
|
|
468
|
-
} catch (err) {
|
|
469
|
-
await stream.writeSSE({
|
|
470
|
-
event: "error",
|
|
471
|
-
data: JSON.stringify(ensureErrorPayload(err).body)
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
try {
|
|
476
|
-
const result = await prepareProject({
|
|
477
|
-
github,
|
|
478
|
-
fleet,
|
|
479
|
-
project,
|
|
480
|
-
userId
|
|
481
|
-
});
|
|
482
|
-
return c.json(result);
|
|
483
|
-
} catch (err) {
|
|
484
|
-
const { status, body } = ensureErrorPayload(err);
|
|
485
|
-
return c.json(body, status);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
}));
|
|
489
433
|
routes.push(registerApiRoute("/web/github/projects/:id/issues", {
|
|
490
434
|
method: "GET",
|
|
491
435
|
requiresAuth: false,
|
|
@@ -775,8 +719,8 @@ function buildGithubRoutes(options) {
|
|
|
775
719
|
routes.push(...buildProjectGitRoutes({
|
|
776
720
|
github,
|
|
777
721
|
auth,
|
|
722
|
+
sandbox,
|
|
778
723
|
users,
|
|
779
|
-
fleet,
|
|
780
724
|
controller,
|
|
781
725
|
memorySettings,
|
|
782
726
|
emitAudit,
|
|
@@ -817,135 +761,12 @@ function identityFromUser(user) {
|
|
|
817
761
|
email: u?.email ?? null
|
|
818
762
|
};
|
|
819
763
|
}
|
|
820
|
-
/**
|
|
821
|
-
* Resolve a live, started sandbox for the caller's per-user sandbox binding. The
|
|
822
|
-
* sandbox must already have been provisioned (`sandboxId` set) — the git write
|
|
823
|
-
* routes never clone, they operate on the existing checkout.
|
|
824
|
-
*/
|
|
825
|
-
async function resolveProjectSandbox(options) {
|
|
826
|
-
const { fleet, sandboxRow } = options;
|
|
827
|
-
if (!sandboxRow.sandboxId) throw new MaterializeError("Project sandbox is not provisioned. Open the project first.", "clone-failed");
|
|
828
|
-
return fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* Load (or create) the caller's per-(project,user) sandbox binding row. The
|
|
832
|
-
* binding inherits its workdir from the org-owned project, but `sandboxId` /
|
|
833
|
-
* `materializedAt` stay null until the user first opens the project.
|
|
834
|
-
*/
|
|
835
|
-
async function loadOrCreateSandboxRow(github, project, userId) {
|
|
836
|
-
return github.sourceControlStorage.sandboxes.getOrCreate({
|
|
837
|
-
projectRepository: project,
|
|
838
|
-
userId
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Provision/reattach the caller's sandbox and materialize the repo into it,
|
|
843
|
-
* emitting coarse progress events as each server step happens. Shared by both
|
|
844
|
-
* the JSON and SSE variants of the `/ensure` route. Throws on failure so the
|
|
845
|
-
* caller can shape the response (HTTP status vs SSE `error` event).
|
|
846
|
-
*/
|
|
847
|
-
async function prepareProject(options) {
|
|
848
|
-
const { github, fleet, userId, onProgress } = options;
|
|
849
|
-
let project = options.project;
|
|
850
|
-
if (project.sandboxProvider !== fleet.provider) {
|
|
851
|
-
const sandboxWorkdir = fleet.computeWorkdir(project.repository.slug);
|
|
852
|
-
await github.sourceControlStorage.projectRepositories.update({
|
|
853
|
-
orgId: project.installation.orgId,
|
|
854
|
-
id: project.id,
|
|
855
|
-
input: {
|
|
856
|
-
sandboxProvider: fleet.provider,
|
|
857
|
-
sandboxWorkdir
|
|
858
|
-
}
|
|
859
|
-
});
|
|
860
|
-
project = {
|
|
861
|
-
...project,
|
|
862
|
-
sandboxProvider: fleet.provider,
|
|
863
|
-
sandboxWorkdir
|
|
864
|
-
};
|
|
865
|
-
}
|
|
866
|
-
let sandboxRow = await loadOrCreateSandboxRow(github, project, userId);
|
|
867
|
-
if (sandboxRow.sandboxWorkdir !== project.sandboxWorkdir) {
|
|
868
|
-
await github.sourceControlStorage.sandboxes.setWorkdir({
|
|
869
|
-
id: sandboxRow.id,
|
|
870
|
-
sandboxWorkdir: project.sandboxWorkdir
|
|
871
|
-
});
|
|
872
|
-
sandboxRow = {
|
|
873
|
-
...sandboxRow,
|
|
874
|
-
sandboxWorkdir: project.sandboxWorkdir,
|
|
875
|
-
materializedAt: null
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
const access = await github.versionControl.getRepositoryAccess({
|
|
879
|
-
orgId: project.installation.orgId,
|
|
880
|
-
repositoryId: project.repository.id
|
|
881
|
-
});
|
|
882
|
-
if (!access.authorization) throw new MaterializeError("Repository access did not include a bearer token.", "clone-failed");
|
|
883
|
-
const ghCliToken = await getGithubPat(() => github.integrationStorage, project.installation.orgId) ?? access.authorization.token;
|
|
884
|
-
const seedCheckpointName = project.baseCheckpoint && !baseCheckpointIsStale(project) ? project.baseCheckpoint.name : void 0;
|
|
885
|
-
const sandbox = await ensureProjectSandbox({
|
|
886
|
-
fleet,
|
|
887
|
-
row: sandboxRow,
|
|
888
|
-
storage: github.sourceControlStorage.sandboxes,
|
|
889
|
-
token: ghCliToken,
|
|
890
|
-
onProgress,
|
|
891
|
-
...seedCheckpointName ? { seedCheckpointName } : {}
|
|
892
|
-
});
|
|
893
|
-
const finalRow = await github.sourceControlStorage.sandboxes.getById({ id: sandboxRow.id }) ?? sandboxRow;
|
|
894
|
-
await materializeRepo({
|
|
895
|
-
row: finalRow,
|
|
896
|
-
repoInfo: {
|
|
897
|
-
repoFullName: project.repository.slug,
|
|
898
|
-
defaultBranch: project.defaultBranch
|
|
899
|
-
},
|
|
900
|
-
sandbox,
|
|
901
|
-
token: access.authorization.token,
|
|
902
|
-
storage: github.sourceControlStorage.sandboxes,
|
|
903
|
-
onProgress,
|
|
904
|
-
skipPullOnExistingCheckout: Boolean(seedCheckpointName && sandbox.seedCheckpointNameUsed === seedCheckpointName)
|
|
905
|
-
});
|
|
906
|
-
const result = {
|
|
907
|
-
resourceId: project.factoryProjectId,
|
|
908
|
-
factoryProjectId: project.factoryProjectId,
|
|
909
|
-
projectRepositoryId: project.id,
|
|
910
|
-
sandboxId: finalRow.sandboxId,
|
|
911
|
-
sandboxWorkdir: finalRow.sandboxWorkdir
|
|
912
|
-
};
|
|
913
|
-
onProgress?.({
|
|
914
|
-
phase: "done",
|
|
915
|
-
message: "Workspace ready."
|
|
916
|
-
});
|
|
917
|
-
return result;
|
|
918
|
-
}
|
|
919
|
-
/** Shape an /ensure failure into an HTTP status + JSON body (also used as the SSE error payload). */
|
|
920
|
-
function ensureErrorPayload(err) {
|
|
921
|
-
if (err instanceof SandboxBudgetError) return {
|
|
922
|
-
status: 429,
|
|
923
|
-
body: {
|
|
924
|
-
error: err.code,
|
|
925
|
-
message: err.message
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
if (err instanceof MaterializeError) return {
|
|
929
|
-
status: 502,
|
|
930
|
-
body: {
|
|
931
|
-
error: err.code,
|
|
932
|
-
message: err.message
|
|
933
|
-
}
|
|
934
|
-
};
|
|
935
|
-
return {
|
|
936
|
-
status: 500,
|
|
937
|
-
body: {
|
|
938
|
-
error: "materialize_failed",
|
|
939
|
-
message: err instanceof Error ? err.message : String(err)
|
|
940
|
-
}
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
/** Map a sandbox/worktree error to an actionable HTTP response. */
|
|
764
|
+
/** Map a sandbox/setup-command error to an actionable HTTP response. */
|
|
944
765
|
function gitErrorResponse(c, err) {
|
|
945
|
-
if (err instanceof
|
|
766
|
+
if (err instanceof SetupCommandError) return c.json({
|
|
946
767
|
error: err.code,
|
|
947
768
|
message: err.message
|
|
948
|
-
},
|
|
769
|
+
}, 502);
|
|
949
770
|
if (err instanceof MaterializeError) return c.json({
|
|
950
771
|
error: err.code,
|
|
951
772
|
message: err.message
|
|
@@ -956,18 +777,17 @@ function gitErrorResponse(c, err) {
|
|
|
956
777
|
}, 500);
|
|
957
778
|
}
|
|
958
779
|
/**
|
|
959
|
-
* Load the org-owned project
|
|
960
|
-
*
|
|
961
|
-
*
|
|
962
|
-
*
|
|
963
|
-
* a ready-to-return error response.
|
|
780
|
+
* Load the org-owned project for a git route. Centralizes the auth +
|
|
781
|
+
* org/ownership checks every git route shares: the project is scoped by
|
|
782
|
+
* `(id, orgId)`. Returns the tenant and project, or a ready-to-return error
|
|
783
|
+
* response.
|
|
964
784
|
*/
|
|
965
785
|
async function loadOwnedProject(options) {
|
|
966
|
-
const { github, auth,
|
|
786
|
+
const { github, auth, sandbox, c } = options;
|
|
967
787
|
const resolved = await resolveOrgTenant(c, auth);
|
|
968
788
|
if ("response" in resolved) return { response: resolved.response };
|
|
969
789
|
const { orgId, userId } = resolved.tenant;
|
|
970
|
-
if (!
|
|
790
|
+
if (!sandbox) return { response: c.json({
|
|
971
791
|
error: "sandbox_not_configured",
|
|
972
792
|
message: "No sandbox provider is configured."
|
|
973
793
|
}, 503) };
|
|
@@ -982,8 +802,7 @@ async function loadOwnedProject(options) {
|
|
|
982
802
|
return {
|
|
983
803
|
orgId,
|
|
984
804
|
userId,
|
|
985
|
-
project
|
|
986
|
-
sandboxRow: await loadOrCreateSandboxRow(github, project, userId)
|
|
805
|
+
project
|
|
987
806
|
};
|
|
988
807
|
}
|
|
989
808
|
/**
|
|
@@ -1064,7 +883,7 @@ function createSessionOwnerProfileResolver(users) {
|
|
|
1064
883
|
return profiles;
|
|
1065
884
|
};
|
|
1066
885
|
}
|
|
1067
|
-
function buildProjectGitRoutes({ github, auth,
|
|
886
|
+
function buildProjectGitRoutes({ github, auth, sandbox, users, controller, memorySettings, emitAudit, sessionRetirement, workItems }) {
|
|
1068
887
|
const nameSession = createSessionNaming();
|
|
1069
888
|
const resolveSessionOwnerProfiles = createSessionOwnerProfileResolver(users);
|
|
1070
889
|
return [
|
|
@@ -1198,11 +1017,7 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1198
1017
|
sessionId: session.sessionId
|
|
1199
1018
|
});
|
|
1200
1019
|
await github.sourceControlStorage.sessions.delete(session.id);
|
|
1201
|
-
reclaimDeletedSessionSandbox({
|
|
1202
|
-
fleet,
|
|
1203
|
-
sourceControl: github.sourceControlStorage,
|
|
1204
|
-
session
|
|
1205
|
-
}).catch((error) => {
|
|
1020
|
+
reclaimDeletedSessionSandbox({ session }).catch((error) => {
|
|
1206
1021
|
console.error("[GitHub Sessions] Failed to reclaim sandbox for deleted session", {
|
|
1207
1022
|
sessionId: session.sessionId,
|
|
1208
1023
|
sandboxId: session.sandboxId,
|
|
@@ -1263,7 +1078,7 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1263
1078
|
const owned = await loadOwnedProject({
|
|
1264
1079
|
github,
|
|
1265
1080
|
auth,
|
|
1266
|
-
|
|
1081
|
+
sandbox,
|
|
1267
1082
|
c: loose(c)
|
|
1268
1083
|
});
|
|
1269
1084
|
if ("response" in owned) return owned.response;
|
|
@@ -1277,13 +1092,10 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1277
1092
|
if (typeof body.message !== "string" || body.message.trim().length === 0 || body.message.length > 5e3) return c.json({ error: "Invalid message" }, 400);
|
|
1278
1093
|
const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);
|
|
1279
1094
|
if (!sessionWorkspace) return c.json({ error: "Invalid sessionId" }, 400);
|
|
1280
|
-
const { workdir,
|
|
1095
|
+
const { workdir, sandbox: sessionSandbox } = sessionWorkspace;
|
|
1281
1096
|
try {
|
|
1282
1097
|
return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {
|
|
1283
|
-
const result = await commitAll(await
|
|
1284
|
-
fleet,
|
|
1285
|
-
sandboxRow: sandboxBinding
|
|
1286
|
-
}), workdir, body.message, identityFromUser(await auth.ensureUser(loose(c))));
|
|
1098
|
+
const result = await commitAll(sessionSandbox, workdir, body.message, identityFromUser(await auth.ensureUser(loose(c))));
|
|
1287
1099
|
if (result.committed) await emitAudit?.({
|
|
1288
1100
|
context: loose(c),
|
|
1289
1101
|
input: {
|
|
@@ -1311,7 +1123,7 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1311
1123
|
const owned = await loadOwnedProject({
|
|
1312
1124
|
github,
|
|
1313
1125
|
auth,
|
|
1314
|
-
|
|
1126
|
+
sandbox,
|
|
1315
1127
|
c: loose(c)
|
|
1316
1128
|
});
|
|
1317
1129
|
if ("response" in owned) return owned.response;
|
|
@@ -1326,19 +1138,15 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1326
1138
|
const branch = body.branch;
|
|
1327
1139
|
const sessionWorkspace = await resolveSessionWorkspace(github, project.id, userId, body.sessionId);
|
|
1328
1140
|
if (!sessionWorkspace) return c.json({ error: "Invalid sessionId" }, 400);
|
|
1329
|
-
const { workdir,
|
|
1141
|
+
const { workdir, sandbox: sessionSandbox } = sessionWorkspace;
|
|
1330
1142
|
try {
|
|
1331
1143
|
return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {
|
|
1332
|
-
const sandbox = await resolveProjectSandbox({
|
|
1333
|
-
fleet,
|
|
1334
|
-
sandboxRow: sandboxBinding
|
|
1335
|
-
});
|
|
1336
1144
|
const access = await github.versionControl.getRepositoryAccess({
|
|
1337
1145
|
orgId,
|
|
1338
1146
|
repositoryId: project.repository.id
|
|
1339
1147
|
});
|
|
1340
1148
|
if (!access.authorization) throw new Error("Repository access did not include a bearer token.");
|
|
1341
|
-
await pushBranch(
|
|
1149
|
+
await pushBranch(sessionSandbox, workdir, branch, access.authorization.token, project.repository.slug);
|
|
1342
1150
|
await emitAudit?.({
|
|
1343
1151
|
context: loose(c),
|
|
1344
1152
|
input: {
|
|
@@ -1372,7 +1180,7 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1372
1180
|
const owned = await loadOwnedProject({
|
|
1373
1181
|
github,
|
|
1374
1182
|
auth,
|
|
1375
|
-
|
|
1183
|
+
sandbox,
|
|
1376
1184
|
c: loose(c)
|
|
1377
1185
|
});
|
|
1378
1186
|
if ("response" in owned) return owned.response;
|
|
@@ -1454,35 +1262,6 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1454
1262
|
}, 502);
|
|
1455
1263
|
}
|
|
1456
1264
|
}
|
|
1457
|
-
}),
|
|
1458
|
-
registerApiRoute("/web/github/projects/:id/sandbox", {
|
|
1459
|
-
method: "DELETE",
|
|
1460
|
-
requiresAuth: false,
|
|
1461
|
-
handler: async (c) => {
|
|
1462
|
-
const owned = await loadOwnedProject({
|
|
1463
|
-
github,
|
|
1464
|
-
auth,
|
|
1465
|
-
fleet,
|
|
1466
|
-
c: loose(c)
|
|
1467
|
-
});
|
|
1468
|
-
if ("response" in owned) return owned.response;
|
|
1469
|
-
const { sandboxRow } = owned;
|
|
1470
|
-
if (!sandboxRow.sandboxId) return c.json({ tornDown: false });
|
|
1471
|
-
try {
|
|
1472
|
-
return await withSessionOperationLock(`sandbox:${sandboxRow.id}`, async () => {
|
|
1473
|
-
const sandbox = await fleet.reattachSandbox(sandboxRow.sandboxId, { actingUserId: sandboxRow.userId });
|
|
1474
|
-
await teardownProjectSandbox({
|
|
1475
|
-
fleet,
|
|
1476
|
-
row: sandboxRow,
|
|
1477
|
-
storage: github.sourceControlStorage.sandboxes,
|
|
1478
|
-
sandbox
|
|
1479
|
-
});
|
|
1480
|
-
return c.json({ tornDown: true });
|
|
1481
|
-
});
|
|
1482
|
-
} catch (err) {
|
|
1483
|
-
return gitErrorResponse(loose(c), err);
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
1265
|
})
|
|
1487
1266
|
];
|
|
1488
1267
|
}
|
|
@@ -1490,19 +1269,13 @@ function buildProjectGitRoutes({ github, auth, users, fleet, controller, memoryS
|
|
|
1490
1269
|
async function resolveSessionWorkspace(github, projectId, userId, sessionId) {
|
|
1491
1270
|
if (typeof sessionId !== "string") return;
|
|
1492
1271
|
const session = await github.sourceControlStorage.sessions.getBySessionId(sessionId);
|
|
1493
|
-
if (session?.projectRepositoryId !== projectId || session.userId !== userId
|
|
1272
|
+
if (session?.projectRepositoryId !== projectId || session.userId !== userId) return;
|
|
1273
|
+
const entry = peekSessionSandbox(session.id);
|
|
1274
|
+
if (!entry?.workdir) return void 0;
|
|
1494
1275
|
return {
|
|
1495
1276
|
session,
|
|
1496
|
-
workdir:
|
|
1497
|
-
|
|
1498
|
-
id: session.id,
|
|
1499
|
-
projectRepositoryId: session.projectRepositoryId,
|
|
1500
|
-
userId: session.userId,
|
|
1501
|
-
sandboxId: session.sandboxId,
|
|
1502
|
-
sandboxWorkdir: session.sandboxWorkdir,
|
|
1503
|
-
materializedAt: session.materializedAt,
|
|
1504
|
-
createdAt: session.createdAt
|
|
1505
|
-
}
|
|
1277
|
+
workdir: entry.workdir,
|
|
1278
|
+
sandbox: requireExec(entry.sandbox)
|
|
1506
1279
|
};
|
|
1507
1280
|
}
|
|
1508
1281
|
//#endregion
|