@truefoundry/trueforge 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +30 -0
  2. package/dist/_frontend/assets/{ConnectorSettings-H37ZFC6Z-BoDzRBt-.js → ConnectorSettings-XEO5ZQO5-BXis0tQK.js} +1 -1
  3. package/dist/_frontend/assets/ConnectorSettings-XEO5ZQO5-BXis0tQK.js.br +0 -0
  4. package/dist/_frontend/assets/ConnectorSettings-XEO5ZQO5-BXis0tQK.js.gz +0 -0
  5. package/dist/_frontend/assets/{DockLayout-KEMFRWIR-2H2_fGVk.js → DockLayout-F2KYSY4U-D8P84kCr.js} +1 -1
  6. package/dist/_frontend/assets/{DrawerLayout-ZVWCKEIS-DFGUqK6q.js → DrawerLayout-FJ7XC2FU-ChH-Qykr.js} +2 -2
  7. package/dist/_frontend/assets/DrawerLayout-FJ7XC2FU-ChH-Qykr.js.br +0 -0
  8. package/dist/_frontend/assets/DrawerLayout-FJ7XC2FU-ChH-Qykr.js.gz +0 -0
  9. package/dist/_frontend/assets/{ModelSettings-QJMYHCMD-DaR_pzAb.js → ModelSettings-2QB7LE22-CDZku4g3.js} +1 -1
  10. package/dist/_frontend/assets/ModelSettings-2QB7LE22-CDZku4g3.js.br +0 -0
  11. package/dist/_frontend/assets/ModelSettings-2QB7LE22-CDZku4g3.js.gz +0 -0
  12. package/dist/_frontend/assets/{SandboxSettings-BUBMLW7Q-ChiNe2Y8.js → SandboxSettings-QDDIPRBP-CImJLa0r.js} +1 -1
  13. package/dist/_frontend/assets/SandboxSettings-QDDIPRBP-CImJLa0r.js.br +0 -0
  14. package/dist/_frontend/assets/SandboxSettings-QDDIPRBP-CImJLa0r.js.gz +0 -0
  15. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js +2 -0
  16. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js.br +0 -0
  17. package/dist/_frontend/assets/SettingsBuilder-4NF3Y7UZ-eXXDLQ6k.js.gz +0 -0
  18. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-CetHx5EA.js +1 -0
  19. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-CetHx5EA.js.br +0 -0
  20. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-CetHx5EA.js.gz +0 -0
  21. package/dist/_frontend/assets/{SidebarLayout-F3XFXW7B-BQV8bkzL.js → SidebarLayout-KX6RSJTP-B8G4CTTb.js} +2 -2
  22. package/dist/_frontend/assets/SidebarLayout-KX6RSJTP-B8G4CTTb.js.br +0 -0
  23. package/dist/_frontend/assets/SidebarLayout-KX6RSJTP-B8G4CTTb.js.gz +0 -0
  24. package/dist/_frontend/assets/{SkillSettings-IRMGDFRG-ChKre3S8.js → SkillSettings-5EETEEDI-DbJE0Ms2.js} +1 -1
  25. package/dist/_frontend/assets/SkillSettings-5EETEEDI-DbJE0Ms2.js.br +0 -0
  26. package/dist/_frontend/assets/SkillSettings-5EETEEDI-DbJE0Ms2.js.gz +0 -0
  27. package/dist/_frontend/assets/TrueForgeUIWithRouter-IAQQTD5V-9G1rELmh.js +1 -0
  28. package/dist/_frontend/assets/{WidgetLayout-SZMABKIR-BRKArpEm.js → WidgetLayout-S6EK62TZ-BPf7T3wa.js} +1 -1
  29. package/dist/_frontend/assets/WidgetLayout-S6EK62TZ-BPf7T3wa.js.br +0 -0
  30. package/dist/_frontend/assets/WidgetLayout-S6EK62TZ-BPf7T3wa.js.gz +0 -0
  31. package/dist/_frontend/assets/chunk-62JRHF6Z-BUuLA42_.js +12 -0
  32. package/dist/_frontend/assets/chunk-62JRHF6Z-BUuLA42_.js.br +0 -0
  33. package/dist/_frontend/assets/chunk-62JRHF6Z-BUuLA42_.js.gz +0 -0
  34. package/dist/_frontend/assets/{chunk-7EEOWDLE-BIwInB6G.js → chunk-PTYEOSHT-C4gdhLwo.js} +2 -2
  35. package/dist/_frontend/assets/chunk-PTYEOSHT-C4gdhLwo.js.br +0 -0
  36. package/dist/_frontend/assets/chunk-PTYEOSHT-C4gdhLwo.js.gz +0 -0
  37. package/dist/_frontend/assets/chunk-X6U2Q7X5-DDlfUle1.js +4 -0
  38. package/dist/_frontend/assets/chunk-X6U2Q7X5-DDlfUle1.js.br +0 -0
  39. package/dist/_frontend/assets/chunk-X6U2Q7X5-DDlfUle1.js.gz +0 -0
  40. package/dist/_frontend/assets/{cssMode-Bb1lR8Ti.js → cssMode-C1whwlDW.js} +1 -1
  41. package/dist/_frontend/assets/cssMode-C1whwlDW.js.br +0 -0
  42. package/dist/_frontend/assets/cssMode-C1whwlDW.js.gz +0 -0
  43. package/dist/_frontend/assets/{freemarker2-BrrF7mKG.js → freemarker2-CaMIS9bY.js} +1 -1
  44. package/dist/_frontend/assets/freemarker2-CaMIS9bY.js.br +0 -0
  45. package/dist/_frontend/assets/freemarker2-CaMIS9bY.js.gz +0 -0
  46. package/dist/_frontend/assets/{handlebars-WQ7HMT1b.js → handlebars-Donx2d9H.js} +1 -1
  47. package/dist/_frontend/assets/handlebars-Donx2d9H.js.br +0 -0
  48. package/dist/_frontend/assets/handlebars-Donx2d9H.js.gz +0 -0
  49. package/dist/_frontend/assets/{html-CoOPnhCb.js → html-CtI8kZ6e.js} +1 -1
  50. package/dist/_frontend/assets/html-CtI8kZ6e.js.br +0 -0
  51. package/dist/_frontend/assets/html-CtI8kZ6e.js.gz +0 -0
  52. package/dist/_frontend/assets/{htmlMode-BW7taYty.js → htmlMode-B6ky8VkF.js} +1 -1
  53. package/dist/_frontend/assets/htmlMode-B6ky8VkF.js.br +0 -0
  54. package/dist/_frontend/assets/htmlMode-B6ky8VkF.js.gz +0 -0
  55. package/dist/_frontend/assets/{index-DFQqb6R1.js → index-DFmgzNuj.js} +3 -3
  56. package/dist/_frontend/assets/index-DFmgzNuj.js.br +0 -0
  57. package/dist/_frontend/assets/index-DFmgzNuj.js.gz +0 -0
  58. package/dist/_frontend/assets/index-DWr7ad72.js +859 -0
  59. package/dist/_frontend/assets/index-DWr7ad72.js.br +0 -0
  60. package/dist/_frontend/assets/index-DWr7ad72.js.gz +0 -0
  61. package/dist/_frontend/assets/{javascript-CPINtbIt.js → javascript-BDngdIws.js} +1 -1
  62. package/dist/_frontend/assets/{jsonMode-C8qDzOfb.js → jsonMode-B7OogXWW.js} +1 -1
  63. package/dist/_frontend/assets/jsonMode-B7OogXWW.js.br +0 -0
  64. package/dist/_frontend/assets/jsonMode-B7OogXWW.js.gz +0 -0
  65. package/dist/_frontend/assets/{liquid-zGC9H1Dt.js → liquid-D_8RkuUW.js} +1 -1
  66. package/dist/_frontend/assets/liquid-D_8RkuUW.js.br +0 -0
  67. package/dist/_frontend/assets/liquid-D_8RkuUW.js.gz +0 -0
  68. package/dist/_frontend/assets/{lspLanguageFeatures-B6VPH2Sv.js → lspLanguageFeatures-DJf8_W2N.js} +1 -1
  69. package/dist/_frontend/assets/lspLanguageFeatures-DJf8_W2N.js.br +0 -0
  70. package/dist/_frontend/assets/lspLanguageFeatures-DJf8_W2N.js.gz +0 -0
  71. package/dist/_frontend/assets/{mdx-BrQrGCP9.js → mdx-HcpZSZ2w.js} +1 -1
  72. package/dist/_frontend/assets/mdx-HcpZSZ2w.js.br +0 -0
  73. package/dist/_frontend/assets/mdx-HcpZSZ2w.js.gz +0 -0
  74. package/dist/_frontend/assets/{python-zKGpYLwR.js → python-CPiT1vB4.js} +1 -1
  75. package/dist/_frontend/assets/python-CPiT1vB4.js.br +0 -0
  76. package/dist/_frontend/assets/python-CPiT1vB4.js.gz +0 -0
  77. package/dist/_frontend/assets/{razor-BJ38lYsd.js → razor-oizHS-vq.js} +1 -1
  78. package/dist/_frontend/assets/razor-oizHS-vq.js.br +0 -0
  79. package/dist/_frontend/assets/razor-oizHS-vq.js.gz +0 -0
  80. package/dist/_frontend/assets/{tsMode-dPLqGMg8.js → tsMode-n5kkpKJX.js} +1 -1
  81. package/dist/_frontend/assets/tsMode-n5kkpKJX.js.br +0 -0
  82. package/dist/_frontend/assets/tsMode-n5kkpKJX.js.gz +0 -0
  83. package/dist/_frontend/assets/{typescript-BJlivWry.js → typescript-BfXupYGq.js} +1 -1
  84. package/dist/_frontend/assets/typescript-BfXupYGq.js.br +0 -0
  85. package/dist/_frontend/assets/typescript-BfXupYGq.js.gz +0 -0
  86. package/dist/_frontend/assets/{workers-fMwav4jB.js → workers-DCX6qMOc.js} +1 -1
  87. package/dist/_frontend/assets/workers-DCX6qMOc.js.br +0 -0
  88. package/dist/_frontend/assets/workers-DCX6qMOc.js.gz +0 -0
  89. package/dist/_frontend/assets/{xml-DZW470wi.js → xml-MX-qfsGl.js} +1 -1
  90. package/dist/_frontend/assets/xml-MX-qfsGl.js.br +0 -0
  91. package/dist/_frontend/assets/xml-MX-qfsGl.js.gz +0 -0
  92. package/dist/_frontend/assets/{yaml-Bs1DumYp.js → yaml-DnKyyO9e.js} +1 -1
  93. package/dist/_frontend/assets/yaml-DnKyyO9e.js.br +0 -0
  94. package/dist/_frontend/assets/yaml-DnKyyO9e.js.gz +0 -0
  95. package/dist/_frontend/index.html +1 -1
  96. package/dist/_frontend/index.html.br +0 -0
  97. package/dist/_frontend/index.html.gz +0 -0
  98. package/dist/cli.js +23 -1
  99. package/dist/cli.js.map +1 -1
  100. package/dist/main.js +525 -178
  101. package/dist/main.js.map +1 -1
  102. package/package.json +11 -7
  103. package/dist/_frontend/assets/ConnectorSettings-H37ZFC6Z-BoDzRBt-.js.br +0 -0
  104. package/dist/_frontend/assets/ConnectorSettings-H37ZFC6Z-BoDzRBt-.js.gz +0 -0
  105. package/dist/_frontend/assets/DrawerLayout-ZVWCKEIS-DFGUqK6q.js.br +0 -0
  106. package/dist/_frontend/assets/DrawerLayout-ZVWCKEIS-DFGUqK6q.js.gz +0 -0
  107. package/dist/_frontend/assets/ModelSettings-QJMYHCMD-DaR_pzAb.js.br +0 -0
  108. package/dist/_frontend/assets/ModelSettings-QJMYHCMD-DaR_pzAb.js.gz +0 -0
  109. package/dist/_frontend/assets/SandboxSettings-BUBMLW7Q-ChiNe2Y8.js.br +0 -0
  110. package/dist/_frontend/assets/SandboxSettings-BUBMLW7Q-ChiNe2Y8.js.gz +0 -0
  111. package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js +0 -2
  112. package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js.br +0 -0
  113. package/dist/_frontend/assets/SettingsBuilder-26XSGIHK-DmgjXL0m.js.gz +0 -0
  114. package/dist/_frontend/assets/SidebarLayout-F3XFXW7B-BQV8bkzL.js.br +0 -0
  115. package/dist/_frontend/assets/SidebarLayout-F3XFXW7B-BQV8bkzL.js.gz +0 -0
  116. package/dist/_frontend/assets/SkillSettings-IRMGDFRG-ChKre3S8.js.br +0 -0
  117. package/dist/_frontend/assets/SkillSettings-IRMGDFRG-ChKre3S8.js.gz +0 -0
  118. package/dist/_frontend/assets/WidgetLayout-SZMABKIR-BRKArpEm.js.br +0 -0
  119. package/dist/_frontend/assets/WidgetLayout-SZMABKIR-BRKArpEm.js.gz +0 -0
  120. package/dist/_frontend/assets/chunk-7EEOWDLE-BIwInB6G.js.br +0 -0
  121. package/dist/_frontend/assets/chunk-7EEOWDLE-BIwInB6G.js.gz +0 -0
  122. package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js +0 -1
  123. package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js.br +0 -0
  124. package/dist/_frontend/assets/chunk-LRQHHZDX-eb14Z2nA.js.gz +0 -0
  125. package/dist/_frontend/assets/cssMode-Bb1lR8Ti.js.br +0 -0
  126. package/dist/_frontend/assets/cssMode-Bb1lR8Ti.js.gz +0 -0
  127. package/dist/_frontend/assets/freemarker2-BrrF7mKG.js.br +0 -0
  128. package/dist/_frontend/assets/freemarker2-BrrF7mKG.js.gz +0 -0
  129. package/dist/_frontend/assets/handlebars-WQ7HMT1b.js.br +0 -0
  130. package/dist/_frontend/assets/handlebars-WQ7HMT1b.js.gz +0 -0
  131. package/dist/_frontend/assets/html-CoOPnhCb.js.br +0 -0
  132. package/dist/_frontend/assets/html-CoOPnhCb.js.gz +0 -0
  133. package/dist/_frontend/assets/htmlMode-BW7taYty.js.br +0 -0
  134. package/dist/_frontend/assets/htmlMode-BW7taYty.js.gz +0 -0
  135. package/dist/_frontend/assets/index-ChCGltYc.js +0 -857
  136. package/dist/_frontend/assets/index-ChCGltYc.js.br +0 -0
  137. package/dist/_frontend/assets/index-ChCGltYc.js.gz +0 -0
  138. package/dist/_frontend/assets/index-DFQqb6R1.js.br +0 -0
  139. package/dist/_frontend/assets/index-DFQqb6R1.js.gz +0 -0
  140. package/dist/_frontend/assets/jsonMode-C8qDzOfb.js.br +0 -0
  141. package/dist/_frontend/assets/jsonMode-C8qDzOfb.js.gz +0 -0
  142. package/dist/_frontend/assets/liquid-zGC9H1Dt.js.br +0 -0
  143. package/dist/_frontend/assets/liquid-zGC9H1Dt.js.gz +0 -0
  144. package/dist/_frontend/assets/lspLanguageFeatures-B6VPH2Sv.js.br +0 -0
  145. package/dist/_frontend/assets/lspLanguageFeatures-B6VPH2Sv.js.gz +0 -0
  146. package/dist/_frontend/assets/mdx-BrQrGCP9.js.br +0 -0
  147. package/dist/_frontend/assets/mdx-BrQrGCP9.js.gz +0 -0
  148. package/dist/_frontend/assets/python-zKGpYLwR.js.br +0 -0
  149. package/dist/_frontend/assets/python-zKGpYLwR.js.gz +0 -0
  150. package/dist/_frontend/assets/razor-BJ38lYsd.js.br +0 -0
  151. package/dist/_frontend/assets/razor-BJ38lYsd.js.gz +0 -0
  152. package/dist/_frontend/assets/tsMode-dPLqGMg8.js.br +0 -0
  153. package/dist/_frontend/assets/tsMode-dPLqGMg8.js.gz +0 -0
  154. package/dist/_frontend/assets/typescript-BJlivWry.js.br +0 -0
  155. package/dist/_frontend/assets/typescript-BJlivWry.js.gz +0 -0
  156. package/dist/_frontend/assets/workers-fMwav4jB.js.br +0 -0
  157. package/dist/_frontend/assets/workers-fMwav4jB.js.gz +0 -0
  158. package/dist/_frontend/assets/xml-DZW470wi.js.br +0 -0
  159. package/dist/_frontend/assets/xml-DZW470wi.js.gz +0 -0
  160. package/dist/_frontend/assets/yaml-Bs1DumYp.js.br +0 -0
  161. package/dist/_frontend/assets/yaml-Bs1DumYp.js.gz +0 -0
