@mastra/code-sdk 1.0.3-alpha.1 → 1.1.0-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 (258) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/acp/agent.js +155 -167
  3. package/dist/acp/agent.js.map +1 -1
  4. package/dist/acp/event-mapper.js +193 -168
  5. package/dist/acp/event-mapper.js.map +1 -1
  6. package/dist/acp/index.js +60 -49
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/acp/server.js +31 -30
  9. package/dist/acp/server.js.map +1 -1
  10. package/dist/acp.js +1 -4
  11. package/dist/agents/credential-resolver.js +40 -29
  12. package/dist/agents/credential-resolver.js.map +1 -1
  13. package/dist/agents/custom-provider-source.js +16 -9
  14. package/dist/agents/custom-provider-source.js.map +1 -1
  15. package/dist/agents/instructions.js +27 -36
  16. package/dist/agents/instructions.js.map +1 -1
  17. package/dist/agents/mastracode-gateway.js +355 -428
  18. package/dist/agents/mastracode-gateway.js.map +1 -1
  19. package/dist/agents/memory.js +87 -78
  20. package/dist/agents/memory.js.map +1 -1
  21. package/dist/agents/model.js +114 -119
  22. package/dist/agents/model.js.map +1 -1
  23. package/dist/agents/modes/build.js +12 -13
  24. package/dist/agents/modes/build.js.map +1 -1
  25. package/dist/agents/modes/explore.js +14 -13
  26. package/dist/agents/modes/explore.js.map +1 -1
  27. package/dist/agents/modes/plan.js +14 -15
  28. package/dist/agents/modes/plan.js.map +1 -1
  29. package/dist/agents/prompts/agent-instructions.js +78 -69
  30. package/dist/agents/prompts/agent-instructions.js.map +1 -1
  31. package/dist/agents/prompts/build.js +19 -16
  32. package/dist/agents/prompts/build.js.map +1 -1
  33. package/dist/agents/prompts/fast.js +8 -4
  34. package/dist/agents/prompts/fast.js.map +1 -1
  35. package/dist/agents/prompts/index.js +48 -47
  36. package/dist/agents/prompts/index.js.map +1 -1
  37. package/dist/agents/prompts/model.js +6 -5
  38. package/dist/agents/prompts/model.js.map +1 -1
  39. package/dist/agents/prompts/plan.js +20 -16
  40. package/dist/agents/prompts/plan.js.map +1 -1
  41. package/dist/agents/prompts/tool-guidance.js +77 -109
  42. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  43. package/dist/agents/sandbox-filesystem.js +245 -259
  44. package/dist/agents/sandbox-filesystem.js.map +1 -1
  45. package/dist/agents/sandbox-reattach.js +9 -11
  46. package/dist/agents/sandbox-reattach.js.map +1 -1
  47. package/dist/agents/thread-caveman-state.js +92 -81
  48. package/dist/agents/thread-caveman-state.js.map +1 -1
  49. package/dist/agents/tool-availability.js +62 -80
  50. package/dist/agents/tool-availability.js.map +1 -1
  51. package/dist/agents/tools.js +99 -139
  52. package/dist/agents/tools.js.map +1 -1
  53. package/dist/agents/workspace.js +232 -225
  54. package/dist/agents/workspace.js.map +1 -1
  55. package/dist/analytics.js +139 -128
  56. package/dist/analytics.js.map +1 -1
  57. package/dist/auth/authorization-input.js +39 -25
  58. package/dist/auth/authorization-input.js.map +1 -1
  59. package/dist/auth/device-code.js +112 -80
  60. package/dist/auth/device-code.js.map +1 -1
  61. package/dist/auth/index.js +2 -9
  62. package/dist/auth/pkce.js +27 -16
  63. package/dist/auth/pkce.js.map +1 -1
  64. package/dist/auth/providers/anthropic.js +107 -93
  65. package/dist/auth/providers/anthropic.js.map +1 -1
  66. package/dist/auth/providers/github-copilot.js +304 -293
  67. package/dist/auth/providers/github-copilot.js.map +1 -1
  68. package/dist/auth/providers/openai-codex.js +442 -460
  69. package/dist/auth/providers/openai-codex.js.map +1 -1
  70. package/dist/auth/providers/xai.js +179 -145
  71. package/dist/auth/providers/xai.js.map +1 -1
  72. package/dist/auth/storage.js +182 -175
  73. package/dist/auth/storage.js.map +1 -1
  74. package/dist/auth/types.js +1 -1
  75. package/dist/clipboard/index.js +206 -172
  76. package/dist/clipboard/index.js.map +1 -1
  77. package/dist/constants.js +11 -16
  78. package/dist/constants.js.map +1 -1
  79. package/dist/error-classification.js +19 -11
  80. package/dist/error-classification.js.map +1 -1
  81. package/dist/evals/context-builder.js +145 -104
  82. package/dist/evals/context-builder.js.map +1 -1
  83. package/dist/evals/index.js +4 -7
  84. package/dist/evals/scorers/classify-command.js +62 -41
  85. package/dist/evals/scorers/classify-command.js.map +1 -1
  86. package/dist/evals/scorers/efficiency.js +239 -181
  87. package/dist/evals/scorers/efficiency.js.map +1 -1
  88. package/dist/evals/scorers/extract-tools.js +51 -47
  89. package/dist/evals/scorers/extract-tools.js.map +1 -1
  90. package/dist/evals/scorers/index.js +1 -5
  91. package/dist/evals/scorers/outcome.js +321 -212
  92. package/dist/evals/scorers/outcome.js.map +1 -1
  93. package/dist/goal-manager.js +266 -261
  94. package/dist/goal-manager.js.map +1 -1
  95. package/dist/goal-signal.js +14 -13
  96. package/dist/goal-signal.js.map +1 -1
  97. package/dist/headless/cli.js +153 -154
  98. package/dist/headless/cli.js.map +1 -1
  99. package/dist/headless/flags.js +180 -178
  100. package/dist/headless/flags.js.map +1 -1
  101. package/dist/headless/format.js +72 -71
  102. package/dist/headless/format.js.map +1 -1
  103. package/dist/headless/index.js +5 -31
  104. package/dist/headless/policy.js +35 -31
  105. package/dist/headless/policy.js.map +1 -1
  106. package/dist/headless/run-mc.js +332 -334
  107. package/dist/headless/run-mc.js.map +1 -1
  108. package/dist/headless/types.js +16 -7
  109. package/dist/headless/types.js.map +1 -1
  110. package/dist/hooks/config.js +56 -61
  111. package/dist/hooks/config.js.map +1 -1
  112. package/dist/hooks/executor.js +118 -116
  113. package/dist/hooks/executor.js.map +1 -1
  114. package/dist/hooks/index.js +4 -15
  115. package/dist/hooks/manager.js +221 -280
  116. package/dist/hooks/manager.js.map +1 -1
  117. package/dist/hooks/types.js +5 -4
  118. package/dist/hooks/types.js.map +1 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +632 -712
  121. package/dist/index.js.map +1 -1
  122. package/dist/ipc/ipc-reporter.js +19 -22
  123. package/dist/ipc/ipc-reporter.js.map +1 -1
  124. package/dist/lsp/client.js +248 -306
  125. package/dist/lsp/client.js.map +1 -1
  126. package/dist/lsp/index.js +1 -6
  127. package/dist/lsp/language.js +39 -43
  128. package/dist/lsp/language.js.map +1 -1
  129. package/dist/lsp/manager.js +78 -93
  130. package/dist/lsp/manager.js.map +1 -1
  131. package/dist/lsp/server.js +151 -120
  132. package/dist/lsp/server.js.map +1 -1
  133. package/dist/lsp/workspace.js +50 -47
  134. package/dist/lsp/workspace.js.map +1 -1
  135. package/dist/mcp/config.js +210 -199
  136. package/dist/mcp/config.js.map +1 -1
  137. package/dist/mcp/index.js +2 -9
  138. package/dist/mcp/manager.js +482 -475
  139. package/dist/mcp/manager.js.map +1 -1
  140. package/dist/mcp/types.js +1 -1
  141. package/dist/onboarding/custom-packs.js +14 -17
  142. package/dist/onboarding/custom-packs.js.map +1 -1
  143. package/dist/onboarding/custom-providers.js +22 -20
  144. package/dist/onboarding/custom-providers.js.map +1 -1
  145. package/dist/onboarding/index.d.ts +1 -1
  146. package/dist/onboarding/index.d.ts.map +1 -1
  147. package/dist/onboarding/index.js +3 -21
  148. package/dist/onboarding/om-settings.d.ts +5 -0
  149. package/dist/onboarding/om-settings.d.ts.map +1 -1
  150. package/dist/onboarding/om-settings.js +41 -20
  151. package/dist/onboarding/om-settings.js.map +1 -1
  152. package/dist/onboarding/packs.d.ts +4 -6
  153. package/dist/onboarding/packs.d.ts.map +1 -1
  154. package/dist/onboarding/packs.js +154 -105
  155. package/dist/onboarding/packs.js.map +1 -1
  156. package/dist/onboarding/settings.js +575 -517
  157. package/dist/onboarding/settings.js.map +1 -1
  158. package/dist/permissions.js +112 -99
  159. package/dist/permissions.js.map +1 -1
  160. package/dist/plugin.js +21 -23
  161. package/dist/plugin.js.map +1 -1
  162. package/dist/plugins/dependencies.js +64 -87
  163. package/dist/plugins/dependencies.js.map +1 -1
  164. package/dist/plugins/install.js +159 -169
  165. package/dist/plugins/install.js.map +1 -1
  166. package/dist/plugins/loader.js +170 -185
  167. package/dist/plugins/loader.js.map +1 -1
  168. package/dist/plugins/manager.js +374 -380
  169. package/dist/plugins/manager.js.map +1 -1
  170. package/dist/plugins/manifest.js +38 -63
  171. package/dist/plugins/manifest.js.map +1 -1
  172. package/dist/plugins/package-link.js +48 -64
  173. package/dist/plugins/package-link.js.map +1 -1
  174. package/dist/plugins/paths.js +18 -19
  175. package/dist/plugins/paths.js.map +1 -1
  176. package/dist/plugins/registry.js +97 -81
  177. package/dist/plugins/registry.js.map +1 -1
  178. package/dist/plugins/scaffold.js +62 -98
  179. package/dist/plugins/scaffold.js.map +1 -1
  180. package/dist/plugins/types.js +1 -1
  181. package/dist/processors/plan-rejection-abort.js +45 -44
  182. package/dist/processors/plan-rejection-abort.js.map +1 -1
  183. package/dist/providers/amazon-bedrock-gateway.js +134 -125
  184. package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
  185. package/dist/providers/amazon-bedrock.js +68 -47
  186. package/dist/providers/amazon-bedrock.js.map +1 -1
  187. package/dist/providers/claude-max.js +153 -133
  188. package/dist/providers/claude-max.js.map +1 -1
  189. package/dist/providers/github-copilot.js +232 -230
  190. package/dist/providers/github-copilot.js.map +1 -1
  191. package/dist/providers/openai-codex.js +271 -260
  192. package/dist/providers/openai-codex.js.map +1 -1
  193. package/dist/providers/xai.js +57 -50
  194. package/dist/providers/xai.js.map +1 -1
  195. package/dist/schema.js +91 -89
  196. package/dist/schema.js.map +1 -1
  197. package/dist/theme-palette.js +18 -14
  198. package/dist/theme-palette.js.map +1 -1
  199. package/dist/tool-names.js +46 -37
  200. package/dist/tool-names.js.map +1 -1
  201. package/dist/tools/index.js +2 -8
  202. package/dist/tools/request-sandbox-access.js +71 -80
  203. package/dist/tools/request-sandbox-access.js.map +1 -1
  204. package/dist/tools/utils.js +26 -16
  205. package/dist/tools/utils.js.map +1 -1
  206. package/dist/tools/web-search.js +51 -55
  207. package/dist/tools/web-search.js.map +1 -1
  208. package/dist/utils/binaries.js +65 -61
  209. package/dist/utils/binaries.js.map +1 -1
  210. package/dist/utils/debug-log.js +51 -47
  211. package/dist/utils/debug-log.js.map +1 -1
  212. package/dist/utils/errors.js +157 -192
  213. package/dist/utils/errors.js.map +1 -1
  214. package/dist/utils/gateway-sync.js +49 -37
  215. package/dist/utils/gateway-sync.js.map +1 -1
  216. package/dist/utils/path-security.js +7 -6
  217. package/dist/utils/path-security.js.map +1 -1
  218. package/dist/utils/plan-diff.js +58 -39
  219. package/dist/utils/plan-diff.js.map +1 -1
  220. package/dist/utils/plans.js +92 -74
  221. package/dist/utils/plans.js.map +1 -1
  222. package/dist/utils/project.js +318 -256
  223. package/dist/utils/project.js.map +1 -1
  224. package/dist/utils/signals-pubsub.js +117 -99
  225. package/dist/utils/signals-pubsub.js.map +1 -1
  226. package/dist/utils/slash-command-loader.js +118 -154
  227. package/dist/utils/slash-command-loader.js.map +1 -1
  228. package/dist/utils/slash-command-processor.js +92 -83
  229. package/dist/utils/slash-command-processor.js.map +1 -1
  230. package/dist/utils/stdin-pipe.js +87 -63
  231. package/dist/utils/stdin-pipe.js.map +1 -1
  232. package/dist/utils/storage-factory.js +104 -84
  233. package/dist/utils/storage-factory.js.map +1 -1
  234. package/dist/utils/storage-maintenance.js +249 -211
  235. package/dist/utils/storage-maintenance.js.map +1 -1
  236. package/dist/utils/thread-lock.js +96 -92
  237. package/dist/utils/thread-lock.js.map +1 -1
  238. package/dist/utils/token-estimator.js +12 -12
  239. package/dist/utils/token-estimator.js.map +1 -1
  240. package/dist/utils/update-check.d.ts +1 -1
  241. package/dist/utils/update-check.js +341 -259
  242. package/dist/utils/update-check.js.map +1 -1
  243. package/dist/voice/stt-registry.js +131 -113
  244. package/dist/voice/stt-registry.js.map +1 -1
  245. package/package.json +12 -12
  246. package/dist/acp.js.map +0 -1
  247. package/dist/auth/index.js.map +0 -1
  248. package/dist/auth/types.js.map +0 -1
  249. package/dist/evals/index.js.map +0 -1
  250. package/dist/evals/scorers/index.js.map +0 -1
  251. package/dist/headless/index.js.map +0 -1
  252. package/dist/hooks/index.js.map +0 -1
  253. package/dist/lsp/index.js.map +0 -1
  254. package/dist/mcp/index.js.map +0 -1
  255. package/dist/mcp/types.js.map +0 -1
  256. package/dist/onboarding/index.js.map +0 -1
  257. package/dist/plugins/types.js.map +0 -1
  258. package/dist/tools/index.js.map +0 -1
