@mastra/factory 0.2.2-alpha.1 → 0.2.2-alpha.2

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 (155) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/auth.js +401 -334
  3. package/dist/auth.js.map +1 -1
  4. package/dist/capabilities/connection.js +1 -1
  5. package/dist/capabilities/intake.js +1 -1
  6. package/dist/capabilities/version-control.js +1 -1
  7. package/dist/factory.js +441 -39622
  8. package/dist/factory.js.map +1 -1
  9. package/dist/index.js +2 -39633
  10. package/dist/integrations/base.js +1 -1
  11. package/dist/integrations/github/config.js +36 -22
  12. package/dist/integrations/github/config.js.map +1 -1
  13. package/dist/integrations/github/factory-session.js +33 -37
  14. package/dist/integrations/github/factory-session.js.map +1 -1
  15. package/dist/integrations/github/integration.js +1037 -3672
  16. package/dist/integrations/github/integration.js.map +1 -1
  17. package/dist/integrations/github/issue-triage.js +71 -71
  18. package/dist/integrations/github/issue-triage.js.map +1 -1
  19. package/dist/integrations/github/pat.js +47 -36
  20. package/dist/integrations/github/pat.js.map +1 -1
  21. package/dist/integrations/github/provenance.js +72 -101
  22. package/dist/integrations/github/provenance.js.map +1 -1
  23. package/dist/integrations/github/routes.js +1272 -1881
  24. package/dist/integrations/github/routes.js.map +1 -1
  25. package/dist/integrations/github/rules.js +203 -471
  26. package/dist/integrations/github/rules.js.map +1 -1
  27. package/dist/integrations/github/sandbox.js +400 -345
  28. package/dist/integrations/github/sandbox.js.map +1 -1
  29. package/dist/integrations/github/session-subscriptions.js +165 -223
  30. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  31. package/dist/integrations/github/subscriptions.js +43 -51
  32. package/dist/integrations/github/subscriptions.js.map +1 -1
  33. package/dist/integrations/github/token-refresh.js +15 -18
  34. package/dist/integrations/github/token-refresh.js.map +1 -1
  35. package/dist/integrations/github/webhook.js +359 -343
  36. package/dist/integrations/github/webhook.js.map +1 -1
  37. package/dist/integrations/linear/agent-tools.js +77 -100
  38. package/dist/integrations/linear/agent-tools.js.map +1 -1
  39. package/dist/integrations/linear/integration.js +611 -1309
  40. package/dist/integrations/linear/integration.js.map +1 -1
  41. package/dist/integrations/linear/routes.js +227 -230
  42. package/dist/integrations/linear/routes.js.map +1 -1
  43. package/dist/integrations/linear/rules.js +126 -346
  44. package/dist/integrations/linear/rules.js.map +1 -1
  45. package/dist/integrations/linear/storage.js +1 -1
  46. package/dist/integrations/platform/api-client.js +131 -135
  47. package/dist/integrations/platform/api-client.js.map +1 -1
  48. package/dist/integrations/platform/github/event-worker.js +275 -573
  49. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  50. package/dist/integrations/platform/github/integration.js +845 -4022
  51. package/dist/integrations/platform/github/integration.js.map +1 -1
  52. package/dist/integrations/platform/linear/integration.js +457 -1309
  53. package/dist/integrations/platform/linear/integration.js.map +1 -1
  54. package/dist/integrations/workos/integration.js +80 -85
  55. package/dist/integrations/workos/integration.js.map +1 -1
  56. package/dist/routes/config.d.ts.map +1 -1
  57. package/dist/routes/config.js +933 -912
  58. package/dist/routes/config.js.map +1 -1
  59. package/dist/routes/custom-provider-source.js +110 -93
  60. package/dist/routes/custom-provider-source.js.map +1 -1
  61. package/dist/routes/fs.js +401 -349
  62. package/dist/routes/fs.js.map +1 -1
  63. package/dist/routes/intake.js +165 -165
  64. package/dist/routes/intake.js.map +1 -1
  65. package/dist/routes/oauth.js +447 -25166
  66. package/dist/routes/oauth.js.map +1 -1
  67. package/dist/routes/projects.js +437 -376
  68. package/dist/routes/projects.js.map +1 -1
  69. package/dist/routes/provider-credentials.js +76 -58
  70. package/dist/routes/provider-credentials.js.map +1 -1
  71. package/dist/routes/route.js +12 -8
  72. package/dist/routes/route.js.map +1 -1
  73. package/dist/routes/skills.js +160 -173
  74. package/dist/routes/skills.js.map +1 -1
  75. package/dist/routes/surface.js +250 -28615
  76. package/dist/routes/surface.js.map +1 -1
  77. package/dist/routes/tenant-credentials.js +141 -166
  78. package/dist/routes/tenant-credentials.js.map +1 -1
  79. package/dist/routes/work-items.js +654 -862
  80. package/dist/routes/work-items.js.map +1 -1
  81. package/dist/rules/binding-context.js +23 -35
  82. package/dist/rules/binding-context.js.map +1 -1
  83. package/dist/rules/defaults.js +200 -309
  84. package/dist/rules/defaults.js.map +1 -1
  85. package/dist/rules/dispatcher.js +438 -683
  86. package/dist/rules/dispatcher.js.map +1 -1
  87. package/dist/rules/index.js +5 -599
  88. package/dist/rules/processor.js +344 -596
  89. package/dist/rules/processor.js.map +1 -1
  90. package/dist/rules/resolve.js +21 -18
  91. package/dist/rules/resolve.js.map +1 -1
  92. package/dist/rules/start-coordinator.js +168 -157
  93. package/dist/rules/start-coordinator.js.map +1 -1
  94. package/dist/rules/tools.js +50 -85
  95. package/dist/rules/tools.js.map +1 -1
  96. package/dist/rules/transition-service.js +183 -454
  97. package/dist/rules/transition-service.js.map +1 -1
  98. package/dist/rules/types.js +33 -29
  99. package/dist/rules/types.js.map +1 -1
  100. package/dist/rules/validation.js +266 -281
  101. package/dist/rules/validation.js.map +1 -1
  102. package/dist/sandbox/fleet.js +272 -250
  103. package/dist/sandbox/fleet.js.map +1 -1
  104. package/dist/sandbox/reattach.js +13 -6
  105. package/dist/sandbox/reattach.js.map +1 -1
  106. package/dist/server-error.js +12 -16
  107. package/dist/server-error.js.map +1 -1
  108. package/dist/skills/service.js +30 -35
  109. package/dist/skills/service.js.map +1 -1
  110. package/dist/spa-static.js +91 -65
  111. package/dist/spa-static.js.map +1 -1
  112. package/dist/state-signing.js +73 -44
  113. package/dist/state-signing.js.map +1 -1
  114. package/dist/storage/domains/audit/agent-audit.js +60 -59
  115. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  116. package/dist/storage/domains/audit/base.js +169 -112
  117. package/dist/storage/domains/audit/base.js.map +1 -1
  118. package/dist/storage/domains/audit/domain.js +155 -153
  119. package/dist/storage/domains/audit/domain.js.map +1 -1
  120. package/dist/storage/domains/credentials/base.js +259 -243
  121. package/dist/storage/domains/credentials/base.js.map +1 -1
  122. package/dist/storage/domains/custom-providers/base.js +138 -143
  123. package/dist/storage/domains/custom-providers/base.js.map +1 -1
  124. package/dist/storage/domains/intake/base.js +75 -57
  125. package/dist/storage/domains/intake/base.js.map +1 -1
  126. package/dist/storage/domains/integrations/base.js +310 -245
  127. package/dist/storage/domains/integrations/base.js.map +1 -1
  128. package/dist/storage/domains/memory-settings/base.js +117 -102
  129. package/dist/storage/domains/memory-settings/base.js.map +1 -1
  130. package/dist/storage/domains/model-packs/base.js +89 -88
  131. package/dist/storage/domains/model-packs/base.js.map +1 -1
  132. package/dist/storage/domains/projects/base.js +97 -92
  133. package/dist/storage/domains/projects/base.js.map +1 -1
  134. package/dist/storage/domains/queue-health/base.js +111 -76
  135. package/dist/storage/domains/queue-health/base.js.map +1 -1
  136. package/dist/storage/domains/source-control/base.js +777 -706
  137. package/dist/storage/domains/source-control/base.js.map +1 -1
  138. package/dist/storage/domains/source-control/inmemory.js +322 -348
  139. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  140. package/dist/storage/domains/work-items/base.js +1266 -1148
  141. package/dist/storage/domains/work-items/base.js.map +1 -1
  142. package/dist/storage/domains/work-items/metrics.js +202 -184
  143. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  144. package/dist/timing.js +29 -22
  145. package/dist/timing.js.map +1 -1
  146. package/dist/workspace.js +236 -477
  147. package/dist/workspace.js.map +1 -1
  148. package/package.json +8 -8
  149. package/dist/capabilities/connection.js.map +0 -1
  150. package/dist/capabilities/intake.js.map +0 -1
  151. package/dist/capabilities/version-control.js.map +0 -1
  152. package/dist/index.js.map +0 -1
  153. package/dist/integrations/base.js.map +0 -1
  154. package/dist/integrations/linear/storage.js.map +0 -1
  155. package/dist/rules/index.js.map +0 -1