package/dist/main.js CHANGED
@@ -92,8 +92,12 @@ function parseBoolean(options) {
92
92
  return defaultValue;
93
93
  }
94
94
  const value = raw.trim().toLowerCase();
95
- if (value === "true") return true;
96
- if (value === "false") return false;
95
+ if (value === "true") {
96
+ return true;
97
+ }
98
+ if (value === "false") {
99
+ return false;
100
+ }
97
101
  throw new Error(`Environment variable ${envKey} must be "true" or "false", got "${raw}"`);
98
102
  }
99
103
  function resolveDefaultFrontendDir() {
@@ -192,11 +196,13 @@ function getPublicBaseUrl(config = configuration) {
192
196
  }
193
197
  return config.PUBLIC_BASE_URL;
194
198
  }
195
- var DEFAULT_PORT, PACKAGE_ROOT, LOCAL_EXECUTOR_ID, ENV_PATHS_APP_NAME, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_HOST, DEFAULT_POSTGRES_PORT, DEFAULT_REDIS_URL, DEFAULT_OIDC_USER_REFERENCE_CLAIM, DEFAULT_OIDC_USER_ROLE_CLAIM, DEFAULT_OIDC_ADMIN_ROLE_VALUE, DEFAULT_OIDC_SCOPES, serverExecutionTimeoutSeconds, standalone, port, shared, configuration, config_default;
199
+ var DEFAULT_PORT, DEFAULT_HOST, DEFAULT_MAX_REQUEST_BODY_BYTES, PACKAGE_ROOT, LOCAL_EXECUTOR_ID, ENV_PATHS_APP_NAME, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_HOST, DEFAULT_POSTGRES_PORT, DEFAULT_REDIS_URL, DEFAULT_OIDC_USER_REFERENCE_CLAIM, DEFAULT_OIDC_USER_ROLE_CLAIM, DEFAULT_OIDC_ADMIN_ROLE_VALUE, DEFAULT_OIDC_SCOPES, serverExecutionTimeoutSeconds, standalone, port, host, shared, configuration, config_default;
196
200
  var init_config = __esm({
197
201
  "src/config.ts"() {
198
202
  "use strict";
199
203
  DEFAULT_PORT = 8790;
204
+ DEFAULT_HOST = "localhost";
205
+ DEFAULT_MAX_REQUEST_BODY_BYTES = 30 * 1024 * 1024;
200
206
  PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
201
207
  LOCAL_EXECUTOR_ID = "local";
202
208
  ENV_PATHS_APP_NAME = "trueforge";
@@ -221,10 +227,12 @@ var init_config = __esm({
221
227
  defaultValue: true
222
228
  });
223
229
  port = parsePort(getEnv("PORT"));
230
+ host = getEnv("HOST", { defaultValue: DEFAULT_HOST }) ?? DEFAULT_HOST;
224
231
  shared = {
225
232
  LOG_LEVEL: getEnv("LOG_LEVEL", { defaultValue: "info" }) ?? "info",
226
233
  NODE_ENV: getEnv("NODE_ENV"),
227
234
  PORT: port,
235
+ HOST: host,
228
236
  EXECUTOR_ID: standalone ? LOCAL_EXECUTOR_ID : randomAlphanumeric(6),
229
237
  MODEL_CATALOG_PATH: resolveOptionalPathEnv("MODEL_CATALOG_PATH"),
230
238
  MCP_CATALOG_PATH: resolveOptionalPathEnv("MCP_CATALOG_PATH"),
@@ -247,6 +255,11 @@ var init_config = __esm({
247
255
  raw: getEnv("SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD"),
248
256
  defaultValue: 20971520
249
257
  }),
258
+ MAX_REQUEST_BODY_BYTES: parsePositiveInt({
259
+ envKey: "MAX_REQUEST_BODY_BYTES",
260
+ raw: getEnv("MAX_REQUEST_BODY_BYTES"),
261
+ defaultValue: DEFAULT_MAX_REQUEST_BODY_BYTES
262
+ }),
250
263
  GRACEFUL_TIMEOUT_SECONDS: parsePositiveInt({
251
264
  envKey: "GRACEFUL_TIMEOUT_SECONDS",
252
265
  raw: getEnv("GRACEFUL_TIMEOUT_SECONDS"),
@@ -576,15 +589,15 @@ __export(migrateSqlite_exports, {
576
589
  migrateSqliteToLatest: () => migrateSqliteToLatest
577
590
  });
578
591
  import { promises as fs2 } from "fs";
579
- import path3 from "path";
592
+ import path4 from "path";
580
593
  import { FileMigrationProvider, Migrator } from "kysely/migration";
581
594
  async function migrateSqliteToLatest(db) {
582
595
  const migrator = new Migrator({
583
596
  db,
584
597
  provider: new FileMigrationProvider({
585
598
  fs: fs2,
586
- path: path3,
587
- migrationFolder: path3.join(import.meta.dirname, "sqlite", "migrations")
599
+ path: path4,
600
+ migrationFolder: path4.join(import.meta.dirname, "sqlite", "migrations")
588
601
  })
589
602
  });
590
603
  const { error, results } = await migrator.migrateToLatest();
@@ -613,8 +626,8 @@ import { sql } from "kysely";
613
626
  function jsonbBind(value) {
614
627
  return sql`jsonb(${JSON.stringify(value)})`;
615
628
  }
616
- function jsonbSet(column, path6, value) {
617
- return sql`jsonb_set(${column}, ${path6}, ${jsonbBind(value)})`;
629
+ function jsonbSet(column, path7, value) {
630
+ return sql`jsonb_set(${column}, ${path7}, ${jsonbBind(value)})`;
618
631
  }
619
632
  function jsonText(column) {
620
633
  return sql`json(${column})`;
@@ -642,9 +655,7 @@ var init_sqlExpressions2 = __esm({
642
655
  });
643
656
 
644
657
  // src/db/sqlite/session-store/queries/turns.ts
645
- import {
646
- CancellationReason as CancellationReason4
647
- } from "@truefoundry/trueforge-core/agent-session/schemas/turn";
658
+ import "@truefoundry/trueforge-core/agent-session/schemas/turn";
648
659
  import { assertCreateTurnThreadDelta } from "@truefoundry/trueforge-core/agent-session/store/assertCreateTurnThreadDelta";
649
660
  import {
650
661
  PreviousTurnRunningError,
@@ -653,7 +664,7 @@ import {
653
664
  SessionStoreInvariantError as SessionStoreInvariantError2,
654
665
  SessionStoreNotFoundError as SessionStoreNotFoundError3,
655
666
  TurnAlreadyExistsError,
656
- TurnNotFoundError,
667
+ TurnNotFoundError as TurnNotFoundError2,
657
668
  TurnNotRunningError
658
669
  } from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
659
670
  import { getEmptyCurrentContextUsage } from "@truefoundry/trueforge-core/core/runtime/contextUsage";
@@ -687,14 +698,14 @@ async function loadTurnState(db, keys) {
687
698
  async function classifyTurnFenceWriteFailure(db, keys) {
688
699
  const state = await loadTurnState(db, keys);
689
700
  if (!state) {
690
- throw new TurnNotFoundError(keys.turn_id);
701
+ throw new TurnNotFoundError2(keys.turn_id);
691
702
  }
692
703
  throw new TurnNotRunningError(keys.turn_id, terminalTurnState(state, keys.turn_id));
693
704
  }
694
705
  async function classifyTurnThreadWriteFailure(db, keys, thread_id) {
695
706
  const state = await loadTurnState(db, keys);
696
707
  if (!state) {
697
- throw new TurnNotFoundError(keys.turn_id);
708
+ throw new TurnNotFoundError2(keys.turn_id);
698
709
  }
699
710
  if (state.status !== "running") {
700
711
  throw new TurnNotRunningError(keys.turn_id, terminalTurnState(state, keys.turn_id));
@@ -704,7 +715,7 @@ async function classifyTurnThreadWriteFailure(db, keys, thread_id) {
704
715
  async function assertTurnRunning(db, keys) {
705
716
  const state = await loadTurnState(db, keys);
706
717
  if (!state) {
707
- throw new TurnNotFoundError(keys.turn_id);
718
+ throw new TurnNotFoundError2(keys.turn_id);
708
719
  }
709
720
  if (state.status !== "running") {
710
721
  throw new TurnNotRunningError(keys.turn_id, terminalTurnState(state, keys.turn_id));
@@ -724,7 +735,9 @@ async function assembleTurnRecord(db, args) {
724
735
  "created_at",
725
736
  "updated_at"
726
737
  ]).where("session_id", "=", args.session_id).where("turn_id", "=", args.turn_id).executeTakeFirst();
727
- if (!turn) return void 0;
738
+ if (!turn) {
739
+ return void 0;
740
+ }
728
741
  const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(
729
742
  "turn_thread_context as ttc",
730
743
  (join) => join.on("ttc.session_id", "=", args.session_id).on("ttc.turn_id", "=", args.turn_id).onRef("ttc.thread_id", "=", "tt.thread_id")
@@ -806,7 +819,9 @@ async function createTurn(db, input) {
806
819
  try {
807
820
  await db.transaction().execute(async (trx) => {
808
821
  const locked = await trx.selectFrom("session").select(["last_turn_id"]).where("session_id", "=", input.session_id).executeTakeFirst();
809
- if (!locked) throw new SessionNotFoundError(input.session_id);
822
+ if (!locked) {
823
+ throw new SessionNotFoundError(input.session_id);
824
+ }
810
825
  let sessionUpdate = trx.updateTable("session").set({
811
826
  last_turn_id: input.turn.turn_id,
812
827
  updated_at: nowIso(),
@@ -845,7 +860,9 @@ async function createTurn(db, input) {
845
860
  }
846
861
  prevCheckpoint = first.turn_checkpoint;
847
862
  for (const row of prevRows) {
848
- if (row.thread_id === null) continue;
863
+ if (row.thread_id === null) {
864
+ continue;
865
+ }
849
866
  if (row.thread_checkpoint === null || row.current_context_usage === null) {
850
867
  throw new SessionStoreInvariantError2(`previous turn_thread row for ${row.thread_id} is incomplete`);
851
868
  }
@@ -997,7 +1014,9 @@ async function createTurn(db, input) {
997
1014
  }
998
1015
  const capabilityStateRows = [];
999
1016
  for (const capability of input.capability_states) {
1000
- if (capability.capability_state === null) continue;
1017
+ if (capability.capability_state === null) {
1018
+ continue;
1019
+ }
1001
1020
  for (const [key, state] of Object.entries(capability.capability_state)) {
1002
1021
  capabilityStateRows.push({
1003
1022
  session_id: input.session_id,
@@ -1014,8 +1033,12 @@ async function createTurn(db, input) {
1014
1033
  }
1015
1034
  });
1016
1035
  } catch (err) {
1017
- if (err instanceof SessionStoreNotFoundError3 || err instanceof SessionStoreConflictError3) throw err;
1018
- if (isUniqueViolation(err)) throw new TurnAlreadyExistsError(input.turn.turn_id, { cause: err });
1036
+ if (err instanceof SessionStoreNotFoundError3 || err instanceof SessionStoreConflictError3) {
1037
+ throw err;
1038
+ }
1039
+ if (isUniqueViolation(err)) {
1040
+ throw new TurnAlreadyExistsError(input.turn.turn_id, { cause: err });
1041
+ }
1019
1042
  throw err;
1020
1043
  }
1021
1044
  }
@@ -1023,7 +1046,7 @@ async function freezeAndGetTurn(db, input) {
1023
1046
  return await db.transaction().execute(async (trx) => {
1024
1047
  const cancelledState = {
1025
1048
  status: "cancelled",
1026
- reason: CancellationReason4.CancelledForNextTurn,
1049
+ reason: input.reason,
1027
1050
  completed_at: nowIso()
1028
1051
  };
1029
1052
  const updateResult = await trx.updateTable("turn").set({
@@ -1040,7 +1063,9 @@ async function freezeAndGetTurn(db, input) {
1040
1063
  }).execute();
1041
1064
  }
1042
1065
  const record = await assembleTurnRecord(trx, input);
1043
- if (!record) throw new TurnNotFoundError(input.turn_id);
1066
+ if (!record) {
1067
+ throw new TurnNotFoundError2(input.turn_id);
1068
+ }
1044
1069
  return record;
1045
1070
  });
1046
1071
  }
@@ -1088,7 +1113,9 @@ async function updateTurnState(db, input) {
1088
1113
  const numUpdated = Number(result.numUpdatedRows);
1089
1114
  if (numUpdated === 0) {
1090
1115
  const existing = await trx.selectFrom("turn").select([jsonText(sql2.ref("state")).as("state")]).where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).executeTakeFirst();
1091
- if (!existing) throw new TurnNotFoundError(input.turn_id);
1116
+ if (!existing) {
1117
+ throw new TurnNotFoundError2(input.turn_id);
1118
+ }
1092
1119
  throw new TurnNotRunningError(input.turn_id, terminalTurnState(existing.state, input.turn_id));
1093
1120
  }
1094
1121
  await trx.insertInto("session_event").values({
@@ -1153,11 +1180,13 @@ import {
1153
1180
  } from "@truefoundry/trueforge-core/agent-session/store/SessionEventPageToken";
1154
1181
  import {
1155
1182
  SessionNotFoundError as SessionNotFoundError2,
1156
- TurnNotFoundError as TurnNotFoundError2
1183
+ TurnNotFoundError as TurnNotFoundError3
1157
1184
  } from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
1158
1185
  import { sql as sql4 } from "kysely";
1159
1186
  async function appendToEvents(db, input) {
1160
- if (input.events.length === 0) return;
1187
+ if (input.events.length === 0) {
1188
+ return;
1189
+ }
1161
1190
  const keys = {
1162
1191
  session_id: input.session_id,
1163
1192
  turn_id: input.turn_id
@@ -1186,7 +1215,7 @@ async function listTurnEvents(db, input) {
1186
1215
  (join) => join.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
1187
1216
  ).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();
1188
1217
  if (rows.length === 0) {
1189
- throw new TurnNotFoundError2(input.turn_id);
1218
+ throw new TurnNotFoundError3(input.turn_id);
1190
1219
  }
1191
1220
  const events = [];
1192
1221
  for (const row of rows) {
@@ -1202,11 +1231,17 @@ async function resolveAncestorChain(db, sessionId, anchor) {
1202
1231
  let oldestId = chain[0];
1203
1232
  while (oldestId && oldestId !== anchor.turn_id) {
1204
1233
  const oldest = await db.selectFrom("turn").select([jsonText(sql4.ref("ancestor_ids")).as("ancestor_ids")]).where("session_id", "=", sessionId).where("turn_id", "=", oldestId).executeTakeFirst();
1205
- if (!oldest) break;
1234
+ if (!oldest) {
1235
+ break;
1236
+ }
1206
1237
  const older = oldest.ancestor_ids.filter((id) => !seen.has(id));
1207
- if (older.length === 0) break;
1238
+ if (older.length === 0) {
1239
+ break;
1240
+ }
1208
1241
  chain.unshift(...older);
1209
- for (const id of older) seen.add(id);
1242
+ for (const id of older) {
1243
+ seen.add(id);
1244
+ }
1210
1245
  oldestId = older[0];
1211
1246
  }
1212
1247
  return chain;
@@ -1228,7 +1263,7 @@ async function listSessionEvents(db, input) {
1228
1263
  };
1229
1264
  const anchor = await db.selectFrom("turn").select(["turn_id", jsonText(sql4.ref("ancestor_ids")).as("ancestor_ids")]).where("session_id", "=", input.session_id).where("turn_id", "=", cursor.last_turn_id).executeTakeFirst();
1230
1265
  if (!anchor) {
1231
- throw new TurnNotFoundError2(cursor.last_turn_id);
1266
+ throw new TurnNotFoundError3(cursor.last_turn_id);
1232
1267
  }
1233
1268
  const chainIds = await resolveAncestorChain(db, input.session_id, {
1234
1269
  turn_id: anchor.turn_id,
@@ -2067,6 +2102,9 @@ async function consumePendingAuthorization(db, params) {
2067
2102
  ...fromStoredOAuthPendingAuthorizationData(row.auth_data)
2068
2103
  };
2069
2104
  }
2105
+ async function deletePendingAuthorizationsForServer(db, params) {
2106
+ await db.deleteFrom("oauth_pending_authorization").where("oauth_server_id", "=", params.id).execute();
2107
+ }
2070
2108
  var init_pendingAuthorization = __esm({
2071
2109
  "src/db/sqlite/token-store/queries/pendingAuthorization.ts"() {
2072
2110
  "use strict";
@@ -2104,6 +2142,9 @@ async function getTokens(db, params) {
2104
2142
  async function deleteToken(db, params) {
2105
2143
  await db.deleteFrom("oauth_token").where("oauth_server_id", "=", params.id).where("user_id", "=", params.userRef).execute();
2106
2144
  }
2145
+ async function deleteTokensForServer(db, params) {
2146
+ await db.deleteFrom("oauth_token").where("oauth_server_id", "=", params.id).execute();
2147
+ }
2107
2148
  var init_token = __esm({
2108
2149
  "src/db/sqlite/token-store/queries/token.ts"() {
2109
2150
  "use strict";
@@ -2152,6 +2193,12 @@ var init_SqliteOAuthTokenStore = __esm({
2152
2193
  deleteToken(params, transaction) {
2153
2194
  return deleteToken(transaction ?? this.db, params);
2154
2195
  }
2196
+ deleteTokensForServer(params, transaction) {
2197
+ return deleteTokensForServer(transaction ?? this.db, params);
2198
+ }
2199
+ deletePendingAuthorizationsForServer(params, transaction) {
2200
+ return deletePendingAuthorizationsForServer(transaction ?? this.db, params);
2201
+ }
2155
2202
  };
2156
2203
  }
2157
2204
  });
@@ -2448,15 +2495,15 @@ __export(migratePostgres_exports, {
2448
2495
  migrateToLatest: () => migrateToLatest
2449
2496
  });
2450
2497
  import { promises as fs3 } from "fs";
2451
- import path4 from "path";
2498
+ import path5 from "path";
2452
2499
  import { FileMigrationProvider as FileMigrationProvider2, Migrator as Migrator2 } from "kysely/migration";
2453
2500
  async function migrateToLatest(db) {
2454
2501
  const migrator = new Migrator2({
2455
2502
  db,
2456
2503
  provider: new FileMigrationProvider2({
2457
2504
  fs: fs3,
2458
- path: path4,
2459
- migrationFolder: path4.join(import.meta.dirname, "postgres", "migrations")
2505
+ path: path5,
2506
+ migrationFolder: path5.join(import.meta.dirname, "postgres", "migrations")
2460
2507
  })
2461
2508
  });
2462
2509
  const { error, results } = await migrator.migrateToLatest();
@@ -2485,12 +2532,12 @@ var redis_exports = {};
2485
2532
  __export(redis_exports, {
2486
2533
  connectRedis: () => connectRedis
2487
2534
  });
2488
- import { extractErrorLogFields as extractErrorLogFields7 } from "@truefoundry/trueforge-core/core";
2535
+ import { extractErrorLogFields as extractErrorLogFields8 } from "@truefoundry/trueforge-core/core";
2489
2536
  import { createClient } from "redis";
2490
2537
  async function connectRedis(input) {
2491
2538
  const client = createClient({ url: input.url });
2492
2539
  client.on("error", (error) => {
2493
- input.logger.error("[Redis] Client error", extractErrorLogFields7(error));
2540
+ input.logger.error("[Redis] Client error", extractErrorLogFields8(error));
2494
2541
  });
2495
2542
  await client.connect();
2496
2543
  return client;
@@ -2506,8 +2553,8 @@ import { sql as sql9 } from "kysely";
2506
2553
  function json(value) {
2507
2554
  return sql9`${JSON.stringify(value)}::jsonb`;
2508
2555
  }
2509
- function jsonbSet2(target, path6, newValue) {
2510
- return sql9`jsonb_set(${target}, ${path6}, ${newValue})`;
2556
+ function jsonbSet2(target, path7, newValue) {
2557
+ return sql9`jsonb_set(${target}, ${path7}, ${newValue})`;
2511
2558
  }
2512
2559
  function now() {
2513
2560
  return sql9`now()`;
@@ -2552,9 +2599,7 @@ var init_sqlExpressions4 = __esm({
2552
2599
  });
2553
2600
 
2554
2601
  // src/db/postgres/session-store/queries/turns.ts
2555
- import {
2556
- CancellationReason as CancellationReason5
2557
- } from "@truefoundry/trueforge-core/agent-session/schemas/turn";
2602
+ import "@truefoundry/trueforge-core/agent-session/schemas/turn";
2558
2603
  import { assertCreateTurnThreadDelta as assertCreateTurnThreadDelta2 } from "@truefoundry/trueforge-core/agent-session/store/assertCreateTurnThreadDelta";
2559
2604
  import {
2560
2605
  PreviousTurnRunningError as PreviousTurnRunningError2,
@@ -2563,7 +2608,7 @@ import {
2563
2608
  SessionStoreInvariantError as SessionStoreInvariantError4,
2564
2609
  SessionStoreNotFoundError as SessionStoreNotFoundError4,
2565
2610
  TurnAlreadyExistsError as TurnAlreadyExistsError2,
2566
- TurnNotFoundError as TurnNotFoundError3,
2611
+ TurnNotFoundError as TurnNotFoundError4,
2567
2612
  TurnNotRunningError as TurnNotRunningError2
2568
2613
  } from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
2569
2614
  import { getEmptyCurrentContextUsage as getEmptyCurrentContextUsage2 } from "@truefoundry/trueforge-core/core/runtime/contextUsage";
@@ -2596,14 +2641,14 @@ function turnRunningFence(db, keys) {
2596
2641
  async function classifyTurnFenceWriteFailure2(db, keys) {
2597
2642
  const row = await db.selectFrom("turn").select("state").where("session_id", "=", keys.session_id).where("turn_id", "=", keys.turn_id).executeTakeFirst();
2598
2643
  if (!row) {
2599
- throw new TurnNotFoundError3(keys.turn_id);
2644
+ throw new TurnNotFoundError4(keys.turn_id);
2600
2645
  }
2601
2646
  throw new TurnNotRunningError2(keys.turn_id, terminalTurnState2(row.state, keys.turn_id));
2602
2647
  }
2603
2648
  async function classifyTurnThreadWriteFailure2(db, keys, thread_id) {
2604
2649
  const row = await db.selectFrom("turn").select("state").where("session_id", "=", keys.session_id).where("turn_id", "=", keys.turn_id).executeTakeFirst();
2605
2650
  if (!row) {
2606
- throw new TurnNotFoundError3(keys.turn_id);
2651
+ throw new TurnNotFoundError4(keys.turn_id);
2607
2652
  }
2608
2653
  if (row.state.status !== "running") {
2609
2654
  throw new TurnNotRunningError2(keys.turn_id, terminalTurnState2(row.state, keys.turn_id));
@@ -2613,7 +2658,7 @@ async function classifyTurnThreadWriteFailure2(db, keys, thread_id) {
2613
2658
  async function assertTurnRunning2(db, keys) {
2614
2659
  const row = await db.selectFrom("turn").select("state").where("session_id", "=", keys.session_id).where("turn_id", "=", keys.turn_id).forShare().executeTakeFirst();
2615
2660
  if (!row) {
2616
- throw new TurnNotFoundError3(keys.turn_id);
2661
+ throw new TurnNotFoundError4(keys.turn_id);
2617
2662
  }
2618
2663
  if (row.state.status !== "running") {
2619
2664
  throw new TurnNotRunningError2(keys.turn_id, terminalTurnState2(row.state, keys.turn_id));
@@ -2621,7 +2666,9 @@ async function assertTurnRunning2(db, keys) {
2621
2666
  }
2622
2667
  async function assembleTurnRecord2(db, args) {
2623
2668
  const turn = await db.selectFrom("turn").selectAll().where("session_id", "=", args.session_id).where("turn_id", "=", args.turn_id).executeTakeFirst();
2624
- if (!turn) return void 0;
2669
+ if (!turn) {
2670
+ return void 0;
2671
+ }
2625
2672
  const contextRows = await db.selectFrom("turn_thread as tt").leftJoin(lateralUnnestBigintArrayWithOrdinality(sql11`tt.context_ids`, "c"), (join) => join.onTrue()).leftJoin(
2626
2673
  "thread_context_log as l",
2627
2674
  (join) => join.on("l.session_id", "=", args.session_id).onRef("l.thread_id", "=", "tt.thread_id").onRef("l.append_id", "=", "c.append_id")
@@ -2690,7 +2737,9 @@ async function createTurn2(db, input) {
2690
2737
  try {
2691
2738
  await db.transaction().execute(async (trx) => {
2692
2739
  const locked = await trx.selectFrom("session").select(["last_turn_id"]).where("session_id", "=", input.session_id).forUpdate().executeTakeFirst();
2693
- if (!locked) throw new SessionNotFoundError4(input.session_id);
2740
+ if (!locked) {
2741
+ throw new SessionNotFoundError4(input.session_id);
2742
+ }
2694
2743
  await trx.updateTable("session").set({
2695
2744
  last_turn_id: input.turn.turn_id,
2696
2745
  updated_at: sql11`now()`,
@@ -2722,7 +2771,9 @@ async function createTurn2(db, input) {
2722
2771
  }
2723
2772
  prevCheckpoint = first.turn_checkpoint;
2724
2773
  for (const row of prevRows) {
2725
- if (row.thread_id === null) continue;
2774
+ if (row.thread_id === null) {
2775
+ continue;
2776
+ }
2726
2777
  if (row.thread_checkpoint === null || row.current_context_usage === null || row.context_ids === null) {
2727
2778
  throw new SessionStoreInvariantError4(`previous turn_thread row for ${row.thread_id} is incomplete`);
2728
2779
  }
@@ -2830,7 +2881,9 @@ async function createTurn2(db, input) {
2830
2881
  }
2831
2882
  const capabilityStateRows = [];
2832
2883
  for (const capability of input.capability_states) {
2833
- if (capability.capability_state === null) continue;
2884
+ if (capability.capability_state === null) {
2885
+ continue;
2886
+ }
2834
2887
  for (const [key, state] of Object.entries(capability.capability_state)) {
2835
2888
  capabilityStateRows.push({
2836
2889
  session_id: input.session_id,
@@ -2847,8 +2900,12 @@ async function createTurn2(db, input) {
2847
2900
  }
2848
2901
  });
2849
2902
  } catch (err) {
2850
- if (err instanceof SessionStoreNotFoundError4 || err instanceof SessionStoreConflictError4) throw err;
2851
- if (isUniqueViolation2(err)) throw new TurnAlreadyExistsError2(input.turn.turn_id, { cause: err });
2903
+ if (err instanceof SessionStoreNotFoundError4 || err instanceof SessionStoreConflictError4) {
2904
+ throw err;
2905
+ }
2906
+ if (isUniqueViolation2(err)) {
2907
+ throw new TurnAlreadyExistsError2(input.turn.turn_id, { cause: err });
2908
+ }
2852
2909
  throw err;
2853
2910
  }
2854
2911
  }
@@ -2856,7 +2913,7 @@ async function freezeAndGetTurn2(db, input) {
2856
2913
  return await db.transaction().execute(async (trx) => {
2857
2914
  const cancelledState = {
2858
2915
  status: "cancelled",
2859
- reason: CancellationReason5.CancelledForNextTurn,
2916
+ reason: input.reason,
2860
2917
  completed_at: (/* @__PURE__ */ new Date()).toISOString()
2861
2918
  };
2862
2919
  const updateResult = await trx.updateTable("turn").set({
@@ -2873,7 +2930,9 @@ async function freezeAndGetTurn2(db, input) {
2873
2930
  }).execute();
2874
2931
  }
2875
2932
  const record = await assembleTurnRecord2(trx, input);
2876
- if (!record) throw new TurnNotFoundError3(input.turn_id);
2933
+ if (!record) {
2934
+ throw new TurnNotFoundError4(input.turn_id);
2935
+ }
2877
2936
  return record;
2878
2937
  });
2879
2938
  }
@@ -2912,7 +2971,9 @@ async function updateTurnState2(db, input) {
2912
2971
  const numUpdated = Number(result.numUpdatedRows);
2913
2972
  if (numUpdated === 0) {
2914
2973
  const existing = await trx.selectFrom("turn").select("state").where("session_id", "=", input.session_id).where("turn_id", "=", input.turn_id).executeTakeFirst();
2915
- if (!existing) throw new TurnNotFoundError3(input.turn_id);
2974
+ if (!existing) {
2975
+ throw new TurnNotFoundError4(input.turn_id);
2976
+ }
2916
2977
  throw new TurnNotRunningError2(input.turn_id, terminalTurnState2(existing.state, input.turn_id));
2917
2978
  }
2918
2979
  await trx.insertInto("session_event").values({
@@ -2979,11 +3040,13 @@ import {
2979
3040
  } from "@truefoundry/trueforge-core/agent-session/store/SessionEventPageToken";
2980
3041
  import {
2981
3042
  SessionNotFoundError as SessionNotFoundError5,
2982
- TurnNotFoundError as TurnNotFoundError4
3043
+ TurnNotFoundError as TurnNotFoundError5
2983
3044
  } from "@truefoundry/trueforge-core/agent-session/store/SessionStoreErrors";
2984
3045
  import { sql as sql13 } from "kysely";
2985
3046
  async function appendToEvents2(db, input) {
2986
- if (input.events.length === 0) return;
3047
+ if (input.events.length === 0) {
3048
+ return;
3049
+ }
2987
3050
  const keys = {
2988
3051
  session_id: input.session_id,
2989
3052
  turn_id: input.turn_id
@@ -3016,7 +3079,7 @@ async function listTurnEvents2(db, input) {
3016
3079
  (join) => join.onRef("e.session_id", "=", "t.session_id").onRef("e.turn_id", "=", "t.turn_id")
3017
3080
  ).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();
3018
3081
  if (rows.length === 0) {
3019
- throw new TurnNotFoundError4(input.turn_id);
3082
+ throw new TurnNotFoundError5(input.turn_id);
3020
3083
  }
3021
3084
  const events = [];
3022
3085
  for (const row of rows) {
@@ -3043,7 +3106,7 @@ async function listSessionEvents2(db, input) {
3043
3106
  };
3044
3107
  const anchor = await db.selectFrom("turn").select(["turn_id", "ancestor_ids"]).where("session_id", "=", input.session_id).where("turn_id", "=", cursor.last_turn_id).executeTakeFirst();
3045
3108
  if (!anchor) {
3046
- throw new TurnNotFoundError4(cursor.last_turn_id);
3109
+ throw new TurnNotFoundError5(cursor.last_turn_id);
3047
3110
  }
3048
3111
  const chainIds = await resolveAncestorChain2(db, input.session_id, anchor);
3049
3112
  const rows = await db.selectFrom(unnestWithOrdinality(chainIds, "c")).innerJoin(
@@ -3058,11 +3121,17 @@ async function resolveAncestorChain2(db, sessionId, anchor) {
3058
3121
  let oldestId = chain[0];
3059
3122
  while (oldestId && oldestId !== anchor.turn_id) {
3060
3123
  const oldest = await db.selectFrom("turn").select(["ancestor_ids"]).where("session_id", "=", sessionId).where("turn_id", "=", oldestId).executeTakeFirst();
3061
- if (!oldest) break;
3124
+ if (!oldest) {
3125
+ break;
3126
+ }
3062
3127
  const older = oldest.ancestor_ids.filter((id) => !seen.has(id));
3063
- if (older.length === 0) break;
3128
+ if (older.length === 0) {
3129
+ break;
3130
+ }
3064
3131
  chain.unshift(...older);
3065
- for (const id of older) seen.add(id);
3132
+ for (const id of older) {
3133
+ seen.add(id);
3134
+ }
3066
3135
  oldestId = older[0];
3067
3136
  }
3068
3137
  return chain;
@@ -3816,6 +3885,9 @@ async function consumePendingAuthorization2(db, params) {
3816
3885
  ...fromStoredOAuthPendingAuthorizationData(row.auth_data)
3817
3886
  };
3818
3887
  }
3888
+ async function deletePendingAuthorizationsForServer2(db, params) {
3889
+ await db.deleteFrom("oauth_pending_authorization").where("oauth_server_id", "=", params.id).execute();
3890
+ }
3819
3891
  var init_pendingAuthorization2 = __esm({
3820
3892
  "src/db/postgres/token-store/queries/pendingAuthorization.ts"() {
3821
3893
  "use strict";
@@ -3853,6 +3925,9 @@ async function getTokens2(db, params) {
3853
3925
  async function deleteToken2(db, params) {
3854
3926
  await db.deleteFrom("oauth_token").where("oauth_server_id", "=", params.id).where("user_id", "=", params.userRef).execute();
3855
3927
  }
3928
+ async function deleteTokensForServer2(db, params) {
3929
+ await db.deleteFrom("oauth_token").where("oauth_server_id", "=", params.id).execute();
3930
+ }
3856
3931
  var init_token2 = __esm({
3857
3932
  "src/db/postgres/token-store/queries/token.ts"() {
3858
3933
  "use strict";
@@ -3901,6 +3976,12 @@ var init_PostgresOAuthTokenStore = __esm({
3901
3976
  deleteToken(params, transaction) {
3902
3977
  return deleteToken2(transaction ?? this.db, params);
3903
3978
  }
3979
+ deleteTokensForServer(params, transaction) {
3980
+ return deleteTokensForServer2(transaction ?? this.db, params);
3981
+ }
3982
+ deletePendingAuthorizationsForServer(params, transaction) {
3983
+ return deletePendingAuthorizationsForServer2(transaction ?? this.db, params);
3984
+ }
3904
3985
  };
3905
3986
  }
3906
3987
  });
@@ -4136,22 +4217,22 @@ var init_PostgresAgentStore = __esm({
4136
4217
  });
4137
4218
 
4138
4219
  // src/main.ts
4139
- import { extractErrorLogFields as extractErrorLogFields8 } from "@truefoundry/trueforge-core/core";
4220
+ import { extractErrorLogFields as extractErrorLogFields9 } from "@truefoundry/trueforge-core/core";
4140
4221
  import { mkdir } from "fs/promises";
4141
- import path5 from "path";
4222
+ import path6 from "path";
4142
4223
  import { serve } from "@hono/node-server";
4143
4224
  import {
4144
- CancellationReason as CancellationReason6,
4225
+ CancellationReason as CancellationReason4,
4145
4226
  Sessions
4146
4227
  } from "@truefoundry/trueforge-core/agent-session";
4147
4228
  import { RequestReplyExecutor, RequestReplyRouter } from "@truefoundry/trueforge-core/request-reply";
4148
- import winston from "winston";
4149
4229
 
4150
4230
  // src/app.ts
4151
4231
  import { swaggerUI } from "@hono/swagger-ui";
4152
4232
  import { OpenAPIHono as OpenAPIHono14, z as z24 } from "@hono/zod-openapi";
4153
- import { extractErrorLogFields as extractErrorLogFields6 } from "@truefoundry/trueforge-core/core";
4154
- import { HTTPException as HTTPException6 } from "hono/http-exception";
4233
+ import { extractErrorLogFields as extractErrorLogFields7 } from "@truefoundry/trueforge-core/core";
4234
+ import { bodyLimit } from "hono/body-limit";
4235
+ import { HTTPException as HTTPException5 } from "hono/http-exception";
4155
4236
 
4156
4237
  // src/apis/agents.ts
4157
4238
  init_agentStore();
@@ -4744,6 +4825,7 @@ function toDaytonaSandboxProvider({
4744
4825
  const { apiKey, ...settings } = toDaytonaSandboxProviderInput(manifest);
4745
4826
  return new DaytonaSandboxProvider({
4746
4827
  client: new Daytona({ apiKey }),
4828
+ apiKey,
4747
4829
  ...settings,
4748
4830
  tenantName: tenant_id,
4749
4831
  sandboxImage: build_metadata?.["image_uri"] ?? SANDBOX_IMAGE_URI,
@@ -4759,6 +4841,13 @@ function toSandboxStatus(build) {
4759
4841
  build_metadata: build.metadata
4760
4842
  };
4761
4843
  }
4844
+ function sandboxStatusFromRecord(record) {
4845
+ return {
4846
+ status: record.status,
4847
+ status_reason: record.status_reason,
4848
+ build_metadata: record.build_metadata
4849
+ };
4850
+ }
4762
4851
  var READY_REVALIDATE_INTERVAL_MS = 13 * 24 * 60 * 60 * 1e3;
4763
4852
  async function checkSnapshotStatus({
4764
4853
  store,
@@ -4769,11 +4858,7 @@ async function checkSnapshotStatus({
4769
4858
  if (!record) {
4770
4859
  return void 0;
4771
4860
  }
4772
- const persisted = {
4773
- status: record.status,
4774
- status_reason: record.status_reason,
4775
- build_metadata: record.build_metadata
4776
- };
4861
+ const persisted = sandboxStatusFromRecord(record);
4777
4862
  const readyIsFresh = record.status === "ready" && Date.now() - Date.parse(record.updated_at) < READY_REVALIDATE_INTERVAL_MS;
4778
4863
  if (record.status === "failed" || readyIsFresh) {
4779
4864
  return persisted;
@@ -4791,8 +4876,8 @@ async function checkSnapshotStatus({
4791
4876
  build = await provider.getImageBuildStatus();
4792
4877
  }
4793
4878
  const next = toSandboxStatus(build);
4794
- await store.updateSandboxStatus({ tenant_id, ...next });
4795
- return next;
4879
+ const updated = await store.updateSandboxStatus({ tenant_id, ...next });
4880
+ return updated ? sandboxStatusFromRecord(updated) : next;
4796
4881
  }
4797
4882
 
4798
4883
  // src/schemas/mcpServer.ts
@@ -5105,10 +5190,14 @@ import {
5105
5190
  CancellationReason,
5106
5191
  SessionStoreConflictError,
5107
5192
  SessionStoreInvariantError,
5108
- SessionStoreNotFoundError
5193
+ SessionStoreNotFoundError,
5194
+ TurnNotFoundError
5109
5195
  } from "@truefoundry/trueforge-core/agent-session";
5110
- import { NoResponderError, redisRequest, RequestTimeoutError } from "@truefoundry/trueforge-core/request-reply";
5111
- import { HTTPException as HTTPException3 } from "hono/http-exception";
5196
+ import { extractErrorLogFields } from "@truefoundry/trueforge-core/core";
5197
+ import {
5198
+ redisRequest,
5199
+ RequestTimeoutError
5200
+ } from "@truefoundry/trueforge-core/request-reply";
5112
5201
  import { ulid as ulid2 } from "ulid";
5113
5202
  import { z as z11 } from "zod";
5114
5203
 
@@ -5529,7 +5618,8 @@ function cancelSessionTurnPeerHandler(activeTurns) {
5529
5618
  };
5530
5619
  }
5531
5620
  async function cancelSessionTurn(deps, input) {
5532
- const { sessionId, turnId, reason = CancellationReason.ClientCancelled } = input;
5621
+ const { turnId, reason = CancellationReason.ClientCancelled } = input;
5622
+ const sessionId = deps.session.session_id;
5533
5623
  const turn = await deps.sessionStore.getTurn({
5534
5624
  session_id: sessionId,
5535
5625
  turn_id: turnId
@@ -5552,33 +5642,39 @@ async function cancelSessionTurn(deps, input) {
5552
5642
  pollIntervalMs: config_default.REDIS_REQUEST_REPLY_POLL_INTERVAL_MS
5553
5643
  }
5554
5644
  });
5555
- if (reply.status !== 200 && reply.status !== 412) {
5556
- throw new HTTPException3(500, { message: "Failed to cancel turn on the owning executor", cause: reply });
5645
+ if (reply.status === 200) {
5646
+ return;
5557
5647
  }
5558
5648
  } catch (error) {
5559
- if (error instanceof NoResponderError) {
5560
- throw new HTTPException3(412, {
5561
- message: `Executor owning the running turn is unreachable: ${owner}`,
5562
- cause: error
5563
- });
5564
- }
5649
+ const fields = {
5650
+ sessionId,
5651
+ turnId,
5652
+ owner,
5653
+ ...extractErrorLogFields(error)
5654
+ };
5565
5655
  if (error instanceof RequestTimeoutError) {
5566
- throw new HTTPException3(424, {
5567
- message: "Timed out waiting for the owning executor to cancel the turn",
5568
- cause: error
5569
- });
5570
- }
5571
- if (error instanceof HTTPException3) {
5572
- throw error;
5656
+ deps.logger.warn("Timed out waiting for owning executor to cancel; freezing the running turn", fields);
5657
+ } else {
5658
+ deps.logger.warn("Failed to reach owning executor over Redis; freezing the running turn", fields);
5573
5659
  }
5574
- throw new HTTPException3(500, {
5575
- message: `Unexpected error while cancelling the turn on the owning executor: ${owner}`,
5576
- cause: error
5577
- });
5578
5660
  }
5661
+ await freezeTurnIgnoringMissing(deps.session, { turnId, reason });
5579
5662
  return;
5580
5663
  }
5581
- cancelTurnOnThisExecutor(deps.activeTurns, { sessionId, turnId, reason });
5664
+ const aborted = cancelTurnOnThisExecutor(deps.activeTurns, { sessionId, turnId, reason });
5665
+ if (!aborted) {
5666
+ await freezeTurnIgnoringMissing(deps.session, { turnId, reason });
5667
+ }
5668
+ }
5669
+ async function freezeTurnIgnoringMissing(session, input) {
5670
+ try {
5671
+ await session.freezeTurn({ turn_id: input.turnId, reason: input.reason });
5672
+ } catch (error) {
5673
+ if (error instanceof TurnNotFoundError) {
5674
+ return;
5675
+ }
5676
+ throw error;
5677
+ }
5582
5678
  }
5583
5679
  var FORBIDDEN_SESSION_ACCESS = "Only the session creator can access this session";
5584
5680
  function checkSessionAccess({ userRef, createdBy }) {
@@ -5708,18 +5804,18 @@ function createSessionsRouter(deps) {
5708
5804
  };
5709
5805
  const cancelSessionHandler = async (c) => {
5710
5806
  const { session_id: sessionId } = c.req.valid("param");
5711
- const record = await deps.sessionStore.getSession({ tenant_id: TENANT_ID, session_id: sessionId });
5712
- if (!record) {
5807
+ const session = await deps.sessions.get({ tenant_id: TENANT_ID, session_id: sessionId });
5808
+ if (!session) {
5713
5809
  return c.json({ error: { message: `Session not found: ${sessionId}` } }, 404);
5714
5810
  }
5715
- if (!checkSessionAccess({ userRef: deps.resolveUserContext(c).userRef, createdBy: record.created_by })) {
5811
+ if (!checkSessionAccess({ userRef: deps.resolveUserContext(c).userRef, createdBy: session.record.created_by })) {
5716
5812
  return c.json({ error: { message: FORBIDDEN_SESSION_ACCESS } }, 403);
5717
5813
  }
5718
- const turnId = record.last_turn_id;
5814
+ const turnId = session.record.last_turn_id;
5719
5815
  if (!turnId) {
5720
5816
  return c.json({}, 200);
5721
5817
  }
5722
- await cancelSessionTurn(deps, { sessionId, turnId });
5818
+ await cancelSessionTurn({ ...deps, session }, { turnId });
5723
5819
  return c.json({}, 200);
5724
5820
  };
5725
5821
  const listSessionEventsHandler = async (c) => {
@@ -5843,7 +5939,7 @@ function createAgentsRouter(deps) {
5843
5939
 
5844
5940
  // src/apis/auth.ts
5845
5941
  import { OpenAPIHono as OpenAPIHono3 } from "@hono/zod-openapi";
5846
- import { extractErrorLogFields } from "@truefoundry/trueforge-core/core";
5942
+ import { extractErrorLogFields as extractErrorLogFields2 } from "@truefoundry/trueforge-core/core";
5847
5943
 
5848
5944
  // src/auth/cookies.ts
5849
5945
  init_config();
@@ -6061,7 +6157,7 @@ function resolveUserContext(c) {
6061
6157
  }
6062
6158
 
6063
6159
  // src/auth/middleware.ts
6064
- import { HTTPException as HTTPException4 } from "hono/http-exception";
6160
+ import { HTTPException as HTTPException3 } from "hono/http-exception";
6065
6161
  import { jwtVerify } from "jose";
6066
6162
  var AUTH_HEADER_TYPE = "Bearer";
6067
6163
  function readBearerIdToken(c) {
@@ -6108,14 +6204,14 @@ var authMiddleware = async (c, next) => {
6108
6204
  try {
6109
6205
  const user = await resolveAuthUser(c);
6110
6206
  if (!user) {
6111
- throw new HTTPException4(401, { message: "Authentication required" });
6207
+ throw new HTTPException3(401, { message: "Authentication required" });
6112
6208
  }
6113
6209
  c.set("user_context", user);
6114
6210
  } catch (error) {
6115
- if (error instanceof HTTPException4) {
6211
+ if (error instanceof HTTPException3) {
6116
6212
  throw error;
6117
6213
  }
6118
- throw new HTTPException4(401, { message: "Authentication required", cause: error });
6214
+ throw new HTTPException3(401, { message: "Authentication required", cause: error });
6119
6215
  }
6120
6216
  return next();
6121
6217
  };
@@ -6127,17 +6223,17 @@ var adminAuthMiddleware = async (c, next) => {
6127
6223
  try {
6128
6224
  const user = await resolveAuthUser(c);
6129
6225
  if (!user) {
6130
- throw new HTTPException4(401, { message: "Authentication required" });
6226
+ throw new HTTPException3(401, { message: "Authentication required" });
6131
6227
  }
6132
6228
  if (!isAdmin(user)) {
6133
- throw new HTTPException4(403, { message: "Admin access required" });
6229
+ throw new HTTPException3(403, { message: "Admin access required" });
6134
6230
  }
6135
6231
  c.set("user_context", user);
6136
6232
  } catch (error) {
6137
- if (error instanceof HTTPException4) {
6233
+ if (error instanceof HTTPException3) {
6138
6234
  throw error;
6139
6235
  }
6140
- throw new HTTPException4(401, { message: "Authentication required", cause: error });
6236
+ throw new HTTPException3(401, { message: "Authentication required", cause: error });
6141
6237
  }
6142
6238
  return next();
6143
6239
  };
@@ -6243,7 +6339,7 @@ function createAuthRouter(params) {
6243
6339
  });
6244
6340
  return c.redirect(authorizationUrl, 302);
6245
6341
  } catch (error) {
6246
- params.logger.error("Failed to build login authorization", extractErrorLogFields(error));
6342
+ params.logger.error("Failed to build login authorization", extractErrorLogFields2(error));
6247
6343
  return c.redirect(oauthErrorRedirect("login_failed"), 302);
6248
6344
  }
6249
6345
  });
@@ -6269,7 +6365,7 @@ function createAuthRouter(params) {
6269
6365
  });
6270
6366
  return c.redirect(safeReturnTo(pending.return_to), 302);
6271
6367
  } catch (error) {
6272
- params.logger.error("Failed to exchange authorization code", extractErrorLogFields(error));
6368
+ params.logger.error("Failed to exchange authorization code", extractErrorLogFields2(error));
6273
6369
  const reason = error instanceof Error ? error.message : "login_failed";
6274
6370
  return c.redirect(oauthErrorRedirect(reason), 302);
6275
6371
  }
@@ -6291,7 +6387,7 @@ function createAuthRouter(params) {
6291
6387
 
6292
6388
  // src/apis/capabilities.ts
6293
6389
  import { OpenAPIHono as OpenAPIHono4 } from "@hono/zod-openapi";
6294
- import { extractErrorLogFields as extractErrorLogFields2 } from "@truefoundry/trueforge-core/core";
6390
+ import { extractErrorLogFields as extractErrorLogFields3 } from "@truefoundry/trueforge-core/core";
6295
6391
 
6296
6392
  // src/routes/capabilityRoutes.ts
6297
6393
  import { createRoute as createRoute4, z as z14 } from "@hono/zod-openapi";
@@ -6348,7 +6444,7 @@ function createCapabilitiesRouter(deps) {
6348
6444
  });
6349
6445
  status = refreshed?.status;
6350
6446
  } catch (error) {
6351
- deps.logger.warn("Sandbox image status check failed; reporting sandbox disabled", extractErrorLogFields2(error));
6447
+ deps.logger.warn("Sandbox image status check failed; reporting sandbox disabled", extractErrorLogFields3(error));
6352
6448
  }
6353
6449
  const sandboxEnabled = status === "ready";
6354
6450
  const settingsEnabled = isAdmin(resolveUserContext(c));
@@ -6732,7 +6828,7 @@ function createCatalogRouter(deps) {
6732
6828
 
6733
6829
  // src/apis/mcpOAuth.ts
6734
6830
  import { OpenAPIHono as OpenAPIHono6 } from "@hono/zod-openapi";
6735
- import { extractErrorLogFields as extractErrorLogFields3, McpConnectionError as McpConnectionError3 } from "@truefoundry/trueforge-core/core";
6831
+ import { extractErrorLogFields as extractErrorLogFields4, McpConnectionError as McpConnectionError3 } from "@truefoundry/trueforge-core/core";
6736
6832
 
6737
6833
  // src/routes/mcpOAuthRoutes.ts
6738
6834
  import { createRoute as createRoute6 } from "@hono/zod-openapi";
@@ -6814,10 +6910,10 @@ function createMcpOAuthRouter(deps) {
6814
6910
  });
6815
6911
  } catch (err) {
6816
6912
  if (err instanceof McpConnectionError3) {
6817
- deps.logger.warn("MCP OAuth callback token exchange failed", extractErrorLogFields3(err));
6913
+ deps.logger.warn("MCP OAuth callback token exchange failed", extractErrorLogFields4(err));
6818
6914
  return callbackFailure({ c, pending, message: err.message });
6819
6915
  }
6820
- deps.logger.error("MCP OAuth callback unexpected failure", extractErrorLogFields3(err));
6916
+ deps.logger.error("MCP OAuth callback unexpected failure", extractErrorLogFields4(err));
6821
6917
  return callbackFailure({ c, pending, message: "Internal server error", jsonStatus: 500 });
6822
6918
  }
6823
6919
  return callbackSuccess({ c, pending });
@@ -6831,7 +6927,7 @@ function createMcpOAuthRouter(deps) {
6831
6927
  init_config();
6832
6928
  init_mcpServerStore();
6833
6929
  import { OpenAPIHono as OpenAPIHono7 } from "@hono/zod-openapi";
6834
- import { extractErrorLogFields as extractErrorLogFields4, isAuthRequired, McpConnectionError as McpConnectionError4, RemoteMCP } from "@truefoundry/trueforge-core/core";
6930
+ import { extractErrorLogFields as extractErrorLogFields5, isAuthRequired, McpConnectionError as McpConnectionError4, RemoteMCP } from "@truefoundry/trueforge-core/core";
6835
6931
 
6836
6932
  // src/routes/mcpServerRoutes.ts
6837
6933
  import { createRoute as createRoute7, z as z21 } from "@hono/zod-openapi";
@@ -7209,7 +7305,7 @@ function createSettingsMcpServersRouter(deps) {
7209
7305
  } catch (error) {
7210
7306
  deps.logger.error(
7211
7307
  `DCR client registration failed for "${incomingManifest.name}"; rejecting create`,
7212
- extractErrorLogFields4(error)
7308
+ extractErrorLogFields5(error)
7213
7309
  );
7214
7310
  const message = error instanceof Error ? error.message : "Failed to register OAuth client for this MCP server";
7215
7311
  return c.json({ error: { message } }, 422);
@@ -7265,9 +7361,9 @@ function createSettingsMcpServersRouter(deps) {
7265
7361
  existing: existing?.manifest
7266
7362
  });
7267
7363
  let dcrClientToSave;
7364
+ const urlChanged = existing !== void 0 && existing.manifest.url !== manifest.url && manifest.auth?.type === "dcr";
7268
7365
  if (manifest.auth?.type === "dcr") {
7269
7366
  const existingClient = existing ? await deps.mcpServerStore.getClient({ id: existing.id }, transaction) : void 0;
7270
- const urlChanged = existing && existing.manifest.url !== manifest.url;
7271
7367
  const needsDcr = existingClient === void 0 || urlChanged;
7272
7368
  if (needsDcr) {
7273
7369
  dcrClientToSave = await createMcpOAuthClient({
@@ -7289,6 +7385,10 @@ function createSettingsMcpServersRouter(deps) {
7289
7385
  if (dcrClientToSave !== void 0) {
7290
7386
  await deps.mcpServerStore.saveClient({ id: saved.id, record: dcrClientToSave }, transaction);
7291
7387
  }
7388
+ if (urlChanged) {
7389
+ await deps.tokenStore.deleteTokensForServer({ id: saved.id }, transaction);
7390
+ await deps.tokenStore.deletePendingAuthorizationsForServer({ id: saved.id }, transaction);
7391
+ }
7292
7392
  return saved;
7293
7393
  });
7294
7394
  const token = record.manifest.auth?.type === "dcr" ? await deps.tokenStore.getToken({ id: record.id, userRef }) : void 0;
@@ -7300,7 +7400,7 @@ function createSettingsMcpServersRouter(deps) {
7300
7400
  if (error instanceof McpConnectionError4) {
7301
7401
  deps.logger.error(
7302
7402
  `DCR client registration failed for "${incomingManifest.name}"; rejecting upsert`,
7303
- extractErrorLogFields4(error)
7403
+ extractErrorLogFields5(error)
7304
7404
  );
7305
7405
  return c.json({ error: { message: error.message } }, 422);
7306
7406
  }
@@ -7340,7 +7440,7 @@ function createSettingsMcpServersRouter(deps) {
7340
7440
  return c.json({ data }, 200);
7341
7441
  } catch (error) {
7342
7442
  if (error instanceof McpConnectionError4) {
7343
- deps.logger.warn(`MCP tools/list failed for "${name}"`, extractErrorLogFields4(error));
7443
+ deps.logger.warn(`MCP tools/list failed for "${name}"`, extractErrorLogFields5(error));
7344
7444
  if (error.statusCode === 401) {
7345
7445
  return c.json({ error: { message: error.message } }, 422);
7346
7446
  }
@@ -7387,7 +7487,7 @@ function createMcpServersRouter(deps) {
7387
7487
  return c.json(authStatus, 200);
7388
7488
  } catch (error) {
7389
7489
  if (error instanceof McpConnectionError4) {
7390
- deps.logger.warn(`MCP authorize failed for "${name}"`, extractErrorLogFields4(error));
7490
+ deps.logger.warn(`MCP authorize failed for "${name}"`, extractErrorLogFields5(error));
7391
7491
  if (error.statusCode === 400) {
7392
7492
  return c.json({ error: { message: error.message } }, 400);
7393
7493
  }
@@ -7399,7 +7499,7 @@ function createMcpServersRouter(deps) {
7399
7499
  }
7400
7500
  return c.json({ error: { message: error.message } }, 500);
7401
7501
  }
7402
- deps.logger.error(`MCP authorize unexpected failure for "${name}"`, extractErrorLogFields4(error));
7502
+ deps.logger.error(`MCP authorize unexpected failure for "${name}"`, extractErrorLogFields5(error));
7403
7503
  return c.json({ error: { message: "Internal server error" } }, 500);
7404
7504
  }
7405
7505
  };
@@ -8002,7 +8102,7 @@ import {
8002
8102
  } from "@truefoundry/trueforge-core/agent-session";
8003
8103
  import {
8004
8104
  AgentHarnessError,
8005
- extractErrorLogFields as extractErrorLogFields5,
8105
+ extractErrorLogFields as extractErrorLogFields6,
8006
8106
  isAgentInputUserMessage,
8007
8107
  isFileContentPart,
8008
8108
  McpConnectionError as McpConnectionError5,
@@ -8010,7 +8110,7 @@ import {
8010
8110
  validateSandboxOwnedByTenant,
8011
8111
  VercelAILLM
8012
8112
  } from "@truefoundry/trueforge-core/core";
8013
- import { HTTPException as HTTPException5 } from "hono/http-exception";
8113
+ import { HTTPException as HTTPException4 } from "hono/http-exception";
8014
8114
  import { streamSSE } from "hono/streaming";
8015
8115
 
8016
8116
  // src/routes/turnRoutes.ts
@@ -8210,6 +8310,10 @@ Use \`previous_turn_id\` to chain to the session's last turn (defaults to \`auto
8210
8310
  content: { "application/json": { schema: RequestErrorResponseSchema } },
8211
8311
  description: "Requested action cannot be performed on the session because it is no longer usable."
8212
8312
  },
8313
+ 413: {
8314
+ content: { "application/json": { schema: RequestErrorResponseSchema } },
8315
+ description: "Request body exceeds the configured maximum size (MAX_REQUEST_BODY_BYTES)."
8316
+ },
8213
8317
  422: {
8214
8318
  content: { "application/json": { schema: RequestErrorResponseSchema } },
8215
8319
  description: "The request is well-formed but cannot be processed: a referenced resource is missing (named agent, model, MCP server, skill, or sandbox provider), sandbox is required but unavailable (e.g. file uploads), or the turn input conflicts with current state (e.g. unresolved tool calls or approvals, tool name collision)."
@@ -8503,30 +8607,30 @@ var StreamGoneError = class extends Error {
8503
8607
  import { SandboxError, validateNoPathTraversal } from "@truefoundry/trueforge-core/core";
8504
8608
  var SandboxInvalidPathError = class extends SandboxError {
8505
8609
  statusCode = 400;
8506
- constructor({ path: path6, reason }) {
8507
- super(`Path ${reason}: ${path6}`);
8610
+ constructor({ path: path7, reason }) {
8611
+ super(`Path ${reason}: ${path7}`);
8508
8612
  this.name = "SandboxInvalidPathError";
8509
8613
  }
8510
8614
  };
8511
8615
  var MAX_PATH_BYTES = 4095;
8512
8616
  var MAX_SEGMENT_BYTES = 255;
8513
- function validateSandboxFilePath(path6) {
8514
- if (!path6.startsWith("/")) {
8515
- throw new SandboxInvalidPathError({ path: path6, reason: "must be absolute" });
8617
+ function validateSandboxFilePath(path7) {
8618
+ if (!path7.startsWith("/")) {
8619
+ throw new SandboxInvalidPathError({ path: path7, reason: "must be absolute" });
8516
8620
  }
8517
- if (path6.includes("\0")) {
8518
- throw new SandboxInvalidPathError({ path: path6, reason: "must not contain a NUL byte" });
8621
+ if (path7.includes("\0")) {
8622
+ throw new SandboxInvalidPathError({ path: path7, reason: "must not contain a NUL byte" });
8519
8623
  }
8520
- if (Buffer.byteLength(path6) > MAX_PATH_BYTES) {
8521
- throw new SandboxInvalidPathError({ path: path6, reason: `must be at most ${String(MAX_PATH_BYTES)} bytes` });
8624
+ if (Buffer.byteLength(path7) > MAX_PATH_BYTES) {
8625
+ throw new SandboxInvalidPathError({ path: path7, reason: `must be at most ${String(MAX_PATH_BYTES)} bytes` });
8522
8626
  }
8523
- if (path6.split("/").some((segment) => Buffer.byteLength(segment) > MAX_SEGMENT_BYTES)) {
8627
+ if (path7.split("/").some((segment) => Buffer.byteLength(segment) > MAX_SEGMENT_BYTES)) {
8524
8628
  throw new SandboxInvalidPathError({
8525
- path: path6,
8629
+ path: path7,
8526
8630
  reason: `must not have a segment longer than ${String(MAX_SEGMENT_BYTES)} bytes`
8527
8631
  });
8528
8632
  }
8529
- validateNoPathTraversal(path6);
8633
+ validateNoPathTraversal(path7);
8530
8634
  }
8531
8635
 
8532
8636
  // src/apis/turns.ts
@@ -8545,8 +8649,8 @@ function toArrayBuffer(content) {
8545
8649
  new Uint8Array(buffer).set(content);
8546
8650
  return buffer;
8547
8651
  }
8548
- function toContentDisposition(path6) {
8549
- const fileName = path6.split("/").filter(Boolean).pop() ?? "download";
8652
+ function toContentDisposition(path7) {
8653
+ const fileName = path7.split("/").filter(Boolean).pop() ?? "download";
8550
8654
  const encoded = encodeURIComponent(fileName).replace(
8551
8655
  /['()*]/g,
8552
8656
  (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
@@ -8591,7 +8695,7 @@ function createTurnResolver(deps) {
8591
8695
  userRef
8592
8696
  });
8593
8697
  if (connection === void 0) {
8594
- throw new HTTPException5(422, {
8698
+ throw new HTTPException4(422, {
8595
8699
  message: `Unknown MCP server "${name}" \u2014 not configured`
8596
8700
  });
8597
8701
  }
@@ -8606,14 +8710,14 @@ function createTurnResolver(deps) {
8606
8710
  logger
8607
8711
  });
8608
8712
  if (provider === void 0) {
8609
- throw new HTTPException5(422, {
8713
+ throw new HTTPException4(422, {
8610
8714
  message: "no sandbox provider configured \u2014 PUT /settings/sandbox-providers"
8611
8715
  });
8612
8716
  }
8613
8717
  if (existingSandboxId === void 0) {
8614
8718
  const status = await checkSnapshotStatus({ store: sandboxProviderStore, tenant_id: TENANT_ID, logger });
8615
8719
  if (status?.status !== "ready") {
8616
- throw new HTTPException5(422, {
8720
+ throw new HTTPException4(422, {
8617
8721
  message: status?.status === "failed" ? `sandbox image build failed (${status.status_reason ?? "unknown error"})` : "sandbox image is activating \u2014 retry shortly"
8618
8722
  });
8619
8723
  }
@@ -8636,7 +8740,7 @@ function createTurnResolver(deps) {
8636
8740
  agent: async (agentId) => {
8637
8741
  const record = await agentStore.getAgent({ tenant_id: TENANT_ID, id: agentId });
8638
8742
  if (record === void 0) {
8639
- throw new HTTPException5(422, { message: `Agent not found: ${agentId}` });
8743
+ throw new HTTPException4(422, { message: `Agent not found: ${agentId}` });
8640
8744
  }
8641
8745
  return record.manifest;
8642
8746
  },
@@ -8688,13 +8792,13 @@ async function drainTurnEvents(input) {
8688
8792
  logger.warn("Turn stream ended after session/turn was removed", {
8689
8793
  sessionId,
8690
8794
  turnId,
8691
- ...extractErrorLogFields5(error)
8795
+ ...extractErrorLogFields6(error)
8692
8796
  });
8693
8797
  } else {
8694
8798
  logger.error("Unexpected error in turn event drain", {
8695
8799
  sessionId,
8696
8800
  turnId,
8697
- ...extractErrorLogFields5(error)
8801
+ ...extractErrorLogFields6(error)
8698
8802
  });
8699
8803
  }
8700
8804
  } finally {
@@ -8706,7 +8810,7 @@ function resolveAfterSequenceNumber(c, bodyAfterSequenceNumber) {
8706
8810
  if (lastEventId) {
8707
8811
  const sequenceNumber = Number(lastEventId);
8708
8812
  if (!Number.isInteger(sequenceNumber) || sequenceNumber < 0) {
8709
- throw new HTTPException5(400, { message: "Invalid Last-Event-Id header" });
8813
+ throw new HTTPException4(400, { message: "Invalid Last-Event-Id header" });
8710
8814
  }
8711
8815
  return sequenceNumber;
8712
8816
  }
@@ -8758,10 +8862,10 @@ function createTurnsRouter(deps) {
8758
8862
  };
8759
8863
  const downloadSandboxFileHandler = async (c) => {
8760
8864
  const { session_id: sessionId, turn_id: turnId } = c.req.valid("param");
8761
- const { path: path6 } = c.req.valid("query");
8865
+ const { path: path7 } = c.req.valid("query");
8762
8866
  let sandboxId;
8763
8867
  try {
8764
- validateSandboxFilePath(path6);
8868
+ validateSandboxFilePath(path7);
8765
8869
  const session = await deps.sessions.get({ tenant_id: TENANT_ID, session_id: sessionId });
8766
8870
  if (!session) {
8767
8871
  return c.json({ error: { message: `Session not found: ${sessionId}` } }, 404);
@@ -8786,11 +8890,11 @@ function createTurnsRouter(deps) {
8786
8890
  return c.json({ error: { message: "No sandbox provider configured" } }, 412);
8787
8891
  }
8788
8892
  validateSandboxOwnedByTenant(sandboxId, TENANT_ID);
8789
- const content = await provider.downloadFile({ sandboxId, path: path6 });
8893
+ const content = await provider.downloadFile({ sandboxId, path: path7 });
8790
8894
  return c.body(toArrayBuffer(content), 200, {
8791
8895
  "Content-Type": "application/octet-stream",
8792
8896
  "Content-Length": String(content.byteLength),
8793
- "Content-Disposition": toContentDisposition(path6),
8897
+ "Content-Disposition": toContentDisposition(path7),
8794
8898
  "Cache-Control": "private, no-store"
8795
8899
  });
8796
8900
  } catch (error) {
@@ -8798,11 +8902,11 @@ function createTurnsRouter(deps) {
8798
8902
  return c.json({ error: { message: error.message } }, error.statusCode);
8799
8903
  }
8800
8904
  deps.logger.error("Sandbox file download failed", {
8801
- ...extractErrorLogFields5(error),
8905
+ ...extractErrorLogFields6(error),
8802
8906
  sessionId,
8803
8907
  turnId,
8804
8908
  sandboxId,
8805
- path: path6
8909
+ path: path7
8806
8910
  });
8807
8911
  return c.json({ error: { message: "Failed to download file from sandbox" } }, 424);
8808
8912
  }
@@ -8934,7 +9038,7 @@ function createTurnsRouter(deps) {
8934
9038
  try {
8935
9039
  await stream.writeSSE(turnEventSsePayload(event, sequenceNumber));
8936
9040
  } catch (error) {
8937
- deps.logger.error("SSE stream write error", extractErrorLogFields5(error));
9041
+ deps.logger.error("SSE stream write error", extractErrorLogFields6(error));
8938
9042
  shouldWriteToSSEStream = false;
8939
9043
  }
8940
9044
  }
@@ -8963,7 +9067,7 @@ function createTurnsRouter(deps) {
8963
9067
  await turnEventStream.assertSubscribable();
8964
9068
  } catch (error) {
8965
9069
  if (error instanceof StreamGoneError) {
8966
- throw new HTTPException5(412, { message: error.message, cause: error });
9070
+ throw new HTTPException4(412, { message: error.message, cause: error });
8967
9071
  }
8968
9072
  throw error;
8969
9073
  }
@@ -8992,7 +9096,7 @@ function createTurnsRouter(deps) {
8992
9096
  }
8993
9097
  } catch (error) {
8994
9098
  if (!subscribeAbort.signal.aborted) {
8995
- deps.logger.error("Unexpected error in turn subscribe SSE loop", extractErrorLogFields5(error));
9099
+ deps.logger.error("Unexpected error in turn subscribe SSE loop", extractErrorLogFields6(error));
8996
9100
  }
8997
9101
  } finally {
8998
9102
  clearTimeout(timeoutHandler);
@@ -9012,6 +9116,28 @@ function createTurnsRouter(deps) {
9012
9116
  return router;
9013
9117
  }
9014
9118
 
9119
+ // src/app.ts
9120
+ init_config();
9121
+
9122
+ // src/packageVersion.ts
9123
+ import { readFileSync } from "fs";
9124
+ import path2 from "path";
9125
+ import { fileURLToPath as fileURLToPath2 } from "url";
9126
+ var PACKAGE_ROOT2 = path2.resolve(path2.dirname(fileURLToPath2(import.meta.url)), "..");
9127
+ function readPackageVersion() {
9128
+ const packageJsonPath = path2.join(PACKAGE_ROOT2, "package.json");
9129
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
9130
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) {
9131
+ throw new Error(`${packageJsonPath} is missing a version field`);
9132
+ }
9133
+ const { version } = parsed;
9134
+ if (typeof version !== "string" || version.length === 0) {
9135
+ throw new Error(`${packageJsonPath} version must be a non-empty string`);
9136
+ }
9137
+ return version;
9138
+ }
9139
+ var PACKAGE_VERSION = readPackageVersion();
9140
+
9015
9141
  // src/zodErrorResponse.ts
9016
9142
  import { z as z23 } from "@hono/zod-openapi";
9017
9143
  function zodErrorResponse(c, error) {
@@ -9026,21 +9152,27 @@ var zodValidationHook = (result, c) => {
9026
9152
 
9027
9153
  // src/app.ts
9028
9154
  var BEARER_AUTH_SCHEME = "BearerAuth";
9155
+ function createRequestBodyLimitMiddleware(maxSize) {
9156
+ return bodyLimit({
9157
+ maxSize,
9158
+ onError: (c) => c.json({ error: { message: `Request body exceeds the maximum size of ${String(maxSize)} bytes` } }, 413)
9159
+ });
9160
+ }
9029
9161
  function createAppErrorHandler(params) {
9030
9162
  return (error, c) => {
9031
9163
  if (error instanceof z24.ZodError) {
9032
9164
  return zodErrorResponse(c, error);
9033
9165
  }
9034
- if (error instanceof HTTPException6) {
9166
+ if (error instanceof HTTPException5) {
9035
9167
  if (error.status >= 500) {
9036
9168
  params.logger.error("Server API error", {
9037
9169
  status: error.status,
9038
- ...extractErrorLogFields6(error)
9170
+ ...extractErrorLogFields7(error)
9039
9171
  });
9040
9172
  }
9041
9173
  return c.json({ error: { message: error.message } }, error.status);
9042
9174
  }
9043
- params.logger.error("Unhandled error", extractErrorLogFields6(error));
9175
+ params.logger.error("Unhandled error", extractErrorLogFields7(error));
9044
9176
  return c.json({ error: { message: "Internal server error" } }, 500);
9045
9177
  };
9046
9178
  }
@@ -9049,7 +9181,7 @@ var openApiDocConfig = {
9049
9181
  info: {
9050
9182
  title: "TrueForge API",
9051
9183
  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.",
9052
- version: "0.1.0"
9184
+ version: PACKAGE_VERSION
9053
9185
  }
9054
9186
  };
9055
9187
  function registerOpenApiBearerAuth(app) {
@@ -9088,6 +9220,7 @@ function withAdminAuth(router) {
9088
9220
  function createServerApp(deps) {
9089
9221
  const app = new OpenAPIHono14({ defaultHook: zodValidationHook });
9090
9222
  const authEnabled = deps.oidcClient != null;
9223
+ app.use("*", createRequestBodyLimitMiddleware(config_default.MAX_REQUEST_BODY_BYTES));
9091
9224
  app.get("/healthz", (c) => c.text("OK!"));
9092
9225
  app.route("/api/v1/auth", createAuthRouter({ oidcClient: deps.oidcClient, logger: deps.logger }));
9093
9226
  app.route(
@@ -9191,7 +9324,8 @@ function createServerApp(deps) {
9191
9324
  sandboxProviderStore: deps.sandboxProviderStore,
9192
9325
  redis: deps.redis,
9193
9326
  requestReplyRouter: deps.requestReplyRouter,
9194
- resolveUserContext
9327
+ resolveUserContext,
9328
+ logger: deps.logger
9195
9329
  })
9196
9330
  )
9197
9331
  );
@@ -9480,7 +9614,7 @@ import { serveStatic } from "@hono/node-server/serve-static";
9480
9614
  import { every } from "hono/combine";
9481
9615
  import { compress } from "hono/compress";
9482
9616
  import { existsSync as existsSync2 } from "fs";
9483
- import path2 from "path";
9617
+ import path3 from "path";
9484
9618
  var SERVER_PATH_PREFIXES = ["/api", "/healthz"];
9485
9619
  var HASHED_ASSET_PREFIX = "/assets/";
9486
9620
  var IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
@@ -9489,7 +9623,7 @@ function isServerPath(pathname) {
9489
9623
  return SERVER_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
9490
9624
  }
9491
9625
  function mountFrontend(app, dir) {
9492
- if (!existsSync2(path2.join(dir, "index.html"))) {
9626
+ if (!existsSync2(path3.join(dir, "index.html"))) {
9493
9627
  return false;
9494
9628
  }
9495
9629
  const serveFile = serveStatic({ root: dir, precompressed: true });
@@ -9504,14 +9638,108 @@ function mountFrontend(app, dir) {
9504
9638
  };
9505
9639
  const serveCompressed = every(compress(), serveWithCacheHeaders);
9506
9640
  const serveBuild = async (c, next) => {
9507
- if (isServerPath(c.req.path)) return next();
9508
- if (c.req.method !== "GET" && c.req.method !== "HEAD") return next();
9641
+ if (isServerPath(c.req.path)) {
9642
+ return next();
9643
+ }
9644
+ if (c.req.method !== "GET" && c.req.method !== "HEAD") {
9645
+ return next();
9646
+ }
9509
9647
  return serveCompressed(c, next);
9510
9648
  };
9649
+ const serveAppShell = serveStatic({ root: dir, rewriteRequestPath: () => "/index.html", precompressed: true });
9650
+ const serveSpaFallback = async (c, next) => {
9651
+ if (isServerPath(c.req.path)) {
9652
+ return next();
9653
+ }
9654
+ if (c.req.method !== "GET" && c.req.method !== "HEAD") {
9655
+ return next();
9656
+ }
9657
+ if (c.req.header("accept")?.includes("text/html") !== true) {
9658
+ return next();
9659
+ }
9660
+ const response = await serveAppShell(c, next);
9661
+ if (response instanceof Response) {
9662
+ response.headers.set("Cache-Control", REVALIDATE_CACHE_CONTROL);
9663
+ response.headers.set("Vary", "Accept-Encoding");
9664
+ }
9665
+ return response;
9666
+ };
9511
9667
  app.use("/*", serveBuild);
9668
+ app.use("/*", serveSpaFallback);
9512
9669
  return true;
9513
9670
  }
9514
9671
 
9672
+ // src/logger.ts
9673
+ import winston from "winston";
9674
+ var STANDALONE_META_SKIP = /* @__PURE__ */ new Set(["level", "message", "timestamp", "version", "stack", "splat"]);
9675
+ function shouldColorize() {
9676
+ const noColor = process.env["NO_COLOR"];
9677
+ if (noColor !== void 0 && noColor !== "") {
9678
+ return false;
9679
+ }
9680
+ const forceColor = process.env["FORCE_COLOR"];
9681
+ if (forceColor === "0") {
9682
+ return false;
9683
+ }
9684
+ if (forceColor !== void 0 && forceColor !== "") {
9685
+ return true;
9686
+ }
9687
+ return process.stderr.isTTY;
9688
+ }
9689
+ function standaloneMeta(info) {
9690
+ const copied = { ...info };
9691
+ const meta = {};
9692
+ for (const key of Object.keys(copied)) {
9693
+ if (STANDALONE_META_SKIP.has(key)) {
9694
+ continue;
9695
+ }
9696
+ meta[key] = copied[key];
9697
+ }
9698
+ if (Object.keys(meta).length === 0) {
9699
+ return "";
9700
+ }
9701
+ return ` ${JSON.stringify(meta)}`;
9702
+ }
9703
+ function standaloneFormat(color) {
9704
+ const parts = [
9705
+ winston.format.timestamp({ format: "HH:mm:ss" }),
9706
+ winston.format.errors({ stack: true })
9707
+ ];
9708
+ if (color) {
9709
+ parts.push(winston.format.colorize({ level: true }));
9710
+ }
9711
+ parts.push(
9712
+ winston.format.printf((info) => {
9713
+ const extra = standaloneMeta(info);
9714
+ const stack = typeof info["stack"] === "string" ? `
9715
+ ${info["stack"]}` : "";
9716
+ return `${String(info["timestamp"])} ${info.level} ${String(info.message)}${extra}${stack}`;
9717
+ })
9718
+ );
9719
+ return winston.format.combine(...parts);
9720
+ }
9721
+ function jsonFormat() {
9722
+ return winston.format.combine(
9723
+ winston.format.timestamp(),
9724
+ winston.format.errors({ stack: true }),
9725
+ winston.format.json()
9726
+ );
9727
+ }
9728
+ function serverLogFormat(options) {
9729
+ if (options.standalone) {
9730
+ return standaloneFormat(shouldColorize());
9731
+ }
9732
+ return jsonFormat();
9733
+ }
9734
+ function createServerLogger(options) {
9735
+ return winston.createLogger({
9736
+ level: options.level,
9737
+ defaultMeta: { version: options.version },
9738
+ format: serverLogFormat({ standalone: options.standalone }),
9739
+ transports: [new winston.transports.Console()]
9740
+ });
9741
+ }
9742
+
9515
9743
  // src/runtime/activeTurns.ts
9516
9744
  import "@truefoundry/trueforge-core/agent-session";
9517
9745
  function activeTurnKey(sessionId, turnId) {
@@ -9594,6 +9822,118 @@ var ActiveTurnRegistry = class {
9594
9822
  }
9595
9823
  };
9596
9824
 
9825
+ // src/startupBanner.ts
9826
+ var STANDALONE_MODE_DISCLAIMER = "Standalone mode is intended for local use on your own machine. It is not hardened for production or shared internet access \u2014 please keep it on localhost. We cannot take responsibility for data loss or unauthorized access if this mode is used beyond that.";
9827
+ var ANSI_SHADOW = {
9828
+ T: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u255A\u2550\u255D "],
9829
+ R: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u255D"],
9830
+ U: ["\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "],
9831
+ E: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u255D ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],
9832
+ F: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u255D ", "\u2588\u2588\u2551 ", "\u255A\u2550\u255D "],
9833
+ O: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "],
9834
+ G: [" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ", "\u2588\u2588\u2551 \u2588\u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "]
9835
+ };
9836
+ var WORDMARK_TEXT = "TRUEFORGE";
9837
+ var WARNING_INNER_WIDTH = 72;
9838
+ var BRAND_COLOR = "\x1B[38;5;99m";
9839
+ var YELLOW = "\x1B[33m";
9840
+ var BOLD = "\x1B[1m";
9841
+ var DIM = "\x1B[2m";
9842
+ var RESET = "\x1B[0m";
9843
+ function glyphFor(ch) {
9844
+ const glyph = ANSI_SHADOW[ch];
9845
+ if (glyph === void 0) {
9846
+ throw new Error(`No ASCII glyph for ${JSON.stringify(ch)}`);
9847
+ }
9848
+ return glyph;
9849
+ }
9850
+ function rowOf(glyph, row) {
9851
+ const cell = glyph[row];
9852
+ if (cell === void 0) {
9853
+ throw new Error(`Glyph is missing row ${String(row)}`);
9854
+ }
9855
+ return cell;
9856
+ }
9857
+ function renderTrueForgeWordmark() {
9858
+ const glyphs = [];
9859
+ for (let i = 0; i < WORDMARK_TEXT.length; i += 1) {
9860
+ const ch = WORDMARK_TEXT[i];
9861
+ if (ch === void 0) {
9862
+ throw new Error(`Missing character at index ${String(i)}`);
9863
+ }
9864
+ glyphs.push(glyphFor(ch));
9865
+ }
9866
+ const rowCount = glyphs[0]?.length;
9867
+ if (rowCount === void 0) {
9868
+ throw new Error("Wordmark text must not be empty");
9869
+ }
9870
+ const rows = [];
9871
+ for (let row = 0; row < rowCount; row += 1) {
9872
+ rows.push(glyphs.map((glyph) => rowOf(glyph, row)).join(""));
9873
+ }
9874
+ return rows.join("\n");
9875
+ }
9876
+ function wrapText(text, width) {
9877
+ const words = text.split(/\s+/).filter((word) => word.length > 0);
9878
+ const lines = [];
9879
+ let current = "";
9880
+ for (const word of words) {
9881
+ if (current.length === 0) {
9882
+ if (word.length > width) {
9883
+ lines.push(word);
9884
+ } else {
9885
+ current = word;
9886
+ }
9887
+ continue;
9888
+ }
9889
+ const next = `${current} ${word}`;
9890
+ if (next.length <= width) {
9891
+ current = next;
9892
+ } else {
9893
+ lines.push(current);
9894
+ current = word.length > width ? "" : word;
9895
+ if (word.length > width) {
9896
+ lines.push(word);
9897
+ }
9898
+ }
9899
+ }
9900
+ if (current.length > 0) {
9901
+ lines.push(current);
9902
+ }
9903
+ return lines;
9904
+ }
9905
+ function paint(options) {
9906
+ if (!options.enabled) {
9907
+ return options.text;
9908
+ }
9909
+ return `${options.color}${options.text}${RESET}`;
9910
+ }
9911
+ function warningBox(message) {
9912
+ const label = " WARNING ";
9913
+ const inner = wrapText(message, WARNING_INNER_WIDTH);
9914
+ const width = Math.max(WARNING_INNER_WIDTH, ...inner.map((line) => line.length), label.length);
9915
+ const topPad = width + 1 - label.length;
9916
+ const top = `\u250C\u2500${label}${"\u2500".repeat(topPad)}\u2510`;
9917
+ const body = inner.map((line) => `\u2502 ${line.padEnd(width)} \u2502`);
9918
+ const bottom = `\u2514${"\u2500".repeat(width + 2)}\u2518`;
9919
+ return [top, ...body, bottom].join("\n");
9920
+ }
9921
+ function formatStandaloneStartupBanner(options) {
9922
+ const { version, color } = options;
9923
+ const wordmark = paint({ text: renderTrueForgeWordmark(), color: `${BOLD}${BRAND_COLOR}`, enabled: color });
9924
+ const subtitle = paint({ text: ` TrueForge v${version} \xB7 standalone`, color: DIM, enabled: color });
9925
+ const warning = paint({ text: warningBox(STANDALONE_MODE_DISCLAIMER), color: `${BOLD}${YELLOW}`, enabled: color });
9926
+ return { wordmark: `
9927
+ ${wordmark}
9928
+ ${subtitle}
9929
+ `, warning };
9930
+ }
9931
+ function printStandaloneStartupBanner(options) {
9932
+ const { wordmark, warning } = formatStandaloneStartupBanner(options);
9933
+ console.log(wordmark);
9934
+ console.warn(warning);
9935
+ }
9936
+
9597
9937
  // src/main.ts
9598
9938
  var configuration2;
9599
9939
  var isOidcConfigured2;
@@ -9608,7 +9948,7 @@ try {
9608
9948
  }
9609
9949
  async function createStandalonePersistence(options) {
9610
9950
  const { sqlitePath, logger } = options;
9611
- await mkdir(path5.dirname(sqlitePath), { recursive: true });
9951
+ await mkdir(path6.dirname(sqlitePath), { recursive: true });
9612
9952
  const [{ createSqliteDb: createSqliteDb2 }, { migrateSqliteToLatest: migrateSqliteToLatest2 }, sqliteStores] = await Promise.all([
9613
9953
  Promise.resolve().then(() => (init_client(), client_exports)),
9614
9954
  Promise.resolve().then(() => (init_migrateSqlite(), migrateSqlite_exports)),
@@ -9750,11 +10090,16 @@ async function createServerRuntime(persistence, logger) {
9750
10090
  return { activeTurns, app, destroyDb, redis, requestReplyRouter };
9751
10091
  }
9752
10092
  try {
9753
- const logger = winston.createLogger({
10093
+ const logger = createServerLogger({
9754
10094
  level: configuration2.LOG_LEVEL,
9755
- format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
9756
- transports: [new winston.transports.Console()]
10095
+ standalone: configuration2.STANDALONE,
10096
+ version: PACKAGE_VERSION
9757
10097
  });
10098
+ if (configuration2.STANDALONE) {
10099
+ printStandaloneStartupBanner({ version: PACKAGE_VERSION, color: shouldColorize() });
10100
+ } else {
10101
+ logger.info("TrueForge starting", { mode: "distributed" });
10102
+ }
9758
10103
  const { activeTurns, app, destroyDb, redis, requestReplyRouter } = configuration2.STANDALONE ? await createServerRuntime(
9759
10104
  await createStandalonePersistence({ sqlitePath: configuration2.SQLITE_PATH, logger }),
9760
10105
  logger
@@ -9771,7 +10116,7 @@ try {
9771
10116
  if (redis) {
9772
10117
  requestReplySubscriber = redis.duplicate();
9773
10118
  requestReplySubscriber.on("error", (error) => {
9774
- logger.error("[RedisSubscriber] Client error", extractErrorLogFields8(error));
10119
+ logger.error("[RedisSubscriber] Client error", extractErrorLogFields9(error));
9775
10120
  });
9776
10121
  await requestReplySubscriber.connect();
9777
10122
  requestReplyExecutor = new RequestReplyExecutor({
@@ -9787,8 +10132,8 @@ try {
9787
10132
  });
9788
10133
  await requestReplyExecutor.init();
9789
10134
  }
9790
- const server = serve({ fetch: app.fetch, port: configuration2.PORT }, (info) => {
9791
- console.log(`Agent server listening on http://localhost:${String(info.port)} (docs at /api/v1/docs)`);
10135
+ const server = serve({ fetch: app.fetch, port: configuration2.PORT, hostname: configuration2.HOST }, (info) => {
10136
+ logger.info(`Agent server listening on http://${configuration2.HOST}:${String(info.port)} (docs at /api/v1/docs)`);
9792
10137
  });
9793
10138
  server.on("error", (error) => {
9794
10139
  console.error("Failed to start server:", error instanceof Error ? error.message : error);
@@ -9797,7 +10142,9 @@ try {
9797
10142
  if (configuration2.NODE_ENV !== "development") {
9798
10143
  let shuttingDown = false;
9799
10144
  const shutdown = async (signal) => {
9800
- if (shuttingDown) return;
10145
+ if (shuttingDown) {
10146
+ return;
10147
+ }
9801
10148
  shuttingDown = true;
9802
10149
  logger.info(`Received ${signal}, draining connections before shutdown`);
9803
10150
  setTimeout(() => {
@@ -9809,14 +10156,14 @@ try {
9809
10156
  resolve();
9810
10157
  });
9811
10158
  });
9812
- await activeTurns.shutdownAndWait(CancellationReason6.Abandoned);
10159
+ await activeTurns.shutdownAndWait(CancellationReason4.Abandoned);
9813
10160
  await closed;
9814
10161
  await requestReplyExecutor?.drain();
9815
10162
  await requestReplySubscriber?.close().catch((error) => {
9816
- logger.warn("[Redis] Error closing subscriber client during shutdown", extractErrorLogFields8(error));
10163
+ logger.warn("[Redis] Error closing subscriber client during shutdown", extractErrorLogFields9(error));
9817
10164
  });
9818
10165
  await redis?.close().catch((error) => {
9819
- logger.warn("[Redis] Error closing client during shutdown", extractErrorLogFields8(error));
10166
+ logger.warn("[Redis] Error closing client during shutdown", extractErrorLogFields9(error));
9820
10167
  });
9821
10168
  await destroyDb();
9822
10169
  process.exit(0);