@truefoundry/trueforge-core 0.1.3 → 0.1.4

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 (111) hide show
  1. package/dist/agent-session/TurnResourceResolver.d.ts.map +1 -1
  2. package/dist/agent-session/TurnResourceResolver.js +1 -4
  3. package/dist/agent-session/TurnResourceResolver.js.map +1 -1
  4. package/dist/agent-session/TurnResourceResolver.mjs +1 -4
  5. package/dist/agent-session/TurnResourceResolver.mjs.map +1 -1
  6. package/dist/agent-session/index.d.ts +1 -1
  7. package/dist/agent-session/index.d.ts.map +1 -1
  8. package/dist/agent-session/index.js.map +1 -1
  9. package/dist/agent-session/index.mjs.map +1 -1
  10. package/dist/agent-session/schemas/agentSpec.d.ts +7 -28
  11. package/dist/agent-session/schemas/agentSpec.d.ts.map +1 -1
  12. package/dist/agent-session/schemas/agentSpec.js +15 -43
  13. package/dist/agent-session/schemas/agentSpec.js.map +1 -1
  14. package/dist/agent-session/schemas/agentSpec.mjs +15 -43
  15. package/dist/agent-session/schemas/agentSpec.mjs.map +1 -1
  16. package/dist/agent-session/schemas/session.d.ts +0 -39
  17. package/dist/agent-session/schemas/session.d.ts.map +1 -1
  18. package/dist/core/index.d.ts +4 -1
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/core/index.js +12 -0
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/core/index.mjs +7 -0
  23. package/dist/core/index.mjs.map +1 -1
  24. package/dist/core/runtime/AgentThread.d.ts.map +1 -1
  25. package/dist/core/runtime/AgentThread.js +25 -11
  26. package/dist/core/runtime/AgentThread.js.map +1 -1
  27. package/dist/core/runtime/AgentThread.mjs +25 -11
  28. package/dist/core/runtime/AgentThread.mjs.map +1 -1
  29. package/dist/core/sandbox/Sandbox.d.ts +15 -4
  30. package/dist/core/sandbox/Sandbox.d.ts.map +1 -1
  31. package/dist/core/sandbox/Sandbox.js +200 -80
  32. package/dist/core/sandbox/Sandbox.js.map +1 -1
  33. package/dist/core/sandbox/Sandbox.mjs +201 -81
  34. package/dist/core/sandbox/Sandbox.mjs.map +1 -1
  35. package/dist/core/sandbox/SandboxErrors.d.ts +7 -3
  36. package/dist/core/sandbox/SandboxErrors.d.ts.map +1 -1
  37. package/dist/core/sandbox/SandboxErrors.js +6 -6
  38. package/dist/core/sandbox/SandboxErrors.js.map +1 -1
  39. package/dist/core/sandbox/SandboxErrors.mjs +6 -6
  40. package/dist/core/sandbox/SandboxErrors.mjs.map +1 -1
  41. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts +22 -0
  42. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts.map +1 -1
  43. package/dist/core/sandbox/codeMode/CodeModeTransport.js.map +1 -1
  44. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts +9 -1
  45. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts.map +1 -1
  46. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js +12 -0
  47. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js.map +1 -1
  48. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs +12 -0
  49. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs.map +1 -1
  50. package/dist/core/sandbox/constants.d.ts +0 -2
  51. package/dist/core/sandbox/constants.d.ts.map +1 -1
  52. package/dist/core/sandbox/constants.js +2 -5
  53. package/dist/core/sandbox/constants.js.map +1 -1
  54. package/dist/core/sandbox/constants.mjs +1 -3
  55. package/dist/core/sandbox/constants.mjs.map +1 -1
  56. package/dist/core/sandbox/provider/DaytonaProvider.d.ts +4 -0
  57. package/dist/core/sandbox/provider/DaytonaProvider.d.ts.map +1 -1
  58. package/dist/core/sandbox/provider/DaytonaProvider.js +27 -5
  59. package/dist/core/sandbox/provider/DaytonaProvider.js.map +1 -1
  60. package/dist/core/sandbox/provider/DaytonaProvider.mjs +27 -4
  61. package/dist/core/sandbox/provider/DaytonaProvider.mjs.map +1 -1
  62. package/dist/core/sandbox/provider/Provider.d.ts +13 -1
  63. package/dist/core/sandbox/provider/Provider.d.ts.map +1 -1
  64. package/dist/core/sandbox/provider/Provider.js.map +1 -1
  65. package/dist/core/sandbox/provider/Provider.mjs.map +1 -1
  66. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts +17 -2
  67. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts.map +1 -1
  68. package/dist/core/sandbox/provider/TFYSandboxProvider.js +81 -17
  69. package/dist/core/sandbox/provider/TFYSandboxProvider.js.map +1 -1
  70. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs +82 -13
  71. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs.map +1 -1
  72. package/dist/core/sandbox/provider/execEnv.d.ts +6 -0
  73. package/dist/core/sandbox/provider/execEnv.d.ts.map +1 -0
  74. package/dist/core/sandbox/provider/execEnv.js +55 -0
  75. package/dist/core/sandbox/provider/execEnv.js.map +1 -0
  76. package/dist/core/sandbox/provider/execEnv.mjs +30 -0
  77. package/dist/core/sandbox/provider/execEnv.mjs.map +1 -0
  78. package/dist/core/sandbox/sandboxImage.d.ts +2 -5
  79. package/dist/core/sandbox/sandboxImage.d.ts.map +1 -1
  80. package/dist/core/sandbox/sandboxImage.js +8 -1
  81. package/dist/core/sandbox/sandboxImage.js.map +1 -1
  82. package/dist/core/sandbox/sandboxImage.mjs +6 -1
  83. package/dist/core/sandbox/sandboxImage.mjs.map +1 -1
  84. package/dist/core/sandbox/sandboxRef.d.ts +26 -0
  85. package/dist/core/sandbox/sandboxRef.d.ts.map +1 -0
  86. package/dist/core/sandbox/sandboxRef.js +69 -0
  87. package/dist/core/sandbox/sandboxRef.js.map +1 -0
  88. package/dist/core/sandbox/sandboxRef.mjs +41 -0
  89. package/dist/core/sandbox/sandboxRef.mjs.map +1 -0
  90. package/dist/core/sandbox/skills/ISkillMounter.d.ts +7 -2
  91. package/dist/core/sandbox/skills/ISkillMounter.d.ts.map +1 -1
  92. package/dist/core/sandbox/skills/ISkillMounter.js.map +1 -1
  93. package/dist/core/sandbox/skills/SkillMounter.d.ts +7 -2
  94. package/dist/core/sandbox/skills/SkillMounter.d.ts.map +1 -1
  95. package/dist/core/sandbox/skills/SkillMounter.js +5 -6
  96. package/dist/core/sandbox/skills/SkillMounter.js.map +1 -1
  97. package/dist/core/sandbox/skills/SkillMounter.mjs +5 -6
  98. package/dist/core/sandbox/skills/SkillMounter.mjs.map +1 -1
  99. package/dist/core/sandbox/skills/constants.d.ts +4 -2
  100. package/dist/core/sandbox/skills/constants.d.ts.map +1 -1
  101. package/dist/core/sandbox/skills/constants.js +2 -5
  102. package/dist/core/sandbox/skills/constants.js.map +1 -1
  103. package/dist/core/sandbox/skills/constants.mjs +2 -4
  104. package/dist/core/sandbox/skills/constants.mjs.map +1 -1
  105. package/dist/core/sandbox/skills/index.d.ts +1 -1
  106. package/dist/core/sandbox/skills/index.d.ts.map +1 -1
  107. package/dist/core/sandbox/skills/index.js +0 -2
  108. package/dist/core/sandbox/skills/index.js.map +1 -1
  109. package/dist/core/sandbox/skills/index.mjs +1 -2
  110. package/dist/core/sandbox/skills/index.mjs.map +1 -1
  111. package/package.json +1 -1
