@truefoundry/trueforge 0.1.2 → 0.1.4-rc.0

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 (164) hide show
  1. package/dist/_frontend/assets/{ConnectorSettings-XEO5ZQO5-BXis0tQK.js → ConnectorSettings-ODC3LVHN-jhiXpbVc.js} +1 -1
  2. package/dist/_frontend/assets/ConnectorSettings-ODC3LVHN-jhiXpbVc.js.br +0 -0
  3. package/dist/_frontend/assets/ConnectorSettings-ODC3LVHN-jhiXpbVc.js.gz +0 -0
  4. package/dist/_frontend/assets/{DockLayout-F2KYSY4U-D8P84kCr.js → DockLayout-2RWDSUKE-DY3y3Is3.js} +1 -1
  5. package/dist/_frontend/assets/{DrawerLayout-FJ7XC2FU-ChH-Qykr.js → DrawerLayout-CZLJYMIN-BYncSNoi.js} +2 -2
  6. package/dist/_frontend/assets/DrawerLayout-CZLJYMIN-BYncSNoi.js.br +0 -0
  7. package/dist/_frontend/assets/DrawerLayout-CZLJYMIN-BYncSNoi.js.gz +0 -0
  8. package/dist/_frontend/assets/{ModelSettings-2QB7LE22-CDZku4g3.js → ModelSettings-CKQ5CVAC-DxQtYKup.js} +1 -1
  9. package/dist/_frontend/assets/ModelSettings-CKQ5CVAC-DxQtYKup.js.br +0 -0
  10. package/dist/_frontend/assets/ModelSettings-CKQ5CVAC-DxQtYKup.js.gz +0 -0
  11. package/dist/_frontend/assets/{SandboxSettings-QDDIPRBP-CImJLa0r.js → SandboxSettings-HSCPYUOC-DMFf-U04.js} +1 -1
  12. package/dist/_frontend/assets/SandboxSettings-HSCPYUOC-DMFf-U04.js.br +0 -0
  13. package/dist/_frontend/assets/SandboxSettings-HSCPYUOC-DMFf-U04.js.gz +0 -0
  14. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-C4p8uaXT.js +2 -0
  15. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-C4p8uaXT.js.br +0 -0
  16. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-C4p8uaXT.js.gz +0 -0
  17. package/dist/_frontend/assets/{ShellRouteSync-T4WLY57Q-CetHx5EA.js → ShellRouteSync-T4WLY57Q-BC8a0ojU.js} +1 -1
  18. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-BC8a0ojU.js.br +0 -0
  19. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-BC8a0ojU.js.gz +0 -0
  20. package/dist/_frontend/assets/{SidebarLayout-KX6RSJTP-B8G4CTTb.js → SidebarLayout-WVY54TGZ-Ds7NVk-f.js} +2 -2
  21. package/dist/_frontend/assets/SidebarLayout-WVY54TGZ-Ds7NVk-f.js.br +0 -0
  22. package/dist/_frontend/assets/SidebarLayout-WVY54TGZ-Ds7NVk-f.js.gz +0 -0
  23. package/dist/_frontend/assets/{SkillSettings-5EETEEDI-DbJE0Ms2.js → SkillSettings-ECH6SHZ7-BtdCmc6B.js} +1 -1
  24. package/dist/_frontend/assets/SkillSettings-ECH6SHZ7-BtdCmc6B.js.br +0 -0
  25. package/dist/_frontend/assets/SkillSettings-ECH6SHZ7-BtdCmc6B.js.gz +0 -0
  26. package/dist/_frontend/assets/{TrueForgeUIWithRouter-IAQQTD5V-9G1rELmh.js → TrueForgeUIWithRouter-RKZ2E7PV-vF7U7cGf.js} +1 -1
  27. package/dist/_frontend/assets/{WidgetLayout-S6EK62TZ-BPf7T3wa.js → WidgetLayout-NWWB2SXI-DJtuM33Y.js} +1 -1
  28. package/dist/_frontend/assets/WidgetLayout-NWWB2SXI-DJtuM33Y.js.br +0 -0
  29. package/dist/_frontend/assets/WidgetLayout-NWWB2SXI-DJtuM33Y.js.gz +0 -0
  30. package/dist/_frontend/assets/{chunk-62JRHF6Z-BUuLA42_.js → chunk-62JRHF6Z-TG4aaXok.js} +1 -1
  31. package/dist/_frontend/assets/chunk-62JRHF6Z-TG4aaXok.js.br +0 -0
  32. package/dist/_frontend/assets/chunk-62JRHF6Z-TG4aaXok.js.gz +0 -0
  33. package/dist/_frontend/assets/{chunk-X6U2Q7X5-DDlfUle1.js → chunk-OZTNBS6V-axorP9qO.js} +1 -1
  34. package/dist/_frontend/assets/chunk-OZTNBS6V-axorP9qO.js.br +0 -0
  35. package/dist/_frontend/assets/chunk-OZTNBS6V-axorP9qO.js.gz +0 -0
  36. package/dist/_frontend/assets/{chunk-PTYEOSHT-C4gdhLwo.js → chunk-TCAVLWYL-BXtNAtCy.js} +2 -2
  37. package/dist/_frontend/assets/chunk-TCAVLWYL-BXtNAtCy.js.br +0 -0
  38. package/dist/_frontend/assets/chunk-TCAVLWYL-BXtNAtCy.js.gz +0 -0
  39. package/dist/_frontend/assets/{cssMode-C1whwlDW.js → cssMode-yEIs6GIw.js} +1 -1
  40. package/dist/_frontend/assets/cssMode-yEIs6GIw.js.br +0 -0
  41. package/dist/_frontend/assets/cssMode-yEIs6GIw.js.gz +0 -0
  42. package/dist/_frontend/assets/{freemarker2-CaMIS9bY.js → freemarker2-aDGnYU8i.js} +1 -1
  43. package/dist/_frontend/assets/freemarker2-aDGnYU8i.js.br +0 -0
  44. package/dist/_frontend/assets/freemarker2-aDGnYU8i.js.gz +0 -0
  45. package/dist/_frontend/assets/{handlebars-Donx2d9H.js → handlebars-B6ny31dN.js} +1 -1
  46. package/dist/_frontend/assets/handlebars-B6ny31dN.js.br +0 -0
  47. package/dist/_frontend/assets/handlebars-B6ny31dN.js.gz +0 -0
  48. package/dist/_frontend/assets/{html-CtI8kZ6e.js → html-D7u-MYoP.js} +1 -1
  49. package/dist/_frontend/assets/html-D7u-MYoP.js.br +0 -0
  50. package/dist/_frontend/assets/html-D7u-MYoP.js.gz +0 -0
  51. package/dist/_frontend/assets/{htmlMode-B6ky8VkF.js → htmlMode-kNcFDXKs.js} +1 -1
  52. package/dist/_frontend/assets/htmlMode-kNcFDXKs.js.br +0 -0
  53. package/dist/_frontend/assets/htmlMode-kNcFDXKs.js.gz +0 -0
  54. package/dist/_frontend/assets/{index-DFmgzNuj.js → index-CLJuaUhx.js} +3 -3
  55. package/dist/_frontend/assets/index-CLJuaUhx.js.br +0 -0
  56. package/dist/_frontend/assets/index-CLJuaUhx.js.gz +0 -0
  57. package/dist/_frontend/assets/{index-DWr7ad72.js → index-D1GDH6ia.js} +122 -122
  58. package/dist/_frontend/assets/index-D1GDH6ia.js.br +0 -0
  59. package/dist/_frontend/assets/index-D1GDH6ia.js.gz +0 -0
  60. package/dist/_frontend/assets/{javascript-BDngdIws.js → javascript-BLSK7s1P.js} +1 -1
  61. package/dist/_frontend/assets/{jsonMode-B7OogXWW.js → jsonMode-XHJKWC_S.js} +1 -1
  62. package/dist/_frontend/assets/jsonMode-XHJKWC_S.js.br +0 -0
  63. package/dist/_frontend/assets/jsonMode-XHJKWC_S.js.gz +0 -0
  64. package/dist/_frontend/assets/{liquid-D_8RkuUW.js → liquid-Db1WZdZB.js} +1 -1
  65. package/dist/_frontend/assets/liquid-Db1WZdZB.js.br +0 -0
  66. package/dist/_frontend/assets/liquid-Db1WZdZB.js.gz +0 -0
  67. package/dist/_frontend/assets/{lspLanguageFeatures-DJf8_W2N.js → lspLanguageFeatures-BFyBtl8M.js} +1 -1
  68. package/dist/_frontend/assets/lspLanguageFeatures-BFyBtl8M.js.br +0 -0
  69. package/dist/_frontend/assets/lspLanguageFeatures-BFyBtl8M.js.gz +0 -0
  70. package/dist/_frontend/assets/{mdx-HcpZSZ2w.js → mdx-DtFWu4ex.js} +1 -1
  71. package/dist/_frontend/assets/mdx-DtFWu4ex.js.br +0 -0
  72. package/dist/_frontend/assets/mdx-DtFWu4ex.js.gz +0 -0
  73. package/dist/_frontend/assets/{python-CPiT1vB4.js → python-2R7BOup6.js} +1 -1
  74. package/dist/_frontend/assets/python-2R7BOup6.js.br +0 -0
  75. package/dist/_frontend/assets/python-2R7BOup6.js.gz +0 -0
  76. package/dist/_frontend/assets/{razor-oizHS-vq.js → razor-DQLxdj72.js} +1 -1
  77. package/dist/_frontend/assets/razor-DQLxdj72.js.br +0 -0
  78. package/dist/_frontend/assets/razor-DQLxdj72.js.gz +0 -0
  79. package/dist/_frontend/assets/{tsMode-n5kkpKJX.js → tsMode-Ctn4PuNt.js} +1 -1
  80. package/dist/_frontend/assets/tsMode-Ctn4PuNt.js.br +0 -0
  81. package/dist/_frontend/assets/tsMode-Ctn4PuNt.js.gz +0 -0
  82. package/dist/_frontend/assets/{typescript-BfXupYGq.js → typescript-DGwzICBa.js} +1 -1
  83. package/dist/_frontend/assets/typescript-DGwzICBa.js.br +0 -0
  84. package/dist/_frontend/assets/typescript-DGwzICBa.js.gz +0 -0
  85. package/dist/_frontend/assets/{workers-DCX6qMOc.js → workers-CRRTWuKZ.js} +1 -1
  86. package/dist/_frontend/assets/workers-CRRTWuKZ.js.br +0 -0
  87. package/dist/_frontend/assets/workers-CRRTWuKZ.js.gz +0 -0
  88. package/dist/_frontend/assets/{xml-MX-qfsGl.js → xml-CFZg-QqB.js} +1 -1
  89. package/dist/_frontend/assets/xml-CFZg-QqB.js.br +0 -0
  90. package/dist/_frontend/assets/xml-CFZg-QqB.js.gz +0 -0
  91. package/dist/_frontend/assets/{yaml-DnKyyO9e.js → yaml-DUIIx9CV.js} +1 -1
  92. package/dist/_frontend/assets/yaml-DUIIx9CV.js.br +0 -0
  93. package/dist/_frontend/assets/yaml-DUIIx9CV.js.gz +0 -0
  94. package/dist/_frontend/index.html +1 -1
  95. package/dist/_frontend/index.html.br +0 -0
  96. package/dist/_frontend/index.html.gz +0 -0
  97. package/dist/main.js +2198 -519
  98. package/dist/main.js.map +1 -1
  99. package/dist/postgres/migrations/20260818_000001_mcp_pending_auth_return_to.js +17 -0
  100. package/dist/postgres/migrations/20260818_000001_mcp_pending_auth_return_to.js.map +1 -0
  101. package/dist/sqlite/migrations/20260818_000001_mcp_pending_auth_return_to.js +19 -0
  102. package/dist/sqlite/migrations/20260818_000001_mcp_pending_auth_return_to.js.map +1 -0
  103. package/package.json +10 -4
  104. package/dist/_frontend/assets/ConnectorSettings-XEO5ZQO5-BXis0tQK.js.br +0 -0
  105. package/dist/_frontend/assets/ConnectorSettings-XEO5ZQO5-BXis0tQK.js.gz +0 -0
  106. package/dist/_frontend/assets/DrawerLayout-FJ7XC2FU-ChH-Qykr.js.br +0 -0
  107. package/dist/_frontend/assets/DrawerLayout-FJ7XC2FU-ChH-Qykr.js.gz +0 -0
  108. package/dist/_frontend/assets/ModelSettings-2QB7LE22-CDZku4g3.js.br +0 -0
  109. package/dist/_frontend/assets/ModelSettings-2QB7LE22-CDZku4g3.js.gz +0 -0
  110. package/dist/_frontend/assets/SandboxSettings-QDDIPRBP-CImJLa0r.js.br +0 -0
  111. package/dist/_frontend/assets/SandboxSettings-QDDIPRBP-CImJLa0r.js.gz +0 -0
  112. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js +0 -2
  113. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js.br +0 -0
  114. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js.gz +0 -0
  115. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-CetHx5EA.js.br +0 -0
  116. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-CetHx5EA.js.gz +0 -0
  117. package/dist/_frontend/assets/SidebarLayout-KX6RSJTP-B8G4CTTb.js.br +0 -0
  118. package/dist/_frontend/assets/SidebarLayout-KX6RSJTP-B8G4CTTb.js.gz +0 -0
  119. package/dist/_frontend/assets/SkillSettings-5EETEEDI-DbJE0Ms2.js.br +0 -0
  120. package/dist/_frontend/assets/SkillSettings-5EETEEDI-DbJE0Ms2.js.gz +0 -0
  121. package/dist/_frontend/assets/WidgetLayout-S6EK62TZ-BPf7T3wa.js.br +0 -0
  122. package/dist/_frontend/assets/WidgetLayout-S6EK62TZ-BPf7T3wa.js.gz +0 -0
  123. package/dist/_frontend/assets/chunk-62JRHF6Z-BUuLA42_.js.br +0 -0
  124. package/dist/_frontend/assets/chunk-62JRHF6Z-BUuLA42_.js.gz +0 -0
  125. package/dist/_frontend/assets/chunk-PTYEOSHT-C4gdhLwo.js.br +0 -0
  126. package/dist/_frontend/assets/chunk-PTYEOSHT-C4gdhLwo.js.gz +0 -0
  127. package/dist/_frontend/assets/chunk-X6U2Q7X5-DDlfUle1.js.br +0 -0
  128. package/dist/_frontend/assets/chunk-X6U2Q7X5-DDlfUle1.js.gz +0 -0
  129. package/dist/_frontend/assets/cssMode-C1whwlDW.js.br +0 -0
  130. package/dist/_frontend/assets/cssMode-C1whwlDW.js.gz +0 -0
  131. package/dist/_frontend/assets/freemarker2-CaMIS9bY.js.br +0 -0
  132. package/dist/_frontend/assets/freemarker2-CaMIS9bY.js.gz +0 -0
  133. package/dist/_frontend/assets/handlebars-Donx2d9H.js.br +0 -0
  134. package/dist/_frontend/assets/handlebars-Donx2d9H.js.gz +0 -0
  135. package/dist/_frontend/assets/html-CtI8kZ6e.js.br +0 -0
  136. package/dist/_frontend/assets/html-CtI8kZ6e.js.gz +0 -0
  137. package/dist/_frontend/assets/htmlMode-B6ky8VkF.js.br +0 -0
  138. package/dist/_frontend/assets/htmlMode-B6ky8VkF.js.gz +0 -0
  139. package/dist/_frontend/assets/index-DFmgzNuj.js.br +0 -0
  140. package/dist/_frontend/assets/index-DFmgzNuj.js.gz +0 -0
  141. package/dist/_frontend/assets/index-DWr7ad72.js.br +0 -0
  142. package/dist/_frontend/assets/index-DWr7ad72.js.gz +0 -0
  143. package/dist/_frontend/assets/jsonMode-B7OogXWW.js.br +0 -0
  144. package/dist/_frontend/assets/jsonMode-B7OogXWW.js.gz +0 -0
  145. package/dist/_frontend/assets/liquid-D_8RkuUW.js.br +0 -0
  146. package/dist/_frontend/assets/liquid-D_8RkuUW.js.gz +0 -0
  147. package/dist/_frontend/assets/lspLanguageFeatures-DJf8_W2N.js.br +0 -0
  148. package/dist/_frontend/assets/lspLanguageFeatures-DJf8_W2N.js.gz +0 -0
  149. package/dist/_frontend/assets/mdx-HcpZSZ2w.js.br +0 -0
  150. package/dist/_frontend/assets/mdx-HcpZSZ2w.js.gz +0 -0
  151. package/dist/_frontend/assets/python-CPiT1vB4.js.br +0 -0
  152. package/dist/_frontend/assets/python-CPiT1vB4.js.gz +0 -0
  153. package/dist/_frontend/assets/razor-oizHS-vq.js.br +0 -0
  154. package/dist/_frontend/assets/razor-oizHS-vq.js.gz +0 -0
  155. package/dist/_frontend/assets/tsMode-n5kkpKJX.js.br +0 -0
  156. package/dist/_frontend/assets/tsMode-n5kkpKJX.js.gz +0 -0
  157. package/dist/_frontend/assets/typescript-BfXupYGq.js.br +0 -0
  158. package/dist/_frontend/assets/typescript-BfXupYGq.js.gz +0 -0
  159. package/dist/_frontend/assets/workers-DCX6qMOc.js.br +0 -0
  160. package/dist/_frontend/assets/workers-DCX6qMOc.js.gz +0 -0
  161. package/dist/_frontend/assets/xml-MX-qfsGl.js.br +0 -0
  162. package/dist/_frontend/assets/xml-MX-qfsGl.js.gz +0 -0
  163. package/dist/_frontend/assets/yaml-DnKyyO9e.js.br +0 -0
  164. package/dist/_frontend/assets/yaml-DnKyyO9e.js.gz +0 -0
package/dist/main.js CHANGED
@@ -8,28 +8,6 @@ var __export = (target, all) => {
8
8
  __defProp(target, name, { get: all[name], enumerable: true });
9
9
  };
10
10
 
11
- // src/db/agentStore.ts
12
- import { AgentSpecSchema } from "@truefoundry/trueforge-core/agent-session";
13
- function parseStoredAgentSpec(manifest) {
14
- return AgentSpecSchema.parse(manifest);
15
- }
16
- var AgentNameConflictError;
17
- var init_agentStore = __esm({
18
- "src/db/agentStore.ts"() {
19
- "use strict";
20
- AgentNameConflictError = class extends Error {
21
- tenant_id;
22
- agent_name;
23
- constructor({ tenant_id, name }, options) {
24
- super(`Agent name already exists: ${name}`, options);
25
- this.name = "AgentNameConflictError";
26
- this.tenant_id = tenant_id;
27
- this.agent_name = name;
28
- }
29
- };
30
- }
31
- });
32
-
33
11
  // src/config.ts
34
12
  var config_exports = {};