@@ -1,244 +1,251 @@
1
- import fs, { existsSync } from "node:fs";
2
- import os from "node:os";
3
- import path, { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { Workspace, LocalFilesystem, LocalSandbox, createWorkspaceTools } from "@mastra/core/workspace";
6
- import { DEFAULT_CONFIG_DIR } from "../constants.js";
1
+ import "../constants.js";
7
2
  import { loadSettings } from "../onboarding/settings.js";
8
- import { isPathWithinRoot } from "../utils/path-security.js";
9
3
  import { getPlansDir } from "../utils/plans.js";
4
+ import { isPathWithinRoot } from "../utils/path-security.js";
10
5
  import { SandboxFilesystem } from "./sandbox-filesystem.js";
11
6
  import { reattachProjectSandbox } from "./sandbox-reattach.js";
12
7
  import { GOAL_JUDGE_READONLY_TOOLS, MASTRACODE_WORKSPACE_TOOLS } from "./tool-availability.js";
8
+ import fs, { existsSync } from "fs";
9
+ import os from "os";
10
+ import path, { dirname, join } from "path";
11
+ import { LocalFilesystem, LocalSandbox, Workspace, createWorkspaceTools } from "@mastra/core/workspace";
12
+ import { fileURLToPath } from "url";
13
+ //#region src/agents/workspace.ts
13
14
  function buildSandboxEnv() {
14
- return {
15
- ...process.env,
16
- // Explicit overrides for non-interactive subprocess execution
17
- FORCE_COLOR: "1",
18
- CLICOLOR_FORCE: "1",
19
- TERM: process.env.TERM || "xterm-256color",
20
- CI: "true",
21
- NONINTERACTIVE: "1",
22
- DEBIAN_FRONTEND: "noninteractive"
23
- };
15
+ return {
16
+ ...process.env,
17
+ FORCE_COLOR: "1",
18
+ CLICOLOR_FORCE: "1",
19
+ TERM: process.env.TERM || "xterm-256color",
20
+ CI: "true",
21
+ NONINTERACTIVE: "1",
22
+ DEBIAN_FRONTEND: "noninteractive"
23
+ };
24
24
  }
25
25
  function collectSkillPaths(skillsDirs, allowedRoot) {
26
- const paths = [];
27
- const seen = /* @__PURE__ */ new Set();
28
- let realAllowedRoot;
29
- if (allowedRoot) {
30
- try {
31
- realAllowedRoot = fs.realpathSync(allowedRoot);
32
- } catch {
33
- return [];
34
- }
35
- }
36
- for (const skillsDir of skillsDirs) {
37
- const skillsDirExists = fs.existsSync(skillsDir);
38
- if (skillsDirExists && realAllowedRoot) {
39
- try {
40
- const realSkillsDir = fs.realpathSync(skillsDir);
41
- if (!isPathWithinRoot(realSkillsDir, realAllowedRoot)) continue;
42
- } catch {
43
- continue;
44
- }
45
- }
46
- const resolved = path.resolve(skillsDir);
47
- if (!seen.has(resolved)) {
48
- seen.add(resolved);
49
- paths.push(skillsDir);
50
- }
51
- if (!skillsDirExists) continue;
52
- try {
53
- const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
54
- for (const entry of entries) {
55
- if (entry.isSymbolicLink()) {
56
- try {
57
- const linkPath = path.join(skillsDir, entry.name);
58
- const realPath = fs.realpathSync(linkPath);
59
- if (realAllowedRoot && !isPathWithinRoot(realPath, realAllowedRoot)) continue;
60
- const stat = fs.statSync(realPath);
61
- if (stat.isDirectory()) {
62
- const realParent = path.dirname(realPath);
63
- if (realAllowedRoot && !isPathWithinRoot(realParent, realAllowedRoot)) continue;
64
- if (!seen.has(realParent)) {
65
- seen.add(realParent);
66
- paths.push(realParent);
67
- }
68
- }
69
- } catch {
70
- continue;
71
- }
72
- }
73
- }
74
- } catch {
75
- }
76
- }
77
- return paths;
26
+ const paths = [];
27
+ const seen = /* @__PURE__ */ new Set();
28
+ let realAllowedRoot;
29
+ if (allowedRoot) try {
30
+ realAllowedRoot = fs.realpathSync(allowedRoot);
31
+ } catch {
32
+ return [];
33
+ }
34
+ for (const skillsDir of skillsDirs) {
35
+ const skillsDirExists = fs.existsSync(skillsDir);
36
+ if (skillsDirExists && realAllowedRoot) try {
37
+ if (!isPathWithinRoot(fs.realpathSync(skillsDir), realAllowedRoot)) continue;
38
+ } catch {
39
+ continue;
40
+ }
41
+ const resolved = path.resolve(skillsDir);
42
+ if (!seen.has(resolved)) {
43
+ seen.add(resolved);
44
+ paths.push(skillsDir);
45
+ }
46
+ if (!skillsDirExists) continue;
47
+ try {
48
+ const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
49
+ for (const entry of entries) if (entry.isSymbolicLink()) try {
50
+ const linkPath = path.join(skillsDir, entry.name);
51
+ const realPath = fs.realpathSync(linkPath);
52
+ if (realAllowedRoot && !isPathWithinRoot(realPath, realAllowedRoot)) continue;
53
+ if (fs.statSync(realPath).isDirectory()) {
54
+ const realParent = path.dirname(realPath);
55
+ if (realAllowedRoot && !isPathWithinRoot(realParent, realAllowedRoot)) continue;
56
+ if (!seen.has(realParent)) {
57
+ seen.add(realParent);
58
+ paths.push(realParent);
59
+ }
60
+ }
61
+ } catch {
62
+ continue;
63
+ }
64
+ } catch {}
65
+ }
66
+ return paths;
78
67
  }
79
68
  function buildSkillPaths(projectPath, configDir, homeDir = os.homedir(), pluginSkillPaths = []) {
80
- const mastraCodeLocalSkillsPath = path.join(projectPath, configDir, "skills");
81
- const claudeLocalSkillsPath = path.join(projectPath, ".claude", "skills");
82
- const agentSkillsLocalPath = path.join(projectPath, ".agents", "skills");
83
- const mastraCodeGlobalSkillsPath = path.join(homeDir, configDir, "skills");
84
- const claudeGlobalSkillsPath = path.join(homeDir, ".claude", "skills");
85
- const agentSkillsGlobalPath = path.join(homeDir, ".agents", "skills");
86
- const paths = [
87
- ...collectSkillPaths([mastraCodeLocalSkillsPath, claudeLocalSkillsPath, agentSkillsLocalPath], projectPath),
88
- ...collectSkillPaths([mastraCodeGlobalSkillsPath, claudeGlobalSkillsPath, agentSkillsGlobalPath]),
89
- ...pluginSkillPaths.flatMap((pluginSkillPath) => collectSkillPaths([pluginSkillPath], pluginSkillPath))
90
- ];
91
- const seenPaths = /* @__PURE__ */ new Set();
92
- return paths.filter((skillPath) => {
93
- let resolved;
94
- try {
95
- resolved = fs.realpathSync(skillPath);
96
- } catch {
97
- resolved = path.resolve(skillPath);
98
- }
99
- if (seenPaths.has(resolved)) return false;
100
- seenPaths.add(resolved);
101
- return true;
102
- });
69
+ const mastraCodeLocalSkillsPath = path.join(projectPath, configDir, "skills");
70
+ const claudeLocalSkillsPath = path.join(projectPath, ".claude", "skills");
71
+ const agentSkillsLocalPath = path.join(projectPath, ".agents", "skills");
72
+ const mastraCodeGlobalSkillsPath = path.join(homeDir, configDir, "skills");
73
+ const claudeGlobalSkillsPath = path.join(homeDir, ".claude", "skills");
74
+ const agentSkillsGlobalPath = path.join(homeDir, ".agents", "skills");
75
+ const paths = [
76
+ ...collectSkillPaths([
77
+ mastraCodeLocalSkillsPath,
78
+ claudeLocalSkillsPath,
79
+ agentSkillsLocalPath
80
+ ], projectPath),
81
+ ...collectSkillPaths([
82
+ mastraCodeGlobalSkillsPath,
83
+ claudeGlobalSkillsPath,
84
+ agentSkillsGlobalPath
85
+ ]),
86
+ ...pluginSkillPaths.flatMap((pluginSkillPath) => collectSkillPaths([pluginSkillPath], pluginSkillPath))
87
+ ];
88
+ const seenPaths = /* @__PURE__ */ new Set();
89
+ return paths.filter((skillPath) => {
90
+ let resolved;
91
+ try {
92
+ resolved = fs.realpathSync(skillPath);
93
+ } catch {
94
+ resolved = path.resolve(skillPath);
95
+ }
96
+ if (seenPaths.has(resolved)) return false;
97
+ seenPaths.add(resolved);
98
+ return true;
99
+ });
103
100
  }
104
- const DEFAULT_ALLOWED_PATHS = [os.tmpdir(), "/tmp", getPlansDir()].reduce((acc, p) => {
105
- const resolved = path.resolve(p);
106
- if (!acc.includes(resolved)) acc.push(resolved);
107
- return acc;
101
+ /**
102
+ * Paths the agent is always allowed to access (in addition to the project root
103
+ * and any per-thread sandboxAllowedPaths). The OS temp directory is included
104
+ * so the agent can use it as a scratchpad without requesting access every time.
105
+ */
106
+ const DEFAULT_ALLOWED_PATHS = [
107
+ os.tmpdir(),
108
+ "/tmp",
109
+ getPlansDir()
110
+ ].reduce((acc, p) => {
111
+ const resolved = path.resolve(p);
112
+ if (!acc.includes(resolved)) acc.push(resolved);
113
+ return acc;
108
114
  }, []);
109
115
  const WORKSPACE_ID_PREFIX = "mastra-code-workspace";
116
+ /**
117
+ * Detect the project's package runner from lock files.
118
+ * Used as a fallback packageRunner for LSP when no binary is found locally or on PATH.
119
+ */
110
120
  function detectPackageRunner(projectPath) {
111
- if (existsSync(join(projectPath, "pnpm-lock.yaml"))) return "pnpm dlx";
112
- if (existsSync(join(projectPath, "bun.lockb")) || existsSync(join(projectPath, "bun.lock"))) return "bunx";
113
- if (existsSync(join(projectPath, "yarn.lock"))) return "yarn dlx";
114
- if (existsSync(join(projectPath, "package-lock.json"))) return "npx --yes";
115
- return "npx --yes";
121
+ if (existsSync(join(projectPath, "pnpm-lock.yaml"))) return "pnpm dlx";
122
+ if (existsSync(join(projectPath, "bun.lockb")) || existsSync(join(projectPath, "bun.lock"))) return "bunx";
123
+ if (existsSync(join(projectPath, "yarn.lock"))) return "yarn dlx";
124
+ if (existsSync(join(projectPath, "package-lock.json"))) return "npx --yes";
125
+ return "npx --yes";
116
126
  }
117
- async function getSandboxWorkspace({
118
- projectRepositoryId,
119
- sandboxId,
120
- workdir,
121
- worktreePath,
122
- configDir,
123
- mastra,
124
- skillExtension
125
- }) {
126
- const boundWorkdir = worktreePath || workdir;
127
- const extensionId = skillExtension ? `-${skillExtension.id}` : "";
128
- const workspaceId = `${WORKSPACE_ID_PREFIX}-repository-${projectRepositoryId}-${sandboxId}-${boundWorkdir}${extensionId}`;
129
- try {
130
- const existing = mastra?.getWorkspaceById(workspaceId);
131
- if (existing) {
132
- existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
133
- return existing;
134
- }
135
- } catch {
136
- }
137
- const sandbox = await reattachProjectSandbox(sandboxId);
138
- const filesystem = new SandboxFilesystem({ sandbox, workdir: boundWorkdir });
139
- const projectSkillPaths = [path.join(configDir, "skills"), ".claude/skills", ".agents/skills"];
140
- const skillPaths = [...skillExtension?.paths ?? [], ...projectSkillPaths];
141
- return new Workspace({
142
- id: workspaceId,
143
- name: "Mastra Code Sandbox Workspace",
144
- filesystem,
145
- sandbox,
146
- tools: MASTRACODE_WORKSPACE_TOOLS,
147
- skills: skillPaths,
148
- skillSource: skillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
149
- });
127
+ /**
128
+ * Build (or reuse) a sandbox-backed Workspace for a linked project repository. The sandbox
129
+ * is reattached by its persisted provider id and a `SandboxFilesystem` is layered
130
+ * over the in-sandbox checkout so file tools and command tools share one VM.
131
+ */
132
+ async function getSandboxWorkspace({ projectRepositoryId, sandboxId, workdir, worktreePath, configDir, mastra, skillExtension }) {
133
+ const boundWorkdir = worktreePath || workdir;
134
+ const extensionId = skillExtension ? `-${skillExtension.id}` : "";
135
+ const workspaceId = `${WORKSPACE_ID_PREFIX}-repository-${projectRepositoryId}-${sandboxId}-${boundWorkdir}${extensionId}`;
136
+ try {
137
+ const existing = mastra?.getWorkspaceById(workspaceId);
138
+ if (existing) {
139
+ existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);
140
+ return existing;
141
+ }
142
+ } catch {}
143
+ const sandbox = await reattachProjectSandbox(sandboxId);
144
+ const filesystem = new SandboxFilesystem({
145
+ sandbox,
146
+ workdir: boundWorkdir
147
+ });
148
+ const projectSkillPaths = [
149
+ path.join(configDir, "skills"),
150
+ ".claude/skills",
151
+ ".agents/skills"
152
+ ];
153
+ return new Workspace({
154
+ id: workspaceId,
155
+ name: "Mastra Code Sandbox Workspace",
156
+ filesystem,
157
+ sandbox,
158
+ tools: MASTRACODE_WORKSPACE_TOOLS,
159
+ skills: [...skillExtension?.paths ?? [], ...projectSkillPaths],
160
+ skillSource: skillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem
161
+ });
150
162
  }
151
- async function getDynamicWorkspace({
152
- requestContext,
153
- mastra,
154
- skillExtension
155
- }) {
156
- const ctx = requestContext.get("controller");
157
- const state = ctx?.getState();
158
- if (state?.projectRepositoryId && state.sandboxId && state.sandboxWorkdir) {
159
- return getSandboxWorkspace({
160
- projectRepositoryId: state.projectRepositoryId,
161
- sandboxId: state.sandboxId,
162
- workdir: state.sandboxWorkdir,
163
- worktreePath: state.worktreePath,
164
- configDir: state.configDir ?? DEFAULT_CONFIG_DIR,
165
- mastra,
166
- skillExtension
167
- });
168
- }
169
- const rawProjectPath = state?.projectPath;
170
- if (!rawProjectPath) {
171
- throw new Error("Project path is required");
172
- }
173
- const projectPath = path.resolve(rawProjectPath);
174
- const configDir = state?.configDir ?? DEFAULT_CONFIG_DIR;
175
- const projectSkillPaths = buildSkillPaths(projectPath, configDir, state?.homeDir, state?.pluginSkillPaths ?? []);
176
- const skillPaths = [...skillExtension?.paths ?? [], ...projectSkillPaths];
177
- const extensionId = skillExtension ? `-${skillExtension.id}` : "";
178
- const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectPath}${extensionId}`;
179
- const sandboxPaths = state?.sandboxAllowedPaths ?? [];
180
- const allowedPaths = [
181
- ...projectSkillPaths,
182
- ...DEFAULT_ALLOWED_PATHS,
183
- ...sandboxPaths.map((p) => path.resolve(p))
184
- ];
185
- const workspaceTools = MASTRACODE_WORKSPACE_TOOLS;
186
- let existing;
187
- try {
188
- existing = mastra?.getWorkspaceById(workspaceId);
189
- } catch {
190
- }
191
- if (existing) {
192
- existing.filesystem.setAllowedPaths(allowedPaths);
193
- existing.setToolsConfig(workspaceTools);
194
- return existing;
195
- }
196
- const userLsp = loadSettings().lsp ?? {};
197
- const mcModulePath = join(dirname(fileURLToPath(import.meta.url)), "..");
198
- const lspConfig = {
199
- ...userLsp,
200
- packageRunner: userLsp.packageRunner || detectPackageRunner(projectPath),
201
- // Detected runner is the fallback — user's packageRunner always wins
202
- searchPaths: [mcModulePath, ...userLsp.searchPaths ?? []]
203
- };
204
- const filesystem = new LocalFilesystem({
205
- basePath: projectPath,
206
- allowedPaths
207
- });
208
- return new Workspace({
209
- id: workspaceId,
210
- name: "Mastra Code Workspace",
211
- filesystem,
212
- sandbox: new LocalSandbox({
213
- workingDirectory: projectPath,
214
- env: buildSandboxEnv()
215
- }),
216
- tools: workspaceTools,
217
- skills: skillPaths,
218
- ...skillExtension ? { skillSource: skillExtension.createSource(filesystem, projectSkillPaths) } : {},
219
- lsp: lspConfig
220
- });
163
+ async function getDynamicWorkspace({ requestContext, mastra, skillExtension }) {
164
+ const state = requestContext.get("controller")?.getState();
165
+ if (state?.projectRepositoryId && state.sandboxId && state.sandboxWorkdir) return getSandboxWorkspace({
166
+ projectRepositoryId: state.projectRepositoryId,
167
+ sandboxId: state.sandboxId,
168
+ workdir: state.sandboxWorkdir,
169
+ worktreePath: state.worktreePath,
170
+ configDir: state.configDir ?? ".mastracode",
171
+ mastra,
172
+ skillExtension
173
+ });
174
+ const rawProjectPath = state?.projectPath;
175
+ if (!rawProjectPath) throw new Error("Project path is required");
176
+ const projectPath = path.resolve(rawProjectPath);
177
+ const projectSkillPaths = buildSkillPaths(projectPath, state?.configDir ?? ".mastracode", state?.homeDir, state?.pluginSkillPaths ?? []);
178
+ const skillPaths = [...skillExtension?.paths ?? [], ...projectSkillPaths];
179
+ const extensionId = skillExtension ? `-${skillExtension.id}` : "";
180
+ const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectPath}${extensionId}`;
181
+ const sandboxPaths = state?.sandboxAllowedPaths ?? [];
182
+ const allowedPaths = [
183
+ ...projectSkillPaths,
184
+ ...DEFAULT_ALLOWED_PATHS,
185
+ ...sandboxPaths.map((p) => path.resolve(p))
186
+ ];
187
+ const workspaceTools = MASTRACODE_WORKSPACE_TOOLS;
188
+ let existing;
189
+ try {
190
+ existing = mastra?.getWorkspaceById(workspaceId);
191
+ } catch {}
192
+ if (existing) {
193
+ existing.filesystem.setAllowedPaths(allowedPaths);
194
+ existing.setToolsConfig(workspaceTools);
195
+ return existing;
196
+ }
197
+ const userLsp = loadSettings().lsp ?? {};
198
+ const mcModulePath = join(dirname(fileURLToPath(import.meta.url)), "..");
199
+ const lspConfig = {
200
+ ...userLsp,
201
+ packageRunner: userLsp.packageRunner || detectPackageRunner(projectPath),
202
+ searchPaths: [mcModulePath, ...userLsp.searchPaths ?? []]
203
+ };
204
+ const filesystem = new LocalFilesystem({
205
+ basePath: projectPath,
206
+ allowedPaths
207
+ });
208
+ return new Workspace({
209
+ id: workspaceId,
210
+ name: "Mastra Code Workspace",
211
+ filesystem,
212
+ sandbox: new LocalSandbox({
213
+ workingDirectory: projectPath,
214
+ env: buildSandboxEnv()
215
+ }),
216
+ tools: workspaceTools,
217
+ skills: skillPaths,
218
+ ...skillExtension ? { skillSource: skillExtension.createSource(filesystem, projectSkillPaths) } : {},
219
+ lsp: lspConfig
220
+ });
221
221
  }
222
- async function getGoalJudgeTools({
223
- requestContext,
224
- mastra
225
- }) {
226
- let workspace;
227
- try {
228
- workspace = await getDynamicWorkspace({ requestContext, mastra });
229
- } catch {
230
- return void 0;
231
- }
232
- const allTools = await createWorkspaceTools(workspace, { requestContext, workspace });
233
- const readonly = {};
234
- for (const name of GOAL_JUDGE_READONLY_TOOLS) {
235
- if (allTools[name]) readonly[name] = allTools[name];
236
- }
237
- return Object.keys(readonly).length > 0 ? readonly : void 0;
222
+ /**
223
+ * Resolver for the agent's `goal.tools` config. Builds the request's workspace
224
+ * (same per-request resolution as the agent's own tools) and returns only the
225
+ * read-only verification subset, remapped to mastracode's tool names (`view`,
226
+ * `search_content`, etc.). Returns `undefined` when no workspace can be resolved
227
+ * (e.g. no project path), keeping the default judge text-only rather than
228
+ * throwing inside the goal step.
229
+ */
230
+ async function getGoalJudgeTools({ requestContext, mastra }) {
231
+ let workspace;
232
+ try {
233
+ workspace = await getDynamicWorkspace({
234
+ requestContext,
235
+ mastra
236
+ });
237
+ } catch {
238
+ return;
239
+ }
240
+ const allTools = await createWorkspaceTools(workspace, {
241
+ requestContext,
242
+ workspace
243
+ });
244
+ const readonly = {};
245
+ for (const name of GOAL_JUDGE_READONLY_TOOLS) if (allTools[name]) readonly[name] = allTools[name];
246
+ return Object.keys(readonly).length > 0 ? readonly : void 0;
238
247
  }
239
- export {
240
- buildSkillPaths,
241
- getDynamicWorkspace,
242
- getGoalJudgeTools
243
- };
248
+ //#endregion
249
+ export { buildSkillPaths, getDynamicWorkspace, getGoalJudgeTools };
250
+
244
251
  //# sourceMappingURL=workspace.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/agents/workspace.ts"],"sourcesContent":["import fs, { existsSync } from 'node:fs';\nimport os from 'node:os';\nimport path, { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ToolsInput } from '@mastra/core/agent';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { Workspace, LocalFilesystem, LocalSandbox, createWorkspaceTools } from '@mastra/core/workspace';\nimport type { LSPConfig, SkillSource } from '@mastra/core/workspace';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { loadSettings } from '../onboarding/settings.js';\nimport type { MastraCodeState } from '../schema.js';\nimport { isPathWithinRoot } from '../utils/path-security.js';\nimport { getPlansDir } from '../utils/plans.js';\nimport { SandboxFilesystem } from './sandbox-filesystem.js';\nimport { reattachProjectSandbox } from './sandbox-reattach.js';\nimport { GOAL_JUDGE_READONLY_TOOLS, MASTRACODE_WORKSPACE_TOOLS } from './tool-availability.js';\n\n// =============================================================================\n// Sandbox Environment\n// =============================================================================\n\nfunction buildSandboxEnv(): NodeJS.ProcessEnv {\n return {\n ...process.env,\n // Explicit overrides for non-interactive subprocess execution\n FORCE_COLOR: '1',\n CLICOLOR_FORCE: '1',\n TERM: process.env.TERM || 'xterm-256color',\n CI: 'true',\n NONINTERACTIVE: '1',\n DEBIAN_FRONTEND: 'noninteractive',\n };\n}\n\n// =============================================================================\n// Create Workspace with Skills\n// =============================================================================\n\n// We support multiple skill locations for compatibility:\n// 1. Project-local: <configDir>/skills (project-specific mastracode skills)\n// 2. Project-local: .claude/skills (Claude Code compatible skills)\n// 3. Project-local: .agents/skills (Agent Skills spec compatible)\n// 4. Global: ~/<configDir>/skills (user-wide mastracode skills)\n// 5. Global: ~/.claude/skills (user-wide Claude Code skills)\n// 6. Global: ~/.agents/skills (user-wide Agent Skills spec compatible)\n\n// Mastra's LocalSkillSource.readdir uses Node's Dirent.isDirectory() which\n// returns false for symlinks. Tools like `npx skills add` install skills as\n// symlinks, so we need to resolve them. For each symlinked skill directory,\n// we add the real (resolved) parent path as an additional skill scan path.\nfunction collectSkillPaths(skillsDirs: string[], allowedRoot?: string): string[] {\n const paths: string[] = [];\n const seen = new Set<string>();\n let realAllowedRoot: string | undefined;\n\n if (allowedRoot) {\n try {\n realAllowedRoot = fs.realpathSync(allowedRoot);\n } catch {\n return [];\n }\n }\n\n for (const skillsDir of skillsDirs) {\n const skillsDirExists = fs.existsSync(skillsDir);\n if (skillsDirExists && realAllowedRoot) {\n try {\n const realSkillsDir = fs.realpathSync(skillsDir);\n if (!isPathWithinRoot(realSkillsDir, realAllowedRoot)) continue;\n } catch {\n continue;\n }\n }\n\n const resolved = path.resolve(skillsDir);\n if (!seen.has(resolved)) {\n seen.add(resolved);\n paths.push(skillsDir);\n }\n\n if (!skillsDirExists) continue;\n\n try {\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isSymbolicLink()) {\n try {\n const linkPath = path.join(skillsDir, entry.name);\n const realPath = fs.realpathSync(linkPath);\n if (realAllowedRoot && !isPathWithinRoot(realPath, realAllowedRoot)) continue;\n const stat = fs.statSync(realPath);\n if (stat.isDirectory()) {\n const realParent = path.dirname(realPath);\n if (realAllowedRoot && !isPathWithinRoot(realParent, realAllowedRoot)) continue;\n if (!seen.has(realParent)) {\n seen.add(realParent);\n paths.push(realParent);\n }\n }\n } catch {\n continue;\n }\n }\n }\n } catch {\n // Ignore errors during symlink resolution\n }\n }\n\n return paths;\n}\n\n// Build skill paths dynamically based on configDir and projectPath\nexport function buildSkillPaths(\n projectPath: string,\n configDir: string,\n homeDir = os.homedir(),\n pluginSkillPaths: string[] = [],\n): string[] {\n const mastraCodeLocalSkillsPath = path.join(projectPath, configDir, 'skills');\n const claudeLocalSkillsPath = path.join(projectPath, '.claude', 'skills');\n const agentSkillsLocalPath = path.join(projectPath, '.agents', 'skills');\n const mastraCodeGlobalSkillsPath = path.join(homeDir, configDir, 'skills');\n const claudeGlobalSkillsPath = path.join(homeDir, '.claude', 'skills');\n const agentSkillsGlobalPath = path.join(homeDir, '.agents', 'skills');\n\n const paths = [\n ...collectSkillPaths([mastraCodeLocalSkillsPath, claudeLocalSkillsPath, agentSkillsLocalPath], projectPath),\n ...collectSkillPaths([mastraCodeGlobalSkillsPath, claudeGlobalSkillsPath, agentSkillsGlobalPath]),\n ...pluginSkillPaths.flatMap(pluginSkillPath => collectSkillPaths([pluginSkillPath], pluginSkillPath)),\n ];\n\n const seenPaths = new Set<string>();\n return paths.filter(skillPath => {\n let resolved: string;\n try {\n resolved = fs.realpathSync(skillPath);\n } catch {\n resolved = path.resolve(skillPath);\n }\n if (seenPaths.has(resolved)) return false;\n seenPaths.add(resolved);\n return true;\n });\n}\n\nexport interface WorkspaceSkillExtension {\n /** Distinguishes extended workspaces from the default resolver cache. */\n id: string;\n /** Additional read-only skill roots prepended to normal project/global skill roots. */\n paths: string[];\n /** Compose the additional roots with the workspace's normal skill source. */\n createSource: (fallback: SkillSource, fallbackSkillRoots: string[]) => SkillSource;\n}\n\n/**\n * Paths the agent is always allowed to access (in addition to the project root\n * and any per-thread sandboxAllowedPaths). The OS temp directory is included\n * so the agent can use it as a scratchpad without requesting access every time.\n */\nconst DEFAULT_ALLOWED_PATHS: string[] = [os.tmpdir(), '/tmp', getPlansDir()].reduce<string[]>((acc, p) => {\n const resolved = path.resolve(p);\n if (!acc.includes(resolved)) acc.push(resolved);\n return acc;\n}, []);\n\nconst WORKSPACE_ID_PREFIX = 'mastra-code-workspace';\n\n/**\n * Detect the project's package runner from lock files.\n * Used as a fallback packageRunner for LSP when no binary is found locally or on PATH.\n */\nfunction detectPackageRunner(projectPath: string): string | undefined {\n if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) return 'pnpm dlx';\n if (existsSync(join(projectPath, 'bun.lockb')) || existsSync(join(projectPath, 'bun.lock'))) return 'bunx';\n if (existsSync(join(projectPath, 'yarn.lock'))) return 'yarn dlx';\n if (existsSync(join(projectPath, 'package-lock.json'))) return 'npx --yes';\n return 'npx --yes';\n}\n\n/**\n * Build (or reuse) a sandbox-backed Workspace for a linked project repository. The sandbox\n * is reattached by its persisted provider id and a `SandboxFilesystem` is layered\n * over the in-sandbox checkout so file tools and command tools share one VM.\n */\nasync function getSandboxWorkspace({\n projectRepositoryId,\n sandboxId,\n workdir,\n worktreePath,\n configDir,\n mastra,\n skillExtension,\n}: {\n projectRepositoryId: string;\n sandboxId: string;\n workdir: string;\n worktreePath?: string;\n configDir: string;\n mastra?: Mastra;\n skillExtension?: WorkspaceSkillExtension;\n}): Promise<Workspace> {\n // Bind the workspace to the active worktree when one is set, so file tools and\n // command tools operate inside the feature branch's working tree rather than\n // the base checkout. Falls back to the repo root when no worktree is active.\n const boundWorkdir = worktreePath || workdir;\n\n // Include the sandbox id *and* worktree path in the reuse key: a new sandbox\n // (e.g. the previous one expired) or a different worktree must each get a\n // fresh Workspace/ProcessManager instead of reusing one bound to a stale\n // sandbox or the wrong working tree.\n const extensionId = skillExtension ? `-${skillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-repository-${projectRepositoryId}-${sandboxId}-${boundWorkdir}${extensionId}`;\n\n // Reuse the existing remote workspace if already registered (preserves the\n // reattached sandbox + ProcessManager state across re-opens).\n try {\n const existing = mastra?.getWorkspaceById(workspaceId) as Workspace | undefined;\n if (existing) {\n existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);\n return existing;\n }\n } catch {\n // Not registered yet.\n }\n\n const sandbox = await reattachProjectSandbox(sandboxId);\n const filesystem = new SandboxFilesystem({ sandbox, workdir: boundWorkdir });\n const projectSkillPaths = [path.join(configDir, 'skills'), '.claude/skills', '.agents/skills'];\n const skillPaths = [...(skillExtension?.paths ?? []), ...projectSkillPaths];\n\n return new Workspace({\n id: workspaceId,\n name: 'Mastra Code Sandbox Workspace',\n filesystem,\n sandbox: sandbox as unknown as ConstructorParameters<typeof Workspace>[0]['sandbox'],\n tools: MASTRACODE_WORKSPACE_TOOLS,\n skills: skillPaths,\n skillSource: skillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem,\n });\n}\n\nexport async function getDynamicWorkspace({\n requestContext,\n mastra,\n skillExtension,\n}: {\n requestContext: RequestContext;\n mastra?: Mastra;\n skillExtension?: WorkspaceSkillExtension;\n}) {\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeState> | undefined;\n const state = ctx?.getState();\n\n // Repository-backed project: the repo lives inside a remote sandbox, not on\n // the server host. Reattach to the already-provisioned + materialized sandbox\n // and build a sandbox-backed Workspace. Optional embedders may add read-only\n // skill roots while project skills remain sandbox-backed.\n if (state?.projectRepositoryId && state.sandboxId && state.sandboxWorkdir) {\n return getSandboxWorkspace({\n projectRepositoryId: state.projectRepositoryId,\n sandboxId: state.sandboxId,\n workdir: state.sandboxWorkdir,\n worktreePath: state.worktreePath,\n configDir: state.configDir ?? DEFAULT_CONFIG_DIR,\n mastra,\n skillExtension,\n });\n }\n\n const rawProjectPath = state?.projectPath;\n\n if (!rawProjectPath) {\n throw new Error('Project path is required');\n }\n\n const projectPath = path.resolve(rawProjectPath);\n const configDir = state?.configDir ?? DEFAULT_CONFIG_DIR;\n const projectSkillPaths = buildSkillPaths(projectPath, configDir, state?.homeDir, state?.pluginSkillPaths ?? []);\n const skillPaths = [...(skillExtension?.paths ?? []), ...projectSkillPaths];\n const extensionId = skillExtension ? `-${skillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectPath}${extensionId}`;\n const sandboxPaths = state?.sandboxAllowedPaths ?? [];\n const allowedPaths = [\n ...projectSkillPaths,\n ...DEFAULT_ALLOWED_PATHS,\n ...sandboxPaths.map((p: string) => path.resolve(p)),\n ];\n\n // All modes share the same workspace tool configuration. Per-mode tool\n // visibility is enforced at LLM-call time via `availableTools` /\n // `activeTools` on the AgentController, not by mutating workspace capabilities.\n const workspaceTools = MASTRACODE_WORKSPACE_TOOLS;\n\n // Reuse existing workspace if already registered (preserves ProcessManager state)\n let existing: Workspace<LocalFilesystem, LocalSandbox> | undefined;\n try {\n existing = mastra?.getWorkspaceById(workspaceId) as Workspace<LocalFilesystem, LocalSandbox>;\n } catch {\n // Not registered yet\n }\n\n if (existing) {\n existing.filesystem.setAllowedPaths(allowedPaths);\n existing.setToolsConfig(workspaceTools);\n return existing;\n }\n\n const userLsp = loadSettings().lsp ?? {};\n const mcModulePath = join(dirname(fileURLToPath(import.meta.url)), '..');\n const lspConfig: LSPConfig = {\n ...userLsp,\n packageRunner: userLsp.packageRunner || detectPackageRunner(projectPath), // Detected runner is the fallback — user's packageRunner always wins\n searchPaths: [mcModulePath, ...(userLsp.searchPaths ?? [])],\n };\n\n // First call for this project — create the workspace\n const filesystem = new LocalFilesystem({\n basePath: projectPath,\n allowedPaths,\n });\n return new Workspace({\n id: workspaceId,\n name: 'Mastra Code Workspace',\n filesystem,\n sandbox: new LocalSandbox({\n workingDirectory: projectPath,\n env: buildSandboxEnv(),\n }),\n tools: workspaceTools,\n skills: skillPaths,\n ...(skillExtension ? { skillSource: skillExtension.createSource(filesystem, projectSkillPaths) } : {}),\n lsp: lspConfig,\n });\n}\n\n/**\n * Resolver for the agent's `goal.tools` config. Builds the request's workspace\n * (same per-request resolution as the agent's own tools) and returns only the\n * read-only verification subset, remapped to mastracode's tool names (`view`,\n * `search_content`, etc.). Returns `undefined` when no workspace can be resolved\n * (e.g. no project path), keeping the default judge text-only rather than\n * throwing inside the goal step.\n */\nexport async function getGoalJudgeTools({\n requestContext,\n mastra,\n}: {\n requestContext: RequestContext;\n mastra?: Mastra;\n}): Promise<ToolsInput | undefined> {\n let workspace: Workspace;\n try {\n workspace = await getDynamicWorkspace({ requestContext, mastra });\n } catch {\n return undefined;\n }\n\n const allTools = await createWorkspaceTools(workspace, { requestContext, workspace });\n const readonly: ToolsInput = {};\n for (const name of GOAL_JUDGE_READONLY_TOOLS) {\n if (allTools[name]) readonly[name] = allTools[name];\n }\n return Object.keys(readonly).length > 0 ? readonly : undefined;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"workspace.js","names":[],"sources":["../../src/agents/workspace.ts"],"sourcesContent":["import fs, { existsSync } from 'node:fs';\nimport os from 'node:os';\nimport path, { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ToolsInput } from '@mastra/core/agent';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { Workspace, LocalFilesystem, LocalSandbox, createWorkspaceTools } from '@mastra/core/workspace';\nimport type { LSPConfig, SkillSource } from '@mastra/core/workspace';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { loadSettings } from '../onboarding/settings.js';\nimport type { MastraCodeState } from '../schema.js';\nimport { isPathWithinRoot } from '../utils/path-security.js';\nimport { getPlansDir } from '../utils/plans.js';\nimport { SandboxFilesystem } from './sandbox-filesystem.js';\nimport { reattachProjectSandbox } from './sandbox-reattach.js';\nimport { GOAL_JUDGE_READONLY_TOOLS, MASTRACODE_WORKSPACE_TOOLS } from './tool-availability.js';\n\n// =============================================================================\n// Sandbox Environment\n// =============================================================================\n\nfunction buildSandboxEnv(): NodeJS.ProcessEnv {\n return {\n ...process.env,\n // Explicit overrides for non-interactive subprocess execution\n FORCE_COLOR: '1',\n CLICOLOR_FORCE: '1',\n TERM: process.env.TERM || 'xterm-256color',\n CI: 'true',\n NONINTERACTIVE: '1',\n DEBIAN_FRONTEND: 'noninteractive',\n };\n}\n\n// =============================================================================\n// Create Workspace with Skills\n// =============================================================================\n\n// We support multiple skill locations for compatibility:\n// 1. Project-local: <configDir>/skills (project-specific mastracode skills)\n// 2. Project-local: .claude/skills (Claude Code compatible skills)\n// 3. Project-local: .agents/skills (Agent Skills spec compatible)\n// 4. Global: ~/<configDir>/skills (user-wide mastracode skills)\n// 5. Global: ~/.claude/skills (user-wide Claude Code skills)\n// 6. Global: ~/.agents/skills (user-wide Agent Skills spec compatible)\n\n// Mastra's LocalSkillSource.readdir uses Node's Dirent.isDirectory() which\n// returns false for symlinks. Tools like `npx skills add` install skills as\n// symlinks, so we need to resolve them. For each symlinked skill directory,\n// we add the real (resolved) parent path as an additional skill scan path.\nfunction collectSkillPaths(skillsDirs: string[], allowedRoot?: string): string[] {\n const paths: string[] = [];\n const seen = new Set<string>();\n let realAllowedRoot: string | undefined;\n\n if (allowedRoot) {\n try {\n realAllowedRoot = fs.realpathSync(allowedRoot);\n } catch {\n return [];\n }\n }\n\n for (const skillsDir of skillsDirs) {\n const skillsDirExists = fs.existsSync(skillsDir);\n if (skillsDirExists && realAllowedRoot) {\n try {\n const realSkillsDir = fs.realpathSync(skillsDir);\n if (!isPathWithinRoot(realSkillsDir, realAllowedRoot)) continue;\n } catch {\n continue;\n }\n }\n\n const resolved = path.resolve(skillsDir);\n if (!seen.has(resolved)) {\n seen.add(resolved);\n paths.push(skillsDir);\n }\n\n if (!skillsDirExists) continue;\n\n try {\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isSymbolicLink()) {\n try {\n const linkPath = path.join(skillsDir, entry.name);\n const realPath = fs.realpathSync(linkPath);\n if (realAllowedRoot && !isPathWithinRoot(realPath, realAllowedRoot)) continue;\n const stat = fs.statSync(realPath);\n if (stat.isDirectory()) {\n const realParent = path.dirname(realPath);\n if (realAllowedRoot && !isPathWithinRoot(realParent, realAllowedRoot)) continue;\n if (!seen.has(realParent)) {\n seen.add(realParent);\n paths.push(realParent);\n }\n }\n } catch {\n continue;\n }\n }\n }\n } catch {\n // Ignore errors during symlink resolution\n }\n }\n\n return paths;\n}\n\n// Build skill paths dynamically based on configDir and projectPath\nexport function buildSkillPaths(\n projectPath: string,\n configDir: string,\n homeDir = os.homedir(),\n pluginSkillPaths: string[] = [],\n): string[] {\n const mastraCodeLocalSkillsPath = path.join(projectPath, configDir, 'skills');\n const claudeLocalSkillsPath = path.join(projectPath, '.claude', 'skills');\n const agentSkillsLocalPath = path.join(projectPath, '.agents', 'skills');\n const mastraCodeGlobalSkillsPath = path.join(homeDir, configDir, 'skills');\n const claudeGlobalSkillsPath = path.join(homeDir, '.claude', 'skills');\n const agentSkillsGlobalPath = path.join(homeDir, '.agents', 'skills');\n\n const paths = [\n ...collectSkillPaths([mastraCodeLocalSkillsPath, claudeLocalSkillsPath, agentSkillsLocalPath], projectPath),\n ...collectSkillPaths([mastraCodeGlobalSkillsPath, claudeGlobalSkillsPath, agentSkillsGlobalPath]),\n ...pluginSkillPaths.flatMap(pluginSkillPath => collectSkillPaths([pluginSkillPath], pluginSkillPath)),\n ];\n\n const seenPaths = new Set<string>();\n return paths.filter(skillPath => {\n let resolved: string;\n try {\n resolved = fs.realpathSync(skillPath);\n } catch {\n resolved = path.resolve(skillPath);\n }\n if (seenPaths.has(resolved)) return false;\n seenPaths.add(resolved);\n return true;\n });\n}\n\nexport interface WorkspaceSkillExtension {\n /** Distinguishes extended workspaces from the default resolver cache. */\n id: string;\n /** Additional read-only skill roots prepended to normal project/global skill roots. */\n paths: string[];\n /** Compose the additional roots with the workspace's normal skill source. */\n createSource: (fallback: SkillSource, fallbackSkillRoots: string[]) => SkillSource;\n}\n\n/**\n * Paths the agent is always allowed to access (in addition to the project root\n * and any per-thread sandboxAllowedPaths). The OS temp directory is included\n * so the agent can use it as a scratchpad without requesting access every time.\n */\nconst DEFAULT_ALLOWED_PATHS: string[] = [os.tmpdir(), '/tmp', getPlansDir()].reduce<string[]>((acc, p) => {\n const resolved = path.resolve(p);\n if (!acc.includes(resolved)) acc.push(resolved);\n return acc;\n}, []);\n\nconst WORKSPACE_ID_PREFIX = 'mastra-code-workspace';\n\n/**\n * Detect the project's package runner from lock files.\n * Used as a fallback packageRunner for LSP when no binary is found locally or on PATH.\n */\nfunction detectPackageRunner(projectPath: string): string | undefined {\n if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) return 'pnpm dlx';\n if (existsSync(join(projectPath, 'bun.lockb')) || existsSync(join(projectPath, 'bun.lock'))) return 'bunx';\n if (existsSync(join(projectPath, 'yarn.lock'))) return 'yarn dlx';\n if (existsSync(join(projectPath, 'package-lock.json'))) return 'npx --yes';\n return 'npx --yes';\n}\n\n/**\n * Build (or reuse) a sandbox-backed Workspace for a linked project repository. The sandbox\n * is reattached by its persisted provider id and a `SandboxFilesystem` is layered\n * over the in-sandbox checkout so file tools and command tools share one VM.\n */\nasync function getSandboxWorkspace({\n projectRepositoryId,\n sandboxId,\n workdir,\n worktreePath,\n configDir,\n mastra,\n skillExtension,\n}: {\n projectRepositoryId: string;\n sandboxId: string;\n workdir: string;\n worktreePath?: string;\n configDir: string;\n mastra?: Mastra;\n skillExtension?: WorkspaceSkillExtension;\n}): Promise<Workspace> {\n // Bind the workspace to the active worktree when one is set, so file tools and\n // command tools operate inside the feature branch's working tree rather than\n // the base checkout. Falls back to the repo root when no worktree is active.\n const boundWorkdir = worktreePath || workdir;\n\n // Include the sandbox id *and* worktree path in the reuse key: a new sandbox\n // (e.g. the previous one expired) or a different worktree must each get a\n // fresh Workspace/ProcessManager instead of reusing one bound to a stale\n // sandbox or the wrong working tree.\n const extensionId = skillExtension ? `-${skillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-repository-${projectRepositoryId}-${sandboxId}-${boundWorkdir}${extensionId}`;\n\n // Reuse the existing remote workspace if already registered (preserves the\n // reattached sandbox + ProcessManager state across re-opens).\n try {\n const existing = mastra?.getWorkspaceById(workspaceId) as Workspace | undefined;\n if (existing) {\n existing.setToolsConfig(MASTRACODE_WORKSPACE_TOOLS);\n return existing;\n }\n } catch {\n // Not registered yet.\n }\n\n const sandbox = await reattachProjectSandbox(sandboxId);\n const filesystem = new SandboxFilesystem({ sandbox, workdir: boundWorkdir });\n const projectSkillPaths = [path.join(configDir, 'skills'), '.claude/skills', '.agents/skills'];\n const skillPaths = [...(skillExtension?.paths ?? []), ...projectSkillPaths];\n\n return new Workspace({\n id: workspaceId,\n name: 'Mastra Code Sandbox Workspace',\n filesystem,\n sandbox: sandbox as unknown as ConstructorParameters<typeof Workspace>[0]['sandbox'],\n tools: MASTRACODE_WORKSPACE_TOOLS,\n skills: skillPaths,\n skillSource: skillExtension?.createSource(filesystem, projectSkillPaths) ?? filesystem,\n });\n}\n\nexport async function getDynamicWorkspace({\n requestContext,\n mastra,\n skillExtension,\n}: {\n requestContext: RequestContext;\n mastra?: Mastra;\n skillExtension?: WorkspaceSkillExtension;\n}) {\n const ctx = requestContext.get('controller') as AgentControllerRequestContext<MastraCodeState> | undefined;\n const state = ctx?.getState();\n\n // Repository-backed project: the repo lives inside a remote sandbox, not on\n // the server host. Reattach to the already-provisioned + materialized sandbox\n // and build a sandbox-backed Workspace. Optional embedders may add read-only\n // skill roots while project skills remain sandbox-backed.\n if (state?.projectRepositoryId && state.sandboxId && state.sandboxWorkdir) {\n return getSandboxWorkspace({\n projectRepositoryId: state.projectRepositoryId,\n sandboxId: state.sandboxId,\n workdir: state.sandboxWorkdir,\n worktreePath: state.worktreePath,\n configDir: state.configDir ?? DEFAULT_CONFIG_DIR,\n mastra,\n skillExtension,\n });\n }\n\n const rawProjectPath = state?.projectPath;\n\n if (!rawProjectPath) {\n throw new Error('Project path is required');\n }\n\n const projectPath = path.resolve(rawProjectPath);\n const configDir = state?.configDir ?? DEFAULT_CONFIG_DIR;\n const projectSkillPaths = buildSkillPaths(projectPath, configDir, state?.homeDir, state?.pluginSkillPaths ?? []);\n const skillPaths = [...(skillExtension?.paths ?? []), ...projectSkillPaths];\n const extensionId = skillExtension ? `-${skillExtension.id}` : '';\n const workspaceId = `${WORKSPACE_ID_PREFIX}-${projectPath}${extensionId}`;\n const sandboxPaths = state?.sandboxAllowedPaths ?? [];\n const allowedPaths = [\n ...projectSkillPaths,\n ...DEFAULT_ALLOWED_PATHS,\n ...sandboxPaths.map((p: string) => path.resolve(p)),\n ];\n\n // All modes share the same workspace tool configuration. Per-mode tool\n // visibility is enforced at LLM-call time via `availableTools` /\n // `activeTools` on the AgentController, not by mutating workspace capabilities.\n const workspaceTools = MASTRACODE_WORKSPACE_TOOLS;\n\n // Reuse existing workspace if already registered (preserves ProcessManager state)\n let existing: Workspace<LocalFilesystem, LocalSandbox> | undefined;\n try {\n existing = mastra?.getWorkspaceById(workspaceId) as Workspace<LocalFilesystem, LocalSandbox>;\n } catch {\n // Not registered yet\n }\n\n if (existing) {\n existing.filesystem.setAllowedPaths(allowedPaths);\n existing.setToolsConfig(workspaceTools);\n return existing;\n }\n\n const userLsp = loadSettings().lsp ?? {};\n const mcModulePath = join(dirname(fileURLToPath(import.meta.url)), '..');\n const lspConfig: LSPConfig = {\n ...userLsp,\n packageRunner: userLsp.packageRunner || detectPackageRunner(projectPath), // Detected runner is the fallback — user's packageRunner always wins\n searchPaths: [mcModulePath, ...(userLsp.searchPaths ?? [])],\n };\n\n // First call for this project — create the workspace\n const filesystem = new LocalFilesystem({\n basePath: projectPath,\n allowedPaths,\n });\n return new Workspace({\n id: workspaceId,\n name: 'Mastra Code Workspace',\n filesystem,\n sandbox: new LocalSandbox({\n workingDirectory: projectPath,\n env: buildSandboxEnv(),\n }),\n tools: workspaceTools,\n skills: skillPaths,\n ...(skillExtension ? { skillSource: skillExtension.createSource(filesystem, projectSkillPaths) } : {}),\n lsp: lspConfig,\n });\n}\n\n/**\n * Resolver for the agent's `goal.tools` config. Builds the request's workspace\n * (same per-request resolution as the agent's own tools) and returns only the\n * read-only verification subset, remapped to mastracode's tool names (`view`,\n * `search_content`, etc.). Returns `undefined` when no workspace can be resolved\n * (e.g. no project path), keeping the default judge text-only rather than\n * throwing inside the goal step.\n */\nexport async function getGoalJudgeTools({\n requestContext,\n mastra,\n}: {\n requestContext: RequestContext;\n mastra?: Mastra;\n}): Promise<ToolsInput | undefined> {\n let workspace: Workspace;\n try {\n workspace = await getDynamicWorkspace({ requestContext, mastra });\n } catch {\n return undefined;\n }\n\n const allTools = await createWorkspaceTools(workspace, { requestContext, workspace });\n const readonly: ToolsInput = {};\n for (const name of GOAL_JUDGE_READONLY_TOOLS) {\n if (allTools[name]) readonly[name] = allTools[name];\n }\n return Object.keys(readonly).length > 0 ? readonly : undefined;\n}\n"],"mappings":"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"}