package/dist/workspace.js CHANGED
@@ -1,488 +1,247 @@
1
- // src/workspace.ts
1
+ import { getFactoryAuthUserId } from "./auth.js";
2
+ import { getGithubPat } from "./integrations/github/pat.js";
3
+ import { registerGithubPatKind, registerGithubTokenInjector } from "./integrations/github/token-refresh.js";
4
+ import { checkoutSessionBranch, materializeRepo, runWorktreeSetup } from "./integrations/github/sandbox.js";
5
+ import { getFactorySessionAddress } from "./rules/binding-context.js";
6
+ import path, { dirname, join } from "path";
7
+ import { LocalSandbox, LocalSkillSource, Workspace } from "@mastra/core/workspace";
8
+ import { DEFAULT_CONFIG_DIR } from "@mastra/code-sdk/constants";
9
+ import { SandboxFilesystem } from "@mastra/code-sdk/agents/sandbox-filesystem";
2
10
  import { existsSync } from "fs";
3
- import path2, { dirname, join } from "path";
4
11
  import { fileURLToPath } from "url";
5
- import { SandboxFilesystem } from "@mastra/code-sdk/agents/sandbox-filesystem";
6
12
  import { MASTRACODE_WORKSPACE_TOOLS } from "@mastra/code-sdk/agents/tool-availability";
7
13
  import { getDynamicWorkspace } from "@mastra/code-sdk/agents/workspace";