35
13
  __export(config_exports, {
@@ -38,7 +16,8 @@ __export(config_exports, {
38
16
  isOidcConfigured: () => isOidcConfigured,
39
17
  parseOidcScopes: () => parseOidcScopes
40
18
  });
41
- import { existsSync } from "fs";
19
+ import { existsSync as existsSync2 } from "fs";
20
+ import os from "os";
42
21
  import path from "path";
43
22
  import { fileURLToPath } from "url";
44
23
  import envPaths from "env-paths";
@@ -102,7 +81,7 @@ function parseBoolean(options) {
102
81
  }
103
82
  function resolveDefaultFrontendDir() {
104
83
  const packaged = path.join(PACKAGE_ROOT, "dist", "_frontend");
105
- if (existsSync(path.join(packaged, "index.html"))) {
84
+ if (existsSync2(path.join(packaged, "index.html"))) {
106
85
  return packaged;
107
86
  }
108
87
  return path.join(PACKAGE_ROOT, "..", "frontend", "dist");
@@ -129,6 +108,12 @@ function resolveSqlitePath() {
129
108
  const paths = envPaths(ENV_PATHS_APP_NAME, { suffix: "" });
130
109
  return path.join(paths.data, "db", "db.sqlite");
131
110
  }
111
+ function resolveLocalSandboxRootParent() {
112
+ return path.join(envPaths(ENV_PATHS_APP_NAME, { suffix: "" }).data, "sandboxes");
113
+ }
114
+ function resolveCodeModeSocketParent() {
115
+ return path.join(os.tmpdir(), "tf_cms");
116
+ }
132
117
  function resolveRedisUrl() {
133
118
  const raw = getEnv("REDIS_URL", { defaultValue: DEFAULT_REDIS_URL }) ?? DEFAULT_REDIS_URL;
134
119
  if (raw.trim() === "") {
@@ -305,7 +290,9 @@ var init_config = __esm({
305
290
  configuration = standalone ? {
306
291
  ...shared,
307
292
  STANDALONE: true,
308
- SQLITE_PATH: resolveSqlitePath()
293
+ SQLITE_PATH: resolveSqlitePath(),
294
+ LOCAL_SANDBOX_ROOT_PARENT: resolveLocalSandboxRootParent(),
295
+ CODE_MODE_SOCKET_PARENT: resolveCodeModeSocketParent()
309
296
  } : {
310
297
  ...shared,
311
298
  STANDALONE: false,
@@ -329,7 +316,1609 @@ var init_config = __esm({
329
316
  REDIS_URL: resolveRedisUrl(),
330
317
  OIDC: resolveOIDCConfig()
331
318
  };
332
- config_default = configuration;
319
+ config_default = configuration;
320
+ }
321
+ });
322
+
323
+ // src/db/agentStore.ts
324
+ import { AgentSpecSchema } from "@truefoundry/trueforge-core/agent-session";
325
+ function parseStoredAgentSpec(manifest) {
326
+ return AgentSpecSchema.parse(manifest);
327
+ }
328
+ var AgentNameConflictError;
329
+ var init_agentStore = __esm({
330
+ "src/db/agentStore.ts"() {
331
+ "use strict";
332
+ AgentNameConflictError = class extends Error {
333
+ tenant_id;
334
+ agent_name;
335
+ constructor({ tenant_id, name }, options) {
336
+ super(`Agent name already exists: ${name}`, options);
337
+ this.name = "AgentNameConflictError";
338
+ this.tenant_id = tenant_id;
339
+ this.agent_name = name;
340
+ }
341
+ };
342
+ }
343
+ });
344
+
345
+ // src/sandbox/local/sandboxScripts.gen.ts
346
+ var sandboxScripts;
347
+ var init_sandboxScripts_gen = __esm({
348
+ "src/sandbox/local/sandboxScripts.gen.ts"() {
349
+ "use strict";
350
+ sandboxScripts = {
351
+ mcpClientLocal: `#!/usr/bin/env python3
352
+ """Code Mode UDS client \u2014 same public surface as product mcp_client.py, stdlib only.
353
+
354
+ Authoritative reference (do not diverge on API/CLI/policy semantics):
355
+ packages/trueforge-core/src/core/sandbox/scripts/mcp_client.py
356
+
357
+ Inlined into TypeScript via scripts/generate-local-sandbox-scripts.mjs
358
+ (src/sandbox/local/sandboxScripts.gen.ts), same pattern as core sandboxScripts.
359
+ """
360
+
361
+ from __future__ import annotations
362
+
363
+ import argparse
364
+ import asyncio
365
+ import base64
366
+ import json
367
+ import logging
368
+ import os
369
+ import socket
370
+ import sys
371
+ import time
372
+ from pathlib import Path
373
+ from typing import Any, TypedDict
374
+
375
+ logger = logging.getLogger(__name__)
376
+
377
+ MAX_MESSAGE_BYTES = 64 * 1024 * 1024
378
+ _TOOLS_CACHE_TTL_SECONDS = 600
379
+
380
+
381
+ class _ServerConfig(TypedDict):
382
+ allowed_tools: list[str]
383
+
384
+
385
+ _inflight_list_tools: dict[str, asyncio.Task[list[dict[str, Any]]]] = {}
386
+
387
+ _raw_servers = os.environ.get("TFY_MCP_SERVERS")
388
+ _servers_map: dict[str, _ServerConfig] = (
389
+ json.loads(base64.b64decode(_raw_servers).decode()) if _raw_servers else {}
390
+ )
391
+ _enable_agent_approvals = os.environ.get("TFY_ENABLE_AGENT_APPROVALS", "true").lower() == "true"
392
+
393
+
394
+ def _sock_path() -> str:
395
+ path = os.environ.get("TFY_MCP_SOCK")
396
+ if not path:
397
+ raise RuntimeError("TFY_MCP_SOCK is not set")
398
+ return path
399
+
400
+
401
+ def _request_timeout() -> float:
402
+ return float(os.environ.get("TFY_CM_REQUEST_TIMEOUT_SECONDS", "60"))
403
+
404
+
405
+ def _check_tool_allowed(server: str, tool_name: str) -> None:
406
+ server_config = _servers_map.get(server)
407
+ if server_config is None:
408
+ raise RuntimeError(f"Access denied: MCP server '{server}' is not available for this agent") from None
409
+ server_tools = server_config.get("allowed_tools") or []
410
+ if len(server_tools) > 0 and tool_name not in server_tools:
411
+ raise RuntimeError(f"Access denied: tool '{tool_name}' is not enabled on server '{server}'") from None
412
+
413
+
414
+ def _cache_path(server: str) -> Path:
415
+ return Path(__file__).parent / f"{server}.tools.json"
416
+
417
+
418
+ def _read_tools_cache(server: str) -> list[dict[str, Any]] | None:
419
+ p = _cache_path(server)
420
+ if not p.exists():
421
+ return None
422
+ try:
423
+ raw = json.loads(p.read_text(encoding="utf-8"))
424
+ if not isinstance(raw, dict):
425
+ raise ValueError("cache root must be object")
426
+ fetched_at = raw.get("fetched_at")
427
+ tools = raw.get("tools")
428
+ if not isinstance(fetched_at, (int, float)) or not isinstance(tools, list):
429
+ raise ValueError("cache shape invalid")
430
+ if time.time() - float(fetched_at) > _TOOLS_CACHE_TTL_SECONDS:
431
+ p.unlink(missing_ok=True)
432
+ return None
433
+ return [t for t in tools if isinstance(t, dict)]
434
+ except Exception:
435
+ logger.exception("_read_tools_cache")
436
+ p.unlink(missing_ok=True)
437
+ return None
438
+
439
+
440
+ def _write_tools_cache(server: str, tools: list[dict[str, Any]]) -> None:
441
+ try:
442
+ payload = {"fetched_at": time.time(), "tools": tools}
443
+ _cache_path(server).write_text(json.dumps(payload), encoding="utf-8")
444
+ except Exception:
445
+ logger.exception("_write_tools_cache")
446
+
447
+
448
+ def _read_message(sock: socket.socket) -> Any:
449
+ body = b""
450
+ while True:
451
+ chunk = sock.recv(65536)
452
+ if not chunk:
453
+ break
454
+ body += chunk
455
+ if len(body) > MAX_MESSAGE_BYTES:
456
+ raise RuntimeError(f"message exceeds max {MAX_MESSAGE_BYTES} bytes")
457
+ return json.loads(body.decode("utf-8"))
458
+
459
+
460
+ def _write_message(sock: socket.socket, value: Any) -> None:
461
+ sock.sendall(json.dumps(value).encode("utf-8"))
462
+
463
+
464
+ def _uds_request_sync(payload: dict[str, Any]) -> Any:
465
+ """Connect \u2192 JSON request \u2192 write-close \u2192 JSON reply (no request_id)."""
466
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
467
+ try:
468
+ sock.settimeout(_request_timeout())
469
+ sock.connect(_sock_path())
470
+ _write_message(sock, payload)
471
+ sock.shutdown(socket.SHUT_WR)
472
+ reply = _read_message(sock)
473
+ finally:
474
+ sock.close()
475
+ if not isinstance(reply, dict):
476
+ raise RuntimeError(f"Code Mode reply is not an object: {reply!r}")
477
+ ok = reply.get("ok")
478
+ if ok is not True:
479
+ source = reply.get("source", "internal")
480
+ error = reply.get("error", "unknown error")
481
+ if source == "caller":
482
+ raise RuntimeError(f"Invalid MCP request: {error}")
483
+ if source == "transport":
484
+ raise RuntimeError(f"Code Mode transport error: {error}")
485
+ raise RuntimeError(f"Internal MCP error: {error}")
486
+ return reply.get("result")
487
+
488
+
489
+ async def _uds_request(payload: dict[str, Any]) -> Any:
490
+ return await asyncio.to_thread(_uds_request_sync, payload)
491
+
492
+
493
+ async def _fetch_tools(server: str) -> list[dict[str, Any]]:
494
+ result = await _uds_request({"op": "list_tools", "server": server})
495
+ if not isinstance(result, dict):
496
+ raise RuntimeError(f"list_tools '{server}' returned unexpected shape: {result!r}") from None
497
+ tools = result.get("tools", [])
498
+ if not isinstance(tools, list):
499
+ raise RuntimeError(f"list_tools '{server}' tools is not a list: {tools!r}") from None
500
+ return [t for t in tools if isinstance(t, dict)]
501
+
502
+
503
+ async def _fetch_and_cache_tools(server: str) -> list[dict[str, Any]]:
504
+ tools = await _fetch_tools(server)
505
+ _write_tools_cache(server, tools)
506
+ return tools
507
+
508
+
509
+ async def _get_tools(server: str) -> list[dict[str, Any]]:
510
+ cached = _read_tools_cache(server)
511
+ if cached is not None:
512
+ return cached
513
+ task = _inflight_list_tools.get(server)
514
+ if task is None:
515
+ task = asyncio.create_task(_fetch_and_cache_tools(server))
516
+ _inflight_list_tools[server] = task
517
+ task.add_done_callback(lambda _t: _inflight_list_tools.pop(server, None))
518
+ return await task
519
+
520
+
521
+ async def _get_tool(server: str, tool_name: str) -> dict[str, Any] | None:
522
+ for t in await _get_tools(server):
523
+ if t.get("name") == tool_name:
524
+ return t
525
+ return None
526
+
527
+
528
+ def _is_destructive(tool: dict[str, Any]) -> bool:
529
+ annotations = tool.get("annotations")
530
+ if annotations is None:
531
+ return False
532
+ if not isinstance(annotations, dict):
533
+ return False
534
+ destructive = annotations.get("destructiveHint")
535
+ read_only = annotations.get("readOnlyHint")
536
+ return bool(destructive) or (not read_only and read_only is not None)
537
+
538
+
539
+ async def _ensure_non_destructive(server: str, tool_name: str) -> None:
540
+ tool = await _get_tool(server, tool_name)
541
+ if tool is None:
542
+ raise RuntimeError(f"Tool '{tool_name}' not found on MCP server '{server}'") from None
543
+ if _is_destructive(tool):
544
+ raise RuntimeError(
545
+ f"Tool '{tool_name}' on MCP server '{server}' is destructive and cannot be called in Code Mode; "
546
+ f"call it directly so it can go through the user approval flow"
547
+ ) from None
548
+
549
+
550
+ def _project_call_tool_result(server: str, tool: str, result: Any) -> Any:
551
+ """Project an MCP-wire CallToolResult-shaped object into the user-facing Python value."""
552
+ if not isinstance(result, dict):
553
+ raise RuntimeError(f"call_tool reply for '{server}/{tool}' is malformed: expected object") from None
554
+
555
+ if result.get("isError"):
556
+ content = result.get("content")
557
+ text_parts: list[str] = []
558
+ if isinstance(content, list):
559
+ for c in content:
560
+ if isinstance(c, dict) and c.get("type") == "text":
561
+ text = c.get("text")
562
+ if isinstance(text, str) and text:
563
+ text_parts.append(text)
564
+ msg = "; ".join(text_parts) if text_parts else "tool returned an error"
565
+ raise RuntimeError(f"MCP tool error (server={server}, tool={tool}): {msg}") from None
566
+
567
+ if result.get("structuredContent") is not None:
568
+ return result["structuredContent"]
569
+
570
+ content = result.get("content")
571
+ if isinstance(content, list) and len(content) == 1:
572
+ first = content[0]
573
+ if isinstance(first, dict) and first.get("type") == "text":
574
+ text = first.get("text")
575
+ if isinstance(text, str) and text:
576
+ try:
577
+ return json.loads(text)
578
+ except Exception:
579
+ pass
580
+ if isinstance(content, list) and content:
581
+ return content
582
+ return None
583
+
584
+
585
+ async def call_tool(server: str, tool: str, body: dict[str, Any]) -> Any:
586
+ _check_tool_allowed(server, tool)
587
+ if _enable_agent_approvals:
588
+ await _ensure_non_destructive(server, tool)
589
+
590
+ raw = await _uds_request(
591
+ {
592
+ "op": "call_tool",
593
+ "server": server,
594
+ "tool": tool,
595
+ "arguments": body,
596
+ },
597
+ )
598
+ return _project_call_tool_result(server, tool, raw)
599
+
600
+
601
+ _USAGE = "mcp_client_local.py call-tool <server> <tool> <args-json>"
602
+
603
+
604
+ def _build_arg_parser() -> argparse.ArgumentParser:
605
+ parser = argparse.ArgumentParser(prog="mcp_client_local.py", usage=_USAGE)
606
+ sub = parser.add_subparsers(dest="cmd", required=True)
607
+
608
+ call_tool_p = sub.add_parser("call-tool", help="Invoke an MCP tool")
609
+ call_tool_p.add_argument("server")
610
+ call_tool_p.add_argument("tool")
611
+ call_tool_p.add_argument("args_json", metavar="args-json", type=json.loads)
612
+
613
+ return parser
614
+
615
+
616
+ async def _main() -> None:
617
+ args = _build_arg_parser().parse_args()
618
+ try:
619
+ if args.cmd == "call-tool":
620
+ result = await call_tool(args.server, args.tool, args.args_json)
621
+ print(json.dumps(result, default=str))
622
+ except RuntimeError as e:
623
+ sys.exit(str(e))
624
+
625
+
626
+ if __name__ == "__main__":
627
+ asyncio.run(_main())
628
+ `
629
+ };
630
+ }
631
+ });
632
+
633
+ // src/sandbox/local/schemas/jsonMessage.ts
634
+ import { z as z5 } from "zod";
635
+ var JsonMessageValueSchema;
636
+ var init_jsonMessage = __esm({
637
+ "src/sandbox/local/schemas/jsonMessage.ts"() {
638
+ "use strict";
639
+ JsonMessageValueSchema = z5.json();
640
+ }
641
+ });
642
+
643
+ // src/sandbox/local/core/frame.ts
644
+ function encodeJsonMessage(value) {
645
+ return Buffer.from(JSON.stringify(value), "utf8");
646
+ }
647
+ var MAX_MESSAGE_BYTES, JsonMessageReader;
648
+ var init_frame = __esm({
649
+ "src/sandbox/local/core/frame.ts"() {
650
+ "use strict";
651
+ init_jsonMessage();
652
+ MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
653
+ JsonMessageReader = class {
654
+ #buffer = Buffer.alloc(0);
655
+ #maxBytes;
656
+ constructor(options = {}) {
657
+ this.#maxBytes = options.maxBytes ?? MAX_MESSAGE_BYTES;
658
+ }
659
+ push(chunk) {
660
+ if (this.#buffer.length + chunk.length > this.#maxBytes) {
661
+ throw new Error(`message exceeds max ${String(this.#maxBytes)} bytes`);
662
+ }
663
+ this.#buffer = Buffer.concat([this.#buffer, chunk]);
664
+ }
665
+ finish() {
666
+ try {
667
+ return JsonMessageValueSchema.parse(JSON.parse(this.#buffer.toString("utf8")));
668
+ } catch (error) {
669
+ throw new Error("invalid JSON message", { cause: error });
670
+ }
671
+ }
672
+ };
673
+ }
674
+ });
675
+
676
+ // src/sandbox/local/core/CodeModeUdsTransport.ts
677
+ import { CodeModeRequestSchema, validateNoPathTraversal } from "@truefoundry/trueforge-core/core";
678
+ import { chmodSync, existsSync as existsSync3, realpathSync, statSync } from "fs";
679
+ import { chmod, mkdir as mkdir2, rm as rm2, symlink, unlink, writeFile } from "fs/promises";
680
+ import { createServer } from "net";
681
+ import { dirname, isAbsolute, join, resolve } from "path";
682
+ import { ulid } from "ulid";
683
+ function assertCodeModeSocketParentPath(path7) {
684
+ if (!isAbsolute(path7)) {
685
+ throw new Error("codeModeSocketParentPath must be an absolute path");
686
+ }
687
+ validateNoPathTraversal(path7);
688
+ const resolved = resolve(path7);
689
+ if (!existsSync3(resolved) || !statSync(resolved).isDirectory()) {
690
+ throw new Error("codeModeSocketParentPath must be an existing directory");
691
+ }
692
+ const real = realpathSync(resolved);
693
+ const bytes = Buffer.byteLength(real);
694
+ if (bytes > MAX_CODE_MODE_SOCKET_PARENT_BYTES) {
695
+ throw new Error(
696
+ `codeModeSocketParentPath (${real}) must be at most ${String(MAX_CODE_MODE_SOCKET_PARENT_BYTES)} bytes (got ${String(bytes)})`
697
+ );
698
+ }
699
+ chmodSync(real, CODE_MODE_SOCKET_PARENT_MODE);
700
+ const mode = statSync(real).mode & 511;
701
+ if (mode !== CODE_MODE_SOCKET_PARENT_MODE) {
702
+ throw new Error(`codeModeSocketParentPath must be mode 0700 after chmod (got 0o${mode.toString(8)})`);
703
+ }
704
+ return real;
705
+ }
706
+ async function probeCodeModeUnixSocket(parentPath) {
707
+ const realParent = assertCodeModeSocketParentPath(parentPath);
708
+ const sockPath = join(realParent, ulid().toLowerCase());
709
+ await unlink(sockPath).catch(() => void 0);
710
+ const server = createServer();
711
+ try {
712
+ await new Promise((resolveListen, reject) => {
713
+ server.once("error", reject);
714
+ server.listen(sockPath, () => {
715
+ server.off("error", reject);
716
+ resolveListen();
717
+ });
718
+ });
719
+ } catch (error) {
720
+ const message = error instanceof Error ? error.message : String(error);
721
+ throw new Error(`listen ${sockPath} (${String(Buffer.byteLength(sockPath))} bytes): ${message}`, { cause: error });
722
+ } finally {
723
+ await new Promise((resolveClose) => {
724
+ server.close(() => {
725
+ resolveClose();
726
+ });
727
+ });
728
+ await unlink(sockPath).catch(() => void 0);
729
+ }
730
+ return { sockPath };
731
+ }
732
+ var MAX_CODE_MODE_SOCKET_PARENT_BYTES, CODE_MODE_SOCKET_PARENT_MODE, CODE_MODE_SOCKET_MODE, CodeModeUdsTransport;
733
+ var init_CodeModeUdsTransport = __esm({
734
+ "src/sandbox/local/core/CodeModeUdsTransport.ts"() {
735
+ "use strict";
736
+ init_sandboxScripts_gen();
737
+ init_frame();
738
+ MAX_CODE_MODE_SOCKET_PARENT_BYTES = 65;
739
+ CODE_MODE_SOCKET_PARENT_MODE = 448;
740
+ CODE_MODE_SOCKET_MODE = 384;
741
+ CodeModeUdsTransport = class {
742
+ codeModeSocketParentPath;
743
+ maxMessageBytes;
744
+ onProtocolError;
745
+ clientRemotePath;
746
+ sessionPromise;
747
+ server;
748
+ sockPath;
749
+ dispatcher;
750
+ cachedEnv;
751
+ constructor(options) {
752
+ this.codeModeSocketParentPath = assertCodeModeSocketParentPath(options.codeModeSocketParentPath);
753
+ this.maxMessageBytes = options.maxMessageBytes ?? MAX_MESSAGE_BYTES;
754
+ this.onProtocolError = options.onProtocolError;
755
+ this.clientRemotePath = options.clientRemotePath;
756
+ }
757
+ getClientInstall(params) {
758
+ return {
759
+ content: sandboxScripts.mcpClientLocal,
760
+ remotePath: this.clientRemotePath(params.sandboxId)
761
+ };
762
+ }
763
+ start(params) {
764
+ this.dispatcher = params.codeModeDispatcher;
765
+ this.sessionPromise ??= this.listenSession(params).catch((e) => {
766
+ this.sessionPromise = void 0;
767
+ this.cachedEnv = void 0;
768
+ throw e;
769
+ });
770
+ return this.sessionPromise;
771
+ }
772
+ async stop() {
773
+ const pending = this.sessionPromise;
774
+ this.sessionPromise = void 0;
775
+ this.cachedEnv = void 0;
776
+ if (pending !== void 0) {
777
+ try {
778
+ await pending;
779
+ } catch {
780
+ }
781
+ }
782
+ const server = this.server;
783
+ const sockPath = this.sockPath;
784
+ this.server = void 0;
785
+ this.sockPath = void 0;
786
+ if (server !== void 0) {
787
+ await new Promise((resolveClose) => {
788
+ server.close(() => {
789
+ resolveClose();
790
+ });
791
+ });
792
+ }
793
+ if (sockPath !== void 0) {
794
+ await unlink(sockPath).catch(() => void 0);
795
+ }
796
+ }
797
+ async listenSession(params) {
798
+ if (this.server !== void 0 && this.cachedEnv !== void 0) {
799
+ return { env: this.cachedEnv };
800
+ }
801
+ assertCodeModeSocketParentPath(this.codeModeSocketParentPath);
802
+ const sockPath = join(this.codeModeSocketParentPath, ulid().toLowerCase());
803
+ await unlink(sockPath).catch(() => void 0);
804
+ const server = createServer({ allowHalfOpen: true });
805
+ try {
806
+ await new Promise((resolveListen, reject) => {
807
+ server.once("error", reject);
808
+ server.listen(sockPath, () => {
809
+ server.off("error", reject);
810
+ resolveListen();
811
+ });
812
+ });
813
+ await chmod(sockPath, CODE_MODE_SOCKET_MODE);
814
+ } catch (error) {
815
+ server.close();
816
+ await unlink(sockPath).catch(() => void 0);
817
+ throw error;
818
+ }
819
+ this.server = server;
820
+ this.sockPath = sockPath;
821
+ server.on("connection", (socket) => {
822
+ this.handleConnection(socket);
823
+ });
824
+ const env = {
825
+ TFY_MCP_SOCK: sockPath,
826
+ TFY_CM_REQUEST_TIMEOUT_SECONDS: String(params.requestTimeoutSeconds)
827
+ };
828
+ this.cachedEnv = env;
829
+ return { env };
830
+ }
831
+ handleConnection(socket) {
832
+ const reader = new JsonMessageReader({ maxBytes: this.maxMessageBytes });
833
+ let settled = false;
834
+ socket.on("error", () => void 0);
835
+ const fail = (message) => {
836
+ if (settled) {
837
+ return;
838
+ }
839
+ settled = true;
840
+ this.onProtocolError?.(message);
841
+ socket.destroy();
842
+ };
843
+ socket.on("data", (chunk) => {
844
+ try {
845
+ reader.push(chunk);
846
+ } catch (error) {
847
+ fail(error instanceof Error ? error.message : String(error));
848
+ }
849
+ });
850
+ socket.on("end", () => {
851
+ if (settled) {
852
+ return;
853
+ }
854
+ settled = true;
855
+ void this.dispatchConnection(socket, reader).catch((error) => {
856
+ this.onProtocolError?.(error instanceof Error ? error.message : String(error));
857
+ socket.destroy();
858
+ });
859
+ });
860
+ }
861
+ async dispatchConnection(socket, reader) {
862
+ let request;
863
+ try {
864
+ const parsed = CodeModeRequestSchema.safeParse(reader.finish());
865
+ if (!parsed.success) {
866
+ const reply2 = {
867
+ ok: false,
868
+ error: "Malformed Code Mode request",
869
+ source: "caller"
870
+ };
871
+ socket.write(encodeJsonMessage(reply2));
872
+ socket.end();
873
+ return;
874
+ }
875
+ request = parsed.data;
876
+ } catch (error) {
877
+ this.onProtocolError?.(error instanceof Error ? error.message : String(error));
878
+ socket.destroy();
879
+ return;
880
+ }
881
+ const dispatcher = this.dispatcher;
882
+ if (dispatcher === void 0) {
883
+ const reply2 = {
884
+ ok: false,
885
+ error: "Code Mode dispatcher is not configured",
886
+ source: "internal"
887
+ };
888
+ socket.write(encodeJsonMessage(reply2));
889
+ socket.end();
890
+ return;
891
+ }
892
+ const reply = await dispatcher.dispatch({ request, traceCarrier: {} });
893
+ try {
894
+ socket.write(encodeJsonMessage(reply));
895
+ } finally {
896
+ socket.end();
897
+ }
898
+ }
899
+ };
900
+ }
901
+ });
902
+
903
+ // src/sandbox/local/core/hostRun.ts
904
+ import { getDefaultWritePaths, SandboxManager } from "@anthropic-ai/sandbox-runtime";
905
+ import { execFile, spawn } from "child_process";
906
+ import { randomUUID } from "crypto";
907
+ import { realpathSync as realpathSync2 } from "fs";
908
+ import { mkdir as mkdir3, rm as rm3 } from "fs/promises";
909
+ import { createRequire } from "module";
910
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2 } from "path";
911
+ import { promisify } from "util";
912
+ function codeModeSocketParentAllow() {
913
+ return codeModeSocketParentPath === void 0 ? [] : [codeModeSocketParentPath];
914
+ }
915
+ function requireActivePlatform() {
916
+ if (activePlatform === void 0) {
917
+ throw new Error("SRT platform is not set; call initSrt({ platform }) first");
918
+ }
919
+ return activePlatform;
920
+ }
921
+ function commandPath(platform) {
922
+ return COMMAND_PATH_BY_PLATFORM[platform];
923
+ }
924
+ function sandboxVenvPath(sandboxRootPath) {
925
+ return join2(sandboxRootPath, SANDBOX_VENV_DIR);
926
+ }
927
+ function allowedNetworkDomains() {
928
+ return [...LOCAL_SANDBOX_ALLOWED_DOMAINS];
929
+ }
930
+ function darwinSandboxNetworkShellPreamble() {
931
+ return [
932
+ 'if [ -n "${HTTP_PROXY:-}" ]; then export HTTP_PROXY="${HTTP_PROXY//localhost/127.0.0.1}"; fi',
933
+ 'if [ -n "${HTTPS_PROXY:-}" ]; then export HTTPS_PROXY="${HTTPS_PROXY//localhost/127.0.0.1}"; fi',
934
+ 'if [ -n "${http_proxy:-}" ]; then export http_proxy="${http_proxy//localhost/127.0.0.1}"; fi',
935
+ 'if [ -n "${https_proxy:-}" ]; then export https_proxy="${https_proxy//localhost/127.0.0.1}"; fi',
936
+ 'if [ -n "${ALL_PROXY:-}" ]; then export ALL_PROXY="${ALL_PROXY//localhost/127.0.0.1}"; fi',
937
+ 'if [ -n "${all_proxy:-}" ]; then export all_proxy="${all_proxy//localhost/127.0.0.1}"; fi',
938
+ 'if [ -n "${GRPC_PROXY:-}" ]; then export GRPC_PROXY="${GRPC_PROXY//localhost/127.0.0.1}"; fi',
939
+ 'if [ -n "${grpc_proxy:-}" ]; then export grpc_proxy="${grpc_proxy//localhost/127.0.0.1}"; fi'
940
+ ].join("; ");
941
+ }
942
+ function wrapSandboxCommand(params) {
943
+ if (params.platform !== "darwin") {
944
+ return params.command;
945
+ }
946
+ return `${darwinSandboxNetworkShellPreamble()}; ${params.command}`;
947
+ }
948
+ function srtHostBinaryNames(platform) {
949
+ return SRT_HOST_BINARIES_BY_PLATFORM[platform];
950
+ }
951
+ async function checkSrtHostDependencies() {
952
+ const result = await SandboxManager.checkDependenciesAsync();
953
+ return { errors: [...result.errors], warnings: [...result.warnings] };
954
+ }
955
+ async function resolveCommandOnHost(params) {
956
+ if (!/^[A-Za-z0-9._+-]+$/.test(params.name)) {
957
+ throw new Error(`invalid command name for resolveCommandOnHost: ${params.name}`);
958
+ }
959
+ const pathEnv = params.pathEnv !== void 0 && params.pathEnv.length > 0 ? params.pathEnv : commandPath(params.platform);
960
+ try {
961
+ const { stdout } = await execFileAsync("/bin/sh", ["-c", `command -v -- ${params.name}`], {
962
+ env: { PATH: pathEnv },
963
+ encoding: "utf8"
964
+ });
965
+ const resolved = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
966
+ if (resolved === void 0 || resolved.length === 0 || !isAbsolute2(resolved)) {
967
+ return void 0;
968
+ }
969
+ return resolved;
970
+ } catch {
971
+ return void 0;
972
+ }
973
+ }
974
+ async function resolvePythonExecutableOnHost(params) {
975
+ if (!isAbsolute2(params.commandPath)) {
976
+ return void 0;
977
+ }
978
+ try {
979
+ const { stdout } = await execFileAsync(params.commandPath, ["-c", "import sys; print(sys.executable)"], {
980
+ encoding: "utf8",
981
+ timeout: 5e3
982
+ });
983
+ const executable = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
984
+ if (executable === void 0 || executable.length === 0 || !isAbsolute2(executable)) {
985
+ return void 0;
986
+ }
987
+ return realpathSync2(executable);
988
+ } catch {
989
+ return void 0;
990
+ }
991
+ }
992
+ function denySharedDefaultWritePaths() {
993
+ return getDefaultWritePaths().filter((path7) => !path7.startsWith("/dev/"));
994
+ }
995
+ function platformAllowRead(platform) {
996
+ return [...ALLOW_READ_BY_PLATFORM[platform]];
997
+ }
998
+ function filesystemPolicy(params) {
999
+ return {
1000
+ allowWrite: [params.sandboxRootPath],
1001
+ denyWrite: denySharedDefaultWritePaths(),
1002
+ denyRead: ["/"],
1003
+ allowRead: [params.sandboxRootPath, ...codeModeSocketParentAllow(), ...platformAllowRead(params.platform)]
1004
+ };
1005
+ }
1006
+ function commandEnv(params) {
1007
+ const tmp = join2(params.sandboxRootPath, ".tmp");
1008
+ const home = join2(params.sandboxRootPath, ".home");
1009
+ const venvDir = sandboxVenvPath(params.sandboxRootPath);
1010
+ const locked = {
1011
+ HOME: home,
1012
+ TMPDIR: tmp,
1013
+ TMP: tmp,
1014
+ TEMP: tmp,
1015
+ VIRTUAL_ENV: venvDir,
1016
+ // Cwd-relative layout dirs (not host-absolute). Absolute paths under
1017
+ // `Application Support` break PATH lookup (`mcp-client: command not found`).
1018
+ PATH: `${join2(SANDBOX_VENV_DIR, "bin")}:mcp-client/bin:${commandPath(params.platform)}`
1019
+ };
1020
+ return {
1021
+ ...params.extra,
1022
+ ...locked
1023
+ };
1024
+ }
1025
+ function sessionFilesystem(platform) {
1026
+ const allowWrite = [];
1027
+ return {
1028
+ allowWrite,
1029
+ denyWrite: denySharedDefaultWritePaths(),
1030
+ denyRead: ["/"],
1031
+ allowRead: [...platformAllowRead(platform), ...codeModeSocketParentAllow()]
1032
+ };
1033
+ }
1034
+ function sessionNetwork(params) {
1035
+ const allowedDomains = allowedNetworkDomains();
1036
+ const deniedDomains = [];
1037
+ if (params.platform === "linux") {
1038
+ return {
1039
+ allowedDomains,
1040
+ deniedDomains,
1041
+ allowAllUnixSockets: true
1042
+ };
1043
+ }
1044
+ return {
1045
+ allowedDomains,
1046
+ deniedDomains,
1047
+ allowAllUnixSockets: false,
1048
+ allowUnixSockets: params.unixSockets ?? []
1049
+ };
1050
+ }
1051
+ function darwinUnixSocketPaths() {
1052
+ return [...darwinUnixSocketSandboxRoots, ...codeModeSocketParentAllow()];
1053
+ }
1054
+ function syncDarwinUnixSockets() {
1055
+ if (SandboxManager.getConfig() === void 0) {
1056
+ return;
1057
+ }
1058
+ const platform = requireActivePlatform();
1059
+ if (platform !== "darwin") {
1060
+ return;
1061
+ }
1062
+ SandboxManager.updateConfig(buildSessionConfig(platform));
1063
+ }
1064
+ function buildSessionConfig(platform) {
1065
+ return {
1066
+ network: sessionNetwork({ platform, unixSockets: darwinUnixSocketPaths() }),
1067
+ filesystem: sessionFilesystem(platform)
1068
+ };
1069
+ }
1070
+ async function createSandbox(sandboxRootPath) {
1071
+ await mkdir3(sandboxRootPath, { recursive: true, mode: 448 });
1072
+ await mkdir3(join2(sandboxRootPath, ".tmp"), { recursive: true, mode: 448 });
1073
+ await mkdir3(join2(sandboxRootPath, ".home"), { recursive: true, mode: 448 });
1074
+ const realRoot = realpathSync2(sandboxRootPath);
1075
+ darwinUnixSocketSandboxRoots.add(realRoot);
1076
+ syncDarwinUnixSockets();
1077
+ return realRoot;
1078
+ }
1079
+ async function removeSandbox(sandboxRootPath) {
1080
+ darwinUnixSocketSandboxRoots.delete(sandboxRootPath);
1081
+ syncDarwinUnixSockets();
1082
+ await rm3(sandboxRootPath, { recursive: true, force: true });
1083
+ }
1084
+ async function initSrt(params) {
1085
+ activePlatform = params.platform;
1086
+ codeModeSocketParentPath = params.codeModeSocketParentPath === void 0 ? void 0 : realpathSync2(params.codeModeSocketParentPath);
1087
+ await SandboxManager.initialize(buildSessionConfig(params.platform));
1088
+ }
1089
+ async function resetSrt() {
1090
+ codeModeSocketParentPath = void 0;
1091
+ activePlatform = void 0;
1092
+ await SandboxManager.reset();
1093
+ }
1094
+ function isSrtInitialized() {
1095
+ return activePlatform !== void 0 && SandboxManager.getConfig() !== void 0;
1096
+ }
1097
+ function killExecTree(child) {
1098
+ if (!child) {
1099
+ return;
1100
+ }
1101
+ const pid = child.pid;
1102
+ if (pid !== void 0 && process.platform !== "win32") {
1103
+ try {
1104
+ process.kill(-pid, "SIGKILL");
1105
+ return;
1106
+ } catch {
1107
+ }
1108
+ }
1109
+ if (!child.killed) {
1110
+ child.kill("SIGKILL");
1111
+ }
1112
+ }
1113
+ async function runSupervisorSession(params) {
1114
+ const {
1115
+ sandboxRootPath,
1116
+ command: rawCommand,
1117
+ shell,
1118
+ platform,
1119
+ cwd = sandboxRootPath,
1120
+ env,
1121
+ stdin,
1122
+ onChildSpawn,
1123
+ timeoutMs
1124
+ } = params;
1125
+ const command = wrapSandboxCommand({ platform, command: rawCommand });
1126
+ const wrap = await SandboxManager.wrapWithSandboxArgv(
1127
+ command,
1128
+ shell,
1129
+ {
1130
+ filesystem: filesystemPolicy({ sandboxRootPath, platform }),
1131
+ network: {
1132
+ allowedDomains: allowedNetworkDomains(),
1133
+ deniedDomains: []
1134
+ }
1135
+ },
1136
+ void 0,
1137
+ sandboxRootPath,
1138
+ { commandId: randomUUID(), commandText: command }
1139
+ );
1140
+ const [argv0, ...argvRest] = wrap.argv;
1141
+ if (argv0 === void 0) {
1142
+ throw new Error("wrapWithSandboxArgv returned empty argv");
1143
+ }
1144
+ const childEnv = {
1145
+ ...commandEnv({ sandboxRootPath, platform, ...env === void 0 ? {} : { extra: env } })
1146
+ };
1147
+ const child = spawn(argv0, argvRest, {
1148
+ cwd,
1149
+ env: childEnv,
1150
+ shell: false,
1151
+ // Detached process groups break stdin forwarding for upload (`cat` via pipe) under Jest.
1152
+ detached: stdin === void 0 && process.platform !== "win32",
1153
+ stdio: [stdin === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
1154
+ });
1155
+ if (child.pid !== void 0) {
1156
+ onChildSpawn?.(child.pid);
1157
+ }
1158
+ if (stdin !== void 0) {
1159
+ const stdinStream = child.stdin;
1160
+ if (stdinStream === null) {
1161
+ killExecTree(child);
1162
+ SandboxManager.cleanupAfterCommand();
1163
+ throw new Error("stdin unavailable for sandboxed command");
1164
+ }
1165
+ stdinStream.on("error", () => void 0);
1166
+ await new Promise((resolve3, reject) => {
1167
+ stdinStream.end(stdin, (error) => {
1168
+ if (error) {
1169
+ reject(error);
1170
+ } else {
1171
+ resolve3();
1172
+ }
1173
+ });
1174
+ });
1175
+ }
1176
+ let stdoutText = "";
1177
+ let stderrText = "";
1178
+ let bufferedOutput = 0;
1179
+ let protocolError;
1180
+ let timedOut = false;
1181
+ let closed = false;
1182
+ const ignoreStreamError = (stream) => {
1183
+ stream?.on("error", () => void 0);
1184
+ };
1185
+ const appendOutput = (stream, chunk) => {
1186
+ bufferedOutput += chunk.length;
1187
+ if (bufferedOutput > MAX_OUTPUT_BYTES) {
1188
+ protocolError = `buffered output exceeded ${String(MAX_OUTPUT_BYTES)} bytes`;
1189
+ killExecTree(child);
1190
+ return;
1191
+ }
1192
+ const text = chunk.toString("utf8");
1193
+ if (stream === "stdout") {
1194
+ stdoutText += text;
1195
+ } else {
1196
+ stderrText += text;
1197
+ }
1198
+ };
1199
+ ignoreStreamError(child.stdout);
1200
+ ignoreStreamError(child.stderr);
1201
+ child.stdout?.on("data", (chunk) => {
1202
+ appendOutput("stdout", chunk);
1203
+ });
1204
+ child.stderr?.on("data", (chunk) => {
1205
+ appendOutput("stderr", chunk);
1206
+ });
1207
+ return await new Promise((resolve3, reject) => {
1208
+ const timer = setTimeout(() => {
1209
+ timedOut = true;
1210
+ killExecTree(child);
1211
+ }, timeoutMs);
1212
+ child.on("error", (error) => {
1213
+ if (closed) {
1214
+ return;
1215
+ }
1216
+ closed = true;
1217
+ clearTimeout(timer);
1218
+ SandboxManager.cleanupAfterCommand();
1219
+ reject(error);
1220
+ });
1221
+ child.on("close", (code) => {
1222
+ if (closed) {
1223
+ return;
1224
+ }
1225
+ closed = true;
1226
+ clearTimeout(timer);
1227
+ SandboxManager.cleanupAfterCommand();
1228
+ resolve3({
1229
+ stdoutText,
1230
+ stderrText,
1231
+ exitCode: typeof code === "number" ? code : timedOut ? 1 : 0,
1232
+ protocolError,
1233
+ timedOut,
1234
+ childPid: child.pid
1235
+ });
1236
+ });
1237
+ });
1238
+ }
1239
+ var execFileAsync, SRT_VENDOR, MAX_OUTPUT_BYTES, activePlatform, codeModeSocketParentPath, COMMAND_PATH_BY_PLATFORM, SANDBOX_VENV_DIR, LOCAL_SANDBOX_ALLOWED_DOMAINS, SRT_HOST_BINARIES_BY_PLATFORM, ALLOW_READ_BY_PLATFORM, darwinUnixSocketSandboxRoots;
1240
+ var init_hostRun = __esm({
1241
+ "src/sandbox/local/core/hostRun.ts"() {
1242
+ "use strict";
1243
+ execFileAsync = promisify(execFile);
1244
+ SRT_VENDOR = join2(
1245
+ dirname2(createRequire(import.meta.url).resolve("@anthropic-ai/sandbox-runtime/package.json")),
1246
+ "vendor"
1247
+ );
1248
+ MAX_OUTPUT_BYTES = 14 * 1024 * 1024;
1249
+ COMMAND_PATH_BY_PLATFORM = {
1250
+ // On macOS, prefer Homebrew ahead of `/usr/bin` shims (those need Xcode select
1251
+ // paths that we intentionally do not allow-read).
1252
+ darwin: "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
1253
+ linux: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
1254
+ };
1255
+ SANDBOX_VENV_DIR = ".venv";
1256
+ LOCAL_SANDBOX_ALLOWED_DOMAINS = [
1257
+ "pypi.org",
1258
+ "*.pypi.org",
1259
+ "pythonhosted.org",
1260
+ "files.pythonhosted.org",
1261
+ "*.pythonhosted.org",
1262
+ "github.com",
1263
+ "api.github.com",
1264
+ "codeload.github.com",
1265
+ "*.github.com",
1266
+ "githubusercontent.com",
1267
+ "raw.githubusercontent.com",
1268
+ "objects.githubusercontent.com",
1269
+ "*.githubusercontent.com"
1270
+ ];
1271
+ SRT_HOST_BINARIES_BY_PLATFORM = {
1272
+ linux: ["bwrap", "socat", "rg"],
1273
+ darwin: []
1274
+ };
1275
+ ALLOW_READ_BY_PLATFORM = {
1276
+ darwin: [
1277
+ "/opt/homebrew/bin",
1278
+ "/usr/local",
1279
+ "/usr/bin",
1280
+ "/bin",
1281
+ "/usr/sbin",
1282
+ "/sbin",
1283
+ "/usr/lib",
1284
+ "/System/Library",
1285
+ "/Library",
1286
+ "/private/var/db/dyld",
1287
+ "/private/var/select",
1288
+ "/opt/homebrew",
1289
+ "/dev",
1290
+ // Darwin `/etc` is a symlink to `/private/etc`. SRT refuses that realpath as
1291
+ // "outside boundary" and keeps `(subpath "/etc")`. Seatbelt still checks the
1292
+ // resolved path, so Apple LibreSSL's fopen(`/private/etc/ssl/openssl.cnf`)
1293
+ // needs `/private/etc` listed too. Do not use a `[/]etc/**` glob: SRT treats
1294
+ // that as cwd-relative (`path.isAbsolute('[/]…')` is false).
1295
+ "/etc",
1296
+ "/private/etc"
1297
+ ],
1298
+ linux: [
1299
+ "/usr/bin",
1300
+ "/bin",
1301
+ "/usr/sbin",
1302
+ "/sbin",
1303
+ "/lib",
1304
+ "/lib64",
1305
+ "/usr/lib",
1306
+ "/usr/lib64",
1307
+ "/usr/local",
1308
+ "/etc",
1309
+ "/dev",
1310
+ "/proc",
1311
+ "/sys",
1312
+ SRT_VENDOR
1313
+ ]
1314
+ };
1315
+ darwinUnixSocketSandboxRoots = /* @__PURE__ */ new Set();
1316
+ }
1317
+ });
1318
+
1319
+ // src/sandbox/local/schemas/xferFileInfo.ts
1320
+ import { z as z6 } from "zod";
1321
+ var XferFileInfoSchema;
1322
+ var init_xferFileInfo = __esm({
1323
+ "src/sandbox/local/schemas/xferFileInfo.ts"() {
1324
+ "use strict";
1325
+ XferFileInfoSchema = z6.object({
1326
+ size: z6.number(),
1327
+ isDir: z6.boolean()
1328
+ });
1329
+ }
1330
+ });
1331
+
1332
+ // src/sandbox/local/provider/LocalSandboxProvider.ts
1333
+ var LocalSandboxProvider_exports = {};
1334
+ __export(LocalSandboxProvider_exports, {
1335
+ LocalSandboxProvider: () => LocalSandboxProvider,
1336
+ formatLocalSandboxSupportReason: () => formatLocalSandboxSupportReason,
1337
+ localSandboxUploadCommand: () => localSandboxUploadCommand
1338
+ });
1339
+ import {
1340
+ absolutizeRelativeExecEnv,
1341
+ SandboxFileNotFoundError,
1342
+ SandboxFileTooLargeError,
1343
+ SandboxNotAvailableError,
1344
+ SandboxPathIsDirectoryError,
1345
+ shellEscape,
1346
+ validateNoPathTraversal as validateNoPathTraversal2
1347
+ } from "@truefoundry/trueforge-core/core";
1348
+ import { execFile as execFile2 } from "child_process";
1349
+ import { existsSync as existsSync4, realpathSync as realpathSync3, statSync as statSync2 } from "fs";
1350
+ import { mkdir as mkdir4, mkdtemp, rm as rm4 } from "fs/promises";
1351
+ import { tmpdir } from "os";
1352
+ import { dirname as dirname3, isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve2, sep } from "path";
1353
+ import { promisify as promisify2 } from "util";
1354
+ import { ulid as ulid2 } from "ulid";
1355
+ function formatLocalSandboxSupportReason(params) {
1356
+ const details = params.attempts.map(formatLocalSandboxSupportAttempt).join("; ");
1357
+ return details.length === 0 ? params.summary : `${params.summary}: ${details}`;
1358
+ }
1359
+ function formatLocalSandboxSupportAttempt(attempt) {
1360
+ if (attempt.resolved === void 0) {
1361
+ return attempt.kind === "host" ? `${attempt.name}: not on PATH` : `${attempt.name}: not on sandbox PATH`;
1362
+ }
1363
+ const parts = [`${attempt.name}: resolved=${attempt.resolved}`];
1364
+ if (attempt.executable !== void 0 && attempt.executable !== attempt.resolved) {
1365
+ parts.push(`executable=${attempt.executable}`);
1366
+ }
1367
+ if (attempt.protocolError !== void 0) {
1368
+ parts.push(`protocolError=${attempt.protocolError}`);
1369
+ }
1370
+ if (attempt.exitCode !== void 0) {
1371
+ parts.push(`exit=${String(attempt.exitCode)}`);
1372
+ }
1373
+ if (attempt.timedOut === true) {
1374
+ parts.push("timedOut");
1375
+ }
1376
+ if (attempt.stderr !== void 0 && attempt.stderr.length > 0) {
1377
+ parts.push(`stderr=${JSON.stringify(attempt.stderr)}`);
1378
+ }
1379
+ if (attempt.stdout !== void 0 && attempt.stdout.length > 0) {
1380
+ parts.push(`stdout=${JSON.stringify(attempt.stdout)}`);
1381
+ }
1382
+ return parts.join(" ");
1383
+ }
1384
+ function probeAttemptFromSession(params) {
1385
+ return {
1386
+ kind: params.kind,
1387
+ name: params.name,
1388
+ resolved: params.resolved,
1389
+ ...params.executable === void 0 ? {} : { executable: params.executable },
1390
+ exitCode: params.session.exitCode,
1391
+ stdout: params.session.stdoutText,
1392
+ stderr: params.session.stderrText,
1393
+ ...params.session.protocolError === void 0 ? {} : { protocolError: params.session.protocolError },
1394
+ timedOut: params.session.timedOut
1395
+ };
1396
+ }
1397
+ function unsupported(params) {
1398
+ return {
1399
+ supported: false,
1400
+ reason: params.reason,
1401
+ ...params.platform === void 0 ? {} : { platform: params.platform },
1402
+ ...params.attempts === void 0 ? {} : { attempts: params.attempts }
1403
+ };
1404
+ }
1405
+ function toSandboxRelativePath(params) {
1406
+ const rel = relative(params.sandboxRootPath, params.absolutePath);
1407
+ return rel === "" ? "." : rel;
1408
+ }
1409
+ function isStrictDescendant(params) {
1410
+ const rel = relative(params.ancestor, params.descendant);
1411
+ return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute3(rel);
1412
+ }
1413
+ function execFileErrorDetail(error) {
1414
+ if (!(error instanceof Error)) {
1415
+ return String(error);
1416
+ }
1417
+ const parts = [error.message];
1418
+ if ("stderr" in error && typeof error.stderr === "string" && error.stderr.length > 0) {
1419
+ parts.push(error.stderr);
1420
+ }
1421
+ if ("stdout" in error && typeof error.stdout === "string" && error.stdout.length > 0) {
1422
+ parts.push(error.stdout);
1423
+ }
1424
+ return parts.join(" ");
1425
+ }
1426
+ function sessionFailDetail(session) {
1427
+ return [session.protocolError, session.stderrText, session.stdoutText].filter((part) => part !== void 0 && part.length > 0).join(" ");
1428
+ }
1429
+ function localSandboxUploadCommand(remotePath) {
1430
+ const parent = dirname3(remotePath);
1431
+ return [
1432
+ `mkdir -p ${shellEscape(parent)}`,
1433
+ `{ chmod u+w ${shellEscape(remotePath)} 2>/dev/null || true; }`,
1434
+ `/bin/cat > ${shellEscape(remotePath)}`
1435
+ ].join(" && ");
1436
+ }
1437
+ var execFileAsync2, DEFAULT_EXEC_TIMEOUT_SECONDS, DEFAULT_FILE_MAX_BYTES, SUPPORT_PROBE_TIMEOUT_MS, VENV_CREATE_TIMEOUT_MS, VENV_PIP_TIMEOUT_MS, VENV_PYDANTIC_PIN, SHELL_CANDIDATES, PYTHON_CANDIDATES, LocalSandboxProvider;
1438
+ var init_LocalSandboxProvider = __esm({
1439
+ "src/sandbox/local/provider/LocalSandboxProvider.ts"() {
1440
+ "use strict";
1441
+ init_CodeModeUdsTransport();
1442
+ init_hostRun();
1443
+ init_xferFileInfo();
1444
+ execFileAsync2 = promisify2(execFile2);
1445
+ DEFAULT_EXEC_TIMEOUT_SECONDS = 60;
1446
+ DEFAULT_FILE_MAX_BYTES = 10 * 1024 * 1024;
1447
+ SUPPORT_PROBE_TIMEOUT_MS = 5e3;
1448
+ VENV_CREATE_TIMEOUT_MS = 6e4;
1449
+ VENV_PIP_TIMEOUT_MS = 12e4;
1450
+ VENV_PYDANTIC_PIN = "pydantic>=2.0.0,<3.0.0";
1451
+ SHELL_CANDIDATES = ["bash", "sh"];
1452
+ PYTHON_CANDIDATES = ["python3", "python"];
1453
+ LocalSandboxProvider = class _LocalSandboxProvider {
1454
+ type = "local";
1455
+ sandboxRootPathParent;
1456
+ codeModeSocketParentPath;
1457
+ support;
1458
+ fileMaxBytesForDownload;
1459
+ defaultExecTimeoutSeconds;
1460
+ srtInitialized = false;
1461
+ logger;
1462
+ /** Local SRT has no image build step — always ready. */
1463
+ static readyBuild = {
1464
+ status: "ready",
1465
+ reason: null,
1466
+ metadata: null
1467
+ };
1468
+ /**
1469
+ * Probe whether this host can run LocalSandboxProvider
1470
+ * (OS + Code Mode UDS listen + SRT host binaries + in-sandbox shell + Python 3).
1471
+ * On success, returns platform/shell/python to pass into the constructor as `support`.
1472
+ */
1473
+ static async isSupported(params) {
1474
+ if (process.platform !== "darwin" && process.platform !== "linux") {
1475
+ return unsupported({
1476
+ reason: `LocalSandboxProvider supports macOS and Linux only (got ${process.platform})`
1477
+ });
1478
+ }
1479
+ const platform = process.platform;
1480
+ let createdSocketParent;
1481
+ const socketParentPath = params?.codeModeSocketParentPath;
1482
+ try {
1483
+ const parentPath = socketParentPath ?? await mkdtemp(join3("/tmp", "tfc-"));
1484
+ if (socketParentPath === void 0) {
1485
+ createdSocketParent = parentPath;
1486
+ }
1487
+ try {
1488
+ await probeCodeModeUnixSocket(parentPath);
1489
+ } catch (error) {
1490
+ const message = error instanceof Error ? error.message : String(error);
1491
+ return unsupported({
1492
+ platform,
1493
+ attempts: [{ kind: "socket", name: "uds", resolved: parentPath, protocolError: message }],
1494
+ reason: `Code Mode UDS listen failed: ${message}`
1495
+ });
1496
+ }
1497
+ } finally {
1498
+ if (createdSocketParent !== void 0) {
1499
+ await rm4(createdSocketParent, { recursive: true, force: true });
1500
+ }
1501
+ }
1502
+ const hostPath = process.env["PATH"];
1503
+ const hostAttempts = [];
1504
+ for (const name of srtHostBinaryNames(platform)) {
1505
+ const resolved = await resolveCommandOnHost({
1506
+ platform,
1507
+ name,
1508
+ ...hostPath === void 0 || hostPath.length === 0 ? {} : { pathEnv: hostPath }
1509
+ });
1510
+ hostAttempts.push({ kind: "host", name, resolved });
1511
+ }
1512
+ if (hostAttempts.some((attempt) => attempt.resolved === void 0)) {
1513
+ const required = srtHostBinaryNames(platform).join(", ");
1514
+ return unsupported({
1515
+ platform,
1516
+ attempts: hostAttempts,
1517
+ reason: formatLocalSandboxSupportReason({
1518
+ summary: `SRT host dependencies missing (${platform}: ${required})`,
1519
+ attempts: hostAttempts
1520
+ })
1521
+ });
1522
+ }
1523
+ const srtDeps = await checkSrtHostDependencies();
1524
+ if (srtDeps.errors.length > 0) {
1525
+ return unsupported({
1526
+ platform,
1527
+ attempts: hostAttempts.length === 0 ? void 0 : hostAttempts,
1528
+ reason: `SRT host dependencies failed: ${srtDeps.errors.join("; ")}`
1529
+ });
1530
+ }
1531
+ const alreadyInitialized = isSrtInitialized();
1532
+ let probeRoot;
1533
+ const attempts = [...hostAttempts];
1534
+ const pythonAttempts = [];
1535
+ try {
1536
+ if (!alreadyInitialized) {
1537
+ await initSrt({
1538
+ platform,
1539
+ ...socketParentPath === void 0 ? {} : { codeModeSocketParentPath: socketParentPath }
1540
+ });
1541
+ }
1542
+ probeRoot = await createSandbox(await mkdtemp(join3(tmpdir(), "tfy-local-sandbox-support-")));
1543
+ let shell;
1544
+ for (const name of SHELL_CANDIDATES) {
1545
+ const resolved = await resolveCommandOnHost({ platform, name });
1546
+ if (resolved === void 0) {
1547
+ attempts.push({ kind: "shell", name, resolved: void 0 });
1548
+ continue;
1549
+ }
1550
+ const probe = await runSupervisorSession({
1551
+ sandboxRootPath: probeRoot,
1552
+ platform,
1553
+ shell: resolved,
1554
+ command: "echo shell-ok",
1555
+ timeoutMs: SUPPORT_PROBE_TIMEOUT_MS
1556
+ });
1557
+ const attempt = probeAttemptFromSession({ kind: "shell", name, resolved, session: probe });
1558
+ if (probe.protocolError === void 0 && probe.exitCode === 0 && probe.stdoutText.includes("shell-ok")) {
1559
+ shell = resolved;
1560
+ break;
1561
+ }
1562
+ attempts.push(attempt);
1563
+ }
1564
+ if (shell === void 0) {
1565
+ return unsupported({
1566
+ platform,
1567
+ attempts,
1568
+ reason: formatLocalSandboxSupportReason({
1569
+ summary: "No usable shell in sandbox (bash or sh via command -v)",
1570
+ attempts
1571
+ })
1572
+ });
1573
+ }
1574
+ let python;
1575
+ for (const name of PYTHON_CANDIDATES) {
1576
+ const resolved = await resolveCommandOnHost({ platform, name });
1577
+ if (resolved === void 0) {
1578
+ pythonAttempts.push({ kind: "python", name, resolved: void 0 });
1579
+ continue;
1580
+ }
1581
+ const executable = await resolvePythonExecutableOnHost({ commandPath: resolved }) ?? resolved;
1582
+ const probe = await runSupervisorSession({
1583
+ sandboxRootPath: probeRoot,
1584
+ platform,
1585
+ shell,
1586
+ command: `${shellEscape(executable)} -c ${shellEscape(
1587
+ "import sys; raise SystemExit(0 if sys.version_info[0] == 3 else 1)"
1588
+ )}`,
1589
+ timeoutMs: SUPPORT_PROBE_TIMEOUT_MS
1590
+ });
1591
+ const attempt = probeAttemptFromSession({
1592
+ kind: "python",
1593
+ name,
1594
+ resolved,
1595
+ executable,
1596
+ session: probe
1597
+ });
1598
+ if (probe.protocolError === void 0 && probe.exitCode === 0) {
1599
+ python = executable;
1600
+ break;
1601
+ }
1602
+ pythonAttempts.push(attempt);
1603
+ }
1604
+ if (python === void 0) {
1605
+ return unsupported({
1606
+ platform,
1607
+ attempts: pythonAttempts,
1608
+ reason: formatLocalSandboxSupportReason({
1609
+ summary: "No usable Python 3 interpreter in sandbox (python3 or python via command -v)",
1610
+ attempts: pythonAttempts
1611
+ })
1612
+ });
1613
+ }
1614
+ return { supported: true, platform, shell, python };
1615
+ } catch (error) {
1616
+ const message = error instanceof Error ? error.message : String(error);
1617
+ const seen = [...attempts, ...pythonAttempts];
1618
+ return unsupported({
1619
+ platform,
1620
+ attempts: seen.length === 0 ? void 0 : seen,
1621
+ reason: seen.length === 0 ? message : `${message}: ${formatLocalSandboxSupportReason({ summary: "probe aborted", attempts: seen })}`
1622
+ });
1623
+ } finally {
1624
+ if (probeRoot !== void 0) {
1625
+ await removeSandbox(probeRoot);
1626
+ }
1627
+ if (!alreadyInitialized) {
1628
+ await resetSrt();
1629
+ }
1630
+ }
1631
+ }
1632
+ constructor(options) {
1633
+ if (!options.support.supported) {
1634
+ throw new Error(`LocalSandboxProvider is not supported: ${options.support.reason}`);
1635
+ }
1636
+ if (!isAbsolute3(options.sandboxRootPathParent)) {
1637
+ throw new Error("sandboxRootPathParent must be an absolute path");
1638
+ }
1639
+ validateNoPathTraversal2(options.sandboxRootPathParent);
1640
+ const resolvedParent = resolve2(options.sandboxRootPathParent);
1641
+ this.sandboxRootPathParent = existsSync4(resolvedParent) && statSync2(resolvedParent).isDirectory() ? realpathSync3(resolvedParent) : resolvedParent;
1642
+ this.codeModeSocketParentPath = assertCodeModeSocketParentPath(options.codeModeSocketParentPath);
1643
+ this.support = options.support;
1644
+ this.fileMaxBytesForDownload = options.fileMaxBytesForDownload ?? DEFAULT_FILE_MAX_BYTES;
1645
+ this.defaultExecTimeoutSeconds = options.defaultExecTimeoutSeconds ?? DEFAULT_EXEC_TIMEOUT_SECONDS;
1646
+ this.logger = options.logger.child({ module: "LocalSandboxProvider" });
1647
+ }
1648
+ pythonC(code, relPath) {
1649
+ return `${this.support.python} -c ${shellEscape(code)} ${shellEscape(relPath)}`;
1650
+ }
1651
+ statCommand(relPath) {
1652
+ const code = [
1653
+ "import json, os, sys",
1654
+ "p = sys.argv[1]",
1655
+ "st = os.stat(p)",
1656
+ 'print(json.dumps({"size": st.st_size, "isDir": os.path.isdir(p)}))'
1657
+ ].join("\n");
1658
+ return this.pythonC(code, relPath);
1659
+ }
1660
+ base64EncodeCommand(relPath) {
1661
+ const code = [
1662
+ "import base64, sys",
1663
+ "p = sys.argv[1]",
1664
+ 'sys.stdout.write(base64.b64encode(open(p, "rb").read()).decode("ascii"))'
1665
+ ].join("\n");
1666
+ return this.pythonC(code, relPath);
1667
+ }
1668
+ buildImage() {
1669
+ return Promise.resolve(_LocalSandboxProvider.readyBuild);
1670
+ }
1671
+ getImageBuildStatus() {
1672
+ return Promise.resolve(_LocalSandboxProvider.readyBuild);
1673
+ }
1674
+ async ensureSrt() {
1675
+ if (this.srtInitialized) {
1676
+ return;
1677
+ }
1678
+ await initSrt({
1679
+ platform: this.support.platform,
1680
+ codeModeSocketParentPath: this.codeModeSocketParentPath
1681
+ });
1682
+ this.srtInitialized = true;
1683
+ }
1684
+ /** Missing, non-directory, or not a child of this provider's parent → recreate path in Sandbox. */
1685
+ ensureSandboxRoot(sandboxRootPath) {
1686
+ if (!isAbsolute3(sandboxRootPath)) {
1687
+ throw new SandboxNotAvailableError(sandboxRootPath);
1688
+ }
1689
+ const resolved = resolve2(sandboxRootPath);
1690
+ if (!existsSync4(resolved) || !statSync2(resolved).isDirectory()) {
1691
+ throw new SandboxNotAvailableError(sandboxRootPath);
1692
+ }
1693
+ const parentReal = existsSync4(this.sandboxRootPathParent) ? realpathSync3(this.sandboxRootPathParent) : this.sandboxRootPathParent;
1694
+ const realRoot = realpathSync3(resolved);
1695
+ if (!isStrictDescendant({ ancestor: parentReal, descendant: realRoot })) {
1696
+ throw new SandboxNotAvailableError(sandboxRootPath);
1697
+ }
1698
+ }
1699
+ /**
1700
+ * Host `python -m venv` (stdlib only), then sandboxed pip for pydantic.
1701
+ * Idempotent: skip create when `.venv/bin/python` exists; skip pip when import works.
1702
+ */
1703
+ async ensureVenv(sandboxRootPath) {
1704
+ const venvDir = join3(sandboxRootPath, SANDBOX_VENV_DIR);
1705
+ const venvPython = join3(venvDir, "bin", "python");
1706
+ if (!existsSync4(venvPython)) {
1707
+ try {
1708
+ await execFileAsync2(this.support.python, ["-m", "venv", venvDir], { timeout: VENV_CREATE_TIMEOUT_MS });
1709
+ } catch (error) {
1710
+ throw new Error(`Failed to create sandbox ${SANDBOX_VENV_DIR}: ${execFileErrorDetail(error)}`, {
1711
+ cause: error
1712
+ });
1713
+ }
1714
+ }
1715
+ const relPython = join3(SANDBOX_VENV_DIR, "bin", "python");
1716
+ const relPip = join3(SANDBOX_VENV_DIR, "bin", "pip");
1717
+ const check = await runSupervisorSession({
1718
+ sandboxRootPath,
1719
+ platform: this.support.platform,
1720
+ shell: this.support.shell,
1721
+ command: `${shellEscape(relPython)} -c ${shellEscape("import pydantic")}`,
1722
+ timeoutMs: SUPPORT_PROBE_TIMEOUT_MS
1723
+ });
1724
+ if (check.protocolError !== void 0) {
1725
+ throw new Error(`Sandbox venv pydantic check failed: ${check.protocolError}`);
1726
+ }
1727
+ if (check.exitCode === 0) {
1728
+ return;
1729
+ }
1730
+ const install = await runSupervisorSession({
1731
+ sandboxRootPath,
1732
+ platform: this.support.platform,
1733
+ shell: this.support.shell,
1734
+ command: `${shellEscape(relPip)} install --trusted-host pypi.org --trusted-host files.pythonhosted.org ${shellEscape(VENV_PYDANTIC_PIN)}`,
1735
+ timeoutMs: VENV_PIP_TIMEOUT_MS
1736
+ });
1737
+ if (install.protocolError !== void 0 || install.exitCode !== 0 || install.timedOut) {
1738
+ throw new Error(
1739
+ `Failed to pip install ${VENV_PYDANTIC_PIN} into sandbox ${SANDBOX_VENV_DIR}: ${sessionFailDetail(install)}`
1740
+ );
1741
+ }
1742
+ }
1743
+ resolveInSandboxRoot(sandboxRootPath, userPath) {
1744
+ validateNoPathTraversal2(userPath);
1745
+ const resolved = userPath.startsWith("/") ? resolve2(userPath) : resolve2(sandboxRootPath, userPath);
1746
+ const root = resolve2(sandboxRootPath);
1747
+ if (resolved !== root && !resolved.startsWith(root + sep)) {
1748
+ throw new SandboxFileNotFoundError(userPath);
1749
+ }
1750
+ return resolved;
1751
+ }
1752
+ async runSandboxCommand(params) {
1753
+ const session = await runSupervisorSession({
1754
+ sandboxRootPath: params.sandboxRootPath,
1755
+ platform: this.support.platform,
1756
+ shell: this.support.shell,
1757
+ command: params.command,
1758
+ ...params.stdin === void 0 ? {} : { stdin: params.stdin },
1759
+ timeoutMs: this.defaultExecTimeoutSeconds * 1e3
1760
+ });
1761
+ if (session.protocolError !== void 0) {
1762
+ throw new Error(session.protocolError);
1763
+ }
1764
+ return {
1765
+ exitCode: session.exitCode,
1766
+ stdoutText: session.stdoutText,
1767
+ stderrText: session.stderrText
1768
+ };
1769
+ }
1770
+ async getFileInfo(params) {
1771
+ const result = await this.runSandboxCommand({
1772
+ sandboxRootPath: params.sandboxRootPath,
1773
+ command: this.statCommand(params.relPath)
1774
+ });
1775
+ if (result.exitCode !== 0) {
1776
+ throw new SandboxFileNotFoundError(params.userPath);
1777
+ }
1778
+ return XferFileInfoSchema.parse(JSON.parse(result.stdoutText.trim()));
1779
+ }
1780
+ async createSandbox() {
1781
+ await this.ensureSrt();
1782
+ const sandboxId = await createSandbox(join3(this.sandboxRootPathParent, ulid2().toLowerCase()));
1783
+ this.logger.info("LocalSandboxProvider created sandbox", {
1784
+ sandboxId,
1785
+ shell: this.support.shell,
1786
+ python: this.support.python
1787
+ });
1788
+ await mkdir4(join3(sandboxId, this.getToolResultDumpDir()), { recursive: true, mode: 448 });
1789
+ await mkdir4(join3(sandboxId, this.getFileUploadsDir()), { recursive: true, mode: 448 });
1790
+ await mkdir4(join3(sandboxId, this.getSkillsDir()), { recursive: true, mode: 448 });
1791
+ await this.ensureVenv(sandboxId);
1792
+ return { sandboxId };
1793
+ }
1794
+ async exec(params) {
1795
+ this.ensureSandboxRoot(params.sandboxId);
1796
+ try {
1797
+ await this.ensureSrt();
1798
+ await this.ensureVenv(params.sandboxId);
1799
+ const sandboxRootPath = params.sandboxId;
1800
+ const cwd = params.cwd === void 0 || params.cwd === "" ? sandboxRootPath : this.resolveInSandboxRoot(sandboxRootPath, params.cwd);
1801
+ const timeoutSeconds = params.timeoutSeconds ?? this.defaultExecTimeoutSeconds;
1802
+ const env = params.env === void 0 ? void 0 : absolutizeRelativeExecEnv({ root: sandboxRootPath, env: params.env });
1803
+ const session = await runSupervisorSession({
1804
+ sandboxRootPath,
1805
+ platform: this.support.platform,
1806
+ shell: this.support.shell,
1807
+ command: params.command,
1808
+ cwd,
1809
+ ...env === void 0 ? {} : { env },
1810
+ timeoutMs: timeoutSeconds * 1e3
1811
+ });
1812
+ if (session.protocolError !== void 0) {
1813
+ return { success: false, error: session.protocolError };
1814
+ }
1815
+ const result = session.stdoutText + (session.stderrText ? session.stderrText : "");
1816
+ return {
1817
+ success: true,
1818
+ response: { exitCode: session.exitCode, result }
1819
+ };
1820
+ } catch (error) {
1821
+ if (error instanceof SandboxNotAvailableError) {
1822
+ throw error;
1823
+ }
1824
+ const message = error instanceof Error ? error.message : String(error);
1825
+ return { success: false, error: message };
1826
+ }
1827
+ }
1828
+ getAdditionalInstructions() {
1829
+ return [
1830
+ "SANDBOX RULES:",
1831
+ `- Platform: ${this.support.platform}.`,
1832
+ `- Commands run under the sandbox shell: ${this.support.shell}.`,
1833
+ "- A Python virtualenv lives at .venv. `python` and `pip` on PATH are that environment; packages you `pip install` persist in this sandbox.",
1834
+ "- uploads, skills, and tool-results live in the sandbox working directory.",
1835
+ "- ALL file creation and writes MUST stay within the sandbox working directory.",
1836
+ "- The Agent must NOT write outside the working directory (including host home and /tmp)."
1837
+ ].join("\n");
1838
+ }
1839
+ // Cwd-relative: SRT cwd is the sandbox root. Init mkdir/ln and the agent prompt must not use
1840
+ // host-absolute paths — those contain spaces under macOS Application Support and lose quoting.
1841
+ // uploads, skills, tool-results, git_downloader.py, .git-credentials, .venv
1842
+ // mcp-client/mcp_client.py
1843
+ getToolResultDumpDir() {
1844
+ return "tool-results";
1845
+ }
1846
+ getGitCredentialsPath() {
1847
+ return ".git-credentials";
1848
+ }
1849
+ getFileUploadsDir() {
1850
+ return "uploads";
1851
+ }
1852
+ getSkillsDir() {
1853
+ return "skills";
1854
+ }
1855
+ getGitDownloaderPath() {
1856
+ return "git_downloader.py";
1857
+ }
1858
+ async downloadFile(params) {
1859
+ this.ensureSandboxRoot(params.sandboxId);
1860
+ await this.ensureSrt();
1861
+ await this.ensureVenv(params.sandboxId);
1862
+ const sandboxRootPath = params.sandboxId;
1863
+ const absolutePath = this.resolveInSandboxRoot(sandboxRootPath, params.path);
1864
+ const relPath = toSandboxRelativePath({ sandboxRootPath, absolutePath });
1865
+ const info = await this.getFileInfo({ sandboxRootPath, relPath, userPath: params.path });
1866
+ if (info.isDir) {
1867
+ throw new SandboxPathIsDirectoryError(params.path);
1868
+ }
1869
+ if (info.size > this.fileMaxBytesForDownload) {
1870
+ throw new SandboxFileTooLargeError(params.path, info.size, this.fileMaxBytesForDownload);
1871
+ }
1872
+ const result = await this.runSandboxCommand({
1873
+ sandboxRootPath,
1874
+ command: this.base64EncodeCommand(relPath)
1875
+ });
1876
+ if (result.exitCode !== 0) {
1877
+ throw new SandboxFileNotFoundError(params.path);
1878
+ }
1879
+ const buf = Buffer.from(result.stdoutText.trim(), "base64");
1880
+ if (buf.length > this.fileMaxBytesForDownload) {
1881
+ throw new SandboxFileTooLargeError(params.path, buf.length, this.fileMaxBytesForDownload);
1882
+ }
1883
+ return buf;
1884
+ }
1885
+ /** Payload on stdin so large uploads stay off argv. */
1886
+ async uploadFile(params) {
1887
+ this.ensureSandboxRoot(params.sandboxId);
1888
+ await this.ensureSrt();
1889
+ await this.ensureVenv(params.sandboxId);
1890
+ if (params.content.length > this.fileMaxBytesForDownload) {
1891
+ throw new SandboxFileTooLargeError(params.remotePath, params.content.length, this.fileMaxBytesForDownload);
1892
+ }
1893
+ const sandboxRootPath = params.sandboxId;
1894
+ const absolutePath = this.resolveInSandboxRoot(sandboxRootPath, params.remotePath);
1895
+ const remotePath = toSandboxRelativePath({ sandboxRootPath, absolutePath });
1896
+ const result = await this.runSandboxCommand({
1897
+ sandboxRootPath,
1898
+ command: localSandboxUploadCommand(remotePath),
1899
+ stdin: params.content
1900
+ });
1901
+ if (result.exitCode !== 0) {
1902
+ const detail = [result.stderrText, result.stdoutText].filter((part) => part.length > 0).join(" ");
1903
+ throw new Error(
1904
+ detail.length > 0 ? `upload ${params.remotePath} failed (exit ${String(result.exitCode)}): ${detail}` : `upload ${params.remotePath} failed (exit ${String(result.exitCode)})`
1905
+ );
1906
+ }
1907
+ }
1908
+ createCodeModeTransport() {
1909
+ return new CodeModeUdsTransport({
1910
+ codeModeSocketParentPath: this.codeModeSocketParentPath,
1911
+ clientRemotePath: () => join3("mcp-client", "mcp_client.py")
1912
+ });
1913
+ }
1914
+ /** Reset process-scoped SRT for this provider. */
1915
+ async dispose() {
1916
+ if (this.srtInitialized) {
1917
+ await resetSrt();
1918
+ this.srtInitialized = false;
1919
+ }
1920
+ }
1921
+ };
333
1922
  }
334
1923
  });
335
1924
 
@@ -380,14 +1969,14 @@ function toStoredOAuthPendingAuthorizationData(pending) {
380
1969
  return {
381
1970
  mcp_server_url: pending.mcpServerUrl,
382
1971
  code_verifier: pending.codeVerifier,
383
- redirect_url: pending.redirectUrl
1972
+ return_to: pending.returnTo
384
1973
  };
385
1974
  }
386
1975
  function fromStoredOAuthPendingAuthorizationData(stored) {
387
1976
  return {
388
1977
  mcpServerUrl: stored.mcp_server_url,
389
1978
  codeVerifier: stored.code_verifier,
390
- redirectUrl: stored.redirect_url
1979
+ returnTo: stored.return_to
391
1980
  };
392
1981
  }
393
1982
  var McpServerNameConflictError, PENDING_AUTHORIZATION_TTL_MS;
@@ -740,10 +2329,10 @@ async function assembleTurnRecord(db, args) {
740
2329
  }
741
2330
  const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(
742
2331
  "turn_thread_context as ttc",
743
- (join) => join.on("ttc.session_id", "=", args.session_id).on("ttc.turn_id", "=", args.turn_id).onRef("ttc.thread_id", "=", "tt.thread_id")
2332
+ (join5) => join5.on("ttc.session_id", "=", args.session_id).on("ttc.turn_id", "=", args.turn_id).onRef("ttc.thread_id", "=", "tt.thread_id")
744
2333
  ).leftJoin(
745
2334
  "thread_context_log as l",
746
- (join) => join.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "ttc.append_id")
2335
+ (join5) => join5.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "ttc.append_id")
747
2336
  ).select([
748
2337
  "tt.thread_id",
749
2338
  jsonText(sql2.ref("tt.checkpoint")).as("checkpoint"),
@@ -840,10 +2429,10 @@ async function createTurn(db, input) {
840
2429
  if (prevTurnId != null) {
841
2430
  const prevRows = await trx.selectFrom("turn as t").leftJoin(
842
2431
  "turn_thread as tt",
843
- (join) => join.onRef("tt.session_id", "=", "t.session_id").onRef("tt.turn_id", "=", "t.turn_id")
2432
+ (join5) => join5.onRef("tt.session_id", "=", "t.session_id").onRef("tt.turn_id", "=", "t.turn_id")
844
2433
  ).leftJoin(
845
2434
  db.selectFrom("turn_thread_context").select(["thread_id", "turn_id", sql2`MAX(pos)`.as("max_pos")]).where("session_id", "=", input.session_id).where("turn_id", "=", prevTurnId).groupBy(["thread_id", "turn_id"]).as("tc_agg"),
846
- (join) => join.onRef("tc_agg.thread_id", "=", "tt.thread_id").onRef("tc_agg.turn_id", "=", "tt.turn_id")
2435
+ (join5) => join5.onRef("tc_agg.thread_id", "=", "tt.thread_id").onRef("tc_agg.turn_id", "=", "tt.turn_id")
847
2436
  ).select([
848
2437
  jsonText(sql2.ref("t.checkpoint")).as("turn_checkpoint"),
849
2438
  jsonText(sql2.ref("t.state")).as("turn_state"),
@@ -1212,7 +2801,7 @@ async function listTurnEvents(db, input) {
1212
2801
  const eventOrder = input.order === "desc" ? "desc" : "asc";
1213
2802
  const rows = await db.selectFrom("turn as t").leftJoin(
1214
2803
  (eb) => eb.selectFrom("session_event").select(["session_id", "turn_id", "event_id", jsonText(sql4.ref("event")).as("event")]).where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).orderBy("event_id", eventOrder).limit(limit + 1).offset(offset).as("e"),
1215
- (join) => join.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
2804
+ (join5) => join5.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
1216
2805
  ).select(["t.turn_id", "e.event"]).where("t.session_id", "=", input.session_id).where("t.turn_id", "=", input.turn_id).orderBy("e.event_id", eventOrder).execute();
1217
2806
  if (rows.length === 0) {
1218
2807
  throw new TurnNotFoundError3(input.turn_id);
@@ -1272,7 +2861,7 @@ async function listSessionEvents(db, input) {
1272
2861
  const chainJson = JSON.stringify(chainIds);
1273
2862
  const rows = await db.selectFrom(sql4`json_each(${chainJson})`.as("c")).innerJoin(
1274
2863
  "session_event as e",
1275
- (join) => join.on("e.session_id", "=", input.session_id).on(sql4`e.turn_id = c.value`)
2864
+ (join5) => join5.on("e.session_id", "=", input.session_id).on(sql4`e.turn_id = c.value`)
1276
2865
  ).select([sql4`c.value`.as("turn_id"), jsonText(sql4.ref("e.event")).as("event")]).orderBy(sql4`c.key`, "desc").orderBy("e.event_id", "desc").limit(limit + 1).offset(cursor.offset).execute();
1277
2866
  return paginateSessionEventRows(rows, limit, cursor);
1278
2867
  }
@@ -1958,7 +3547,7 @@ var SqliteMcpServerStore_exports = {};
1958
3547
  __export(SqliteMcpServerStore_exports, {
1959
3548
  SqliteMcpServerStore: () => SqliteMcpServerStore
1960
3549
  });
1961
- import { ulid as ulid3 } from "ulid";
3550
+ import { ulid as ulid5 } from "ulid";
1962
3551
  function recordColumns2(eb) {
1963
3552
  return [
1964
3553
  "id",
@@ -2008,7 +3597,7 @@ var init_SqliteMcpServerStore = __esm({
2008
3597
  const timestamp = nowIso();
2009
3598
  try {
2010
3599
  return await db.insertInto("mcp_server").values({
2011
- id: ulid3(),
3600
+ id: ulid5(),
2012
3601
  tenant_id: input.tenant_id,
2013
3602
  name: input.name,
2014
3603
  manifest: jsonbBind(input.manifest),
@@ -2028,7 +3617,7 @@ var init_SqliteMcpServerStore = __esm({
2028
3617
  const db = transaction ?? this.#db;
2029
3618
  const timestamp = nowIso();
2030
3619
  return await db.insertInto("mcp_server").values({
2031
- id: ulid3(),
3620
+ id: ulid5(),
2032
3621
  tenant_id: input.tenant_id,
2033
3622
  name: input.name,
2034
3623
  manifest: jsonbBind(input.manifest),
@@ -2358,7 +3947,7 @@ var SqliteAgentStore_exports = {};
2358
3947
  __export(SqliteAgentStore_exports, {
2359
3948
  SqliteAgentStore: () => SqliteAgentStore
2360
3949
  });
2361
- import { ulid as ulid4 } from "ulid";
3950
+ import { ulid as ulid6 } from "ulid";
2362
3951
  function recordColumns5(eb) {
2363
3952
  return [
2364
3953
  "id",
@@ -2405,7 +3994,7 @@ var init_SqliteAgentStore = __esm({
2405
3994
  const timestamp = nowIso();
2406
3995
  try {
2407
3996
  const row = await db.insertInto("agent").values({
2408
- id: ulid4().toLowerCase(),
3997
+ id: ulid6().toLowerCase(),
2409
3998
  tenant_id: input.tenant_id,
2410
3999
  name: input.name,
2411
4000
  manifest: jsonbBind(input.manifest),
@@ -2669,9 +4258,9 @@ async function assembleTurnRecord2(db, args) {
2669
4258
  if (!turn) {
2670
4259
  return void 0;
2671
4260
  }
2672
- const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(lateralUnnestBigintArrayWithOrdinality(sql11`tt.context_ids`, "c"), (join) => join.onTrue()).leftJoin(
4261
+ const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(lateralUnnestBigintArrayWithOrdinality(sql11`tt.context_ids`, "c"), (join5) => join5.onTrue()).leftJoin(
2673
4262
  "thread_context_log as l",
2674
- (join) => join.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "c.append_id")
4263
+ (join5) => join5.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "c.append_id")
2675
4264
  ).select(["tt.thread_id", "tt.checkpoint", "tt.agent_info", "tt.current_context_usage", "l.body", "c.pos"]).where("tt.session_id", "=", args.session_id).where("tt.turn_id", "=", args.turn_id).orderBy("tt.thread_id").orderBy("c.pos").execute();
2676
4265
  const capabilityRows = await db.selectFrom("thread_capability_state").select(["thread_id", sql11`jsonb_object_agg(key, state)`.as("capability_state")]).where("session_id", "=", args.session_id).where("turn_id", "=", args.turn_id).groupBy("thread_id").execute();
2677
4266
  const capabilityByThread = /* @__PURE__ */ new Map();
@@ -2754,7 +4343,7 @@ async function createTurn2(db, input) {
2754
4343
  if (prevTurnId != null) {
2755
4344
  const prevRows = await trx.selectFrom("turn as t").leftJoin(
2756
4345
  "turn_thread as tt",
2757
- (join) => join.onRef("tt.session_id", "=", "t.session_id").onRef("tt.turn_id", "=", "t.turn_id")
4346
+ (join5) => join5.onRef("tt.session_id", "=", "t.session_id").onRef("tt.turn_id", "=", "t.turn_id")
2758
4347
  ).select([
2759
4348
  "t.checkpoint as turn_checkpoint",
2760
4349
  "t.state as turn_state",
@@ -3076,7 +4665,7 @@ async function listTurnEvents2(db, input) {
3076
4665
  const eventOrder = input.order === "desc" ? "desc" : "asc";
3077
4666
  const rows = await db.selectFrom("turn as t").leftJoin(
3078
4667
  (eb) => eb.selectFrom("session_event").select(["session_id", "turn_id", "event_id", "event"]).where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).orderBy("event_id", eventOrder).limit(limit + 1).offset(offset).as("e"),
3079
- (join) => join.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
4668
+ (join5) => join5.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
3080
4669
  ).select(["t.turn_id", "e.event"]).where("t.session_id", "=", input.session_id).where("t.turn_id", "=", input.turn_id).orderBy("e.event_id", eventOrder).execute();
3081
4670
  if (rows.length === 0) {
3082
4671
  throw new TurnNotFoundError5(input.turn_id);
@@ -3111,7 +4700,7 @@ async function listSessionEvents2(db, input) {
3111
4700
  const chainIds = await resolveAncestorChain2(db, input.session_id, anchor);
3112
4701
  const rows = await db.selectFrom(unnestWithOrdinality(chainIds, "c")).innerJoin(
3113
4702
  "session_event as e",
3114
- (join) => join.on("e.session_id", "=", input.session_id).onRef("e.turn_id", "=", "c.turn_id")
4703
+ (join5) => join5.on("e.session_id", "=", input.session_id).onRef("e.turn_id", "=", "c.turn_id")
3115
4704
  ).select(["e.turn_id as turn_id", "e.event as event"]).orderBy("c.pos", "desc").orderBy("e.event_id", "desc").limit(limit + 1).offset(cursor.offset).execute();
3116
4705
  return paginateSessionEventRows2(rows, limit, cursor);
3117
4706
  }
@@ -3751,7 +5340,7 @@ var PostgresMcpServerStore_exports = {};
3751
5340
  __export(PostgresMcpServerStore_exports, {
3752
5341
  PostgresMcpServerStore: () => PostgresMcpServerStore
3753
5342
  });
3754
- import { ulid as ulid5 } from "ulid";
5343
+ import { ulid as ulid7 } from "ulid";
3755
5344
  function toRecord3(row) {
3756
5345
  return {
3757
5346
  id: row.id,
@@ -3799,7 +5388,7 @@ var init_PostgresMcpServerStore = __esm({
3799
5388
  const db = transaction ?? this.#db;
3800
5389
  try {
3801
5390
  const row = await db.insertInto("mcp_server").values({
3802
- id: ulid5(),
5391
+ id: ulid7(),
3803
5392
  tenant_id: input.tenant_id,
3804
5393
  name: input.name,
3805
5394
  manifest: json(input.manifest),
@@ -3819,7 +5408,7 @@ var init_PostgresMcpServerStore = __esm({
3819
5408
  async upsertServer(input, transaction) {
3820
5409
  const db = transaction ?? this.#db;
3821
5410
  const row = await db.insertInto("mcp_server").values({
3822
- id: ulid5(),
5411
+ id: ulid7(),
3823
5412
  tenant_id: input.tenant_id,
3824
5413
  name: input.name,
3825
5414
  manifest: json(input.manifest),
@@ -4142,7 +5731,7 @@ var PostgresAgentStore_exports = {};
4142
5731
  __export(PostgresAgentStore_exports, {
4143
5732
  PostgresAgentStore: () => PostgresAgentStore
4144
5733
  });
4145
- import { ulid as ulid6 } from "ulid";
5734
+ import { ulid as ulid8 } from "ulid";
4146
5735
  function toRecord6(row) {
4147
5736
  return {
4148
5737
  id: row.id,
@@ -4185,7 +5774,7 @@ var init_PostgresAgentStore = __esm({
4185
5774
  const db = transaction ?? this.#db;
4186
5775
  try {
4187
5776
  const row = await db.insertInto("agent").values({
4188
- id: ulid6().toLowerCase(),
5777
+ id: ulid8().toLowerCase(),
4189
5778
  tenant_id: input.tenant_id,
4190
5779
  name: input.name,
4191
5780
  manifest: json(input.manifest),
@@ -4218,8 +5807,41 @@ var init_PostgresAgentStore = __esm({
4218
5807
 
4219
5808
  // src/main.ts
4220
5809
  import { extractErrorLogFields as extractErrorLogFields9 } from "@truefoundry/trueforge-core/core";
4221
- import { mkdir } from "fs/promises";
5810
+ import { mkdir as mkdir5 } from "fs/promises";
4222
5811
  import path6 from "path";
5812
+
5813
+ // src/sandbox/localLifecycle.ts
5814
+ import { existsSync } from "fs";
5815
+ import { mkdir, rm } from "fs/promises";
5816
+ var SOCKET_PARENT_MODE = 448;
5817
+ async function prepareCodeModeSocketParent(params) {
5818
+ if (existsSync(params.path)) {
5819
+ params.logger.warn("Removing leftover Code Mode socket parent", { path: params.path });
5820
+ await rm(params.path, { recursive: true, force: true });
5821
+ }
5822
+ await mkdir(params.path, { recursive: true, mode: SOCKET_PARENT_MODE });
5823
+ }
5824
+ async function removeCodeModeSocketParent(socketParentPath) {
5825
+ await rm(socketParentPath, { recursive: true, force: true });
5826
+ }
5827
+ async function ensureLocalSandboxRootParent(sandboxRootPathParent) {
5828
+ await mkdir(sandboxRootPathParent, { recursive: true, mode: SOCKET_PARENT_MODE });
5829
+ }
5830
+
5831
+ // src/sandbox/localRuntime.ts
5832
+ init_config();
5833
+ var cachedSupport;
5834
+ function setCachedLocalSandboxSupport(support) {
5835
+ cachedSupport = support;
5836
+ }
5837
+ function getCachedLocalSandboxSupport() {
5838
+ return cachedSupport;
5839
+ }
5840
+ function isLocalSandboxFallbackEnabled() {
5841
+ return config_default.STANDALONE && cachedSupport?.supported === true;
5842
+ }
5843
+
5844
+ // src/main.ts
4223
5845
  import { serve } from "@hono/node-server";
4224
5846
  import {
4225
5847
  CancellationReason as CancellationReason4,
@@ -4229,7 +5851,7 @@ import { RequestReplyExecutor, RequestReplyRouter } from "@truefoundry/trueforge
4229
5851
 
4230
5852
  // src/app.ts
4231
5853
  import { swaggerUI } from "@hono/swagger-ui";
4232
- import { OpenAPIHono as OpenAPIHono14, z as z24 } from "@hono/zod-openapi";
5854
+ import { OpenAPIHono as OpenAPIHono14, z as z26 } from "@hono/zod-openapi";
4233
5855
  import { extractErrorLogFields as extractErrorLogFields7 } from "@truefoundry/trueforge-core/core";
4234
5856
  import { bodyLimit } from "hono/body-limit";
4235
5857
  import { HTTPException as HTTPException5 } from "hono/http-exception";
@@ -4251,6 +5873,8 @@ var NameSchema = z.string().min(2).max(64).regex(
4251
5873
  /^[a-z](?:[a-z0-9._-]{0,62}[a-z0-9])$/,
4252
5874
  'must be 2\u201364 lowercase chars: start with a letter, end with alphanumeric, optionally separated by ".", "_" or "-"'
4253
5875
  ).openapi("ResourceName");
5876
+ var PAGE_LIMIT = 25;
5877
+ var EVENTS_PAGE_LIMIT = 100;
4254
5878
  function uniqueNames(entries, ctx) {
4255
5879
  const seen = /* @__PURE__ */ new Set();
4256
5880
  for (const entry of entries) {
@@ -4281,9 +5905,9 @@ var CreateAgentRequestSchema = z2.object({
4281
5905
  name: NameSchema,
4282
5906
  manifest: AgentSpecSchema2
4283
5907
  }).strict().openapi("CreateAgentRequest");
4284
- var PutAgentRequestSchema = z2.object({
5908
+ var UpdateAgentRequestSchema = z2.object({
4285
5909
  manifest: AgentSpecSchema2
4286
- }).strict().openapi("PutAgentRequest");
5910
+ }).strict().openapi("UpdateAgentRequest");
4287
5911
  var AgentSchema = z2.object({
4288
5912
  id: z2.string().min(1).describe("Immutable server-generated agent identifier."),
4289
5913
  name: NameSchema,
@@ -4304,15 +5928,26 @@ var RequestErrorResponseSchema = z3.object({
4304
5928
  })
4305
5929
  }).openapi("RequestErrorResponse");
4306
5930
 
5931
+ // src/routes/openapiTags.ts
5932
+ var OPENAPI_DOCUMENT_TAGS = [
5933
+ { name: "Auth" /* AUTH */ },
5934
+ { name: "Capabilities" /* CAPABILITIES */ },
5935
+ { name: "Models" /* MODELS */ },
5936
+ { name: "MCP Servers" /* MCP_SERVERS */ },
5937
+ { name: "Skills" /* SKILLS */ },
5938
+ { name: "Sandboxes" /* SANDBOXES */ },
5939
+ { name: "Agents" /* AGENTS */ },
5940
+ { name: "Agent Sessions" /* AGENT_SESSIONS */ }
5941
+ ];
5942
+
4307
5943
  // src/routes/agentRoutes.ts
4308
- var AGENTS_TAG = "Agents";
4309
5944
  var AgentIdParamsSchema = z4.object({
4310
5945
  agent_id: z4.string().min(1).max(64).describe("Immutable agent identifier.")
4311
5946
  });
4312
5947
  var listAgentsRoute = createRoute({
4313
5948
  method: "get",
4314
5949
  path: "/",
4315
- tags: [AGENTS_TAG],
5950
+ tags: ["Agents" /* AGENTS */],
4316
5951
  summary: "List agents",
4317
5952
  description: "All configured agents for the tenant.",
4318
5953
  "x-fern-sdk-group-name": ["agents"],
@@ -4331,7 +5966,7 @@ var listAgentsRoute = createRoute({
4331
5966
  var createAgentRoute = createRoute({
4332
5967
  method: "post",
4333
5968
  path: "/",
4334
- tags: [AGENTS_TAG],
5969
+ tags: ["Agents" /* AGENTS */],
4335
5970
  summary: "Create an agent",
4336
5971
  description: "Creates an agent and allocates an immutable id. Fails if `name` is already taken. Name cannot be changed later.",
4337
5972
  "x-fern-sdk-group-name": ["agents"],
@@ -4364,7 +5999,7 @@ var createAgentRoute = createRoute({
4364
5999
  var getAgentRoute = createRoute({
4365
6000
  method: "get",
4366
6001
  path: "/{agent_id}",
4367
- tags: [AGENTS_TAG],
6002
+ tags: ["Agents" /* AGENTS */],
4368
6003
  summary: "Get an agent",
4369
6004
  description: "Fetch a configured agent by immutable id.",
4370
6005
  "x-fern-sdk-group-name": ["agents"],
@@ -4386,7 +6021,7 @@ var getAgentRoute = createRoute({
4386
6021
  var deleteAgentRoute = createRoute({
4387
6022
  method: "delete",
4388
6023
  path: "/{agent_id}",
4389
- tags: [AGENTS_TAG],
6024
+ tags: ["Agents" /* AGENTS */],
4390
6025
  summary: "Delete an agent",
4391
6026
  description: "Delete a configured agent by immutable id. Idempotent if already gone.",
4392
6027
  "x-fern-sdk-group-name": ["agents"],
@@ -4408,7 +6043,7 @@ var deleteAgentRoute = createRoute({
4408
6043
  var putAgentRoute = createRoute({
4409
6044
  method: "put",
4410
6045
  path: "/{agent_id}",
4411
- tags: [AGENTS_TAG],
6046
+ tags: ["Agents" /* AGENTS */],
4412
6047
  summary: "Update an agent",
4413
6048
  description: "Replaces the manifest for an existing agent keyed by immutable `agent_id`.",
4414
6049
  "x-fern-sdk-group-name": ["agents"],
@@ -4416,7 +6051,7 @@ var putAgentRoute = createRoute({
4416
6051
  request: {
4417
6052
  params: AgentIdParamsSchema,
4418
6053
  body: {
4419
- content: { "application/json": { schema: PutAgentRequestSchema } },
6054
+ content: { "application/json": { schema: UpdateAgentRequestSchema } },
4420
6055
  required: true
4421
6056
  }
4422
6057
  },
@@ -4447,6 +6082,7 @@ import {
4447
6082
  SkillMounter
4448
6083
  } from "@truefoundry/trueforge-core/core";
4449
6084
  import { HTTPException } from "hono/http-exception";
6085
+ import { join as join4 } from "path";
4450
6086
 
4451
6087
  // src/mcp/auth/mcpDcr.ts
4452
6088
  import {
@@ -4511,19 +6147,6 @@ function isOAuthAccessTokenUsable(expiresAtIso, nowMs) {
4511
6147
  const expiresAtMs = Date.parse(expiresAtIso);
4512
6148
  return !Number.isNaN(expiresAtMs) && expiresAtMs > nowMs;
4513
6149
  }
4514
- function validateRedirectUris({ redirectUris }) {
4515
- for (const redirectUri of redirectUris) {
4516
- let parsed;
4517
- try {
4518
- parsed = new URL(redirectUri);
4519
- } catch (error) {
4520
- throw new McpConnectionError(`Invalid redirect URI: ${redirectUri}. Must be a valid URL.`, 400, { cause: error });
4521
- }
4522
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
4523
- throw new McpConnectionError(`Invalid redirect URI: ${redirectUri}. Must be a valid URL.`, 400);
4524
- }
4525
- }
4526
- }
4527
6150
 
4528
6151
  // src/mcp/auth/mcpDcr.ts
4529
6152
  var MCP_OAUTH_HTTP_TIMEOUT_MS = 15e3;
@@ -4674,7 +6297,7 @@ async function buildMcpAuthorizationUrl(params) {
4674
6297
  userRef: params.userRef,
4675
6298
  mcpServerUrl: params.mcpServerUrl,
4676
6299
  codeVerifier: started.codeVerifier,
4677
- redirectUrl: params.redirectUrl ?? null
6300
+ returnTo: params.returnTo ?? null
4678
6301
  });
4679
6302
  return started.authorizationUrl;
4680
6303
  }
@@ -4717,7 +6340,7 @@ async function resolveMcpAuth(params) {
4717
6340
  userRef: params.userRef,
4718
6341
  mcpServerUrl: params.mcpServerUrl,
4719
6342
  mcpServerName: params.mcpServerName,
4720
- ...params.redirectUrl !== void 0 ? { redirectUrl: params.redirectUrl } : {}
6343
+ ...params.returnTo !== void 0 ? { returnTo: params.returnTo } : {}
4721
6344
  });
4722
6345
  return { authUrl };
4723
6346
  }
@@ -4761,46 +6384,49 @@ async function completeMcpAuthorization(params) {
4761
6384
  });
4762
6385
  }
4763
6386
 
6387
+ // src/runtime/sessionResources.ts
6388
+ init_LocalSandboxProvider();
6389
+
4764
6390
  // src/sandbox/providerUtils.ts
4765
6391
  init_config();
4766
6392
  import { Daytona, DaytonaError } from "@daytona/sdk";
4767
6393
  import { DaytonaSandboxProvider, SANDBOX_IMAGE_URI } from "@truefoundry/trueforge-core/core";
4768
6394
 
4769
6395
  // src/schemas/sandboxProvider.ts
4770
- import { z as z5 } from "@hono/zod-openapi";
4771
- var DaytonaSandboxProviderAuthSchema = z5.object({
4772
- api_key: z5.string().min(1).describe(
6396
+ import { z as z7 } from "@hono/zod-openapi";
6397
+ var DaytonaSandboxProviderAuthSchema = z7.object({
6398
+ api_key: z7.string().min(1).describe(
4773
6399
  "Daytona API key. Responses are redacted; on PUT, a real value sets/rotates and a redacted value keeps the stored key."
4774
6400
  )
4775
6401
  }).strict().describe("Daytona authentication credentials.").openapi("DaytonaSandboxProviderAuth");
4776
- var DaytonaSandboxProviderSchema = z5.object({
4777
- type: z5.literal("daytona").describe("Daytona sandbox provider."),
6402
+ var DaytonaSandboxProviderSchema = z7.object({
6403
+ type: z7.literal("daytona").describe("Daytona sandbox provider."),
4778
6404
  auth: DaytonaSandboxProviderAuthSchema,
4779
- exec_timeout_ms: z5.number().int().positive().describe("Default sandbox command exec timeout in milliseconds."),
4780
- auto_stop_interval_in_minutes: z5.number().int().nonnegative().describe("Minutes of idle time before Daytona auto-stops the sandbox (0 disables)."),
4781
- auto_archive_interval_in_minutes: z5.number().int().nonnegative().describe("Minutes before Daytona auto-archives the sandbox (0 disables)."),
4782
- auto_delete_interval_in_minutes: z5.number().int().nonnegative().describe("Minutes before Daytona auto-deletes the sandbox (0 disables).")
6405
+ exec_timeout_ms: z7.number().int().positive().describe("Default sandbox command exec timeout in milliseconds."),
6406
+ auto_stop_interval_in_minutes: z7.number().int().nonnegative().describe("Minutes of idle time before Daytona auto-stops the sandbox (0 disables)."),
6407
+ auto_archive_interval_in_minutes: z7.number().int().nonnegative().describe("Minutes before Daytona auto-archives the sandbox (0 disables)."),
6408
+ auto_delete_interval_in_minutes: z7.number().int().nonnegative().describe("Minutes before Daytona auto-deletes the sandbox (0 disables).")
4783
6409
  }).strict();
4784
6410
  var SandboxProviderManifestSchema = DaytonaSandboxProviderSchema.openapi("SandboxProviderManifest");
4785
- var SandboxBuildStatusSchema = z5.enum(["pending", "ready", "failed"]).describe("Current build status.").openapi("SandboxBuildStatus");
4786
- var SandboxBuildMetadataSchema = z5.record(z5.string(), z5.string()).describe("Provider-specific build metadata (opaque string map).");
4787
- var SandboxStatusSchema = z5.object({
6411
+ var SandboxBuildStatusSchema = z7.enum(["pending", "ready", "failed"]).describe("Current build status.").openapi("SandboxBuildStatus");
6412
+ var SandboxBuildMetadataSchema = z7.record(z7.string(), z7.string()).describe("Provider-specific build metadata (opaque string map).");
6413
+ var SandboxStatusSchema = z7.object({
4788
6414
  status: SandboxBuildStatusSchema,
4789
- status_reason: z5.string().nullable().describe("Human-readable detail for the current status; null when ready."),
6415
+ status_reason: z7.string().nullable().describe("Human-readable detail for the current status; null when ready."),
4790
6416
  build_metadata: SandboxBuildMetadataSchema.nullable().describe(
4791
6417
  "Provider-specific build metadata; null when the provider has none."
4792
6418
  )
4793
6419
  }).strict();
4794
- var SandboxProviderSchema = z5.object({
6420
+ var ConfiguredSandboxProviderSchema = z7.object({
4795
6421
  manifest: SandboxProviderManifestSchema,
4796
6422
  status: SandboxBuildStatusSchema,
4797
- status_reason: z5.string().nullable().describe("Human-readable detail for the current status; null when ready.")
4798
- }).strict().openapi("SandboxProvider");
4799
- var PutSandboxProviderRequestSchema = z5.object({
6423
+ status_reason: z7.string().nullable().describe("Human-readable detail for the current status; null when ready.")
6424
+ }).strict().openapi("ConfiguredSandboxProvider");
6425
+ var UpdateSandboxProviderRequestSchema = z7.object({
4800
6426
  manifest: SandboxProviderManifestSchema
4801
- }).strict().openapi("PutSandboxProviderRequest");
4802
- var GetSandboxProviderResponseSchema = z5.object({
4803
- data: SandboxProviderSchema
6427
+ }).strict().openapi("UpdateSandboxProviderRequest");
6428
+ var GetSandboxProviderResponseSchema = z7.object({
6429
+ data: ConfiguredSandboxProviderSchema
4804
6430
  }).openapi("GetSandboxProviderResponse");
4805
6431
  function toDaytonaSandboxProviderInput(manifest) {
4806
6432
  return {
@@ -4881,57 +6507,57 @@ async function checkSnapshotStatus({
4881
6507
  }
4882
6508
 
4883
6509
  // src/schemas/mcpServer.ts
4884
- import { z as z6 } from "@hono/zod-openapi";
4885
- var McpServerTypeSchema = z6.enum(["remote"]).openapi("McpServerType");
4886
- var McpServerHeaderAuthSchema = z6.object({
4887
- type: z6.literal("header").describe("Authenticate with static HTTP headers."),
4888
- headers: z6.record(z6.string().min(1), z6.string().min(1)).refine((headers) => Object.keys(headers).length > 0, {
6510
+ import { z as z8 } from "@hono/zod-openapi";
6511
+ var McpServerTypeSchema = z8.enum(["remote"]).openapi("MCPServerType");
6512
+ var McpServerHeaderAuthSchema = z8.object({
6513
+ type: z8.literal("header").describe("Authenticate with static HTTP headers."),
6514
+ headers: z8.record(z8.string().min(1), z8.string().min(1)).refine((headers) => Object.keys(headers).length > 0, {
4889
6515
  message: "must include at least one header"
4890
6516
  }).describe(
4891
6517
  "Request headers for this MCP server. Responses are redacted; on PUT, a real value sets/rotates and a redacted value keeps the stored secret for that header name."
4892
6518
  )
4893
- }).strict().openapi("McpServerHeaderAuth");
4894
- var McpServerDcrAuthSchema = z6.object({
4895
- type: z6.literal("dcr").describe("Authenticate via OAuth Dynamic Client Registration.")
4896
- }).strict().openapi("McpServerDcrAuth");
4897
- var McpServerManifestAuthSchema = z6.discriminatedUnion("type", [McpServerHeaderAuthSchema, McpServerDcrAuthSchema]).describe("Optional auth settings. Omit when the server needs no credentials.").openapi("McpServerManifestAuth");
4898
- var McpServerDescriptionSchema = z6.string().trim().min(1).describe("Concise summary of what this MCP server provides.");
4899
- var McpServerManifestObjectSchema = z6.object({
6519
+ }).strict().openapi("MCPServerHeaderAuth");
6520
+ var McpServerDcrAuthSchema = z8.object({
6521
+ type: z8.literal("dcr").describe("Authenticate via OAuth Dynamic Client Registration.")
6522
+ }).strict().openapi("MCPServerDcrAuth");
6523
+ var McpServerManifestAuthSchema = z8.discriminatedUnion("type", [McpServerHeaderAuthSchema, McpServerDcrAuthSchema]).describe("Optional auth settings. Omit when the server needs no credentials.").openapi("MCPServerManifestAuth");
6524
+ var McpServerDescriptionSchema = z8.string().trim().min(1).describe("Concise summary of what this MCP server provides.");
6525
+ var McpServerManifestObjectSchema = z8.object({
4900
6526
  type: McpServerTypeSchema,
4901
6527
  name: NameSchema,
4902
- url: z6.url().describe("URL of the remote MCP server."),
6528
+ url: z8.url().describe("URL of the remote MCP server."),
4903
6529
  description: McpServerDescriptionSchema,
4904
6530
  auth: McpServerManifestAuthSchema.optional()
4905
6531
  }).strict();
4906
- var McpServerManifestSchema = McpServerManifestObjectSchema.openapi("McpServerManifest");
4907
- var McpAuthStatusSchema = z6.object({
4908
- status: z6.enum(["authenticated", "auth_required", "not_required"]).describe("Current auth state for this MCP server."),
4909
- authorization_url: z6.url().optional().describe("When auth is required, this contains the URL to redirect the user to for authorization.")
4910
- }).strict().describe("Current auth state.").openapi("McpAuthStatus");
4911
- var ConfiguredMcpServerSchema = z6.object({
6532
+ var McpServerManifestSchema = McpServerManifestObjectSchema.openapi("MCPServerManifest");
6533
+ var McpAuthStatusSchema = z8.object({
6534
+ status: z8.enum(["authenticated", "auth_required", "not_required"]).describe("Current auth state for this MCP server."),
6535
+ authorization_url: z8.url().optional().describe("When auth is required, this contains the URL to redirect the user to for authorization.")
6536
+ }).strict().describe("Current auth state.").openapi("MCPAuthStatus");
6537
+ var ConfiguredMcpServerSchema = z8.object({
4912
6538
  name: NameSchema,
4913
6539
  manifest: McpServerManifestSchema,
4914
6540
  auth_status: McpAuthStatusSchema
4915
- }).strict().openapi("ConfiguredMcpServer");
4916
- var CreateMcpServerRequestSchema = z6.object({
6541
+ }).strict().openapi("ConfiguredMCPServer");
6542
+ var CreateMcpServerRequestSchema = z8.object({
4917
6543
  manifest: McpServerManifestSchema
4918
- }).strict().openapi("CreateMcpServerRequest");
4919
- var PutMcpServerRequestSchema = z6.object({
6544
+ }).strict().openapi("CreateMCPServerRequest");
6545
+ var UpdateMcpServerRequestSchema = z8.object({
4920
6546
  manifest: McpServerManifestSchema
4921
- }).strict().openapi("PutMcpServerRequest");
4922
- var GetMcpServerResponseSchema = z6.object({ data: ConfiguredMcpServerSchema }).openapi("GetMcpServerResponse");
4923
- var ListMcpServersResponseSchema = z6.object({ data: z6.array(ConfiguredMcpServerSchema) }).openapi("ListMcpServersResponse");
4924
- var McpServerAuthPublicSchema = z6.discriminatedUnion("type", [
4925
- z6.object({ type: z6.literal("dcr") }).strict(),
4926
- z6.object({ type: z6.literal("header") }).strict()
4927
- ]).describe("Auth mechanism when configured (no secrets). Omit when the server needs no credentials.").openapi("McpServerAuthPublic");
4928
- var McpServerReadEntrySchema = z6.object({
6547
+ }).strict().openapi("UpdateMCPServerRequest");
6548
+ var GetMcpServerResponseSchema = z8.object({ data: ConfiguredMcpServerSchema }).openapi("GetMCPServerResponse");
6549
+ var ListMcpServersResponseSchema = z8.object({ data: z8.array(ConfiguredMcpServerSchema) }).openapi("ListMCPServersResponse");
6550
+ var McpServerAuthPublicSchema = z8.discriminatedUnion("type", [
6551
+ z8.object({ type: z8.literal("dcr") }).strict(),
6552
+ z8.object({ type: z8.literal("header") }).strict()
6553
+ ]).describe("Auth mechanism when configured (no secrets). Omit when the server needs no credentials.").openapi("MCPServerAuthPublic");
6554
+ var AvailableMcpServerSchema = z8.object({
4929
6555
  name: NameSchema,
4930
- url: z6.url().describe("URL of the remote MCP server."),
6556
+ url: z8.url().describe("URL of the remote MCP server."),
4931
6557
  auth: McpServerAuthPublicSchema.optional(),
4932
6558
  auth_status: McpAuthStatusSchema
4933
- }).strict().openapi("McpServerReadEntry");
4934
- var ListAvailableMcpServersResponseSchema = z6.object({ data: z6.array(McpServerReadEntrySchema) }).openapi("ListAvailableMcpServersResponse");
6559
+ }).strict().openapi("AvailableMCPServer");
6560
+ var ListAvailableMcpServersResponseSchema = z8.object({ data: z8.array(AvailableMcpServerSchema) }).openapi("ListAvailableMCPServersResponse");
4935
6561
  function resolveConfiguredMcpRequestHeaders(manifest) {
4936
6562
  if (manifest.auth?.type === "header") {
4937
6563
  return { ...manifest.auth.headers };
@@ -5079,20 +6705,40 @@ async function resolveGitSkills({
5079
6705
  }
5080
6706
  return resolved;
5081
6707
  }
6708
+ function localSandboxSessionSegment(sessionId) {
6709
+ if (sessionId === void 0 || sessionId.length === 0 || sessionId.includes("/") || sessionId.includes("..")) {
6710
+ return "_";
6711
+ }
6712
+ return sessionId;
6713
+ }
5082
6714
  async function resolveSandboxProvider({
5083
6715
  tenant_id,
5084
6716
  store,
5085
- logger
6717
+ logger,
6718
+ sessionId
5086
6719
  }) {
5087
6720
  const record = await store.getSandboxProvider(tenant_id);
5088
- if (record === void 0) {
6721
+ if (record !== void 0) {
6722
+ return toDaytonaSandboxProvider({
6723
+ manifest: record.manifest,
6724
+ tenant_id,
6725
+ logger,
6726
+ build_metadata: record.build_metadata
6727
+ });
6728
+ }
6729
+ if (!config_default.STANDALONE) {
5089
6730
  return void 0;
5090
6731
  }
5091
- return toDaytonaSandboxProvider({
5092
- manifest: record.manifest,
5093
- tenant_id,
5094
- logger,
5095
- build_metadata: record.build_metadata
6732
+ const support = getCachedLocalSandboxSupport();
6733
+ if (support?.supported !== true) {
6734
+ return void 0;
6735
+ }
6736
+ return new LocalSandboxProvider({
6737
+ sandboxRootPathParent: join4(config_default.LOCAL_SANDBOX_ROOT_PARENT, localSandboxSessionSegment(sessionId)),
6738
+ codeModeSocketParentPath: config_default.CODE_MODE_SOCKET_PARENT,
6739
+ support,
6740
+ fileMaxBytesForDownload: config_default.SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD,
6741
+ logger
5096
6742
  });
5097
6743
  }
5098
6744
  function buildTurnSandbox(input) {
@@ -5104,9 +6750,6 @@ function buildTurnSandbox(input) {
5104
6750
  blockDestructiveToolsInCodeMode: true,
5105
6751
  mcpRequestTimeoutMs: config_default.MCP_REQUEST_TIMEOUT_MS,
5106
6752
  mcpConnectTimeoutMs: config_default.MCP_CONNECT_TIMEOUT_MS,
5107
- // Sandbox reads its tenant from TFY_TENANT_NAME for the ownership check
5108
- // against provider-created sandbox ids (`<tenant>.<uuid>`).
5109
- execExtraEnv: { TFY_TENANT_NAME: input.tenantName },
5110
6753
  ...skillMounter ? { skillMounter } : {},
5111
6754
  tracing: input.tracing,
5112
6755
  logger: input.logger
@@ -5175,7 +6818,7 @@ async function validateAgentSpec({
5175
6818
  const hasSkills = requestedSkills.length > 0;
5176
6819
  if (wantsSandbox || hasSkills) {
5177
6820
  const record = await sandboxProviderStore.getSandboxProvider(tenant_id);
5178
- if (record === void 0) {
6821
+ if (record === void 0 && !isLocalSandboxFallbackEnabled()) {
5179
6822
  throw new HTTPException(422, {
5180
6823
  message: hasSkills ? "skills require a sandbox provider \u2014 configure via PUT /settings/sandbox-providers" : "sandbox is enabled but no sandbox provider is configured \u2014 PUT /settings/sandbox-providers"
5181
6824
  });
@@ -5198,14 +6841,14 @@ import {
5198
6841
  redisRequest,
5199
6842
  RequestTimeoutError
5200
6843
  } from "@truefoundry/trueforge-core/request-reply";
5201
- import { ulid as ulid2 } from "ulid";
5202
- import { z as z11 } from "zod";
6844
+ import { ulid as ulid4 } from "ulid";
6845
+ import { z as z13 } from "zod";
5203
6846
 
5204
6847
  // src/routes/sessionRoutes.ts
5205
- import { createRoute as createRoute2, z as z10 } from "@hono/zod-openapi";
6848
+ import { createRoute as createRoute2, z as z12 } from "@hono/zod-openapi";
5206
6849
 
5207
6850
  // src/schemas/events.ts
5208
- import { z as z7 } from "@hono/zod-openapi";
6851
+ import { z as z9 } from "@hono/zod-openapi";
5209
6852
  import {
5210
6853
  EventType,
5211
6854
  SessionEventItemSchema,
@@ -5225,7 +6868,7 @@ import {
5225
6868
  ToolResponseEventSchema,
5226
6869
  ToolResponseRequiredEventSchema
5227
6870
  } from "@truefoundry/trueforge-core/core";
5228
- var TurnStreamingEventSchema = z7.discriminatedUnion("type", [
6871
+ var TurnStreamingEventSchema = z9.discriminatedUnion("type", [
5229
6872
  ModelMessageEventSchema,
5230
6873
  ModelMessageDeltaEventSchema,
5231
6874
  ToolResponseEventSchema,
@@ -5239,105 +6882,94 @@ var TurnStreamingEventSchema = z7.discriminatedUnion("type", [
5239
6882
  TurnCreatedEventSchema,
5240
6883
  TurnDoneEventSchema
5241
6884
  ]).openapi("TurnStreamingEvent");
5242
- var SESSION_EVENTS_LIMIT = 100;
5243
- var ListSessionEventsRequestQuerySchema = z7.object({
5244
- page_token: z7.string().optional().describe(
6885
+ var ListSessionEventsRequestQuerySchema = z9.object({
6886
+ page_token: z9.string().optional().describe(
5245
6887
  "Pagination cursor from `pagination.next_page_token`. It retains the branch anchor turn and returns older events toward the session start."
5246
6888
  ),
5247
- last_turn_id: z7.string().optional().describe(
6889
+ last_turn_id: z9.string().optional().describe(
5248
6890
  "Newest turn in the listing window (initial load only; ignored when `page_token` is set). Lists that turn and its ancestors, newest events first. Omit to use the session last turn."
5249
6891
  ),
5250
- limit: z7.coerce.number().int().min(1).max(SESSION_EVENTS_LIMIT).optional().default(SESSION_EVENTS_LIMIT).describe(
5251
- `Max events per response. Default ${String(SESSION_EVENTS_LIMIT)}, max ${String(SESSION_EVENTS_LIMIT)}.`
5252
- )
6892
+ limit: z9.coerce.number().int().min(1).max(EVENTS_PAGE_LIMIT).optional().default(EVENTS_PAGE_LIMIT).describe(`Page size. Defaults to ${String(EVENTS_PAGE_LIMIT)}, max ${String(EVENTS_PAGE_LIMIT)}.`)
5253
6893
  }).openapi("ListSessionEventsRequestQuery");
5254
- var ListSessionEventsResponseSchema = z7.object({
5255
- data: z7.array(SessionEventItemSchema),
6894
+ var ListSessionEventsResponseSchema = z9.object({
6895
+ data: z9.array(SessionEventItemSchema),
5256
6896
  pagination: TokenPaginationSchema
5257
6897
  }).openapi("ListSessionEventsResponse");
5258
6898
 
5259
6899
  // src/schemas/session.ts
5260
- import { z as z8 } from "@hono/zod-openapi";
6900
+ import { z as z10 } from "@hono/zod-openapi";
5261
6901
  import { AgentSpecSchema as AgentSpecSchema3, SessionSchema, TokenPaginationSchema as TokenPaginationSchema2 } from "@truefoundry/trueforge-core/agent-session";
5262
- var SessionAgentNameRefSchema = z8.object({ name: NameSchema }).strict().openapi("SessionAgentNameRef");
5263
- var SessionAgentSpecBodySchema = z8.object({ spec: AgentSpecSchema3 }).strict().openapi("SessionAgentSpecBody");
5264
- var CreateSessionAgentSchema = z8.union([SessionAgentNameRefSchema, SessionAgentSpecBodySchema]).openapi("CreateSessionAgent");
6902
+ var SessionAgentNameRefSchema = z10.object({ name: NameSchema }).strict().openapi("SessionAgentNameRef");
6903
+ var SessionAgentSpecBodySchema = z10.object({ spec: AgentSpecSchema3 }).strict().openapi("SessionAgentSpecBody");
6904
+ var CreateSessionAgentSchema = z10.union([SessionAgentNameRefSchema, SessionAgentSpecBodySchema]).openapi("CreateSessionAgent");
5265
6905
  function isSessionAgentNameRef(agent) {
5266
6906
  return SessionAgentNameRefSchema.safeParse(agent).success;
5267
6907
  }
5268
- var CreateSessionRequestSchema = z8.object({
6908
+ var CreateSessionRequestSchema = z10.object({
5269
6909
  agent: CreateSessionAgentSchema
5270
6910
  }).strict().openapi("CreateSessionRequest");
5271
- var UpdateSessionRequestSchema = z8.object({
6911
+ var UpdateSessionRequestSchema = z10.object({
5272
6912
  agent: SessionAgentSpecBodySchema.optional()
5273
6913
  }).strict().openapi("UpdateSessionRequest");
5274
- var DEFAULT_SESSIONS_LIMIT = 10;
5275
- var SESSIONS_MAX_LIMIT = 100;
5276
- var IsoTimestampQueryParam = z8.iso.datetime({ offset: true }).openapi({ type: "string", format: "date-time" }).transform((s) => new Date(s));
5277
- var ListSessionsRequestQuerySchema = z8.object({
5278
- limit: z8.coerce.number().int().min(1).max(SESSIONS_MAX_LIMIT).optional().default(DEFAULT_SESSIONS_LIMIT).describe(`Page size. Defaults to ${String(DEFAULT_SESSIONS_LIMIT)}, max ${String(SESSIONS_MAX_LIMIT)}.`),
5279
- order: z8.enum(["asc", "desc"]).optional().default("desc").describe('Sort sessions by `updated_at`. Defaults to "desc".').openapi("ListSessionsOrder"),
5280
- page_token: z8.string().min(1).optional().describe("Opaque keyset cursor from a previous response `next_page_token`."),
6914
+ var IsoTimestampQueryParam = z10.iso.datetime({ offset: true }).openapi({ type: "string", format: "date-time" }).transform((s) => new Date(s));
6915
+ var ListSessionsRequestQuerySchema = z10.object({
6916
+ limit: z10.coerce.number().int().min(1).max(PAGE_LIMIT).optional().default(PAGE_LIMIT).describe(`Page size. Defaults to ${String(PAGE_LIMIT)}, max ${String(PAGE_LIMIT)}.`),
6917
+ order: z10.enum(["asc", "desc"]).optional().default("desc").describe('Sort sessions by `updated_at`. Defaults to "desc".').openapi("ListSessionsOrder"),
6918
+ page_token: z10.string().min(1).optional().describe("Opaque keyset cursor from a previous response `next_page_token`."),
5281
6919
  start_timestamp: IsoTimestampQueryParam.optional().describe(
5282
6920
  "Inclusive lower bound on `created_at` (ISO-8601 / RFC 3339)."
5283
6921
  ),
5284
6922
  end_timestamp: IsoTimestampQueryParam.optional().describe(
5285
6923
  "Inclusive upper bound on `created_at` (ISO-8601 / RFC 3339)."
5286
6924
  ),
5287
- agent_id: z8.string().min(1).optional().describe("When set, only sessions bound to this agent id are returned.")
6925
+ agent_id: z10.string().min(1).optional().describe("When set, only sessions bound to this agent id are returned.")
5288
6926
  }).openapi("ListSessionsRequestQuery");
5289
- var GetSessionResponseSchema = z8.object({
6927
+ var GetSessionResponseSchema = z10.object({
5290
6928
  data: SessionSchema
5291
6929
  }).openapi("GetSessionResponse");
5292
- var ListSessionsResponseSchema = z8.object({
5293
- data: z8.array(SessionSchema),
6930
+ var ListSessionsResponseSchema = z10.object({
6931
+ data: z10.array(SessionSchema),
5294
6932
  pagination: TokenPaginationSchema2
5295
6933
  }).openapi("ListSessionsResponse");
5296
6934
 
5297
6935
  // src/schemas/turn.ts
5298
- import { z as z9 } from "@hono/zod-openapi";
6936
+ import { z as z11 } from "@hono/zod-openapi";
5299
6937
  import { SessionEventSchema, TokenPaginationSchema as TokenPaginationSchema3, TurnSchema } from "@truefoundry/trueforge-core/agent-session";
5300
6938
  import { CreateTurnRequestSchema, TurnSchema as TurnSchema2 } from "@truefoundry/trueforge-core/agent-session";
5301
- var SubscribeTurnQuerySchema = z9.object({
6939
+ var SubscribeTurnQuerySchema = z11.object({
5302
6940
  // Query strings need coerce; map null/'' to undefined first so Number(null)→0
5303
6941
  // cannot silently become a resume cursor (and so OpenAPI does not advertise null).
5304
- after_sequence_number: z9.preprocess(
6942
+ after_sequence_number: z11.preprocess(
5305
6943
  (val) => val === null || val === "" ? void 0 : val,
5306
- z9.coerce.number().int().nonnegative().optional().describe(
6944
+ z11.coerce.number().int().nonnegative().optional().describe(
5307
6945
  "Exclusive resume cursor: replay only events with a sequence number greater than this value. Omit to start from the beginning of the live buffer."
5308
6946
  )
5309
6947
  )
5310
6948
  }).openapi("SubscribeTurnQuery");
5311
- var CancelSessionRequestSchema = z9.object({}).describe("Empty request body. Cancel identifies the session via the path only.").openapi("CancelSessionRequest");
5312
- var CancelSessionResponseSchema = z9.object({}).describe("Empty success body. HTTP 200 means the cancel request was accepted (or nothing was running).").openapi("CancelSessionResponse");
5313
- var DEFAULT_TURNS_LIMIT = 10;
5314
- var TURNS_MAX_LIMIT = 100;
5315
- var ListTurnsRequestQuerySchema = z9.object({
5316
- limit: z9.coerce.number().int().min(1).max(TURNS_MAX_LIMIT).optional().default(DEFAULT_TURNS_LIMIT).describe(`Page size. Defaults to ${String(DEFAULT_TURNS_LIMIT)}, max ${String(TURNS_MAX_LIMIT)}.`),
5317
- page_token: z9.string().optional().describe("Opaque token from a previous response `next_page_token`.")
6949
+ var CancelSessionRequestSchema = z11.object({}).describe("Empty request body. Cancel identifies the session via the path only.").openapi("CancelSessionRequest");
6950
+ var CancelSessionResponseSchema = z11.object({}).describe("Empty success body. HTTP 200 means the cancel request was accepted (or nothing was running).").openapi("CancelSessionResponse");
6951
+ var ListTurnsRequestQuerySchema = z11.object({
6952
+ limit: z11.coerce.number().int().min(1).max(PAGE_LIMIT).optional().default(PAGE_LIMIT).describe(`Page size. Defaults to ${String(PAGE_LIMIT)}, max ${String(PAGE_LIMIT)}.`),
6953
+ page_token: z11.string().optional().describe("Opaque token from a previous response `next_page_token`.")
5318
6954
  }).openapi("ListTurnsRequestQuery");
5319
- var GetTurnResponseSchema = z9.object({
6955
+ var GetTurnResponseSchema = z11.object({
5320
6956
  data: TurnSchema
5321
6957
  }).openapi("GetTurnResponse");
5322
- var ListTurnsResponseSchema = z9.object({
5323
- data: z9.array(TurnSchema),
6958
+ var ListTurnsResponseSchema = z11.object({
6959
+ data: z11.array(TurnSchema),
5324
6960
  pagination: TokenPaginationSchema3
5325
6961
  }).openapi("ListTurnsResponse");
5326
- var DEFAULT_TURN_EVENTS_LIMIT = 25;
5327
- var TURN_EVENTS_MAX_LIMIT = 100;
5328
- var ListTurnEventsRequestQuerySchema = z9.object({
5329
- limit: z9.coerce.number().int().min(1).max(TURN_EVENTS_MAX_LIMIT).optional().default(DEFAULT_TURN_EVENTS_LIMIT).describe(
5330
- `Max events per response. Default ${String(DEFAULT_TURN_EVENTS_LIMIT)}, max ${String(TURN_EVENTS_MAX_LIMIT)}.`
5331
- ),
5332
- page_token: z9.string().optional().describe("Opaque token from a previous response `next_page_token`."),
5333
- order: z9.enum(["asc", "desc"]).optional().default("asc").describe('Sort events by insertion order. Defaults to "asc".').openapi("ListTurnEventsOrder")
6962
+ var ListTurnEventsRequestQuerySchema = z11.object({
6963
+ limit: z11.coerce.number().int().min(1).max(EVENTS_PAGE_LIMIT).optional().default(EVENTS_PAGE_LIMIT).describe(`Page size. Defaults to ${String(EVENTS_PAGE_LIMIT)}, max ${String(EVENTS_PAGE_LIMIT)}.`),
6964
+ page_token: z11.string().optional().describe("Opaque token from a previous response `next_page_token`."),
6965
+ order: z11.enum(["asc", "desc"]).optional().default("asc").describe('Sort events by insertion order. Defaults to "asc".').openapi("ListTurnEventsOrder")
5334
6966
  }).openapi("ListTurnEventsRequestQuery");
5335
- var ListTurnEventsResponseSchema = z9.object({
5336
- data: z9.array(SessionEventSchema),
6967
+ var ListTurnEventsResponseSchema = z11.object({
6968
+ data: z11.array(SessionEventSchema),
5337
6969
  pagination: TokenPaginationSchema3
5338
6970
  }).openapi("ListTurnEventsResponse");
5339
- var DownloadSandboxFileRequestQuerySchema = z9.object({
5340
- path: z9.string().min(1).describe(
6971
+ var DownloadSandboxFileRequestQuerySchema = z11.object({
6972
+ path: z11.string().min(1).describe(
5341
6973
  "Absolute path of the file inside the sandbox, as listed in the assistant's `sandbox_artifacts` block."
5342
6974
  )
5343
6975
  }).openapi("DownloadSandboxFileRequestQuery");
@@ -5350,14 +6982,13 @@ var TOKEN_PAGINATION = {
5350
6982
  };
5351
6983
 
5352
6984
  // src/routes/sessionRoutes.ts
5353
- var SESSIONS_TAG = "Sessions";
5354
- var SessionIdParamsSchema = z10.object({
5355
- session_id: z10.string().min(1).max(64).describe("Session identifier.")
6985
+ var SessionIdParamsSchema = z12.object({
6986
+ session_id: z12.string().min(1).max(64).describe("Session identifier.")
5356
6987
  });
5357
6988
  var createSessionRoute = createRoute2({
5358
6989
  method: "post",
5359
6990
  path: "/",
5360
- tags: [SESSIONS_TAG],
6991
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5361
6992
  summary: "Create a session",
5362
6993
  description: 'Create a session with `agent` as either `{ name }` (named registry binding) or `{ spec: AgentSpec }` (inline). Named sessions snapshot the agent name at create and resolve the live agent on each turn. Responses use `{ type: "reference", name, id }` or `{ type: "inline", spec }`.',
5363
6994
  "x-fern-sdk-group-name": ["sessions"],
@@ -5390,7 +7021,7 @@ var createSessionRoute = createRoute2({
5390
7021
  var getSessionRoute = createRoute2({
5391
7022
  method: "get",
5392
7023
  path: "/{session_id}",
5393
- tags: [SESSIONS_TAG],
7024
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5394
7025
  summary: "Get a session",
5395
7026
  description: "Fetch a session by ID. Only the session creator (`created_by`) may fetch it.",
5396
7027
  "x-fern-sdk-group-name": ["sessions"],
@@ -5416,7 +7047,7 @@ var getSessionRoute = createRoute2({
5416
7047
  var deleteSessionRoute = createRoute2({
5417
7048
  method: "delete",
5418
7049
  path: "/{session_id}",
5419
- tags: [SESSIONS_TAG],
7050
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5420
7051
  summary: "Delete a session",
5421
7052
  description: "Delete a session and all related turns, events, and internal state. Only the session creator (`created_by`) may delete it. Idempotent if already gone.",
5422
7053
  "x-fern-sdk-group-name": ["sessions"],
@@ -5437,7 +7068,7 @@ var deleteSessionRoute = createRoute2({
5437
7068
  var updateSessionRoute = createRoute2({
5438
7069
  method: "patch",
5439
7070
  path: "/{session_id}",
5440
- tags: [SESSIONS_TAG],
7071
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5441
7072
  summary: "Update a session",
5442
7073
  description: "Update a session by replacing `agent` with `{ spec: AgentSpec }`. Named (reference) sessions reject agent updates. An empty body is a valid no-op that refreshes `updated_at`. Only the session creator (`created_by`) may update it.",
5443
7074
  "x-fern-sdk-group-name": ["sessions"],
@@ -5475,7 +7106,7 @@ var updateSessionRoute = createRoute2({
5475
7106
  var listSessionsRoute = createRoute2({
5476
7107
  method: "get",
5477
7108
  path: "/",
5478
- tags: [SESSIONS_TAG],
7109
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5479
7110
  summary: "List sessions",
5480
7111
  description: "List the caller's sessions (newest first by default), token-paginated. Results are scoped to the authenticated identity via the session store's `created_by` filter (not a client query param). Optional `agent_id` filters to sessions bound to that named agent. Pass `page_token` to fetch the next page, keeping the other query params constant.",
5481
7112
  "x-fern-sdk-group-name": ["sessions"],
@@ -5498,7 +7129,7 @@ var listSessionsRoute = createRoute2({
5498
7129
  var cancelSessionRoute = createRoute2({
5499
7130
  method: "post",
5500
7131
  path: "/{session_id}/cancel",
5501
- tags: [SESSIONS_TAG],
7132
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5502
7133
  summary: "Cancel a running turn in a session",
5503
7134
  description: "Cancel the running last turn for a session. Only the session creator (`created_by`) may cancel.",
5504
7135
  "x-fern-sdk-group-name": ["sessions"],
@@ -5532,7 +7163,7 @@ var cancelSessionRoute = createRoute2({
5532
7163
  var listSessionEventsRoute = createRoute2({
5533
7164
  method: "get",
5534
7165
  path: "/{session_id}/events",
5535
- tags: [SESSIONS_TAG],
7166
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
5536
7167
  summary: "List session events",
5537
7168
  description: "List session events as `{ turn_id, event }` across the active turn branch (newest first), including persisted events from a running tip. Each turn contributes turn.created, content events (model.message, tool.call, \u2026), and turn.done when terminal; streaming deltas are not included. Use `page_token` to paginate backward toward older events while retaining the original branch anchor. Only the session creator (`created_by`) may list events.",
5538
7169
  "x-fern-sdk-group-name": ["sessions"],
@@ -5564,9 +7195,9 @@ var listSessionEventsRoute = createRoute2({
5564
7195
 
5565
7196
  // src/runtime/peeringIds.ts
5566
7197
  import { HTTPException as HTTPException2 } from "hono/http-exception";
5567
- import { ulid } from "ulid";
7198
+ import { ulid as ulid3 } from "ulid";
5568
7199
  function mintPeeredTurnId(executorId) {
5569
- return `${ulid().toLowerCase()}.${executorId}`;
7200
+ return `${ulid3().toLowerCase()}.${executorId}`;
5570
7201
  }
5571
7202
  function executorFromTurnId(turnId) {
5572
7203
  const parts = turnId.split(".");
@@ -5579,10 +7210,10 @@ function executorFromTurnId(turnId) {
5579
7210
  // src/apis/sessions.ts
5580
7211
  var TENANT_ID = "default";
5581
7212
  var SESSIONS_CANCEL_PATH = "sessions/cancel";
5582
- var CancelPeerBodySchema = z11.object({
5583
- session_id: z11.string(),
5584
- turn_id: z11.string(),
5585
- reason: z11.enum(CancellationReason)
7213
+ var CancelPeerBodySchema = z13.object({
7214
+ session_id: z13.string(),
7215
+ turn_id: z13.string(),
7216
+ reason: z13.enum(CancellationReason)
5586
7217
  });
5587
7218
  function toWireSession(record) {
5588
7219
  return {
@@ -5683,7 +7314,7 @@ function checkSessionAccess({ userRef, createdBy }) {
5683
7314
  function createSessionsRouter(deps) {
5684
7315
  const createSessionHandler = async (c) => {
5685
7316
  const body = c.req.valid("json");
5686
- const sessionId = ulid2().toLowerCase();
7317
+ const sessionId = ulid4().toLowerCase();
5687
7318
  if (isSessionAgentNameRef(body.agent)) {
5688
7319
  const agent = await deps.agentStore.getAgent({ tenant_id: TENANT_ID, name: body.agent.name });
5689
7320
  if (agent === void 0) {
@@ -5944,13 +7575,13 @@ import { extractErrorLogFields as extractErrorLogFields2 } from "@truefoundry/tr
5944
7575
  // src/auth/cookies.ts
5945
7576
  init_config();
5946
7577
  import { deleteCookie, getCookie, setCookie } from "hono/cookie";
5947
- import { z as z12 } from "zod";
7578
+ import { z as z14 } from "zod";
5948
7579
  var OAUTH_STATE_COOKIE = "oauth_state";
5949
7580
  var ID_TOKEN_COOKIE = "id_token";
5950
- var OAuthStateSchema = z12.object({
5951
- state: z12.string(),
5952
- code_verifier: z12.string(),
5953
- return_to: z12.string()
7581
+ var OAuthStateSchema = z14.object({
7582
+ state: z14.string(),
7583
+ code_verifier: z14.string(),
7584
+ return_to: z14.string()
5954
7585
  });
5955
7586
  function getAuthCookieAttributes() {
5956
7587
  return {
@@ -6044,6 +7675,18 @@ function buildAuthorizationRequestParams(config) {
6044
7675
  };
6045
7676
  }
6046
7677
 
7678
+ // src/auth/safeReturnTo.ts
7679
+ var SAFE_RETURN_TO = /^\/(?!\/|api(?:\/|$)).*/;
7680
+ function isSafeReturnTo(value) {
7681
+ return SAFE_RETURN_TO.test(value);
7682
+ }
7683
+ function safeReturnTo(value) {
7684
+ if (value && isSafeReturnTo(value)) {
7685
+ return value;
7686
+ }
7687
+ return "/";
7688
+ }
7689
+
6047
7690
  // src/auth/oidc.ts
6048
7691
  var CALLBACK_PATH = "/api/v1/auth/callback";
6049
7692
  var OAUTH_STATE_MAX_AGE_SECONDS = 10 * 60;
@@ -6080,13 +7723,6 @@ function authCallbackUrl() {
6080
7723
  const publicBaseUrl = getPublicBaseUrl();
6081
7724
  return `${publicBaseUrl}${CALLBACK_PATH}`;
6082
7725
  }
6083
- var SAFE_RETURN_TO = /^\/(?!\/|api(?:\/|$)).*/;
6084
- function safeReturnTo(value) {
6085
- if (value && SAFE_RETURN_TO.test(value)) {
6086
- return value;
6087
- }
6088
- return "/";
6089
- }
6090
7726
  async function buildLoginAuthorization(params) {
6091
7727
  const oidcConfig = getOidcVerify()?.oidcConfig;
6092
7728
  if (!oidcConfig) {
@@ -6242,36 +7878,36 @@ var adminAuthMiddleware = async (c, next) => {
6242
7878
  import { createRoute as createRoute3 } from "@hono/zod-openapi";
6243
7879
 
6244
7880
  // src/schemas/auth.ts
6245
- import { z as z13 } from "@hono/zod-openapi";
6246
- var AuthLoginQuerySchema = z13.object({
6247
- return_to: z13.string().optional().describe('Path to return to after login. Must be a same-origin relative path; anything else falls back to "/".')
7881
+ import { z as z15 } from "@hono/zod-openapi";
7882
+ var AuthLoginQuerySchema = z15.object({
7883
+ return_to: z15.string().optional().describe('Path to return to after login. Must be a same-origin relative path; anything else falls back to "/".')
6248
7884
  });
6249
- var OAuthCallbackQuerySchema = z13.object({
6250
- code: z13.string().min(1).optional().describe("Authorization code, present when the user granted consent."),
6251
- state: z13.string().min(1).describe("Opaque token; correlates this callback to its pending login. Always present, success or error."),
6252
- error: z13.string().optional().describe("Error code from the identity provider, present instead of `code` if the user denied consent."),
6253
- error_description: z13.string().optional().describe("Human-readable error detail from the identity provider when `error` is set.")
7885
+ var OAuthCallbackQuerySchema = z15.object({
7886
+ code: z15.string().min(1).optional().describe("Authorization code, present when the user granted consent."),
7887
+ state: z15.string().min(1).describe("Opaque token; correlates this callback to its pending login. Always present, success or error."),
7888
+ error: z15.string().optional().describe("Error code from the identity provider, present instead of `code` if the user denied consent."),
7889
+ error_description: z15.string().optional().describe("Human-readable error detail from the identity provider when `error` is set.")
6254
7890
  });
6255
- var OAuthCallbackSuccessSchema = z13.object({
6256
- success: z13.literal(true).describe("Present when the OAuth callback completed without a redirect_url.")
7891
+ var OAuthCallbackSuccessSchema = z15.object({
7892
+ success: z15.literal(true).describe("Present when the OAuth callback completed without a return_to.")
6257
7893
  });
6258
- var MeResponseSchema = z13.object({
6259
- type: z13.enum(["default", "oidc-connected"]).describe(
7894
+ var GetMeResponseSchema = z15.object({
7895
+ type: z15.enum(["default", "oidc-connected"]).describe(
6260
7896
  "Session kind: `default` when no valid OIDC session; `oidc-connected` after a successful browser login."
6261
7897
  ),
6262
- email: z13.string().describe('User email from the ID token when connected; `"default"` when anonymous.'),
6263
- role: z13.string().describe("Caller role.")
6264
- }).openapi("MeResponse");
7898
+ email: z15.string().describe('User email from the ID token when connected; `"default"` when anonymous.'),
7899
+ role: z15.string().describe("Caller role.")
7900
+ }).openapi("GetMeResponse");
6265
7901
 
6266
7902
  // src/routes/authRoutes.ts
6267
- var AUTH_TAG = "Auth";
6268
7903
  var authLoginRoute = createRoute3({
6269
7904
  method: "get",
6270
7905
  path: "/login",
6271
- tags: [AUTH_TAG],
7906
+ tags: ["Auth" /* AUTH */],
6272
7907
  summary: "Start the login flow",
6273
7908
  description: "Redirects the browser to the configured identity provider. In local/single-binary mode, redirects straight back into the app \u2014 there is nothing to log into.",
6274
7909
  "x-fern-ignore": true,
7910
+ "x-excluded": true,
6275
7911
  request: { query: AuthLoginQuerySchema },
6276
7912
  responses: {
6277
7913
  302: { description: "Redirect to the IdP authorization endpoint." }
@@ -6280,10 +7916,11 @@ var authLoginRoute = createRoute3({
6280
7916
  var oAuthCallbackRoute = createRoute3({
6281
7917
  method: "get",
6282
7918
  path: "/callback",
6283
- tags: [AUTH_TAG],
7919
+ tags: ["Auth" /* AUTH */],
6284
7920
  summary: "Login callback",
6285
7921
  description: "Browser-redirect target hit by the identity provider after login, never called directly by SDK consumers. In local/single-binary mode, redirects straight back into the app.",
6286
7922
  "x-fern-ignore": true,
7923
+ "x-excluded": true,
6287
7924
  request: { query: OAuthCallbackQuerySchema },
6288
7925
  responses: {
6289
7926
  302: { description: "Redirect back into the app on success, or to /?error=<reason> on failure." }
@@ -6292,11 +7929,11 @@ var oAuthCallbackRoute = createRoute3({
6292
7929
  var authLogoutRoute = createRoute3({
6293
7930
  method: "post",
6294
7931
  path: "/logout",
6295
- tags: [AUTH_TAG],
7932
+ tags: ["Auth" /* AUTH */],
6296
7933
  summary: "Clear the local session",
6297
7934
  description: "Ends the local harness session only \u2014 does not hit the IdP end-session endpoint. A no-op in local/single-binary mode, since there is no real session to clear.",
6298
- "x-fern-sdk-group-name": ["auth"],
6299
- "x-fern-sdk-method-name": "logout",
7935
+ "x-fern-ignore": true,
7936
+ "x-excluded": true,
6300
7937
  responses: {
6301
7938
  204: { description: "Session cookie cleared." }
6302
7939
  }
@@ -6304,14 +7941,14 @@ var authLogoutRoute = createRoute3({
6304
7941
  var meRoute = createRoute3({
6305
7942
  method: "get",
6306
7943
  path: "/me",
6307
- tags: [AUTH_TAG],
7944
+ tags: ["Auth" /* AUTH */],
6308
7945
  summary: "Current session",
6309
7946
  description: "Returns the authenticated caller identity. When auth is enabled this requires a valid `id_token` cookie or `Authorization: Bearer` ID token (401 otherwise). When auth is disabled, returns the default identity.",
6310
7947
  "x-fern-sdk-group-name": ["auth"],
6311
7948
  "x-fern-sdk-method-name": "me",
6312
7949
  responses: {
6313
7950
  200: {
6314
- content: { "application/json": { schema: MeResponseSchema } },
7951
+ content: { "application/json": { schema: GetMeResponseSchema } },
6315
7952
  description: "Session type and identity for the current request."
6316
7953
  },
6317
7954
  401: {
@@ -6351,6 +7988,9 @@ function createAuthRouter(params) {
6351
7988
  const pending = readOAuthStateCookie({ context: c, logger: params.logger });
6352
7989
  clearAuthCookie({ context: c, name: OAUTH_STATE_COOKIE });
6353
7990
  if (pending?.state !== query.state || query.error || !query.code) {
7991
+ if (await resolveAuthUser(c)) {
7992
+ return c.redirect("/", 302);
7993
+ }
6354
7994
  const description = query.error_description?.trim();
6355
7995
  const reason = query.error && description ? description : "login_failed";
6356
7996
  return c.redirect(oauthErrorRedirect(reason), 302);
@@ -6366,6 +8006,9 @@ function createAuthRouter(params) {
6366
8006
  return c.redirect(safeReturnTo(pending.return_to), 302);
6367
8007
  } catch (error) {
6368
8008
  params.logger.error("Failed to exchange authorization code", extractErrorLogFields2(error));
8009
+ if (await resolveAuthUser(c)) {
8010
+ return c.redirect(safeReturnTo(pending.return_to), 302);
8011
+ }
6369
8012
  const reason = error instanceof Error ? error.message : "login_failed";
6370
8013
  return c.redirect(oauthErrorRedirect(reason), 302);
6371
8014
  }
@@ -6390,25 +8033,29 @@ import { OpenAPIHono as OpenAPIHono4 } from "@hono/zod-openapi";
6390
8033
  import { extractErrorLogFields as extractErrorLogFields3 } from "@truefoundry/trueforge-core/core";
6391
8034
 
6392
8035
  // src/routes/capabilityRoutes.ts
6393
- import { createRoute as createRoute4, z as z14 } from "@hono/zod-openapi";
6394
- var GetCapabilitiesResponseSchema = z14.object({
6395
- data: z14.object({
6396
- sandbox: z14.object({
6397
- enabled: z14.boolean().describe("Whether a sandbox provider is configured for this tenant.")
6398
- }),
6399
- skill: z14.object({
6400
- enabled: z14.boolean().describe("Whether skills are available. False when sandbox is not enabled (skills require a sandbox)."),
6401
- reason: z14.string().optional().describe("Present when skills are disabled. Explains why.")
6402
- }),
6403
- settings: z14.object({
6404
- enabled: z14.boolean().describe("Whether the settings UI/API is enabled.")
6405
- })
6406
- })
8036
+ import { createRoute as createRoute4, z as z16 } from "@hono/zod-openapi";
8037
+ var SandboxCapabilitySchema = z16.object({
8038
+ enabled: z16.boolean().describe("Whether a sandbox provider is configured for this tenant.")
8039
+ }).openapi("SandboxCapability");
8040
+ var SkillCapabilitySchema = z16.object({
8041
+ enabled: z16.boolean().describe("Whether skills are available. False when sandbox is not enabled (skills require a sandbox)."),
8042
+ reason: z16.string().optional().describe("Present when skills are disabled. Explains why.")
8043
+ }).openapi("SkillCapability");
8044
+ var SettingsCapabilitySchema = z16.object({
8045
+ enabled: z16.boolean().describe("Whether the settings UI/API is enabled.")
8046
+ }).openapi("SettingsCapability");
8047
+ var CapabilitiesDataSchema = z16.object({
8048
+ sandbox: SandboxCapabilitySchema,
8049
+ skill: SkillCapabilitySchema,
8050
+ settings: SettingsCapabilitySchema
8051
+ }).openapi("CapabilitiesData");
8052
+ var GetCapabilitiesResponseSchema = z16.object({
8053
+ data: CapabilitiesDataSchema
6407
8054
  }).openapi("GetCapabilitiesResponse");
6408
8055
  var getCapabilitiesRoute = createRoute4({
6409
8056
  method: "get",
6410
8057
  path: "/",
6411
- tags: ["Capabilities"],
8058
+ tags: ["Capabilities" /* CAPABILITIES */],
6412
8059
  summary: "Get server capabilities",
6413
8060
  "x-fern-sdk-group-name": ["server"],
6414
8061
  "x-fern-sdk-method-name": "get_capabilities",
@@ -6446,7 +8093,7 @@ function createCapabilitiesRouter(deps) {
6446
8093
  } catch (error) {
6447
8094
  deps.logger.warn("Sandbox image status check failed; reporting sandbox disabled", extractErrorLogFields3(error));
6448
8095
  }
6449
- const sandboxEnabled = status === "ready";
8096
+ const sandboxEnabled = status === "ready" || status === void 0 && isLocalSandboxFallbackEnabled();
6450
8097
  const settingsEnabled = isAdmin(resolveUserContext(c));
6451
8098
  return c.json(
6452
8099
  {
@@ -6470,42 +8117,42 @@ import { SUPPORTED_REASONING_EFFORTS as SUPPORTED_REASONING_EFFORTS2 } from "@tr
6470
8117
  import { createRoute as createRoute5 } from "@hono/zod-openapi";
6471
8118
 
6472
8119
  // src/schemas/mcpCatalog.ts
6473
- import { z as z15 } from "@hono/zod-openapi";
6474
- var CatalogMcpServerSchema = z15.object({
8120
+ import { z as z17 } from "@hono/zod-openapi";
8121
+ var CatalogMcpServerSchema = z17.object({
6475
8122
  type: McpServerTypeSchema,
6476
8123
  name: NameSchema,
6477
- logo: z15.url().optional().describe("URL of the MCP server logo asset."),
6478
- url: z15.url().describe("URL of the remote MCP server."),
8124
+ logo: z17.url().optional().describe("URL of the MCP server logo asset."),
8125
+ url: z17.url().describe("URL of the remote MCP server."),
6479
8126
  description: McpServerDescriptionSchema,
6480
8127
  auth: McpServerManifestAuthSchema.optional()
6481
- }).strict().openapi("CatalogMcpServer");
6482
- var McpCatalogFileSchema = z15.object({
6483
- mcp_servers: z15.array(CatalogMcpServerSchema)
8128
+ }).strict().openapi("CatalogMCPServer");
8129
+ var McpCatalogFileSchema = z17.object({
8130
+ mcp_servers: z17.array(CatalogMcpServerSchema)
6484
8131
  }).strict().superRefine((file, ctx) => {
6485
8132
  uniqueNames(file.mcp_servers, ctx);
6486
8133
  });
6487
- var GetMcpServerCatalogResponseSchema = z15.object({
6488
- data: z15.array(CatalogMcpServerSchema)
6489
- }).openapi("GetMcpServerCatalogResponse");
8134
+ var GetMcpServerCatalogResponseSchema = z17.object({
8135
+ data: z17.array(CatalogMcpServerSchema)
8136
+ }).openapi("GetMCPServerCatalogResponse");
6490
8137
 
6491
8138
  // src/schemas/modelCatalog.ts
6492
- import { z as z17 } from "@hono/zod-openapi";
8139
+ import { z as z19 } from "@hono/zod-openapi";
6493
8140
 
6494
8141
  // src/schemas/modelProvider.ts
6495
- import { z as z16 } from "@hono/zod-openapi";
8142
+ import { z as z18 } from "@hono/zod-openapi";
6496
8143
  import { SUPPORTED_REASONING_EFFORTS, VERCEL_AI_PROVIDER_NAMES } from "@truefoundry/trueforge-core/core";
6497
- var ModelProviderTypeSchema = z16.enum(VERCEL_AI_PROVIDER_NAMES).openapi("ModelProviderType");
6498
- var ReasoningEffortSchema = z16.enum(SUPPORTED_REASONING_EFFORTS).openapi("ReasoningEffort");
6499
- var ModelPropertiesSchema = z16.object({
6500
- context_length: z16.number().int().positive().optional().describe("Maximum context window size in tokens."),
6501
- max_output_tokens: z16.number().int().positive().optional().describe("Maximum output tokens the model can generate."),
6502
- reasoning_efforts: z16.array(ReasoningEffortSchema).min(1).optional().describe("Supported reasoning-effort values for this model.")
8144
+ var ModelProviderTypeSchema = z18.enum(VERCEL_AI_PROVIDER_NAMES).openapi("ModelProviderType");
8145
+ var ReasoningEffortSchema = z18.enum(SUPPORTED_REASONING_EFFORTS).openapi("ReasoningEffort");
8146
+ var ModelPropertiesSchema = z18.object({
8147
+ context_length: z18.number().int().positive().optional().describe("Maximum context window size in tokens."),
8148
+ max_output_tokens: z18.number().int().positive().optional().describe("Maximum output tokens the model can generate."),
8149
+ reasoning_efforts: z18.array(ReasoningEffortSchema).min(1).optional().describe("Supported reasoning-effort values for this model.")
6503
8150
  }).strict().describe("Optional model capability metadata.").openapi("ModelProperties");
6504
- var ModelEntrySchema = z16.object({
6505
- model_id: z16.string().min(1).describe("Upstream, provider-specific identifier sent to the provider API."),
8151
+ var ConfiguredModelSchema = z18.object({
8152
+ model_id: z18.string().min(1).describe("Upstream, provider-specific identifier sent to the provider API."),
6506
8153
  name: NameSchema,
6507
8154
  properties: ModelPropertiesSchema
6508
- }).strict().openapi("ModelEntry");
8155
+ }).strict().openapi("ConfiguredModel");
6509
8156
  function refineUniqueModels(models, ctx) {
6510
8157
  uniqueNames(models, ctx);
6511
8158
  const seenModelIds = /* @__PURE__ */ new Set();
@@ -6520,22 +8167,22 @@ function refineUniqueModels(models, ctx) {
6520
8167
  seenModelIds.add(model.model_id);
6521
8168
  }
6522
8169
  }
6523
- var ModelProviderAuthSchema = z16.object({
6524
- api_key: z16.string().min(1).describe(
8170
+ var ModelProviderAuthSchema = z18.object({
8171
+ api_key: z18.string().min(1).describe(
6525
8172
  "Provider API key. Responses are redacted; on PUT, a real value sets/rotates and a redacted value keeps the stored key."
6526
8173
  )
6527
8174
  }).strict().describe("Provider authentication credentials.").openapi("ModelProviderAuth");
6528
- var ModelProviderManifestBaseSchema = z16.object({
8175
+ var ModelProviderManifestBaseSchema = z18.object({
6529
8176
  auth: ModelProviderAuthSchema,
6530
- models: z16.array(ModelEntrySchema).min(1).describe("Models exposed by this provider (at least one).")
8177
+ models: z18.array(ConfiguredModelSchema).min(1).describe("Models exposed by this provider (at least one).")
6531
8178
  }).strict();
6532
8179
  function wellKnownProviderSchema({
6533
8180
  type,
6534
8181
  base_url
6535
8182
  }) {
6536
8183
  return ModelProviderManifestBaseSchema.extend({
6537
- type: z16.literal(type),
6538
- base_url: z16.url().default(base_url).describe("Override of the provider's default API base URL.")
8184
+ type: z18.literal(type),
8185
+ base_url: z18.url().default(base_url).describe("Override of the provider's default API base URL.")
6539
8186
  }).strict();
6540
8187
  }
6541
8188
  var OpenAiModelProviderSchema = wellKnownProviderSchema({
@@ -6571,15 +8218,15 @@ var AlibabaModelProviderSchema = wellKnownProviderSchema({
6571
8218
  base_url: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
6572
8219
  }).openapi("AlibabaModelProvider");
6573
8220
  var CustomModelProviderSchema = ModelProviderManifestBaseSchema.extend({
6574
- type: z16.literal("custom"),
8221
+ type: z18.literal("custom"),
6575
8222
  name: NameSchema,
6576
- base_url: z16.url().describe("Base URL of the provider's API."),
8223
+ base_url: z18.url().describe("Base URL of the provider's API."),
6577
8224
  auth: ModelProviderAuthSchema.optional()
6578
8225
  }).strict().openapi("CustomModelProvider");
6579
8226
  function refineModelProviderManifest(manifest, ctx) {
6580
8227
  refineUniqueModels(manifest.models, ctx);
6581
8228
  }
6582
- var ModelProviderBodySchema = z16.discriminatedUnion("type", [
8229
+ var ModelProviderBodySchema = z18.discriminatedUnion("type", [
6583
8230
  OpenAiModelProviderSchema,
6584
8231
  AnthropicModelProviderSchema,
6585
8232
  GoogleGeminiModelProviderSchema,
@@ -6594,87 +8241,87 @@ var ModelProviderManifestSchema = ModelProviderBodySchema.openapi("ModelProvider
6594
8241
  function modelProviderName(provider) {
6595
8242
  return provider.type === "custom" ? provider.name : provider.type;
6596
8243
  }
6597
- var ModelProviderSchema = z16.object({
8244
+ var ConfiguredModelProviderSchema = z18.object({
6598
8245
  name: NameSchema,
6599
8246
  manifest: ModelProviderManifestSchema
6600
- }).strict().openapi("ModelProvider");
6601
- var CreateModelProviderRequestSchema = z16.object({
8247
+ }).strict().openapi("ConfiguredModelProvider");
8248
+ var CreateModelProviderRequestSchema = z18.object({
6602
8249
  manifest: ModelProviderManifestSchema
6603
8250
  }).strict().openapi("CreateModelProviderRequest");
6604
- var PutModelProviderRequestSchema = z16.object({
8251
+ var UpdateModelProviderRequestSchema = z18.object({
6605
8252
  manifest: ModelProviderManifestSchema
6606
- }).strict().openapi("PutModelProviderRequest");
6607
- var GetModelProviderResponseSchema = z16.object({
6608
- data: ModelProviderSchema
8253
+ }).strict().openapi("UpdateModelProviderRequest");
8254
+ var GetModelProviderResponseSchema = z18.object({
8255
+ data: ConfiguredModelProviderSchema
6609
8256
  }).openapi("GetModelProviderResponse");
6610
- var ListModelProvidersResponseSchema = z16.object({
6611
- data: z16.array(ModelProviderSchema)
8257
+ var ListModelProvidersResponseSchema = z18.object({
8258
+ data: z18.array(ConfiguredModelProviderSchema)
6612
8259
  }).openapi("ListModelProvidersResponse");
6613
- var ModelListProviderSchema = z16.object({
6614
- name: z16.string().min(1).describe("Configured provider resource name; matches the FQN prefix of `name`.")
6615
- }).strict().describe("Owning configured provider.").openapi("ModelListProvider");
6616
- var ModelSchema = z16.object({
6617
- name: z16.string().describe('Fully qualified name `provider_name/model_name`, e.g. "openai/gpt-5-6-sol". Unique within a tenant.'),
6618
- model_id: z16.string().describe("Upstream, provider-specific identifier sent to the provider API."),
6619
- provider: ModelListProviderSchema,
8260
+ var AvailableModelProviderSchema = z18.object({
8261
+ name: z18.string().min(1).describe("Configured provider resource name; matches the FQN prefix of `name`.")
8262
+ }).strict().describe("Owning configured provider.").openapi("AvailableModelProvider");
8263
+ var AvailableModelSchema = z18.object({
8264
+ name: z18.string().describe('Fully qualified name `provider_name/model_name`, e.g. "openai/gpt-5-6-sol". Unique within a tenant.'),
8265
+ model_id: z18.string().describe("Upstream, provider-specific identifier sent to the provider API."),
8266
+ provider: AvailableModelProviderSchema,
6620
8267
  properties: ModelPropertiesSchema
6621
- }).strict().openapi("Model");
6622
- var ListModelsResponseSchema = z16.object({
6623
- data: z16.array(ModelSchema)
6624
- }).openapi("ListModelsResponse");
8268
+ }).strict().openapi("AvailableModel");
8269
+ var ListAvailableModelsResponseSchema = z18.object({
8270
+ data: z18.array(AvailableModelSchema)
8271
+ }).openapi("ListAvailableModelsResponse");
6625
8272
 
6626
8273
  // src/schemas/modelCatalog.ts
6627
8274
  var CatalogWellKnownModelProviderTypeSchema = ModelProviderTypeSchema.exclude(["custom"]).openapi(
6628
8275
  "CatalogWellKnownModelProviderType"
6629
8276
  );
6630
- var CatalogWellKnownModelProviderSchema = z17.object({
8277
+ var CatalogModelSchema = ConfiguredModelSchema.openapi("CatalogModel");
8278
+ var CatalogWellKnownModelProviderSchema = z19.object({
6631
8279
  type: CatalogWellKnownModelProviderTypeSchema,
6632
- logo: z17.url().optional().describe("URL of the provider logo asset"),
6633
- models: z17.array(ModelEntrySchema).describe("Preset models")
8280
+ logo: z19.url().optional().describe("URL of the provider logo asset"),
8281
+ models: z19.array(CatalogModelSchema).describe("Preset models")
6634
8282
  }).strict().openapi("CatalogWellKnownModelProvider");
6635
- var CatalogCustomModelProviderSchema = z17.object({
6636
- type: z17.literal("custom"),
6637
- supported_reasoning_efforts: z17.array(ReasoningEffortSchema).describe("Supported reasoning-effort values for this provider")
8283
+ var CatalogCustomModelProviderSchema = z19.object({
8284
+ type: z19.literal("custom"),
8285
+ supported_reasoning_efforts: z19.array(ReasoningEffortSchema).describe("Supported reasoning-effort values for this provider")
6638
8286
  }).strict().openapi("CatalogCustomModelProvider");
6639
- var CatalogModelProviderSchema = z17.union([CatalogWellKnownModelProviderSchema, CatalogCustomModelProviderSchema]).openapi("CatalogModelProvider");
6640
- var ModelCatalogFileSchema = z17.object({
6641
- providers: z17.array(CatalogWellKnownModelProviderSchema)
8287
+ var CatalogModelProviderSchema = z19.union([CatalogWellKnownModelProviderSchema, CatalogCustomModelProviderSchema]).openapi("CatalogModelProvider");
8288
+ var ModelCatalogFileSchema = z19.object({
8289
+ providers: z19.array(CatalogWellKnownModelProviderSchema)
6642
8290
  }).strict().superRefine((file, ctx) => {
6643
8291
  uniqueTypes(file.providers, ctx);
6644
8292
  for (const provider of file.providers) {
6645
8293
  refineUniqueModels(provider.models, ctx);
6646
8294
  }
6647
8295
  });
6648
- var GetModelProviderCatalogResponseSchema = z17.object({
6649
- data: z17.array(CatalogModelProviderSchema)
8296
+ var GetModelProviderCatalogResponseSchema = z19.object({
8297
+ data: z19.array(CatalogModelProviderSchema)
6650
8298
  }).openapi("GetModelProviderCatalogResponse");
6651
8299
 
6652
8300
  // src/schemas/sandboxCatalog.ts
6653
- import { z as z18 } from "@hono/zod-openapi";
6654
- var CatalogDaytonaSandboxProviderSchema = DaytonaSandboxProviderSchema.omit({ auth: true }).strict().openapi("CatalogDaytonaSandboxProvider");
6655
- var CatalogSandboxProviderSchema = CatalogDaytonaSandboxProviderSchema;
6656
- var SandboxCatalogFileSchema = z18.object({
6657
- providers: z18.array(CatalogSandboxProviderSchema)
8301
+ import { z as z20 } from "@hono/zod-openapi";
8302
+ var CatalogSandboxProviderSchema = DaytonaSandboxProviderSchema.omit({ auth: true }).strict().openapi("CatalogSandboxProvider");
8303
+ var SandboxCatalogFileSchema = z20.object({
8304
+ providers: z20.array(CatalogSandboxProviderSchema)
6658
8305
  }).strict();
6659
- var GetSandboxProviderCatalogResponseSchema = z18.object({
6660
- data: z18.array(CatalogSandboxProviderSchema)
8306
+ var GetSandboxProviderCatalogResponseSchema = z20.object({
8307
+ data: z20.array(CatalogSandboxProviderSchema)
6661
8308
  }).openapi("GetSandboxProviderCatalogResponse");
6662
8309
 
6663
8310
  // src/schemas/skillCatalog.ts
6664
- import { z as z20 } from "@hono/zod-openapi";
8311
+ import { z as z22 } from "@hono/zod-openapi";
6665
8312
 
6666
8313
  // src/schemas/skill.ts
6667
- import { z as z19 } from "@hono/zod-openapi";
6668
- var SkillTypeSchema = z19.enum(["git"]).openapi("SkillType");
8314
+ import { z as z21 } from "@hono/zod-openapi";
8315
+ var SkillTypeSchema = z21.enum(["git"]).openapi("SkillType");
6669
8316
  var GIT_URL_REGEX = /^https:\/\/(github\.com\/[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+|gitlab\.com\/[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)+)(\/|\.git)?$/;
6670
8317
  var GIT_REF_REGEX = /^[A-Za-z0-9._\-/]+$/;
6671
8318
  var SKILL_PATH_REGEX = /^[A-Za-z0-9._\-/]+$/;
6672
8319
  var hasParentTraversal = (value) => value.split("/").includes("..");
6673
- var SkillGitUrlSchema = z19.string().trim().min(1).regex(GIT_URL_REGEX, "Must be a GitHub or GitLab HTTPS URL").refine((v) => !hasParentTraversal(v), 'URL must not contain ".." segments').describe("Full HTTPS URL of a GitHub or GitLab repository.");
6674
- var SkillGitPathSchema = z19.string().trim().min(1).regex(SKILL_PATH_REGEX, 'Path may only contain letters, numbers, ".", "_", "-", and "/"').refine((v) => !hasParentTraversal(v), 'Path must not contain ".." segments').refine((v) => !v.split("/").includes("."), 'Path must not contain "." segments').refine((v) => v.replace(/^\/+|\/+$/g, "").length > 0, "Path must reference a subdirectory, not only slashes").describe("Path to the skill directory within the repository. Omit to use the repository root.");
6675
- var SkillGitRefSchema = z19.string().trim().min(1).regex(GIT_REF_REGEX, 'Ref may only contain letters, numbers, ".", "_", "-", and "/"').refine((v) => !hasParentTraversal(v), 'Ref must not contain ".." segments').refine((v) => v.replace(/^\/+|\/+$/g, "").length > 0, "Ref must not consist only of slashes").describe("Git ref \u2014 branch name, tag, or commit SHA.");
6676
- var SkillDescriptionSchema = z19.string().trim().min(1).describe("Concise guidance for when the agent should use the skill.");
6677
- var SkillManifestObjectSchema = z19.object({
8320
+ var SkillGitUrlSchema = z21.string().trim().min(1).regex(GIT_URL_REGEX, "Must be a GitHub or GitLab HTTPS URL").refine((v) => !hasParentTraversal(v), 'URL must not contain ".." segments').describe("Full HTTPS URL of a GitHub or GitLab repository.");
8321
+ var SkillGitPathSchema = z21.string().trim().min(1).regex(SKILL_PATH_REGEX, 'Path may only contain letters, numbers, ".", "_", "-", and "/"').refine((v) => !hasParentTraversal(v), 'Path must not contain ".." segments').refine((v) => !v.split("/").includes("."), 'Path must not contain "." segments').refine((v) => v.replace(/^\/+|\/+$/g, "").length > 0, "Path must reference a subdirectory, not only slashes").describe("Path to the skill directory within the repository. Omit to use the repository root.");
8322
+ var SkillGitRefSchema = z21.string().trim().min(1).regex(GIT_REF_REGEX, 'Ref may only contain letters, numbers, ".", "_", "-", and "/"').refine((v) => !hasParentTraversal(v), 'Ref must not contain ".." segments').refine((v) => v.replace(/^\/+|\/+$/g, "").length > 0, "Ref must not consist only of slashes").describe("Git ref \u2014 branch name, tag, or commit SHA.");
8323
+ var SkillDescriptionSchema = z21.string().trim().min(1).describe("Concise guidance for when the agent should use the skill.");
8324
+ var SkillManifestObjectSchema = z21.object({
6678
8325
  type: SkillTypeSchema,
6679
8326
  name: NameSchema,
6680
8327
  url: SkillGitUrlSchema,
@@ -6683,26 +8330,26 @@ var SkillManifestObjectSchema = z19.object({
6683
8330
  description: SkillDescriptionSchema
6684
8331
  }).strict();
6685
8332
  var SkillManifestSchema = SkillManifestObjectSchema.openapi("SkillManifest");
6686
- var ConfiguredSkillSchema = z19.object({
8333
+ var ConfiguredSkillSchema = z21.object({
6687
8334
  name: NameSchema,
6688
8335
  manifest: SkillManifestSchema
6689
8336
  }).strict().openapi("ConfiguredSkill");
6690
- var CreateSkillRequestSchema = z19.object({
8337
+ var CreateSkillRequestSchema = z21.object({
6691
8338
  manifest: SkillManifestSchema
6692
8339
  }).strict().openapi("CreateSkillRequest");
6693
- var PutSkillRequestSchema = z19.object({
8340
+ var UpdateSkillRequestSchema = z21.object({
6694
8341
  manifest: SkillManifestSchema
6695
- }).strict().openapi("PutSkillRequest");
6696
- var GetSkillResponseSchema = z19.object({ data: ConfiguredSkillSchema }).openapi("GetSkillResponse");
6697
- var ListSkillsResponseSchema = z19.object({ data: z19.array(ConfiguredSkillSchema) }).openapi("ListSkillsResponse");
6698
- var SkillReadEntrySchema = z19.object({
8342
+ }).strict().openapi("UpdateSkillRequest");
8343
+ var GetSkillResponseSchema = z21.object({ data: ConfiguredSkillSchema }).openapi("GetSkillResponse");
8344
+ var ListSkillsResponseSchema = z21.object({ data: z21.array(ConfiguredSkillSchema) }).openapi("ListSkillsResponse");
8345
+ var AvailableSkillSchema = z21.object({
6699
8346
  name: NameSchema,
6700
8347
  description: SkillDescriptionSchema
6701
- }).strict().openapi("SkillReadEntry");
6702
- var ListAvailableSkillsResponseSchema = z19.object({ data: z19.array(SkillReadEntrySchema) }).openapi("ListAvailableSkillsResponse");
8348
+ }).strict().openapi("AvailableSkill");
8349
+ var ListAvailableSkillsResponseSchema = z21.object({ data: z21.array(AvailableSkillSchema) }).openapi("ListAvailableSkillsResponse");
6703
8350
 
6704
8351
  // src/schemas/skillCatalog.ts
6705
- var CatalogSkillSchema = z20.object({
8352
+ var CatalogSkillSchema = z22.object({
6706
8353
  type: SkillTypeSchema,
6707
8354
  name: NameSchema,
6708
8355
  url: SkillGitUrlSchema,
@@ -6710,24 +8357,23 @@ var CatalogSkillSchema = z20.object({
6710
8357
  ref: SkillGitRefSchema,
6711
8358
  description: SkillDescriptionSchema
6712
8359
  }).strict().openapi("CatalogSkill");
6713
- var SkillCatalogFileSchema = z20.object({
6714
- skills: z20.array(CatalogSkillSchema)
8360
+ var SkillCatalogFileSchema = z22.object({
8361
+ skills: z22.array(CatalogSkillSchema)
6715
8362
  }).strict().superRefine((file, ctx) => {
6716
8363
  uniqueNames(file.skills, ctx);
6717
8364
  });
6718
- var GetSkillCatalogResponseSchema = z20.object({
6719
- data: z20.array(CatalogSkillSchema)
8365
+ var GetSkillCatalogResponseSchema = z22.object({
8366
+ data: z22.array(CatalogSkillSchema)
6720
8367
  }).openapi("GetSkillCatalogResponse");
6721
8368
 
6722
8369
  // src/routes/catalogRoutes.ts
6723
- var CATALOG_TAG = "Catalog";
6724
8370
  var listModelProviderCatalogRoute = createRoute5({
6725
8371
  method: "get",
6726
8372
  path: "/model-providers",
6727
- tags: [CATALOG_TAG],
8373
+ tags: ["Models" /* MODELS */],
6728
8374
  summary: "Get the model catalog",
6729
8375
  description: "Shipped model-provider presets (discovery-only). Copy into PUT /settings/model-providers to configure. Includes a `custom` sentinel with `supported_reasoning_efforts`.",
6730
- "x-fern-sdk-group-name": ["catalog", "modelProviders"],
8376
+ "x-fern-sdk-group-name": ["catalogs", "modelProviders"],
6731
8377
  "x-fern-sdk-method-name": "list",
6732
8378
  responses: {
6733
8379
  200: {
@@ -6743,10 +8389,10 @@ var listModelProviderCatalogRoute = createRoute5({
6743
8389
  var listMcpServerCatalogRoute = createRoute5({
6744
8390
  method: "get",
6745
8391
  path: "/mcp-servers",
6746
- tags: [CATALOG_TAG],
8392
+ tags: ["MCP Servers" /* MCP_SERVERS */],
6747
8393
  summary: "Get the MCP catalog",
6748
8394
  description: "Shipped MCP server presets (discovery-only). Copy into PUT /settings/mcp-servers to configure.",
6749
- "x-fern-sdk-group-name": ["catalog", "mcpServers"],
8395
+ "x-fern-sdk-group-name": ["catalogs", "mcpServers"],
6750
8396
  "x-fern-sdk-method-name": "list",
6751
8397
  responses: {
6752
8398
  200: {
@@ -6762,10 +8408,10 @@ var listMcpServerCatalogRoute = createRoute5({
6762
8408
  var listSkillCatalogRoute = createRoute5({
6763
8409
  method: "get",
6764
8410
  path: "/skills",
6765
- tags: [CATALOG_TAG],
8411
+ tags: ["Skills" /* SKILLS */],
6766
8412
  summary: "Get the skill catalog",
6767
8413
  description: "Shipped skill presets (discovery-only). Copy into PUT /settings/skills to configure.",
6768
- "x-fern-sdk-group-name": ["catalog", "skills"],
8414
+ "x-fern-sdk-group-name": ["catalogs", "skills"],
6769
8415
  "x-fern-sdk-method-name": "list",
6770
8416
  responses: {
6771
8417
  200: {
@@ -6781,10 +8427,10 @@ var listSkillCatalogRoute = createRoute5({
6781
8427
  var listSandboxProviderCatalogRoute = createRoute5({
6782
8428
  method: "get",
6783
8429
  path: "/sandbox-providers",
6784
- tags: [CATALOG_TAG],
8430
+ tags: ["Sandboxes" /* SANDBOXES */],
6785
8431
  summary: "Get the sandbox provider catalog",
6786
8432
  description: "Shipped sandbox-provider presets (discovery-only). Copy into PUT /settings/sandbox-providers to configure.",
6787
- "x-fern-sdk-group-name": ["catalog", "sandboxProviders"],
8433
+ "x-fern-sdk-group-name": ["catalogs", "sandboxProviders"],
6788
8434
  "x-fern-sdk-method-name": "list",
6789
8435
  responses: {
6790
8436
  200: {
@@ -6832,25 +8478,25 @@ import { extractErrorLogFields as extractErrorLogFields4, McpConnectionError as
6832
8478
 
6833
8479
  // src/routes/mcpOAuthRoutes.ts
6834
8480
  import { createRoute as createRoute6 } from "@hono/zod-openapi";
6835
- var MCP_OAUTH_TAG = "MCP OAuth";
6836
8481
  var mcpOAuthCallbackRoute = createRoute6({
6837
8482
  method: "get",
6838
8483
  path: "/callback",
6839
- tags: [MCP_OAUTH_TAG],
8484
+ tags: ["MCP Servers" /* MCP_SERVERS */],
6840
8485
  summary: "OAuth callback for MCP authorization",
6841
- description: "Browser redirect target for MCP server OAuth. The authorization server redirects here with `code`/`state` (or `error`). Exchanges the code for tokens, then either returns JSON or redirects to the `redirect_url` supplied at authorize time. Not called by the SDK \u2014 browsers hit this URL directly.",
8486
+ description: "Browser redirect target for MCP server OAuth. The authorization server redirects here with `code`/`state` (or `error`). Exchanges the code for tokens, then either returns JSON or redirects to the `return_to` path supplied at authorize time. Not called by the SDK \u2014 browsers hit this URL directly.",
6842
8487
  // Browser-redirect target hit directly by the authorization server, never called by SDK.
6843
8488
  "x-fern-ignore": true,
8489
+ "x-excluded": true,
6844
8490
  request: {
6845
8491
  query: OAuthCallbackQuerySchema
6846
8492
  },
6847
8493
  responses: {
6848
8494
  200: {
6849
8495
  content: { "application/json": { schema: OAuthCallbackSuccessSchema } },
6850
- description: "Token exchanged successfully and no `redirect_url` was given at authorize time."
8496
+ description: "Token exchanged successfully and no `return_to` was given at authorize time."
6851
8497
  },
6852
8498
  302: {
6853
- description: "Redirect to the `redirect_url` given at authorize time, with `isSuccess` (and `reason` when it failed) appended to its existing query params."
8499
+ description: "Redirect to the `return_to` path given at authorize time, with `isSuccess` (and `reason` when it failed) appended to its existing query params."
6854
8500
  },
6855
8501
  400: {
6856
8502
  content: { "application/json": { schema: RequestErrorResponseSchema } },
@@ -6864,25 +8510,28 @@ var mcpOAuthCallbackRoute = createRoute6({
6864
8510
  });
6865
8511
 
6866
8512
  // src/apis/mcpOAuth.ts
6867
- function callbackLandingUrl(params) {
6868
- const url = new URL(params.redirectUrl);
8513
+ function callbackLandingPath(params) {
8514
+ const url = new URL(params.returnTo, params.c.req.url);
6869
8515
  url.searchParams.set("isSuccess", String(params.isSuccess));
6870
8516
  if (params.reason) {
6871
8517
  url.searchParams.set("reason", params.reason);
6872
8518
  }
6873
- return url.href;
8519
+ return `${url.pathname}${url.search}`;
6874
8520
  }
6875
8521
  function callbackSuccess(params) {
6876
- const redirectUrl = params.pending.redirectUrl;
6877
- if (redirectUrl) {
6878
- return params.c.redirect(callbackLandingUrl({ redirectUrl, isSuccess: true }), 302);
8522
+ const returnTo = params.pending.returnTo;
8523
+ if (returnTo) {
8524
+ return params.c.redirect(callbackLandingPath({ c: params.c, returnTo, isSuccess: true }), 302);
6879
8525
  }
6880
8526
  return params.c.json({ success: true }, 200);
6881
8527
  }
6882
8528
  function callbackFailure(params) {
6883
- const redirectUrl = params.pending?.redirectUrl;
6884
- if (redirectUrl) {
6885
- return params.c.redirect(callbackLandingUrl({ redirectUrl, isSuccess: false, reason: params.message }), 302);
8529
+ const returnTo = params.pending?.returnTo;
8530
+ if (returnTo) {
8531
+ return params.c.redirect(
8532
+ callbackLandingPath({ c: params.c, returnTo, isSuccess: false, reason: params.message }),
8533
+ 302
8534
+ );
6886
8535
  }
6887
8536
  return params.c.json({ error: { message: params.message } }, params.jsonStatus ?? 400);
6888
8537
  }
@@ -6924,18 +8573,17 @@ function createMcpOAuthRouter(deps) {
6924
8573
  }
6925
8574
 
6926
8575
  // src/apis/mcpServers.ts
6927
- init_config();
6928
- init_mcpServerStore();
6929
8576
  import { OpenAPIHono as OpenAPIHono7 } from "@hono/zod-openapi";
6930
8577
  import { extractErrorLogFields as extractErrorLogFields5, isAuthRequired, McpConnectionError as McpConnectionError4, RemoteMCP } from "@truefoundry/trueforge-core/core";
8578
+ init_config();
8579
+ init_mcpServerStore();
6931
8580
 
6932
8581
  // src/routes/mcpServerRoutes.ts
6933
- import { createRoute as createRoute7, z as z21 } from "@hono/zod-openapi";
6934
- var MCP_SERVERS_TAG = "MCP Servers";
8582
+ import { createRoute as createRoute7, z as z23 } from "@hono/zod-openapi";
6935
8583
  var listAvailableMcpServersRoute = createRoute7({
6936
8584
  method: "get",
6937
8585
  path: "/",
6938
- tags: [MCP_SERVERS_TAG],
8586
+ tags: ["MCP Servers" /* MCP_SERVERS */],
6939
8587
  summary: "List MCP servers for chat",
6940
8588
  description: "MCP servers as a slim name/url list for the composer. No auth or auth_status.",
6941
8589
  "x-fern-sdk-group-name": ["mcpServers"],
@@ -6954,7 +8602,7 @@ var listAvailableMcpServersRoute = createRoute7({
6954
8602
  var listMcpServersRoute = createRoute7({
6955
8603
  method: "get",
6956
8604
  path: "/",
6957
- tags: [MCP_SERVERS_TAG],
8605
+ tags: ["MCP Servers" /* MCP_SERVERS */],
6958
8606
  summary: "List MCP servers",
6959
8607
  description: "All MCP servers with nested auth_status (settings / admin projection). Header auth values are redacted.",
6960
8608
  "x-fern-sdk-group-name": ["settings", "mcpServers"],
@@ -6974,13 +8622,13 @@ var listMcpServersRoute = createRoute7({
6974
8622
  }
6975
8623
  }
6976
8624
  });
6977
- var McpServerNameParamsSchema = z21.object({
6978
- name: z21.string().min(1).describe("MCP server name.")
8625
+ var McpServerNameParamsSchema = z23.object({
8626
+ name: z23.string().min(1).describe("MCP server name.")
6979
8627
  });
6980
8628
  var getMcpServerRoute = createRoute7({
6981
8629
  method: "get",
6982
8630
  path: "/{name}",
6983
- tags: [MCP_SERVERS_TAG],
8631
+ tags: ["MCP Servers" /* MCP_SERVERS */],
6984
8632
  summary: "Get a single MCP server by name",
6985
8633
  description: "A single MCP server by name, with nested auth_status (settings / admin projection). Header auth values are redacted.",
6986
8634
  "x-fern-sdk-group-name": ["settings", "mcpServers"],
@@ -7002,7 +8650,7 @@ var getMcpServerRoute = createRoute7({
7002
8650
  var createMcpServerRoute = createRoute7({
7003
8651
  method: "post",
7004
8652
  path: "/",
7005
- tags: [MCP_SERVERS_TAG],
8653
+ tags: ["MCP Servers" /* MCP_SERVERS */],
7006
8654
  summary: "Create an MCP server",
7007
8655
  description: "Creates an MCP server by `name`. Fails if `name` is already taken. Runs DCR registration when `auth.type` is `dcr`. Header secrets: real value required; redacted with no stored value returns 400.",
7008
8656
  "x-fern-sdk-group-name": ["settings", "mcpServers"],
@@ -7035,14 +8683,14 @@ var createMcpServerRoute = createRoute7({
7035
8683
  var putMcpServerRoute = createRoute7({
7036
8684
  method: "put",
7037
8685
  path: "/",
7038
- tags: [MCP_SERVERS_TAG],
8686
+ tags: ["MCP Servers" /* MCP_SERVERS */],
7039
8687
  summary: "Create or replace an MCP server",
7040
8688
  description: "Create or replace by `name`. Does not start DCR or change oauth client columns. Header secrets: real value sets/rotates; redacted keeps existing (400 if none).",
7041
8689
  "x-fern-sdk-group-name": ["settings", "mcpServers"],
7042
- "x-fern-sdk-method-name": "upsert",
8690
+ "x-fern-sdk-method-name": "create_or_update",
7043
8691
  request: {
7044
8692
  body: {
7045
- content: { "application/json": { schema: PutMcpServerRequestSchema } },
8693
+ content: { "application/json": { schema: UpdateMcpServerRequestSchema } },
7046
8694
  required: true
7047
8695
  }
7048
8696
  },
@@ -7061,16 +8709,16 @@ var putMcpServerRoute = createRoute7({
7061
8709
  }
7062
8710
  }
7063
8711
  });
7064
- var ListMcpServerToolsResponseSchema = z21.object({
8712
+ var ListMcpServerToolsResponseSchema = z23.object({
7065
8713
  // TODO: Type tools/list entries to the MCP tool shape (name, description, inputSchema, …) for OpenAPI quality.
7066
- data: z21.array(z21.record(z21.string(), z21.unknown())).describe("MCP `tools/list` entries, passed through verbatim from the MCP server.")
7067
- }).openapi("ListMcpServerToolsResponse");
8714
+ data: z23.array(z23.record(z23.string(), z23.unknown())).describe("MCP `tools/list` entries, passed through verbatim from the MCP server.")
8715
+ }).openapi("ListMCPServerToolsResponse");
7068
8716
  var listMcpServerToolsRoute = createRoute7({
7069
8717
  method: "get",
7070
8718
  path: "/{name}/tools",
7071
- tags: [MCP_SERVERS_TAG],
8719
+ tags: ["MCP Servers" /* MCP_SERVERS */],
7072
8720
  summary: "List tools of an MCP server",
7073
- "x-fern-sdk-group-name": ["settings", "mcpServers"],
8721
+ "x-fern-sdk-group-name": ["mcpServers"],
7074
8722
  "x-fern-sdk-method-name": "list_tools",
7075
8723
  description: "All tools exposed by the given MCP server (non-paginated), as returned by the MCP `tools/list` call.",
7076
8724
  request: {
@@ -7083,7 +8731,7 @@ var listMcpServerToolsRoute = createRoute7({
7083
8731
  },
7084
8732
  401: {
7085
8733
  content: { "application/json": { schema: RequestErrorResponseSchema } },
7086
- description: "Harness session login required."
8734
+ description: "OIDC is configured and the request has no valid session cookie."
7087
8735
  },
7088
8736
  404: {
7089
8737
  content: { "application/json": { schema: RequestErrorResponseSchema } },
@@ -7099,17 +8747,19 @@ var listMcpServerToolsRoute = createRoute7({
7099
8747
  }
7100
8748
  }
7101
8749
  });
7102
- var McpAuthorizeQuerySchema = z21.object({
7103
- redirect_url: z21.url().optional().describe("Optional FE landing URL the OAuth callback redirects to, with `isSuccess`/`reason` appended.")
8750
+ var McpAuthorizeQuerySchema = z23.object({
8751
+ return_to: z23.string().optional().describe(
8752
+ "Optional path to return to after OAuth. Must be a same-origin relative path; the OAuth callback redirects here with `isSuccess`/`reason` appended."
8753
+ )
7104
8754
  });
7105
8755
  var authorizeMcpServerRoute = createRoute7({
7106
8756
  method: "get",
7107
8757
  path: "/{name}/authorize",
7108
- tags: [MCP_SERVERS_TAG],
8758
+ tags: ["MCP Servers" /* MCP_SERVERS */],
7109
8759
  summary: "Start (or short-circuit) the auth flow for an MCP server",
7110
8760
  "x-fern-sdk-group-name": ["mcpServers"],
7111
8761
  "x-fern-sdk-method-name": "authorize",
7112
- description: "For servers without auth returns not_required, and for header credentials returns authenticated (no browser flow). For auth.type dcr, returns authenticated when a usable (or refreshable) token exists; otherwise runs DCR if needed and returns auth_required with an authorization URL. Optional redirect_url is where the OAuth callback then redirects the browser; without it the callback returns JSON.",
8762
+ description: "For servers without auth returns not_required, and for header credentials returns authenticated (no browser flow). For auth.type dcr, returns authenticated when a usable (or refreshable) token exists; otherwise runs DCR if needed and returns auth_required with an authorization URL. Optional return_to is where the OAuth callback then redirects the browser; without it the callback returns JSON.",
7113
8763
  request: {
7114
8764
  params: McpServerNameParamsSchema,
7115
8765
  query: McpAuthorizeQuerySchema
@@ -7121,7 +8771,7 @@ var authorizeMcpServerRoute = createRoute7({
7121
8771
  },
7122
8772
  400: {
7123
8773
  content: { "application/json": { schema: RequestErrorResponseSchema } },
7124
- description: "Invalid redirect_url."
8774
+ description: "Invalid return_to."
7125
8775
  },
7126
8776
  404: {
7127
8777
  content: { "application/json": { schema: RequestErrorResponseSchema } },
@@ -7141,13 +8791,13 @@ var authorizeMcpServerRoute = createRoute7({
7141
8791
  }
7142
8792
  }
7143
8793
  });
7144
- var deleteAuthorizeMcpServerRoute = createRoute7({
8794
+ var deleteAuthorizationMcpServerRoute = createRoute7({
7145
8795
  method: "delete",
7146
8796
  path: "/{name}/authorize",
7147
- tags: [MCP_SERVERS_TAG],
8797
+ tags: ["MCP Servers" /* MCP_SERVERS */],
7148
8798
  summary: "Disconnect OAuth for an MCP server",
7149
8799
  "x-fern-sdk-group-name": ["mcpServers"],
7150
- "x-fern-sdk-method-name": "delete_authorize",
8800
+ "x-fern-sdk-method-name": "delete_authorization",
7151
8801
  description: "For auth.type dcr, deletes the stored OAuth token and returns the server with auth_status auth_required, keeping the dynamically registered OAuth client so the next authorize can reuse it. No-op for header or no-auth servers (returns the server unchanged).",
7152
8802
  request: {
7153
8803
  params: McpServerNameParamsSchema
@@ -7251,7 +8901,7 @@ function toConfiguredMcpServer({
7251
8901
  })
7252
8902
  };
7253
8903
  }
7254
- function toMcpServerReadEntry({
8904
+ function toAvailableMcpServer({
7255
8905
  record,
7256
8906
  token
7257
8907
  }) {
@@ -7407,60 +9057,17 @@ function createSettingsMcpServersRouter(deps) {
7407
9057
  throw error;
7408
9058
  }
7409
9059
  };
7410
- const listToolsHandler = async (c) => {
7411
- const { name } = c.req.valid("param");
7412
- const userRef = deps.resolveUserContext(c).userRef;
7413
- const connection = await getMcpConnection({
7414
- tenant_id: TENANT_ID,
7415
- name,
7416
- store: deps.mcpServerStore,
7417
- tokenStore: deps.tokenStore,
7418
- clientName: config_default.MCP_DCR_OAUTH_CLIENT_NAME,
7419
- userRef
7420
- });
7421
- if (connection === void 0) {
7422
- return c.json({ error: { message: `MCP server not found: ${name}` } }, 404);
7423
- }
7424
- const remote = new RemoteMCP({
7425
- id: name,
7426
- name,
7427
- url: connection.url,
7428
- headers: connection.headers,
7429
- requestTimeoutMs: config_default.MCP_REQUEST_TIMEOUT_MS,
7430
- connectTimeoutMs: config_default.MCP_CONNECT_TIMEOUT_MS,
7431
- logger: deps.logger,
7432
- signal: c.req.raw.signal
7433
- });
7434
- try {
7435
- const response = await remote.listTools();
7436
- if (isAuthRequired(response)) {
7437
- return c.json({ error: { message: `MCP server "${name}" requires authentication` } }, 422);
7438
- }
7439
- const data = response.result.tools.map((tool) => omitUndefinedEntries({ ...tool }));
7440
- return c.json({ data }, 200);
7441
- } catch (error) {
7442
- if (error instanceof McpConnectionError4) {
7443
- deps.logger.warn(`MCP tools/list failed for "${name}"`, extractErrorLogFields5(error));
7444
- if (error.statusCode === 401) {
7445
- return c.json({ error: { message: error.message } }, 422);
7446
- }
7447
- return c.json({ error: { message: error.message } }, 502);
7448
- }
7449
- throw error;
7450
- }
7451
- };
7452
9060
  const router = new OpenAPIHono7();
7453
9061
  router.openapi(listMcpServersRoute, listHandler);
7454
9062
  router.openapi(createMcpServerRoute, createHandler);
7455
9063
  router.openapi(putMcpServerRoute, putHandler);
7456
- router.openapi(listMcpServerToolsRoute, listToolsHandler);
7457
9064
  router.openapi(getMcpServerRoute, getHandler);
7458
9065
  return router;
7459
9066
  }
7460
9067
  function createMcpServersRouter(deps) {
7461
9068
  const authorizeHandler = async (c) => {
7462
9069
  const { name } = c.req.valid("param");
7463
- const { redirect_url: redirectUrl } = c.req.valid("query");
9070
+ const { return_to: returnTo } = c.req.valid("query");
7464
9071
  const userRef = deps.resolveUserContext(c).userRef;
7465
9072
  const record = await deps.mcpServerStore.getServer({ tenant_id: TENANT_ID, name });
7466
9073
  if (!record) {
@@ -7469,10 +9076,10 @@ function createMcpServersRouter(deps) {
7469
9076
  if (record.manifest.auth?.type !== "dcr") {
7470
9077
  return c.json(resolveMcpAuthStatus({ manifest: record.manifest }), 200);
7471
9078
  }
9079
+ if (returnTo && safeReturnTo(returnTo) !== returnTo) {
9080
+ return c.json({ error: { message: "Invalid return_to: must be a same-origin relative path" } }, 400);
9081
+ }
7472
9082
  try {
7473
- if (redirectUrl) {
7474
- validateRedirectUris({ redirectUris: [redirectUrl] });
7475
- }
7476
9083
  const result = await resolveMcpAuth({
7477
9084
  tokenStore: deps.tokenStore,
7478
9085
  mcpServerStore: deps.mcpServerStore,
@@ -7481,7 +9088,7 @@ function createMcpServersRouter(deps) {
7481
9088
  mcpServerUrl: record.manifest.url,
7482
9089
  mcpServerName: record.name,
7483
9090
  clientName: config_default.MCP_DCR_OAUTH_CLIENT_NAME,
7484
- ...redirectUrl !== void 0 ? { redirectUrl } : {}
9091
+ ...returnTo !== void 0 ? { returnTo } : {}
7485
9092
  });
7486
9093
  const authStatus = isMcpAuthRequired(result) ? { status: "auth_required", authorization_url: result.authUrl.href } : { status: "authenticated" };
7487
9094
  return c.json(authStatus, 200);
@@ -7503,7 +9110,49 @@ function createMcpServersRouter(deps) {
7503
9110
  return c.json({ error: { message: "Internal server error" } }, 500);
7504
9111
  }
7505
9112
  };
7506
- const deleteAuthorizeHandler = async (c) => {
9113
+ const listToolsHandler = async (c) => {
9114
+ const { name } = c.req.valid("param");
9115
+ const userRef = deps.resolveUserContext(c).userRef;
9116
+ const connection = await getMcpConnection({
9117
+ tenant_id: TENANT_ID,
9118
+ name,
9119
+ store: deps.mcpServerStore,
9120
+ tokenStore: deps.tokenStore,
9121
+ clientName: config_default.MCP_DCR_OAUTH_CLIENT_NAME,
9122
+ userRef
9123
+ });
9124
+ if (connection === void 0) {
9125
+ return c.json({ error: { message: `MCP server not found: ${name}` } }, 404);
9126
+ }
9127
+ const remote = new RemoteMCP({
9128
+ id: name,
9129
+ name,
9130
+ url: connection.url,
9131
+ headers: connection.headers,
9132
+ requestTimeoutMs: config_default.MCP_REQUEST_TIMEOUT_MS,
9133
+ connectTimeoutMs: config_default.MCP_CONNECT_TIMEOUT_MS,
9134
+ logger: deps.logger,
9135
+ signal: c.req.raw.signal
9136
+ });
9137
+ try {
9138
+ const response = await remote.listTools();
9139
+ if (isAuthRequired(response)) {
9140
+ return c.json({ error: { message: `MCP server "${name}" requires authentication` } }, 422);
9141
+ }
9142
+ const data = response.result.tools.map((tool) => omitUndefinedEntries({ ...tool }));
9143
+ return c.json({ data }, 200);
9144
+ } catch (error) {
9145
+ if (error instanceof McpConnectionError4) {
9146
+ deps.logger.warn(`MCP tools/list failed for "${name}"`, extractErrorLogFields5(error));
9147
+ if (error.statusCode === 401) {
9148
+ return c.json({ error: { message: error.message } }, 422);
9149
+ }
9150
+ return c.json({ error: { message: error.message } }, 502);
9151
+ }
9152
+ throw error;
9153
+ }
9154
+ };
9155
+ const deleteAuthorizationHandler = async (c) => {
7507
9156
  const { name } = c.req.valid("param");
7508
9157
  const userRef = deps.resolveUserContext(c).userRef;
7509
9158
  const record = await deps.mcpServerStore.getServer({ tenant_id: TENANT_ID, name });
@@ -7523,13 +9172,14 @@ function createMcpServersRouter(deps) {
7523
9172
  const tokens = await deps.tokenStore.getTokens({ ids: dcrIds, userRef });
7524
9173
  return c.json(
7525
9174
  {
7526
- data: records.map((record) => toMcpServerReadEntry({ record, token: tokens.get(record.id) }))
9175
+ data: records.map((record) => toAvailableMcpServer({ record, token: tokens.get(record.id) }))
7527
9176
  },
7528
9177
  200
7529
9178
  );
7530
9179
  });
9180
+ router.openapi(listMcpServerToolsRoute, listToolsHandler);
7531
9181
  router.openapi(authorizeMcpServerRoute, authorizeHandler);
7532
- router.openapi(deleteAuthorizeMcpServerRoute, deleteAuthorizeHandler);
9182
+ router.openapi(deleteAuthorizationMcpServerRoute, deleteAuthorizationHandler);
7533
9183
  return router;
7534
9184
  }
7535
9185
 
@@ -7538,18 +9188,18 @@ import { OpenAPIHono as OpenAPIHono8 } from "@hono/zod-openapi";
7538
9188
 
7539
9189
  // src/routes/modelRoutes.ts
7540
9190
  import { createRoute as createRoute8 } from "@hono/zod-openapi";
7541
- var listModelsRoute = createRoute8({
9191
+ var listAvailableModelsRoute = createRoute8({
7542
9192
  method: "get",
7543
9193
  path: "/",
7544
- tags: ["Models"],
7545
- summary: "List models",
9194
+ tags: ["Models" /* MODELS */],
9195
+ summary: "List models for chat",
7546
9196
  "x-fern-sdk-group-name": ["models"],
7547
9197
  "x-fern-sdk-method-name": "list",
7548
- description: "Models across all configured model providers, addressed by fully qualified name `name/model_name`.",
9198
+ description: "Configured models as a slim FQN list for the composer.",
7549
9199
  responses: {
7550
9200
  200: {
7551
- content: { "application/json": { schema: ListModelsResponseSchema } },
7552
- description: "All models of all configured providers."
9201
+ content: { "application/json": { schema: ListAvailableModelsResponseSchema } },
9202
+ description: "All configured models (chat projection)."
7553
9203
  },
7554
9204
  401: {
7555
9205
  content: { "application/json": { schema: RequestErrorResponseSchema } },
@@ -7562,7 +9212,7 @@ var listModelsRoute = createRoute8({
7562
9212
  function createModelsRouter(deps) {
7563
9213
  const router = new OpenAPIHono8();
7564
9214
  router.openapi(
7565
- listModelsRoute,
9215
+ listAvailableModelsRoute,
7566
9216
  async (c) => c.json({ data: await deps.modelProviderStore.listModels(TENANT_ID) }, 200)
7567
9217
  );
7568
9218
  return router;
@@ -7577,11 +9227,10 @@ import { OpenAPIHono as OpenAPIHono9 } from "@hono/zod-openapi";
7577
9227
 
7578
9228
  // src/routes/modelProviderRoutes.ts
7579
9229
  import { createRoute as createRoute9 } from "@hono/zod-openapi";
7580
- var MODEL_PROVIDERS_TAG = "Model Providers";
7581
9230
  var listModelProvidersRoute = createRoute9({
7582
9231
  method: "get",
7583
9232
  path: "/",
7584
- tags: [MODEL_PROVIDERS_TAG],
9233
+ tags: ["Models" /* MODELS */],
7585
9234
  summary: "List configured model providers",
7586
9235
  description: "All configured providers with nested manifests.",
7587
9236
  "x-fern-sdk-group-name": ["settings", "modelProviders"],
@@ -7604,7 +9253,7 @@ var listModelProvidersRoute = createRoute9({
7604
9253
  var createModelProviderRoute = createRoute9({
7605
9254
  method: "post",
7606
9255
  path: "/",
7607
- tags: [MODEL_PROVIDERS_TAG],
9256
+ tags: ["Models" /* MODELS */],
7608
9257
  summary: "Create a model provider",
7609
9258
  description: "Creates a provider (models included). Fails if `name` is already taken. Well-known types use `type` as `name` (one each); `custom` is named by the caller. `auth.api_key`: real value required; redacted with no stored secret returns 400.",
7610
9259
  "x-fern-sdk-group-name": ["settings", "modelProviders"],
@@ -7633,14 +9282,14 @@ var createModelProviderRoute = createRoute9({
7633
9282
  var putModelProviderRoute = createRoute9({
7634
9283
  method: "put",
7635
9284
  path: "/",
7636
- tags: [MODEL_PROVIDERS_TAG],
9285
+ tags: ["Models" /* MODELS */],
7637
9286
  summary: "Create or replace a model provider",
7638
9287
  description: "Create or replace a provider (models included). Well-known types use `type` as `name` (one each); `custom` is named by the caller. `auth.api_key`: real value sets/rotates; redacted keeps existing (400 if none).",
7639
9288
  "x-fern-sdk-group-name": ["settings", "modelProviders"],
7640
- "x-fern-sdk-method-name": "upsert",
9289
+ "x-fern-sdk-method-name": "create_or_update",
7641
9290
  request: {
7642
9291
  body: {
7643
- content: { "application/json": { schema: PutModelProviderRequestSchema } },
9292
+ content: { "application/json": { schema: UpdateModelProviderRequestSchema } },
7644
9293
  required: true
7645
9294
  }
7646
9295
  },
@@ -7749,11 +9398,10 @@ import { withTimeout } from "@truefoundry/trueforge-core/core";
7749
9398
 
7750
9399
  // src/routes/sandboxProviderRoutes.ts
7751
9400
  import { createRoute as createRoute10 } from "@hono/zod-openapi";
7752
- var SANDBOX_PROVIDERS_TAG = "Sandbox Providers";
7753
9401
  var getSandboxProviderRoute = createRoute10({
7754
9402
  method: "get",
7755
9403
  path: "/",
7756
- tags: [SANDBOX_PROVIDERS_TAG],
9404
+ tags: ["Sandboxes" /* SANDBOXES */],
7757
9405
  summary: "Get the configured sandbox provider",
7758
9406
  description: "The single configured sandbox provider for this tenant. `auth.api_key` is redacted.",
7759
9407
  "x-fern-sdk-group-name": ["settings", "sandboxProviders"],
@@ -7772,14 +9420,14 @@ var getSandboxProviderRoute = createRoute10({
7772
9420
  var putSandboxProviderRoute = createRoute10({
7773
9421
  method: "put",
7774
9422
  path: "/",
7775
- tags: [SANDBOX_PROVIDERS_TAG],
9423
+ tags: ["Sandboxes" /* SANDBOXES */],
7776
9424
  summary: "Create or replace the sandbox provider",
7777
9425
  description: "Upserts the single sandbox provider for this tenant: creates it or replaces its entire configuration. `auth.api_key`: real value sets/rotates; redacted keeps existing (400 if none).",
7778
9426
  "x-fern-sdk-group-name": ["settings", "sandboxProviders"],
7779
- "x-fern-sdk-method-name": "upsert",
9427
+ "x-fern-sdk-method-name": "create_or_update",
7780
9428
  request: {
7781
9429
  body: {
7782
- content: { "application/json": { schema: PutSandboxProviderRequestSchema } },
9430
+ content: { "application/json": { schema: UpdateSandboxProviderRequestSchema } },
7783
9431
  required: true
7784
9432
  }
7785
9433
  },
@@ -7892,11 +9540,10 @@ import { OpenAPIHono as OpenAPIHono11 } from "@hono/zod-openapi";
7892
9540
 
7893
9541
  // src/routes/skillRoutes.ts
7894
9542
  import { createRoute as createRoute11 } from "@hono/zod-openapi";
7895
- var SKILLS_TAG = "Skills";
7896
9543
  var listAvailableSkillsRoute = createRoute11({
7897
9544
  method: "get",
7898
9545
  path: "/",
7899
- tags: [SKILLS_TAG],
9546
+ tags: ["Skills" /* SKILLS */],
7900
9547
  summary: "List skills for chat",
7901
9548
  description: "Configured skills as a slim name/description list for the composer.",
7902
9549
  "x-fern-sdk-group-name": ["skills"],
@@ -7915,7 +9562,7 @@ var listAvailableSkillsRoute = createRoute11({
7915
9562
  var listConfiguredSkillsRoute = createRoute11({
7916
9563
  method: "get",
7917
9564
  path: "/",
7918
- tags: [SKILLS_TAG],
9565
+ tags: ["Skills" /* SKILLS */],
7919
9566
  summary: "List configured skills",
7920
9567
  description: "All configured skills with nested manifests (settings / admin projection).",
7921
9568
  "x-fern-sdk-group-name": ["settings", "skills"],
@@ -7938,7 +9585,7 @@ var listConfiguredSkillsRoute = createRoute11({
7938
9585
  var createSkillRoute = createRoute11({
7939
9586
  method: "post",
7940
9587
  path: "/",
7941
- tags: [SKILLS_TAG],
9588
+ tags: ["Skills" /* SKILLS */],
7942
9589
  summary: "Create a skill",
7943
9590
  description: "Creates a skill keyed by `name`. Fails if `name` is already taken.",
7944
9591
  "x-fern-sdk-group-name": ["settings", "skills"],
@@ -7967,14 +9614,14 @@ var createSkillRoute = createRoute11({
7967
9614
  var putSkillRoute = createRoute11({
7968
9615
  method: "put",
7969
9616
  path: "/",
7970
- tags: [SKILLS_TAG],
9617
+ tags: ["Skills" /* SKILLS */],
7971
9618
  summary: "Create or replace a skill",
7972
9619
  description: "Full upsert keyed by `name`: creates the skill or replaces its entire manifest.",
7973
9620
  "x-fern-sdk-group-name": ["settings", "skills"],
7974
- "x-fern-sdk-method-name": "upsert",
9621
+ "x-fern-sdk-method-name": "create_or_update",
7975
9622
  request: {
7976
9623
  body: {
7977
- content: { "application/json": { schema: PutSkillRequestSchema } },
9624
+ content: { "application/json": { schema: UpdateSkillRequestSchema } },
7978
9625
  required: true
7979
9626
  }
7980
9627
  },
@@ -8102,27 +9749,27 @@ import {
8102
9749
  } from "@truefoundry/trueforge-core/agent-session";
8103
9750
  import {
8104
9751
  AgentHarnessError,
9752
+ existingSandboxIdForProvider,
8105
9753
  extractErrorLogFields as extractErrorLogFields6,
8106
9754
  isAgentInputUserMessage,
8107
9755
  isFileContentPart,
8108
9756
  McpConnectionError as McpConnectionError5,
9757
+ rawSandboxId,
8109
9758
  SandboxError as SandboxError2,
8110
- validateSandboxOwnedByTenant,
8111
9759
  VercelAILLM
8112
9760
  } from "@truefoundry/trueforge-core/core";
8113
9761
  import { HTTPException as HTTPException4 } from "hono/http-exception";
8114
9762
  import { streamSSE } from "hono/streaming";
8115
9763
 
8116
9764
  // src/routes/turnRoutes.ts
8117
- import { createRoute as createRoute12, z as z22 } from "@hono/zod-openapi";
8118
- var SESSIONS_TAG2 = "Sessions";
9765
+ import { createRoute as createRoute12, z as z24 } from "@hono/zod-openapi";
8119
9766
  var TurnIdParamsSchema = SessionIdParamsSchema.extend({
8120
- turn_id: z22.string().min(1).describe("Turn identifier.")
9767
+ turn_id: z24.string().min(1).describe("Turn identifier.")
8121
9768
  });
8122
9769
  var listTurnsRoute = createRoute12({
8123
9770
  method: "get",
8124
9771
  path: "/{session_id}/turns",
8125
- tags: [SESSIONS_TAG2],
9772
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8126
9773
  summary: "List turns in a session",
8127
9774
  description: "List turns for a session (newest first by default), token-paginated. Only the session creator (`created_by`) may list turns.",
8128
9775
  "x-fern-sdk-group-name": ["sessions"],
@@ -8154,7 +9801,7 @@ var listTurnsRoute = createRoute12({
8154
9801
  var getTurnRoute = createRoute12({
8155
9802
  method: "get",
8156
9803
  path: "/{session_id}/turns/{turn_id}",
8157
- tags: [SESSIONS_TAG2],
9804
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8158
9805
  summary: "Get a turn",
8159
9806
  description: "Fetch a single turn by ID. Only the session creator (`created_by`) may fetch it.",
8160
9807
  "x-fern-sdk-group-name": ["sessions"],
@@ -8179,8 +9826,8 @@ var getTurnRoute = createRoute12({
8179
9826
  });
8180
9827
  var downloadSandboxFileRoute = createRoute12({
8181
9828
  method: "get",
8182
- path: "/{session_id}/turns/{turn_id}/download",
8183
- tags: [SESSIONS_TAG2],
9829
+ path: "/{session_id}/turns/{turn_id}/download-sandbox-file",
9830
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8184
9831
  summary: "Download a file from the turn sandbox",
8185
9832
  description: "Download a file from the sandbox this turn ran in. Paths come from the assistant's `sandbox_artifacts` block. Only the session creator (`created_by`) may download.",
8186
9833
  "x-fern-sdk-group-name": ["sessions"],
@@ -8191,7 +9838,7 @@ var downloadSandboxFileRoute = createRoute12({
8191
9838
  },
8192
9839
  responses: {
8193
9840
  200: {
8194
- content: { "application/octet-stream": { schema: z22.string().openapi({ format: "binary" }) } },
9841
+ content: { "application/octet-stream": { schema: z24.string().openapi({ format: "binary" }) } },
8195
9842
  description: "File contents."
8196
9843
  },
8197
9844
  400: {
@@ -8200,7 +9847,7 @@ var downloadSandboxFileRoute = createRoute12({
8200
9847
  },
8201
9848
  403: {
8202
9849
  content: { "application/json": { schema: RequestErrorResponseSchema } },
8203
- description: "Caller is not the session creator, or sandbox belongs to another tenant."
9850
+ description: "Caller is not the session creator."
8204
9851
  },
8205
9852
  404: {
8206
9853
  content: { "application/json": { schema: RequestErrorResponseSchema } },
@@ -8227,7 +9874,7 @@ var downloadSandboxFileRoute = createRoute12({
8227
9874
  var listTurnEventsRoute = createRoute12({
8228
9875
  method: "get",
8229
9876
  path: "/{session_id}/turns/{turn_id}/events",
8230
- tags: [SESSIONS_TAG2],
9877
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8231
9878
  summary: "List turn events",
8232
9879
  description: "Paginated persisted events for a turn (insertion order by default). Only the session creator (`created_by`) may list events.",
8233
9880
  "x-fern-sdk-group-name": ["sessions"],
@@ -8259,7 +9906,7 @@ var listTurnEventsRoute = createRoute12({
8259
9906
  var createAndExecuteTurnRoute = createRoute12({
8260
9907
  method: "post",
8261
9908
  path: "/{session_id}/turns",
8262
- tags: [SESSIONS_TAG2],
9909
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8263
9910
  summary: "Create and execute a turn in a session",
8264
9911
  description: `Create a turn within a session and execute it.
8265
9912
  Only the session creator (\`created_by\`) may create turns.
@@ -8323,7 +9970,7 @@ Use \`previous_turn_id\` to chain to the session's last turn (defaults to \`auto
8323
9970
  var subscribeTurnRoute = createRoute12({
8324
9971
  method: "get",
8325
9972
  path: "/{session_id}/turns/{turn_id}/subscribe",
8326
- tags: [SESSIONS_TAG2],
9973
+ tags: ["Agent Sessions" /* AGENT_SESSIONS */],
8327
9974
  summary: "Subscribe to a running turn",
8328
9975
  description: "Subscribe to the live SSE stream for a turn. Only the session creator (`created_by`) may subscribe. Pass `after_sequence_number` to resume after a disconnect (exclusive \u2014 events after this sequence number are replayed).",
8329
9976
  "x-fern-sdk-group-name": ["sessions"],
@@ -8604,7 +10251,7 @@ var StreamGoneError = class extends Error {
8604
10251
  };
8605
10252
 
8606
10253
  // src/runtime/sandboxFilePath.ts
8607
- import { SandboxError, validateNoPathTraversal } from "@truefoundry/trueforge-core/core";
10254
+ import { SandboxError, validateNoPathTraversal as validateNoPathTraversal3 } from "@truefoundry/trueforge-core/core";
8608
10255
  var SandboxInvalidPathError = class extends SandboxError {
8609
10256
  statusCode = 400;
8610
10257
  constructor({ path: path7, reason }) {
@@ -8630,7 +10277,7 @@ function validateSandboxFilePath(path7) {
8630
10277
  reason: `must not have a segment longer than ${String(MAX_SEGMENT_BYTES)} bytes`
8631
10278
  });
8632
10279
  }
8633
- validateNoPathTraversal(path7);
10280
+ validateNoPathTraversal3(path7);
8634
10281
  }
8635
10282
 
8636
10283
  // src/apis/turns.ts
@@ -8667,7 +10314,8 @@ function createTurnResolver(deps) {
8667
10314
  modelProviderStore,
8668
10315
  logger,
8669
10316
  signal,
8670
- userRef
10317
+ userRef,
10318
+ sessionId
8671
10319
  } = deps;
8672
10320
  return new TurnResourceResolver({
8673
10321
  llm: async (name) => {
@@ -8707,14 +10355,19 @@ function createTurnResolver(deps) {
8707
10355
  const provider = await resolveSandboxProvider({
8708
10356
  tenant_id: TENANT_ID,
8709
10357
  store: sandboxProviderStore,
8710
- logger
10358
+ logger,
10359
+ sessionId
8711
10360
  });
8712
10361
  if (provider === void 0) {
8713
10362
  throw new HTTPException4(422, {
8714
10363
  message: "no sandbox provider configured \u2014 PUT /settings/sandbox-providers"
8715
10364
  });
8716
10365
  }
8717
- if (existingSandboxId === void 0) {
10366
+ const carriedSandboxId = existingSandboxIdForProvider({
10367
+ existingSandboxId,
10368
+ currentProviderType: provider.type
10369
+ });
10370
+ if (carriedSandboxId === void 0 && provider.type !== "local") {
8718
10371
  const status = await checkSnapshotStatus({ store: sandboxProviderStore, tenant_id: TENANT_ID, logger });
8719
10372
  if (status?.status !== "ready") {
8720
10373
  throw new HTTPException4(422, {
@@ -8732,9 +10385,8 @@ function createTurnResolver(deps) {
8732
10385
  logger,
8733
10386
  gitSkills,
8734
10387
  fileDownloadEnabled: spec.config.sandbox.file_downloads,
8735
- existingSandboxId,
8736
- tracing,
8737
- tenantName: TENANT_ID
10388
+ existingSandboxId: carriedSandboxId,
10389
+ tracing
8738
10390
  });
8739
10391
  },
8740
10392
  agent: async (agentId) => {
@@ -8884,13 +10536,13 @@ function createTurnsRouter(deps) {
8884
10536
  const provider = await resolveSandboxProvider({
8885
10537
  tenant_id: TENANT_ID,
8886
10538
  store: deps.sandboxProviderStore,
8887
- logger: deps.logger
10539
+ logger: deps.logger,
10540
+ sessionId
8888
10541
  });
8889
10542
  if (provider === void 0) {
8890
10543
  return c.json({ error: { message: "No sandbox provider configured" } }, 412);
8891
10544
  }
8892
- validateSandboxOwnedByTenant(sandboxId, TENANT_ID);
8893
- const content = await provider.downloadFile({ sandboxId, path: path7 });
10545
+ const content = await provider.downloadFile({ sandboxId: rawSandboxId(sandboxId), path: path7 });
8894
10546
  return c.body(toArrayBuffer(content), 200, {
8895
10547
  "Content-Type": "application/octet-stream",
8896
10548
  "Content-Length": String(content.byteLength),
@@ -8959,7 +10611,8 @@ function createTurnsRouter(deps) {
8959
10611
  modelProviderStore: deps.modelProviderStore,
8960
10612
  logger: deps.logger,
8961
10613
  signal: abortController.signal,
8962
- userRef: deps.resolveUserContext(c).userRef
10614
+ userRef: deps.resolveUserContext(c).userRef,
10615
+ sessionId
8963
10616
  });
8964
10617
  const title = session.record.last_turn_id ? void 0 : deriveSessionTitle(body.input);
8965
10618
  let turn;
@@ -9139,9 +10792,9 @@ function readPackageVersion() {
9139
10792
  var PACKAGE_VERSION = readPackageVersion();
9140
10793
 
9141
10794
  // src/zodErrorResponse.ts
9142
- import { z as z23 } from "@hono/zod-openapi";
10795
+ import { z as z25 } from "@hono/zod-openapi";
9143
10796
  function zodErrorResponse(c, error) {
9144
- return c.json({ error: { message: z23.prettifyError(error) } }, 400);
10797
+ return c.json({ error: { message: z25.prettifyError(error) } }, 400);
9145
10798
  }
9146
10799
  var zodValidationHook = (result, c) => {
9147
10800
  if (!result.success) {
@@ -9160,7 +10813,7 @@ function createRequestBodyLimitMiddleware(maxSize) {
9160
10813
  }
9161
10814
  function createAppErrorHandler(params) {
9162
10815
  return (error, c) => {
9163
- if (error instanceof z24.ZodError) {
10816
+ if (error instanceof z26.ZodError) {
9164
10817
  return zodErrorResponse(c, error);
9165
10818
  }
9166
10819
  if (error instanceof HTTPException5) {
@@ -9182,7 +10835,8 @@ var openApiDocConfig = {
9182
10835
  title: "TrueForge API",
9183
10836
  description: "HTTP API for the TrueForge agent server (`/api/v1`). Interactive docs are served at `/api/v1/docs` (OpenAPI JSON at `/api/v1/openapi.json`).\n\n**Authentication:** Standalone deployments (no OIDC) accept requests without credentials \u2014 middleware stamps a local default user. When OIDC is configured, protected routes require a valid `id_token` cookie or `Authorization: Bearer` ID token. There is no built-in API-key scheme; pass custom headers only if your reverse proxy or IdP layer requires them.\n\nCovers DB-backed sessions, the agent registry, settings catalogs, and model/MCP/skill/sandbox providers.",
9184
10837
  version: PACKAGE_VERSION
9185
- }
10838
+ },
10839
+ tags: OPENAPI_DOCUMENT_TAGS
9186
10840
  };
9187
10841
  function registerOpenApiBearerAuth(app) {
9188
10842
  app.openAPIRegistry.registerComponent("securitySchemes", BEARER_AUTH_SCHEME, {
@@ -9243,7 +10897,7 @@ function createServerApp(deps) {
9243
10897
  )
9244
10898
  );
9245
10899
  app.route(
9246
- "/api/v1/catalog",
10900
+ "/api/v1/catalogs",
9247
10901
  withAuth(
9248
10902
  createCatalogRouter({
9249
10903
  modelCatalog: deps.modelCatalog,
@@ -9613,7 +11267,7 @@ init_config();
9613
11267
  import { serveStatic } from "@hono/node-server/serve-static";
9614
11268
  import { every } from "hono/combine";
9615
11269
  import { compress } from "hono/compress";
9616
- import { existsSync as existsSync2 } from "fs";
11270
+ import { existsSync as existsSync5 } from "fs";
9617
11271
  import path3 from "path";
9618
11272
  var SERVER_PATH_PREFIXES = ["/api", "/healthz"];
9619
11273
  var HASHED_ASSET_PREFIX = "/assets/";
@@ -9623,7 +11277,7 @@ function isServerPath(pathname) {
9623
11277
  return SERVER_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
9624
11278
  }
9625
11279
  function mountFrontend(app, dir) {
9626
- if (!existsSync2(path3.join(dir, "index.html"))) {
11280
+ if (!existsSync5(path3.join(dir, "index.html"))) {
9627
11281
  return false;
9628
11282
  }
9629
11283
  const serveFile = serveStatic({ root: dir, precompressed: true });
@@ -9756,9 +11410,9 @@ var ActiveTurnRegistry = class {
9756
11410
  */
9757
11411
  track(input) {
9758
11412
  const key = activeTurnKey(input.sessionId, input.turnId);
9759
- const { promise: waitUntilCompleted, resolve } = Promise.withResolvers();
11413
+ const { promise: waitUntilCompleted, resolve: resolve3 } = Promise.withResolvers();
9760
11414
  const markCompleted = () => {
9761
- resolve(void 0);
11415
+ resolve3(void 0);
9762
11416
  };
9763
11417
  const run = {
9764
11418
  abortController: input.abortController,
@@ -9948,7 +11602,7 @@ try {
9948
11602
  }
9949
11603
  async function createStandalonePersistence(options) {
9950
11604
  const { sqlitePath, logger } = options;
9951
- await mkdir(path6.dirname(sqlitePath), { recursive: true });
11605
+ await mkdir5(path6.dirname(sqlitePath), { recursive: true });
9952
11606
  const [{ createSqliteDb: createSqliteDb2 }, { migrateSqliteToLatest: migrateSqliteToLatest2 }, sqliteStores] = await Promise.all([
9953
11607
  Promise.resolve().then(() => (init_client(), client_exports)),
9954
11608
  Promise.resolve().then(() => (init_migrateSqlite(), migrateSqlite_exports)),
@@ -10097,6 +11751,26 @@ try {
10097
11751
  });
10098
11752
  if (configuration2.STANDALONE) {
10099
11753
  printStandaloneStartupBanner({ version: PACKAGE_VERSION, color: shouldColorize() });
11754
+ await prepareCodeModeSocketParent({ path: configuration2.CODE_MODE_SOCKET_PARENT, logger });
11755
+ await ensureLocalSandboxRootParent(configuration2.LOCAL_SANDBOX_ROOT_PARENT);
11756
+ const { LocalSandboxProvider: LocalSandboxProvider2 } = await Promise.resolve().then(() => (init_LocalSandboxProvider(), LocalSandboxProvider_exports));
11757
+ const support = await LocalSandboxProvider2.isSupported({
11758
+ codeModeSocketParentPath: configuration2.CODE_MODE_SOCKET_PARENT
11759
+ });
11760
+ setCachedLocalSandboxSupport(support);
11761
+ if (support.supported) {
11762
+ logger.info("Local sandbox fallback is available", {
11763
+ platform: support.platform,
11764
+ shell: support.shell,
11765
+ python: support.python
11766
+ });
11767
+ } else {
11768
+ logger.warn("Local sandbox fallback is unavailable", {
11769
+ reason: support.reason,
11770
+ ...support.platform === void 0 ? {} : { platform: support.platform },
11771
+ ...support.attempts === void 0 ? {} : { attempts: support.attempts }
11772
+ });
11773
+ }
10100
11774
  } else {
10101
11775
  logger.info("TrueForge starting", { mode: "distributed" });
10102
11776
  }
@@ -10151,9 +11825,9 @@ try {
10151
11825
  logger.warn(`Drain timed out after ${String(configuration2.GRACEFUL_TIMEOUT_SECONDS)}s, exiting`);
10152
11826
  process.exit(1);
10153
11827
  }, configuration2.GRACEFUL_TIMEOUT_SECONDS * 1e3).unref();
10154
- const closed = new Promise((resolve) => {
11828
+ const closed = new Promise((resolve3) => {
10155
11829
  server.close(() => {
10156
- resolve();
11830
+ resolve3();
10157
11831
  });
10158
11832
  });
10159
11833
  await activeTurns.shutdownAndWait(CancellationReason4.Abandoned);
@@ -10165,6 +11839,11 @@ try {
10165
11839
  await redis?.close().catch((error) => {
10166
11840
  logger.warn("[Redis] Error closing client during shutdown", extractErrorLogFields9(error));
10167
11841
  });
11842
+ if (configuration2.STANDALONE) {
11843
+ await removeCodeModeSocketParent(configuration2.CODE_MODE_SOCKET_PARENT).catch((error) => {
11844
+ logger.warn("Error removing Code Mode socket parent during shutdown", extractErrorLogFields9(error));
11845
+ });
11846
+ }
10168
11847
  await destroyDb();
10169
11848
  process.exit(0);
10170
11849
  };