@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.
Files changed (157) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/factory.d.ts +2 -22
  3. package/dist/factory.d.ts.map +1 -1
  4. package/dist/factory.js +21 -59
  5. package/dist/factory.js.map +1 -1
  6. package/dist/feed-events.d.ts +13 -0
  7. package/dist/feed-events.d.ts.map +1 -0
  8. package/dist/feed-events.js +25 -0
  9. package/dist/feed-events.js.map +1 -0
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/integrations/base.d.ts +5 -13
  13. package/dist/integrations/base.d.ts.map +1 -1
  14. package/dist/integrations/github/config.d.ts +4 -4
  15. package/dist/integrations/github/config.d.ts.map +1 -1
  16. package/dist/integrations/github/config.js +3 -3
  17. package/dist/integrations/github/config.js.map +1 -1
  18. package/dist/integrations/github/integration.d.ts.map +1 -1
  19. package/dist/integrations/github/integration.js +2 -4
  20. package/dist/integrations/github/integration.js.map +1 -1
  21. package/dist/integrations/github/reconcile-worker.d.ts +0 -5
  22. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  23. package/dist/integrations/github/reconcile-worker.js +1 -8
  24. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  25. package/dist/integrations/github/routes.d.ts +6 -5
  26. package/dist/integrations/github/routes.d.ts.map +1 -1
  27. package/dist/integrations/github/routes.js +36 -263
  28. package/dist/integrations/github/routes.js.map +1 -1
  29. package/dist/integrations/github/sandbox-release.d.ts +17 -47
  30. package/dist/integrations/github/sandbox-release.d.ts.map +1 -1
  31. package/dist/integrations/github/sandbox-release.js +24 -103
  32. package/dist/integrations/github/sandbox-release.js.map +1 -1
  33. package/dist/integrations/github/sandbox.d.ts +25 -139
  34. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  35. package/dist/integrations/github/sandbox.js +24 -212
  36. package/dist/integrations/github/sandbox.js.map +1 -1
  37. package/dist/integrations/github/webhook.d.ts.map +1 -1
  38. package/dist/integrations/github/webhook.js +1 -2
  39. package/dist/integrations/github/webhook.js.map +1 -1
  40. package/dist/integrations/issue-reconcile-worker.js +1 -1
  41. package/dist/integrations/platform/github/event-worker.d.ts +0 -2
  42. package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
  43. package/dist/integrations/platform/github/event-worker.js +1 -8
  44. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  45. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  46. package/dist/integrations/platform/github/integration.js +5 -7
  47. package/dist/integrations/platform/github/integration.js.map +1 -1
  48. package/dist/integrations/platform/linear/event-worker.js +1 -1
  49. package/dist/routes/attention-activity.d.ts +24 -0
  50. package/dist/routes/attention-activity.d.ts.map +1 -0
  51. package/dist/routes/attention-activity.js +143 -0
  52. package/dist/routes/attention-activity.js.map +1 -0
  53. package/dist/routes/attention-providers.d.ts +31 -1
  54. package/dist/routes/attention-providers.d.ts.map +1 -1
  55. package/dist/routes/attention-providers.js +4 -4
  56. package/dist/routes/attention-providers.js.map +1 -1
  57. package/dist/routes/attention.d.ts.map +1 -1
  58. package/dist/routes/attention.js +39 -11
  59. package/dist/routes/attention.js.map +1 -1
  60. package/dist/routes/config.d.ts.map +1 -1
  61. package/dist/routes/config.js +3 -1
  62. package/dist/routes/config.js.map +1 -1
  63. package/dist/routes/fs.d.ts +4 -6
  64. package/dist/routes/fs.d.ts.map +1 -1
  65. package/dist/routes/fs.js +28 -34
  66. package/dist/routes/fs.js.map +1 -1
  67. package/dist/routes/skills.d.ts.map +1 -1
  68. package/dist/routes/skills.js +6 -3
  69. package/dist/routes/skills.js.map +1 -1
  70. package/dist/routes/surface.d.ts +4 -9
  71. package/dist/routes/surface.d.ts.map +1 -1
  72. package/dist/routes/surface.js +3 -5
  73. package/dist/routes/surface.js.map +1 -1
  74. package/dist/sandbox/materialization.d.ts +36 -0
  75. package/dist/sandbox/materialization.d.ts.map +1 -0
  76. package/dist/sandbox/materialization.js +18 -0
  77. package/dist/sandbox/materialization.js.map +1 -0
  78. package/dist/sandbox/session-retirement.d.ts +8 -6
  79. package/dist/sandbox/session-retirement.d.ts.map +1 -1
  80. package/dist/sandbox/session-retirement.js +28 -123
  81. package/dist/sandbox/session-retirement.js.map +1 -1
  82. package/dist/sandbox/session-sandbox.d.ts +117 -0
  83. package/dist/sandbox/session-sandbox.d.ts.map +1 -0
  84. package/dist/sandbox/session-sandbox.js +132 -0
  85. package/dist/sandbox/session-sandbox.js.map +1 -0
  86. package/dist/sandbox/workdir.d.ts +30 -0
  87. package/dist/sandbox/workdir.d.ts.map +1 -0
  88. package/dist/sandbox/workdir.js +48 -0
  89. package/dist/sandbox/workdir.js.map +1 -0
  90. package/dist/session/filesystem-capture.d.ts +2 -1
  91. package/dist/session/filesystem-capture.d.ts.map +1 -1
  92. package/dist/session/filesystem-capture.js +45 -4
  93. package/dist/session/filesystem-capture.js.map +1 -1
  94. package/dist/session/first-exec-capture.d.ts +1 -0
  95. package/dist/session/first-exec-capture.d.ts.map +1 -1
  96. package/dist/session/first-exec-capture.js +1 -1
  97. package/dist/session/first-exec-capture.js.map +1 -1
  98. package/dist/storage/domains/comments/activity.d.ts +40 -0
  99. package/dist/storage/domains/comments/activity.d.ts.map +1 -0
  100. package/dist/storage/domains/comments/activity.js +94 -0
  101. package/dist/storage/domains/comments/activity.js.map +1 -0
  102. package/dist/storage/domains/comments/base.d.ts +13 -1
  103. package/dist/storage/domains/comments/base.d.ts.map +1 -1
  104. package/dist/storage/domains/comments/base.js +41 -3
  105. package/dist/storage/domains/comments/base.js.map +1 -1
  106. package/dist/storage/domains/comments/domain.d.ts +4 -1
  107. package/dist/storage/domains/comments/domain.d.ts.map +1 -1
  108. package/dist/storage/domains/comments/domain.js +17 -5
  109. package/dist/storage/domains/comments/domain.js.map +1 -1
  110. package/dist/storage/domains/comments/parse.d.ts +1 -0
  111. package/dist/storage/domains/comments/parse.d.ts.map +1 -1
  112. package/dist/storage/domains/comments/parse.js +2 -2
  113. package/dist/storage/domains/comments/parse.js.map +1 -1
  114. package/dist/storage/domains/comments/routes.d.ts +2 -0
  115. package/dist/storage/domains/comments/routes.d.ts.map +1 -1
  116. package/dist/storage/domains/comments/routes.js +49 -3
  117. package/dist/storage/domains/comments/routes.js.map +1 -1
  118. package/dist/storage/domains/comments/schema.d.ts +1 -0
  119. package/dist/storage/domains/comments/schema.d.ts.map +1 -1
  120. package/dist/storage/domains/comments/schema.js +45 -1
  121. package/dist/storage/domains/comments/schema.js.map +1 -1
  122. package/dist/storage/domains/integrations/base.d.ts +1 -1
  123. package/dist/storage/domains/integrations/base.js +1 -1
  124. package/dist/storage/domains/integrations/base.js.map +1 -1
  125. package/dist/storage/domains/source-control/base.d.ts +0 -144
  126. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  127. package/dist/storage/domains/source-control/base.js +3 -290
  128. package/dist/storage/domains/source-control/base.js.map +1 -1
  129. package/dist/storage/domains/source-control/inmemory.d.ts +1 -63
  130. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  131. package/dist/storage/domains/source-control/inmemory.js +0 -89
  132. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  133. package/dist/storage/domains/work-items/base.d.ts +14 -1
  134. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  135. package/dist/storage/domains/work-items/base.js +60 -11
  136. package/dist/storage/domains/work-items/base.js.map +1 -1
  137. package/dist/workspace.d.ts +5 -37
  138. package/dist/workspace.d.ts.map +1 -1
  139. package/dist/workspace.js +107 -245
  140. package/dist/workspace.js.map +1 -1
  141. package/package.json +6 -6
  142. package/dist/sandbox/base-checkpoint-triggers.d.ts +0 -77
  143. package/dist/sandbox/base-checkpoint-triggers.d.ts.map +0 -1
  144. package/dist/sandbox/base-checkpoint-triggers.js +0 -137
  145. package/dist/sandbox/base-checkpoint-triggers.js.map +0 -1
  146. package/dist/sandbox/base-checkpoint.d.ts +0 -59
  147. package/dist/sandbox/base-checkpoint.d.ts.map +0 -1
  148. package/dist/sandbox/base-checkpoint.js +0 -145
  149. package/dist/sandbox/base-checkpoint.js.map +0 -1
  150. package/dist/sandbox/fleet.d.ts +0 -258
  151. package/dist/sandbox/fleet.d.ts.map +0 -1
  152. package/dist/sandbox/fleet.js +0 -356
  153. package/dist/sandbox/fleet.js.map +0 -1
  154. package/dist/sandbox/reattach.d.ts +0 -3
  155. package/dist/sandbox/reattach.d.ts.map +0 -1
  156. package/dist/sandbox/reattach.js +0 -16
  157. 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;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,KAAK,EAAuD,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEhH,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;AASrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA2C1D,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;;;;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,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,CAgsB/E;AAkQD,KAAK,wBAAwB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,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, getGithubPat, getGithubPatStatus, setGithubPat } from "./pat.js";