@@ -49,29 +49,36 @@ var import_LocalToolMCP = require("../mcp/LocalToolMCP.js");
49
49
  var import_DeferredTool = require("../runtime/DeferredTool.js");
50
50
  var import_errorLogFields = require("../util/errorLogFields.js");
51
51
  var import_CodeModeDispatcher = require("./codeMode/CodeModeDispatcher.js");
52
- var import_constants = require("./constants.js");
52
+ var import_CodeModeTransport = require("./codeMode/CodeModeTransport.js");
53
53
  var import_Provider = require("./provider/Provider.js");
54
54
  var import_SandboxErrors = require("./SandboxErrors.js");
55
- var import_sandboxScripts = require("./sandboxScripts.gen.js");
56
- var import_constants2 = require("./skills/constants.js");
55
+ var import_sandboxRef = require("./sandboxRef.js");
56
+ var import_node_path = require("path");
57
+ function mcpClientLayout(remotePath) {
58
+ const pythonPath = (0, import_node_path.dirname)(remotePath);
59
+ const binDir = (0, import_node_path.join)(pythonPath, "bin");
60
+ return { pythonPath, binDir, binLink: (0, import_node_path.join)(binDir, "mcp-client") };
61
+ }
57
62
  var SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;
58
63
  var NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;
59
64
  function buildWriteAndRunScriptCommand(params) {
60
65
  const b64 = Buffer.from(params.scriptContent, "utf-8").toString("base64");
66
+ const scriptPath = (0, import_Provider.shellEscape)(params.scriptPath);
61
67
  return [
62
- `mkdir -p "$(dirname ${params.scriptPath})"`,
63
- `rm -f ${params.scriptPath}`,
64
- `echo ${(0, import_Provider.shellEscape)(b64)} | base64 -d > ${params.scriptPath}`,
65
- `chmod a-w ${params.scriptPath}`,
66
- `python3 ${params.scriptPath}`
68
+ `mkdir -p "$(dirname ${scriptPath})"`,
69
+ `rm -f ${scriptPath}`,
70
+ `echo ${(0, import_Provider.shellEscape)(b64)} | base64 -d > ${scriptPath}`,
71
+ `chmod a-w ${scriptPath}`,
72
+ `python3 ${scriptPath}`
67
73
  ].join(" && ");
68
74
  }