8
- import { DEFAULT_CONFIG_DIR } from "@mastra/code-sdk/constants";
9
- import { LocalSandbox, LocalSkillSource, Workspace } from "@mastra/core/workspace";
10
-
11
- // src/auth.ts
12
- import { MastraAuthWorkos } from "@mastra/auth-workos";
13
- import {
14
- registerApiRoute,
15
- isAuthHttpHandler,
16
- isCredentialsProvider,
17
- isOrganizationsProvider,
18
- isSessionProvider,
19
- isSSOProvider
20
- } from "@mastra/core/server";
21
- function getFactoryAuthUserId(user) {
22
- return user?.workosId ?? user?.id;
23
- }
24
- function getFactoryAuthOrgId(user) {
25
- return user?.organizationId;
26
- }
27
-
28
- // src/integrations/github/pat.ts
29
- var PAT_SETTINGS_USER_ID = "__github_org_settings__";
30
- function asToken(value) {
31
- return typeof value === "string" && value.length > 0 ? value : null;
32
- }
33
- async function getGithubPat(getStorage, orgId, kind = "default") {
34
- try {
35
- const settings = await getStorage().settings.get(orgId, PAT_SETTINGS_USER_ID);
36
- if (!settings) return null;
37
- if (kind === "reviewer") return asToken(settings.reviewerPat) ?? asToken(settings.pat);
38
- return asToken(settings.pat);
39
- } catch {
40
- return null;
41
- }
42
- }
43
-
44
- // src/integrations/github/sandbox.ts
45
- import { createHash } from "crypto";
46
-
47
- // src/sandbox/fleet.ts
48
- import path from "path";
49
- function reportProgress(onProgress, event) {
50
- if (!onProgress) return;
51
- try {
52
- onProgress(event);
53
- } catch {
54
- }
55
- }
56
-
57
- // src/integrations/github/sandbox.ts
58
- function shellQuote(value) {
59
- return `'` + value.split(`'`).join(`'\\''`) + `'`;
60
- }
61
- var DEFAULT_COMMAND_TIMEOUT_MS = 15 * 6e4;
62
- var CHECKOUT_COMMAND_TIMEOUT_MS = 5 * 6e4;
63
- async function sh(sandbox, script, options = {}) {
64
- const timeoutMs = options.timeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
65
- let timer;
66
- const hangGuard = new Promise((_, reject) => {
67
- timer = setTimeout(() => {
68
- const phase = options.phase ? ` during ${options.phase}` : "";
69
- reject(new Error(`Sandbox command timed out after ${Math.round(timeoutMs / 1e3)}s${phase}.`));
70
- }, timeoutMs);
71
- timer.unref?.();
72
- });
73
- try {
74
- return await Promise.race([sandbox.executeCommand("sh", ["-c", script], { timeout: timeoutMs }), hangGuard]);
75
- } finally {
76
- clearTimeout(timer);
77
- }
78
- }
79
- var MaterializeError = class extends Error {
80
- constructor(message, code) {
81
- super(message);
82
- this.code = code;
83
- this.name = "MaterializeError";
84
- }
85
- code;
86
- };
87
- function tokenUrl(repoFullName, token) {
88
- return `https://x-access-token:${token}@github.com/${repoFullName}.git`;
89
- }
90
- function cleanUrl(repoFullName) {
91
- return `https://github.com/${repoFullName}.git`;
92
- }
93
- async function materializeRepo(options) {
94
- const { row: sandboxRow, repoInfo, sandbox, token, storage, onProgress } = options;
95
- const workdir = sandboxRow.sandboxWorkdir;
96
- const repo = repoInfo.repoFullName;
97
- if (!/^[\w.-]+\/[\w.-]+$/.test(repo)) {
98
- throw new MaterializeError(`Refusing to materialize: invalid repo full name '${repo}'.`, "clone-failed");
99
- }
100
- if (!/^[A-Za-z0-9_./-]+$/.test(repoInfo.defaultBranch)) {
101
- throw new MaterializeError(
102
- `Refusing to materialize: invalid default branch '${repoInfo.defaultBranch}'.`,
103
- "clone-failed"
104
- );
105
- }
106
- const gitVersion = await sh(sandbox, "git --version");
107
- if (gitVersion.exitCode !== 0) {
108
- throw new MaterializeError(
109
- "git is not installed in the sandbox. The sandbox template must include git.",
110
- "git-missing"
111
- );
112
- }
113
- const authUrl = tokenUrl(repo, token);
114
- const alreadyMaterialized = await hasExistingCheckout(sandbox, workdir, repo);
115
- let succeeded = false;
116
- try {
117
- if (!alreadyMaterialized) {
118
- reportProgress(onProgress, {
119
- phase: "cloning",
120
- message: `Cloning ${repo} (first open can take a minute)\u2026`
121
- });
122
- const clone = await sh(
123
- sandbox,
124
- `git clone --depth=1 --single-branch --branch ${shellQuote(repoInfo.defaultBranch)} ${shellQuote(authUrl)} ${shellQuote(workdir)}`,
125
- { phase: "repository clone" }
126
- );
127
- if (clone.exitCode !== 0) {
128
- throw classifyGitFailure(clone, "clone-failed");
129
- }
130
- } else {
131
- reportProgress(onProgress, { phase: "pulling", message: `Updating ${repo} to the latest changes\u2026` });
132
- const setUrl = await sh(sandbox, `git -C ${shellQuote(workdir)} remote set-url origin ${shellQuote(authUrl)}`);
133
- if (setUrl.exitCode !== 0) {
134
- throw new MaterializeError(`Failed to set git remote: ${setUrl.stderr}`, "pull-failed");
135
- }
136
- const pull = await sh(sandbox, `git -C ${shellQuote(workdir)} pull --ff-only`, { phase: "repository pull" });
137
- if (pull.exitCode !== 0) {
138
- throw classifyGitFailure(pull, "pull-failed");
139
- }
140
- }
141
- succeeded = true;
142
- } finally {
143
- await scrubRemote(sandbox, workdir, repo, succeeded);
144
- }
145
- reportProgress(onProgress, { phase: "finalizing", message: "Finalizing workspace\u2026" });
146
- await storage.markMaterialized({ id: sandboxRow.id });
147
- }
148
- async function checkoutSessionBranch(sandbox, workdir, {
149
- branch,
150
- baseBranch,
151
- token,
152
- repoFullName
153
- }) {
154
- if (!isValidGitRef(branch) || !isValidGitRef(baseBranch)) {
155
- throw new MaterializeError("Refusing to create a session from an invalid branch name.", "clone-failed");
156
- }
157
- const current = await sh(sandbox, `git -C ${shellQuote(workdir)} branch --show-current`);
158
- if (current.exitCode === 0 && current.stdout.trim() === branch) return;
159
- const local = await sh(
160
- sandbox,
161
- `git -C ${shellQuote(workdir)} show-ref --verify --quiet refs/heads/${shellQuote(branch)}`
162
- );
163
- if (local.exitCode === 0) {
164
- const checkout = await sh(sandbox, `git -C ${shellQuote(workdir)} checkout ${shellQuote(branch)}`);
165
- if (checkout.exitCode !== 0) throw classifyGitFailure(checkout, "clone-failed");
166
- return;
167
- }
168
- const authUrl = tokenUrl(repoFullName, token);
169
- try {
170
- const setUrl = await sh(sandbox, `git -C ${shellQuote(workdir)} remote set-url origin ${shellQuote(authUrl)}`);
171
- if (setUrl.exitCode !== 0) throw classifyGitFailure(setUrl, "pull-failed");
172
- const fetch = await sh(
173
- sandbox,
174
- `git -C ${shellQuote(workdir)} fetch origin ${shellQuote(baseBranch)} && git -C ${shellQuote(workdir)} checkout -b ${shellQuote(branch)} FETCH_HEAD`,
175
- { timeoutMs: CHECKOUT_COMMAND_TIMEOUT_MS, phase: "branch checkout" }
176
- );
177
- if (fetch.exitCode !== 0) throw classifyGitFailure(fetch, "clone-failed");
178
- } finally {
179
- await sh(sandbox, `git -C ${shellQuote(workdir)} remote set-url origin ${shellQuote(cleanUrl(repoFullName))}`);
180
- }
181
- }
182
- async function hasExistingCheckout(sandbox, workdir, repoFullName) {
183
- const result = await sh(sandbox, `git -C ${shellQuote(workdir)} remote get-url origin`);
184
- if (result.exitCode !== 0) return false;
185
- const url = result.stdout.trim().toLowerCase();
186
- const suffix = `github.com/${repoFullName.toLowerCase()}`;
187
- return url.endsWith(`${suffix}.git`) || url.endsWith(suffix);
188
- }
189
- async function scrubRemote(sandbox, workdir, repoFullName, expectGitDir) {
190
- const result = await sh(
191
- sandbox,
192
- `git -C ${shellQuote(workdir)} remote set-url origin ${shellQuote(cleanUrl(repoFullName))}`
193
- );
194
- if (result.exitCode !== 0 && expectGitDir) {
195
- throw new MaterializeError(
196
- `Failed to scrub installation token from git remote: ${result.stderr.trim() || result.stdout.trim()}`,
197
- "pull-failed"
198
- );
199
- }
200
- }
201
- function classifyGitFailure(result, fallback) {
202
- const stderr = result.stderr || "";
203
- if (/could not resolve host|failed to connect|network is unreachable|Connection timed out/i.test(stderr)) {
204
- return new MaterializeError(
205
- "The sandbox could not reach github.com. The sandbox network must allow outbound egress to github.com.",
206
- "egress-blocked"
207
- );
208
- }
209
- const verb = fallback === "clone-failed" ? "clone" : fallback === "pull-failed" ? "pull" : "push";
210
- return new MaterializeError(`git ${verb} failed: ${stderr}`, fallback);
211
- }
212
- function isValidGitRef(value) {
213
- return typeof value === "string" && value.length > 0 && value.length <= 255 && // Reject leading-dash refs (e.g. `--mirror`) so the value can never be
214
- // parsed as a git option when interpolated into a command.
215
- !value.startsWith("-") && /^[A-Za-z0-9_./-]+$/.test(value);
216
- }
217
- var WorktreeError = class extends Error {
218
- constructor(message, code) {
219
- super(message);
220
- this.code = code;
221
- this.name = "WorktreeError";
222
- }
223
- code;
224
- };
225
- async function runWorktreeSetup(sandbox, worktreePath, command) {
226
- const result = await sh(sandbox, `cd ${shellQuote(worktreePath)} && { ${command}
227
- }`, { phase: "worktree setup" });
228
- if (result.exitCode !== 0) {
229
- const detail = (result.stderr.trim() || result.stdout.trim()).slice(-2e3);
230
- throw new WorktreeError(`Setup command failed (exit ${result.exitCode}): ${detail}`, "setup-failed");
231
- }
232
- }
233
-
234
- // src/integrations/github/token-refresh.ts
235
- var GITHUB_TOKEN_INJECTOR_CONTEXT_KEY = "factoryGithubTokenInjector";
236
- var GITHUB_PAT_KIND_CONTEXT_KEY = "factoryGithubPatKind";
237
- function registerGithubTokenInjector(requestContext, injector) {
238
- requestContext.set(GITHUB_TOKEN_INJECTOR_CONTEXT_KEY, injector);
239
- }
240
- function registerGithubPatKind(requestContext, kind) {
241
- requestContext.set(GITHUB_PAT_KIND_CONTEXT_KEY, kind);
242
- }
243
-
244
- // src/rules/binding-context.ts
245
- function getFactorySessionCoordinates(requestContext) {
246
- if (!requestContext || typeof requestContext.get !== "function") return null;
247
- const context = requestContext.get("controller");
248
- const factoryProjectId = context?.getState().factoryProjectId;
249
- if (!context?.threadId || !context.resourceId || !factoryProjectId) return null;
250
- return {
251
- factoryProjectId,
252
- threadId: context.threadId,
253
- resourceId: context.resourceId,
254
- sessionId: context.resourceId
255
- };
256
- }
257
- function getFactorySessionAddress(requestContext) {
258
- const coordinates = getFactorySessionCoordinates(requestContext);
259
- if (!coordinates || !requestContext || typeof requestContext.get !== "function") return null;
260
- const user = requestContext.get("user");
261
- const orgId = getFactoryAuthOrgId(user);
262
- if (!orgId) return null;
263
- return { orgId, ...coordinates };
264
- }
265
-
266
- // src/workspace.ts
267
- var WORKSPACE_ID_PREFIX = "mfw";
268
- var SESSION_CHECKPOINT_PREFIX = "mastracode-session";
14
+ //#region src/workspace.ts
15
+ const WORKSPACE_ID_PREFIX = "mfw";
16
+ const SESSION_CHECKPOINT_PREFIX = "mastracode-session";
269
17
  function checkpointNameForSession(sessionId) {
270
- return `${SESSION_CHECKPOINT_PREFIX}-${sessionId}`;
271
- }
272
- var bundleDirectory = dirname(fileURLToPath(import.meta.url));
273
- var bundledFactorySkillsPath = join(bundleDirectory, "factory-skills");
274
- var FACTORY_SKILLS_SOURCE_PATH = [
275
- // Deploy bundle: the consumer copies `factory-skills/` next to the built
276
- // server module (e.g. via its public/ dir).
277
- bundledFactorySkillsPath,
278
- // Package layout: `dist/../factory-skills` (also `src/../factory-skills`
279
- // when running tests against sources).
280
- join(bundleDirectory, "..", "factory-skills"),
281
- // Consumer repo running from its package root before a build.
282
- join(process.cwd(), "src", "mastra", "public", "factory-skills")
18
+ return `${SESSION_CHECKPOINT_PREFIX}-${sessionId}`;
19
+ }
20
+ const bundleDirectory = dirname(fileURLToPath(import.meta.url));
21
+ const bundledFactorySkillsPath = join(bundleDirectory, "factory-skills");
22
+ const FACTORY_SKILLS_SOURCE_PATH = [
23
+ bundledFactorySkillsPath,
24
+ join(bundleDirectory, "..", "factory-skills"),
25
+ join(process.cwd(), "src", "mastra", "public", "factory-skills")
283
26
  ].find(existsSync) ?? bundledFactorySkillsPath;