1
+ import { clearGithubPat, getGithubPatStatus, setGithubPat } from "./pat.js";
2
2
  import { listPullRequestSubscriptionsForThread, subscribeToPullRequest } from "./subscriptions.js";
3
- import { SandboxBudgetError } from "../../sandbox/fleet.js";
4
- import { MaterializeError, WorktreeError, commitAll, ensureProjectSandbox, isValidGitRef as isValidGitRef$1, materializeRepo, pushBranch, teardownProjectSandbox } from "./sandbox.js";
5
- import { baseCheckpointIsStale } from "../../sandbox/base-checkpoint-triggers.js";
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, users, fleet, storage, github, stateSigner, controller, memorySettings, emitAudit, sessionRetirement, workItems } = options;
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
- fleet
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: fleet.enabled,
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: fleet.enabled,
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: fleet.provider,
427
- sandboxWorkdir: fleet.computeWorkdir(repo.fullName)
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 WorktreeError) return c.json({
766
+ if (err instanceof SetupCommandError) return c.json({
946
767
  error: err.code,
947
768
  message: err.message
948
- }, err.code === "invalid-branch" ? 400 : 502);
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 and the caller's per-user sandbox binding for a git
960
- * route. Centralizes the auth + org/ownership checks every git route shares:
961
- * the project is scoped by `(id, orgId)`, the sandbox binding by
962
- * `(projectRepositoryId, userId)`. Returns the tenant, project, and sandbox row, or
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, fleet, c } = options;
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 (!fleet.enabled) return { response: c.json({
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, users, fleet, controller, memorySettings, emitAudit, sessionRetirement, workItems }) {
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
- fleet,
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, sandboxBinding } = sessionWorkspace;
1095
+ const { workdir, sandbox: sessionSandbox } = sessionWorkspace;
1281
1096
  try {
1282
1097
  return await withSessionOperationLock(sessionWorkspace.session.sessionId, async () => {
1283
- const result = await commitAll(await resolveProjectSandbox({
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
- fleet,
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, sandboxBinding } = sessionWorkspace;
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(sandbox, workdir, branch, access.authorization.token, project.repository.slug);
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
- fleet,
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 || !session.sandboxId || !session.sandboxWorkdir) return;
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: session.sandboxWorkdir,
1497
- sandboxBinding: {
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