69
75
  function buildSyncGitCredentialsCommand(credentialsContent, credentialsPath) {
76
+ const path = (0, import_Provider.shellEscape)(credentialsPath);
70
77
  if (credentialsContent === null) {
71
- return `rm -f ${credentialsPath}`;
78
+ return `rm -f ${path}`;
72
79
  }
73
80
  const b64 = Buffer.from(credentialsContent, "utf-8").toString("base64");
74
- return `mkdir -p "$(dirname ${credentialsPath})" && echo '${b64}' | base64 -d > ${credentialsPath} && chmod 600 ${credentialsPath}`;
81
+ return `mkdir -p "$(dirname ${path})" && echo '${b64}' | base64 -d > ${path} && chmod 600 ${path}`;
75
82
  }
76
83
  function buildGitCredentialHelperEnv(credentialsPath) {
77
84
  return {
@@ -85,9 +92,6 @@ var SANDBOX_MCP_REMINDER_TAG = "sandbox-mcp-code-mode";
85
92
  var SANDBOX_FILE_OUTPUT_TAG = "sandbox-file-output";
86
93
  var SANDBOX_SCHEMA_INFER_TAG = "sandbox-schema-infer";
87
94
  var SANDBOX_FILE_UPLOADS_TAG = "sandbox-file-uploads";
88
- var MCP_CLIENT_DIR = "/opt/tfy/mcp-client";
89
- var MCP_CLIENT_PATH = `${MCP_CLIENT_DIR}/mcp_client.py`;
90
- var MCP_CLIENT_BIN_SYMLINK = "/usr/local/bin/mcp-client";
91
95
  function injectTraceContextEnv() {
92
96
  const carrier = {};
93
97
  import_api.propagation.inject(import_api.context.active(), carrier);
@@ -103,9 +107,13 @@ function injectTraceContextEnv() {
103
107
  function injectMCPClientEnv(params) {
104
108
  const codeModeEnv = params.codeModeEnv ?? {};
105
109
  const hasCodeModeTransport = Object.keys(codeModeEnv).length > 0;
110
+ const install = params.mcpClientInstall;
111
+ const layout = install === void 0 ? void 0 : mcpClientLayout(install.remotePath);
106
112
  return {
107
113
  ...params.env ?? {},
108
- PYTHONPATH: MCP_CLIENT_DIR,
114
+ ...layout !== void 0 && {
115
+ PYTHONPATH: layout.pythonPath
116
+ },
109
117
  ...Object.keys(params.mcpServers).length > 0 && {
110
118
  TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString("base64")
111
119
  },
@@ -137,14 +145,12 @@ function createSandboxLargeToolResponseGuidance() {
137
145
  return `For use cases where the Agent needs a subset of fields from the MCP response or needs deterministic processing, write code with the provided MCP client and use <${SANDBOX_MCP_REMINDER_TAG}>.`;
138
146
  }
139
147
  var SANDBOX_MCP_SERVER_ID = "sandbox";
140
- var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
148
+ var Sandbox = class extends import_LocalToolMCP.LocalToolMCP {
141
149
  name = SANDBOX_MCP_SERVER_ID;
142
150
  displayName = "Sandbox";
143
151
  description = "Persistent sandbox environment for code execution";
144
- static FILE_UPLOADS_DIR = import_constants.SANDBOX_FILE_UPLOADS_DIR;
145
152
  provider;
146
153
  existingSandboxId;
147
- tenantName;
148
154
  existingSandboxInfo;
149
155
  // Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.
150
156
  sandboxCreationPromise;
@@ -154,12 +160,13 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
154
160
  requestTimeoutSeconds;
155
161
  skillMounter;
156
162
  cachedSkillsSection;
157
- mcpClientScriptBase64;
158
163
  logger;
159
164
  // Pre-resolved credential-store file content (null = clear / no git auth).
160
165
  resolvedGitCredentialsContent;
161
166
  codeModeDispatcher;
162
167
  codeModeTransport;
168
+ /** Cached from transport.getClientInstall after sandbox init (when Code Mode is configured). */
169
+ mcpClientInstall;
163
170
  tools = [
164
171
  (0, import_LocalToolMCP.defineTool)({
165
172
  name: SANDBOX_EXEC_TOOL_NAME,
@@ -172,19 +179,24 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
172
179
  super({ tracing: options.tracing });
173
180
  this.provider = options.provider;
174
181
  this.existingSandboxId = options.existingSandboxId;
175
- this.tenantName = options.tenantName;
176
182
  this.skillMounter = options.skillMounter;
177
183
  this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;
178
184
  const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;
179
185
  this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
180
- this.mcpClientScriptBase64 = Buffer.from(import_sandboxScripts.sandboxScripts.mcpClient, "utf-8").toString("base64");
181
186
  this.logger = options.logger.child({ module: "Sandbox" });
182
187
  this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;
183
188
  if (this.existingSandboxId) {
184
- (0, import_SandboxErrors.validateSandboxOwnedByTenant)(this.existingSandboxId, this.tenantName);
185
189
  this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };
186
190
  }
187
191
  }
192
+ /** Provider-facing id (unwraps `v1:type:raw`; legacy ids pass through). */
193
+ providerSandboxId(sessionId) {
194
+ return (0, import_sandboxRef.rawSandboxId)(sessionId);
195
+ }
196
+ /** Raw id for prompt layout paths before create (empty when this turn has no existing sandbox). */
197
+ promptSandboxId() {
198
+ return this.existingSandboxId === void 0 ? "" : (0, import_sandboxRef.rawSandboxId)(this.existingSandboxId);
199
+ }
188
200
  buildMcpServersEnvelope() {
189
201
  const out = {};
190
202
  for (const server of this.codeExecToolSets) {
@@ -214,7 +226,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
214
226
  renderSkillsSection() {
215
227
  if (this.cachedSkillsSection === void 0) {
216
228
  const skills = new import_InstructionBuilder.InstructionBuilder("skills");
217
- this.skillMounter?.instruction(skills);
229
+ this.skillMounter?.instruction(skills, { skillsDir: this.provider.getSkillsDir(this.promptSandboxId()) });
218
230
  this.cachedSkillsSection = skills.build();
219
231
  }
220
232
  return this.cachedSkillsSection;
@@ -238,7 +250,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
238
250
  buildFileUploadsSection(builder) {
239
251
  builder.addSection(
240
252
  SANDBOX_FILE_UPLOADS_TAG,
241
- `User-uploaded files are placed in ${_Sandbox.FILE_UPLOADS_DIR}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`
253
+ `User-uploaded files are placed in ${this.provider.getFileUploadsDir(this.promptSandboxId())}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`
242
254
  );
243
255
  }
244
256
  buildSchemaSection(builder) {
@@ -360,86 +372,168 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
360
372
  }
361
373
  return this.existingSandboxInfo;
362
374
  }
375
+ clearExistingSandbox() {
376
+ this.existingSandboxInfo = void 0;
377
+ this.sandboxCreationPromise = void 0;
378
+ this.sandboxInitPromise = void 0;
379
+ this.mcpClientInstall = void 0;
380
+ }
363
381
  async ensureSandboxCreated() {
364
382
  if (this.existingSandboxInfo) {
365
383
  return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: void 0 };
366
384
  }
367
- this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => {
368
- (0, import_SandboxErrors.validateSandboxOwnedByTenant)(sandboxId, this.tenantName);
369
- return { sandbox_id: sandboxId };
370
- }).catch((e) => {
385
+ this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => ({
386
+ sandbox_id: (0, import_sandboxRef.formatSandboxId)({ providerType: this.provider.type, rawId: sandboxId })
387
+ })).catch((e) => {
371
388
  this.sandboxCreationPromise = void 0;
372
389
  throw e;
373
390
  });
374
391
  const sandboxInfo = await this.sandboxCreationPromise;
375
- const prior = this.existingSandboxInfo;
376
- const isNew = prior === void 0;
392
+ const raced = this.peekExistingSandboxInfo();
393
+ if (raced !== void 0) {
394
+ return { sandboxInfo: raced, sandboxCreated: void 0 };
395
+ }
377
396
  this.existingSandboxInfo = sandboxInfo;
378
- return { sandboxInfo, sandboxCreated: isNew ? sandboxInfo : void 0 };
397
+ return { sandboxInfo, sandboxCreated: sandboxInfo };
379
398
  }
380
- async handleExec(input) {
381
- const { sandboxInfo, sandboxCreated } = await this.ensureSandboxCreated();
382
- const sandboxCreatedFlag = Boolean(sandboxCreated);
399
+ peekExistingSandboxInfo() {
400
+ return this.existingSandboxInfo;
401
+ }
402
+ /** Same-type missing remote/local root: drop the stale id and create a new fancy id. */
403
+ async recreateAfterUnavailable() {
404
+ this.clearExistingSandbox();
405
+ const created = await this.ensureSandboxCreated();
406
+ if (created.sandboxCreated === void 0) {
407
+ throw new Error("Sandbox recreate did not create a new sandbox");
408
+ }
409
+ return { sandboxInfo: created.sandboxInfo, sandboxCreated: created.sandboxCreated };
410
+ }
411
+ /**
412
+ * Create or reattach, then init. A missing same-type sandbox throws
413
+ * `SandboxNotAvailableError` from the provider; reattach then recreates.
414
+ */
415
+ async ensureReadySandbox() {
416
+ const first = await this.ensureSandboxCreated();
383
417
  try {
384
418
  await this.ensureSandboxInitialized();
419
+ return first;
420
+ } catch (error) {
421
+ if (!(error instanceof import_SandboxErrors.SandboxNotAvailableError) || first.sandboxCreated !== void 0) {
422
+ throw error;
423
+ }
424
+ const recreated = await this.recreateAfterUnavailable();
425
+ await this.ensureSandboxInitialized();
426
+ return recreated;
427
+ }
428
+ }
429
+ async handleExec(input) {
430
+ let sandboxInfo;
431
+ let sandboxCreated;
432
+ try {
433
+ ({ sandboxInfo, sandboxCreated } = await this.ensureReadySandbox());
385
434
  } catch (e) {
386
435
  this.logger.error("Sandbox initialization failed", (0, import_errorLogFields.extractErrorLogFields)(e));
387
436
  const message = e instanceof Error ? e.message : "Sandbox initialization failed";
437
+ const fallback = this.existingSandboxInfo;
388
438
  return (0, import_IMCPServer.toolResultResponse)({
389
439
  text: `Sandbox initialization failed: ${message}`,
390
440
  isError: true,
391
- overrides: { sandboxCreated: sandboxCreatedFlag, sandboxInfo }
441
+ overrides: {
442
+ sandboxCreated: Boolean(fallback),
443
+ ...fallback !== void 0 ? { sandboxInfo: fallback } : {}
444
+ }
392
445
  });
393
446
  }
394
- const codeModeEnv = await this.ensureCodeModeStarted(sandboxInfo.sandbox_id);
447
+ const sandboxCreatedFlag = Boolean(sandboxCreated);
448
+ const rawId = this.providerSandboxId(sandboxInfo.sandbox_id);
449
+ const codeModeEnv = await this.ensureCodeModeStarted(rawId);
395
450
  const mcpClientEnv = injectMCPClientEnv({
396
451
  env: input.env,
397
452
  mcpServers: this.buildMcpServersEnvelope(),
398
- codeModeEnv
453
+ codeModeEnv,
454
+ mcpClientInstall: this.mcpClientInstall
399
455
  });
400
- const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(sandboxInfo.sandbox_id)) : {};
456
+ const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(rawId)) : {};
401
457
  const env = { ...mcpClientEnv, ...gitAuthEnv };
402
- const result = await this.provider.exec({
403
- sandboxId: sandboxInfo.sandbox_id,
404
- command: input.command,
405
- cwd: input.cwd,
406
- env
407
- });
408
- return {
409
- result: {
410
- content: [{ type: "text", text: JSON.stringify(result) }],
411
- isError: !result.success
412
- },
413
- wasInitialized: void 0,
414
- sandboxCreated: sandboxCreatedFlag,
415
- sandboxInfo
416
- };
458
+ try {
459
+ const result = await this.provider.exec({
460
+ sandboxId: rawId,
461
+ command: input.command,
462
+ cwd: input.cwd,
463
+ env
464
+ });
465
+ return {
466
+ result: {
467
+ content: [{ type: "text", text: JSON.stringify(result) }],
468
+ isError: !result.success
469
+ },
470
+ wasInitialized: void 0,
471
+ sandboxCreated: sandboxCreatedFlag,
472
+ sandboxInfo
473
+ };
474
+ } catch (error) {
475
+ if (!(error instanceof import_SandboxErrors.SandboxNotAvailableError) || sandboxCreated !== void 0) {
476
+ throw error;
477
+ }
478
+ const recreated = await this.recreateAfterUnavailable();
479
+ await this.ensureSandboxInitialized();
480
+ const recreatedRawId = this.providerSandboxId(recreated.sandboxInfo.sandbox_id);
481
+ const retryCodeModeEnv = await this.ensureCodeModeStarted(recreatedRawId);
482
+ const retryEnv = {
483
+ ...injectMCPClientEnv({
484
+ env: input.env,
485
+ mcpServers: this.buildMcpServersEnvelope(),
486
+ codeModeEnv: retryCodeModeEnv,
487
+ mcpClientInstall: this.mcpClientInstall
488
+ }),
489
+ ...this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(recreatedRawId)) : {}
490
+ };
491
+ const retryResult = await this.provider.exec({
492
+ sandboxId: recreatedRawId,
493
+ command: input.command,
494
+ cwd: input.cwd,
495
+ env: retryEnv
496
+ });
497
+ return {
498
+ result: {
499
+ content: [{ type: "text", text: JSON.stringify(retryResult) }],
500
+ isError: !retryResult.success
501
+ },
502
+ wasInitialized: void 0,
503
+ sandboxCreated: true,
504
+ sandboxInfo: recreated.sandboxInfo
505
+ };
506
+ }
417
507
  }
418
508
  async getToolResultDumpDir() {
419
- const { sandboxCreated } = await this.ensureSandboxCreated();
420
- const dir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id).replace(/\/+$/, "");
509
+ const { sandboxCreated, sandboxInfo } = await this.ensureSandboxCreated();
510
+ const dir = this.provider.getToolResultDumpDir(this.providerSandboxId(sandboxInfo.sandbox_id)).replace(/\/+$/, "");
421
511
  return { dir, sandboxCreated };
422
512
  }
423
513
  async uploadFile(params) {
424
- const { sandboxCreated } = await this.ensureSandboxCreated();
425
- await this.ensureSandboxInitialized();
426
- const { sandbox_id: sandboxId } = this.requiredSandboxInfo;
514
+ const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
427
515
  const fileName = params.fileName.replace(/^\/+/, "");
428
516
  const targetDir = params.targetDir.replace(/\/+$/, "");
429
517
  const filePath = `${targetDir}/${fileName}`;
430
- await this.provider.uploadFile({ sandboxId, remotePath: filePath, content: params.content });
518
+ await this.provider.uploadFile({
519
+ sandboxId: this.providerSandboxId(sandboxInfo.sandbox_id),
520
+ remotePath: filePath,
521
+ content: params.content
522
+ });
431
523
  return { filePath, sandboxCreated };
432
524
  }
433
525
  async uploadUserFile(input) {
434
526
  (0, import_SandboxErrors.validateNoPathTraversal)(input.fileName);
527
+ const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
435
528
  const result = await this.uploadFile({
436
- targetDir: _Sandbox.FILE_UPLOADS_DIR,
529
+ targetDir: this.provider.getFileUploadsDir(this.providerSandboxId(sandboxInfo.sandbox_id)),
437
530
  fileName: input.fileName,
438
531
  content: input.content
439
532
  });
533
+ const created = sandboxCreated ?? result.sandboxCreated;
440
534
  return {
441
535
  filePath: result.filePath,
442
- ...result.sandboxCreated && { sandboxCreated: result.sandboxCreated }
536
+ ...created && { sandboxCreated: created }
443
537
  };
444
538
  }
445
539
  async writeArtifact(input) {
@@ -468,7 +562,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
468
562
  await this.sandboxInitPromise;
469
563
  }
470
564
  async writeGitCredentials() {
471
- const sandboxId = this.requiredSandboxInfo.sandbox_id;
565
+ const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
472
566
  const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);
473
567
  const result = await this.provider.exec({
474
568
  sandboxId,
@@ -477,30 +571,56 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
477
571
  (0, import_Provider.ensureExecSuccess)(result);
478
572
  }
479
573
  async initSandboxEnvironment() {
480
- const toolResultDumpDir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id);
574
+ const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
575
+ const fileUploadsDir = this.provider.getFileUploadsDir(sandboxId);
576
+ const skillsDir = this.provider.getSkillsDir(sandboxId);
577
+ const toolResultDumpDir = this.provider.getToolResultDumpDir(sandboxId);
481
578
  this.logger.info("Uploading MCP client script and preparing skills directory in sandbox");
482
- const initSteps = [
483
- `mkdir -p ${MCP_CLIENT_DIR} ${_Sandbox.FILE_UPLOADS_DIR} ${toolResultDumpDir} ${import_constants2.SKILLS_DIR}`,
484
- `rm -f ${MCP_CLIENT_PATH}`,
485
- `echo '${this.mcpClientScriptBase64}' | base64 -d > ${MCP_CLIENT_PATH}`,
486
- // Make executable + symlink onto PATH so `mcp-client` runs by name.
487
- `chmod 0555 ${MCP_CLIENT_PATH}`,
488
- `ln -sf ${MCP_CLIENT_PATH} ${MCP_CLIENT_BIN_SYMLINK}`
489
- ];
490
- const skillInit = this.skillMounter?.getSandboxInit();
579
+ this.mcpClientInstall = this.codeModeTransport?.getClientInstall({ sandboxId });
580
+ const install = this.mcpClientInstall;
581
+ const dirs = [(0, import_Provider.shellEscape)(fileUploadsDir), (0, import_Provider.shellEscape)(toolResultDumpDir), (0, import_Provider.shellEscape)(skillsDir)];
582
+ if (install !== void 0) {
583
+ const { pythonPath, binDir } = mcpClientLayout(install.remotePath);
584
+ dirs.push((0, import_Provider.shellEscape)(pythonPath));
585
+ if (install.pathBinSymlink === void 0) {
586
+ dirs.push((0, import_Provider.shellEscape)(binDir));
587
+ }
588
+ }
589
+ (0, import_Provider.ensureExecSuccess)(await this.provider.exec({ sandboxId, command: `mkdir -p ${dirs.join(" ")}` }));
590
+ const initSteps = [];
591
+ if (install !== void 0) {
592
+ await this.provider.uploadFile({
593
+ sandboxId,
594
+ remotePath: install.remotePath,
595
+ content: Buffer.from(install.content, "utf-8")
596
+ });
597
+ initSteps.push(`chmod 0555 ${(0, import_Provider.shellEscape)(install.remotePath)}`);
598
+ if (install.pathBinSymlink !== void 0) {
599
+ initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)(install.remotePath)} ${(0, import_Provider.shellEscape)(install.pathBinSymlink)}`);
600
+ } else {
601
+ const { binDir, binLink } = mcpClientLayout(install.remotePath);
602
+ initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)((0, import_node_path.relative)(binDir, install.remotePath))} ${(0, import_Provider.shellEscape)(binLink)}`);
603
+ }
604
+ }
605
+ const skillInit = this.skillMounter?.getSandboxInit({
606
+ skillsDir,
607
+ gitDownloaderPath: this.provider.getGitDownloaderPath(sandboxId)
608
+ });
491
609
  if (skillInit) {
492
610
  initSteps.push(skillInit.command);
493
611
  }
494
- const script = initSteps.join(" && ");
495
- const result = await this.provider.exec({
496
- sandboxId: this.requiredSandboxInfo.sandbox_id,
497
- command: script,
498
- env: skillInit?.env,
499
- timeoutSeconds: skillInit?.timeoutSeconds
500
- });
501
- (0, import_Provider.ensureExecSuccess)(result);
612
+ if (initSteps.length > 0) {
613
+ (0, import_Provider.ensureExecSuccess)(
614
+ await this.provider.exec({
615
+ sandboxId,
616
+ command: initSteps.join(" && "),
617
+ env: skillInit?.env,
618
+ timeoutSeconds: skillInit?.timeoutSeconds
619
+ })
620
+ );
621
+ }
502
622
  this.logger.info(
503
- `Sandbox initialized: MCP client at ${MCP_CLIENT_PATH} (symlinked to ${MCP_CLIENT_BIN_SYMLINK}); skills dir ${import_constants2.SKILLS_DIR}`
623
+ install === void 0 ? `Sandbox initialized: skills dir ${skillsDir}` : `Sandbox initialized: MCP client at ${install.remotePath}; skills dir ${skillsDir}`
504
624
  );
505
625
  await this.writeGitCredentials();
506
626
  }