284
- var FACTORY_SKILLS_MOUNT = path2.resolve(path2.parse(process.cwd()).root, "__mastracode_factory_skills__");
285
- var FACTORY_SKILL_NAMES = /* @__PURE__ */ new Set(["configure-factory-rules", "factory-plan", "factory-review", "factory-triage"]);
27
+ const FACTORY_SKILLS_MOUNT = path.resolve(path.parse(process.cwd()).root, "__mastracode_factory_skills__");
28
+ const FACTORY_SKILL_NAMES = /* @__PURE__ */ new Set([
29
+ "configure-factory-rules",
30
+ "factory-plan",
31
+ "factory-review",
32
+ "factory-triage"
33
+ ]);
286
34
  var FactorySkillSource = class {
287
- constructor(fallback, fallbackSkillRoots) {
288
- this.fallback = fallback;
289
- this.#fallbackSkillRoots = new Set(fallbackSkillRoots.map((skillPath) => path2.normalize(skillPath)));
290
- }
291
- fallback;
292
- #factorySource = new LocalSkillSource({ basePath: FACTORY_SKILLS_SOURCE_PATH });
293
- #fallbackSkillRoots;
294
- #isFactoryPath(skillPath) {
295
- const normalized = path2.normalize(skillPath);
296
- return normalized === FACTORY_SKILLS_MOUNT || normalized.startsWith(`${FACTORY_SKILLS_MOUNT}${path2.sep}`);
297
- }
298
- #factoryPath(skillPath) {
299
- return path2.relative(FACTORY_SKILLS_MOUNT, path2.normalize(skillPath));
300
- }
301
- exists(skillPath) {
302
- return this.#isFactoryPath(skillPath) ? this.#factorySource.exists(this.#factoryPath(skillPath)) : this.fallback.exists(skillPath);
303
- }
304
- stat(skillPath) {
305
- return this.#isFactoryPath(skillPath) ? this.#factorySource.stat(this.#factoryPath(skillPath)) : this.fallback.stat(skillPath);
306
- }
307
- readFile(skillPath) {
308
- return this.#isFactoryPath(skillPath) ? this.#factorySource.readFile(this.#factoryPath(skillPath)) : this.fallback.readFile(skillPath);
309
- }
310
- async readdir(skillPath) {
311
- if (this.#isFactoryPath(skillPath)) {
312
- return this.#factorySource.readdir(this.#factoryPath(skillPath));
313
- }
314
- const entries = await this.fallback.readdir(skillPath);
315
- if (this.#fallbackSkillRoots.has(path2.normalize(skillPath))) {
316
- return entries.filter((entry) => !FACTORY_SKILL_NAMES.has(entry.name));
317
- }
318
- return entries;
319
- }
320
- realpath(skillPath) {
321
- if (this.#isFactoryPath(skillPath)) return Promise.resolve(path2.normalize(skillPath));
322
- return this.fallback.realpath ? this.fallback.realpath(skillPath) : Promise.resolve(skillPath);
323
- }
35
+ fallback;
36
+ #factorySource = new LocalSkillSource({ basePath: FACTORY_SKILLS_SOURCE_PATH });
37
+ #fallbackSkillRoots;
38
+ constructor(fallback, fallbackSkillRoots) {
39
+ this.fallback = fallback;
40
+ this.#fallbackSkillRoots = new Set(fallbackSkillRoots.map((skillPath) => path.normalize(skillPath)));
41
+ }
42
+ #isFactoryPath(skillPath) {
43
+ const normalized = path.normalize(skillPath);
44
+ return normalized === FACTORY_SKILLS_MOUNT || normalized.startsWith(`${FACTORY_SKILLS_MOUNT}${path.sep}`);
45
+ }
46
+ #factoryPath(skillPath) {
47
+ return path.relative(FACTORY_SKILLS_MOUNT, path.normalize(skillPath));
48
+ }
49
+ exists(skillPath) {
50
+ return this.#isFactoryPath(skillPath) ? this.#factorySource.exists(this.#factoryPath(skillPath)) : this.fallback.exists(skillPath);
51
+ }
52
+ stat(skillPath) {
53
+ return this.#isFactoryPath(skillPath) ? this.#factorySource.stat(this.#factoryPath(skillPath)) : this.fallback.stat(skillPath);
54
+ }
55
+ readFile(skillPath) {
56
+ return this.#isFactoryPath(skillPath) ? this.#factorySource.readFile(this.#factoryPath(skillPath)) : this.fallback.readFile(skillPath);
57
+ }
58
+ async readdir(skillPath) {
59
+ if (this.#isFactoryPath(skillPath)) return this.#factorySource.readdir(this.#factoryPath(skillPath));
60
+ const entries = await this.fallback.readdir(skillPath);
61
+ if (this.#fallbackSkillRoots.has(path.normalize(skillPath))) return entries.filter((entry) => !FACTORY_SKILL_NAMES.has(entry.name));
62
+ return entries;
63
+ }
64
+ realpath(skillPath) {
65
+ if (this.#isFactoryPath(skillPath)) return Promise.resolve(path.normalize(skillPath));
66
+ return this.fallback.realpath ? this.fallback.realpath(skillPath) : Promise.resolve(skillPath);
67
+ }
324
68
  };
325
- var factorySkillExtension = {
326
- id: "web-factory",
327
- paths: [FACTORY_SKILLS_MOUNT],
328
- createSource: (fallback, fallbackSkillRoots) => new FactorySkillSource(fallback, fallbackSkillRoots)
69
+ const factorySkillExtension = {
70
+ id: "web-factory",
71
+ paths: [FACTORY_SKILLS_MOUNT],
72
+ createSource: (fallback, fallbackSkillRoots) => new FactorySkillSource(fallback, fallbackSkillRoots)
329
73
  };
330
74
  function createWorkspaceFactory(options = {}) {
331
- const { sandbox: sandboxConfig, github, fleet, workItems } = options;
332
- const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;
333
- const githubTokenInjectors = /* @__PURE__ */ new Map();
334
- const inflightMaterializations = /* @__PURE__ */ new Map();
335
- return async ({ requestContext, mastra, skillExtension }) => {
336
- const effectiveSkillExtension = skillExtension ?? factorySkillExtension;
337
- const ctx = requestContext.get("controller");
338
- const session = ctx?.resourceId && github ? await github.sourceControlStorage.sessions.getBySessionId(ctx.resourceId) : null;
339
- if (!session) {
340
- if (sandboxConfig && !isLocalSandbox) {
341
- throw new Error("A Factory session ID is required to create a remote sandbox workspace");
342
- }
343
- return getDynamicWorkspace({ requestContext, mastra, skillExtension: effectiveSkillExtension });
344
- }
345
- const user = requestContext.get("user");
346
- const userId = getFactoryAuthUserId(user);
347
- if (!user?.organizationId || !userId || user.organizationId !== session.orgId || userId !== session.userId) {
348
- throw new Error(`Factory session ${session.sessionId} is not available to the current user`);
349
- }
350
- if (!sandboxConfig || !github || !fleet) {
351
- throw new Error("GitHub and sandbox providers are required to create a Factory session workspace");
352
- }
353
- const storage = github.sourceControlStorage;
354
- const projectRepository = await storage.projectRepositories.get({
355
- orgId: session.orgId,
356
- id: session.projectRepositoryId
357
- });
358
- if (!projectRepository) throw new Error(`Repository link ${session.projectRepositoryId} was not found`);
359
- const connection = await storage.connections.get({ orgId: session.orgId, id: projectRepository.connectionId });
360
- const repository = await storage.repositories.get({ orgId: session.orgId, id: projectRepository.repositoryId });
361
- if (!connection || !repository) throw new Error(`Repository link ${session.projectRepositoryId} is incomplete`);
362
- const installation = await storage.installations.get({ orgId: session.orgId, id: connection.installationId });
363
- if (!installation) throw new Error(`GitHub installation ${connection.installationId} was not found`);
364
- const repoFullName = repository.slug;
365
- const workdir = isLocalSandbox ? fleet.computeLocalSessionWorkdir(repoFullName, session.id) : session.sandboxWorkdir ?? projectRepository.sandboxWorkdir;
366
- const binding = {
367
- sandboxId: session.sandboxId,
368
- checkpointName: checkpointNameForSession(session.id),
369
- setSandboxId: async (id) => {
370
- await storage.sessions.setSandbox({ id: session.id, sandboxId: id, sandboxWorkdir: workdir });
371
- session.sandboxId = id;
372
- session.sandboxWorkdir = workdir;
373
- },
374
- clear: async () => {
375
- await storage.sessions.setSandbox({ id: session.id, sandboxId: null, sandboxWorkdir: workdir });
376
- session.sandboxId = null;
377
- }
378
- };
379
- const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : "";
380
- const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;
381
- const configDir = sandboxConfig.workdir ?? DEFAULT_CONFIG_DIR;
382
- try {
383
- const existing = mastra?.getWorkspaceById(workspaceId);
384
- if (existing) {
385
- existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
386
- const registered = githubTokenInjectors.get(workspaceId);
387
- if (registered) {
388
- registerGithubTokenInjector(requestContext, registered.inject);
389
- registerGithubPatKind(requestContext, registered.patKind);
390
- try {
391
- const pat = await getGithubPat(() => github.integrationStorage, session.orgId, registered.patKind);
392
- if (pat && pat !== registered.ghToken) {
393
- registered.inject(pat);
394
- }
395
- } catch {
396
- }
397
- }
398
- return existing;
399
- }
400
- } catch {
401
- }
402
- const materialize = async () => {
403
- const access = await github.versionControl.getRepositoryAccess({
404
- orgId: session.orgId,
405
- repositoryId: repository.id
406
- });
407
- const token = access.authorization?.token;
408
- if (!token) throw new Error("Repository access did not include a bearer token for the Factory session");
409
- let patKind = "default";
410
- if (workItems) {
411
- try {
412
- const address = getFactorySessionAddress(requestContext);
413
- const runBinding = address ? await workItems.findRunBindingBySession(address) : null;
414
- if (runBinding?.role === "review" && runBinding.orgId === session.orgId) patKind = "reviewer";
415
- } catch {
416
- }
417
- }
418
- const ghCliToken = await getGithubPat(() => github.integrationStorage, session.orgId, patKind) ?? token;
419
- const sandbox = await fleet.ensureSandbox(
420
- binding,
421
- { GH_TOKEN: ghCliToken },
422
- void 0,
423
- isLocalSandbox ? { workingDirectory: workdir } : {}
424
- );
425
- await materializeRepo({
426
- row: { id: session.id, sandboxWorkdir: workdir, materializedAt: session.materializedAt },
427
- repoInfo: { repoFullName, defaultBranch: repository.defaultBranch },
428
- sandbox,
429
- token,
430
- storage: storage.sessions
431
- });
432
- await checkoutSessionBranch(sandbox, workdir, {
433
- branch: session.branch,
434
- baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,
435
- token,
436
- repoFullName
437
- });
438
- if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
439
- const injectGithubToken = (freshToken) => {
440
- if (!sandbox.setEnvironmentVariable) {
441
- throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
442
- }
443
- sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
444
- const registered = githubTokenInjectors.get(workspaceId);
445
- if (registered) registered.ghToken = freshToken;
446
- };
447
- githubTokenInjectors.set(workspaceId, { inject: injectGithubToken, patKind, ghToken: ghCliToken });
448
- registerGithubTokenInjector(requestContext, injectGithubToken);
449
- registerGithubPatKind(requestContext, patKind);
450
- const filesystem = new SandboxFilesystem({ sandbox, workdir });
451
- const projectSkillPaths = [path2.join(configDir, "skills"), ".claude/skills", ".agents/skills"];
452
- const skillPaths = [...effectiveSkillExtension?.paths ?? [], ...projectSkillPaths];
453
- return new Workspace({
454
- id: workspaceId,
455
- name: "Mastra Code Factory Session Workspace",
456
- filesystem,
457
- sandbox,
458
- tools: MASTRACODE_WORKSPACE_TOOLS,
459
- skills: skillPaths,
460
- skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
461
- });
462
- };
463
- const inflight = inflightMaterializations.get(workspaceId);
464
- if (inflight) {
465
- const workspace = await inflight;
466
- const registered = githubTokenInjectors.get(workspaceId);
467
- if (registered) {
468
- registerGithubTokenInjector(requestContext, registered.inject);
469
- registerGithubPatKind(requestContext, registered.patKind);
470
- }
471
- return workspace;
472
- }
473
- const materialization = materialize();
474
- inflightMaterializations.set(workspaceId, materialization);
475
- try {
476
- return await materialization;
477
- } finally {
478
- inflightMaterializations.delete(workspaceId);
479
- }
480
- };
481
- }
482
- var getFactoryWorkspace = createWorkspaceFactory();
483
- export {
484
- checkpointNameForSession,
485
- createWorkspaceFactory,
486
- getFactoryWorkspace
487
- };
75
+ const { sandbox: sandboxConfig, github, fleet, workItems } = options;
76
+ const isLocalSandbox = sandboxConfig?.machine instanceof LocalSandbox;
77
+ const githubTokenInjectors = /* @__PURE__ */ new Map();
78
+ const inflightMaterializations = /* @__PURE__ */ new Map();
79
+ return async ({ requestContext, mastra, skillExtension }) => {
80
+ const effectiveSkillExtension = skillExtension ?? factorySkillExtension;
81
+ const ctx = requestContext.get("controller");
82
+ const session = ctx?.resourceId && github ? await github.sourceControlStorage.sessions.getBySessionId(ctx.resourceId) : null;
83
+ if (!session) {
84
+ if (sandboxConfig && !isLocalSandbox) throw new Error("A Factory session ID is required to create a remote sandbox workspace");
85
+ return getDynamicWorkspace({
86
+ requestContext,
87
+ mastra,
88
+ skillExtension: effectiveSkillExtension
89
+ });
90
+ }
91
+ const user = requestContext.get("user");
92
+ const userId = getFactoryAuthUserId(user);
93
+ if (!user?.organizationId || !userId || user.organizationId !== session.orgId || userId !== session.userId) throw new Error(`Factory session ${session.sessionId} is not available to the current user`);
94
+ if (!sandboxConfig || !github || !fleet) throw new Error("GitHub and sandbox providers are required to create a Factory session workspace");
95
+ const storage = github.sourceControlStorage;
96
+ const projectRepository = await storage.projectRepositories.get({
97
+ orgId: session.orgId,
98
+ id: session.projectRepositoryId
99
+ });
100
+ if (!projectRepository) throw new Error(`Repository link ${session.projectRepositoryId} was not found`);
101
+ const connection = await storage.connections.get({
102
+ orgId: session.orgId,
103
+ id: projectRepository.connectionId
104
+ });
105
+ const repository = await storage.repositories.get({
106
+ orgId: session.orgId,
107
+ id: projectRepository.repositoryId
108
+ });
109
+ if (!connection || !repository) throw new Error(`Repository link ${session.projectRepositoryId} is incomplete`);
110
+ if (!await storage.installations.get({
111
+ orgId: session.orgId,
112
+ id: connection.installationId
113
+ })) throw new Error(`GitHub installation ${connection.installationId} was not found`);
114
+ const repoFullName = repository.slug;
115
+ const workdir = isLocalSandbox ? fleet.computeLocalSessionWorkdir(repoFullName, session.id) : session.sandboxWorkdir ?? projectRepository.sandboxWorkdir;
116
+ const binding = {
117
+ sandboxId: session.sandboxId,
118
+ checkpointName: checkpointNameForSession(session.id),
119
+ setSandboxId: async (id) => {
120
+ await storage.sessions.setSandbox({
121
+ id: session.id,
122
+ sandboxId: id,
123
+ sandboxWorkdir: workdir
124
+ });
125
+ session.sandboxId = id;
126
+ session.sandboxWorkdir = workdir;
127
+ },
128
+ clear: async () => {
129
+ await storage.sessions.setSandbox({
130
+ id: session.id,
131
+ sandboxId: null,
132
+ sandboxWorkdir: workdir
133
+ });
134
+ session.sandboxId = null;
135
+ }
136
+ };
137
+ const extensionId = effectiveSkillExtension ? `-${effectiveSkillExtension.id}` : "";
138
+ const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectRepository.id}-${session.id}${extensionId}`;
139
+ const configDir = sandboxConfig.workdir ?? DEFAULT_CONFIG_DIR;
140
+ try {
141
+ const existing = mastra?.getWorkspaceById(workspaceId);
142
+ if (existing) {
143
+ existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
144
+ const registered = githubTokenInjectors.get(workspaceId);
145
+ if (registered) {
146
+ registerGithubTokenInjector(requestContext, registered.inject);
147
+ registerGithubPatKind(requestContext, registered.patKind);
148
+ try {
149
+ const pat = await getGithubPat(() => github.integrationStorage, session.orgId, registered.patKind);
150
+ if (pat && pat !== registered.ghToken) registered.inject(pat);
151
+ } catch {}
152
+ }
153
+ return existing;
154
+ }
155
+ } catch {}
156
+ const materialize = async () => {
157
+ const token = (await github.versionControl.getRepositoryAccess({
158
+ orgId: session.orgId,
159
+ repositoryId: repository.id
160
+ })).authorization?.token;
161
+ if (!token) throw new Error("Repository access did not include a bearer token for the Factory session");
162
+ let patKind = "default";
163
+ if (workItems) try {
164
+ const address = getFactorySessionAddress(requestContext);
165
+ const runBinding = address ? await workItems.findRunBindingBySession(address) : null;
166
+ if (runBinding?.role === "review" && runBinding.orgId === session.orgId) patKind = "reviewer";
167
+ } catch {}
168
+ const ghCliToken = await getGithubPat(() => github.integrationStorage, session.orgId, patKind) ?? token;
169
+ const sandbox = await fleet.ensureSandbox(binding, { GH_TOKEN: ghCliToken }, void 0, isLocalSandbox ? { workingDirectory: workdir } : {});
170
+ await materializeRepo({
171
+ row: {
172
+ id: session.id,
173
+ sandboxWorkdir: workdir,
174
+ materializedAt: session.materializedAt
175
+ },
176
+ repoInfo: {
177
+ repoFullName,
178
+ defaultBranch: repository.defaultBranch
179
+ },
180
+ sandbox,
181
+ token,
182
+ storage: storage.sessions
183
+ });
184
+ await checkoutSessionBranch(sandbox, workdir, {
185
+ branch: session.branch,
186
+ baseBranch: session.baseBranch || projectRepository.branch || repository.defaultBranch,
187
+ token,
188
+ repoFullName
189
+ });
190
+ if (projectRepository.setupCommand) await runWorktreeSetup(sandbox, workdir, projectRepository.setupCommand);
191
+ const injectGithubToken = (freshToken) => {
192
+ if (!sandbox.setEnvironmentVariable) throw new Error("The active sandbox provider does not support runtime GitHub token refresh.");
193
+ sandbox.setEnvironmentVariable("GH_TOKEN", freshToken);
194
+ const registered = githubTokenInjectors.get(workspaceId);
195
+ if (registered) registered.ghToken = freshToken;
196
+ };
197
+ githubTokenInjectors.set(workspaceId, {
198
+ inject: injectGithubToken,
199
+ patKind,
200
+ ghToken: ghCliToken
201
+ });
202
+ registerGithubTokenInjector(requestContext, injectGithubToken);
203
+ registerGithubPatKind(requestContext, patKind);
204
+ const filesystem = new SandboxFilesystem({
205
+ sandbox,
206
+ workdir
207
+ });
208
+ const projectSkillPaths = [
209
+ path.join(configDir, "skills"),
210
+ ".claude/skills",
211
+ ".agents/skills"
212
+ ];
213
+ const skillPaths = [...effectiveSkillExtension?.paths ?? [], ...projectSkillPaths];
214
+ return new Workspace({
215
+ id: workspaceId,
216
+ name: "Mastra Code Factory Session Workspace",
217
+ filesystem,
218
+ sandbox,
219
+ tools: MASTRACODE_WORKSPACE_TOOLS,
220
+ skills: skillPaths,
221
+ skillSource: effectiveSkillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
222
+ });
223
+ };
224
+ const inflight = inflightMaterializations.get(workspaceId);
225
+ if (inflight) {
226
+ const workspace = await inflight;
227
+ const registered = githubTokenInjectors.get(workspaceId);
228
+ if (registered) {
229
+ registerGithubTokenInjector(requestContext, registered.inject);
230
+ registerGithubPatKind(requestContext, registered.patKind);
231
+ }
232
+ return workspace;
233
+ }
234
+ const materialization = materialize();
235
+ inflightMaterializations.set(workspaceId, materialization);
236
+ try {
237
+ return await materialization;
238
+ } finally {
239
+ inflightMaterializations.delete(workspaceId);
240
+ }
241
+ };
242
+ }
243
+ const getFactoryWorkspace = createWorkspaceFactory();
244
+ //#endregion
245
+ export { checkpointNameForSession, createWorkspaceFactory, getFactoryWorkspace };
246
+
488
247
  //# sourceMappingURL=workspace.js.map