@truefoundry/trueforge 0.1.4 → 0.2.0-rc.1

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 (252) hide show
  1. package/README.md +1 -1
  2. package/dist/_frontend/assets/AgentCodeSnippets-NZOFJE57-Bn94i1Ie.js +1 -0
  3. package/dist/_frontend/assets/AgentCodeSnippets-NZOFJE57-Bn94i1Ie.js.br +0 -0
  4. package/dist/_frontend/assets/AgentCodeSnippets-NZOFJE57-Bn94i1Ie.js.gz +0 -0
  5. package/dist/_frontend/assets/AgentMetricChart-JPU3MFQ2-pn-oatgo.js +1 -0
  6. package/dist/_frontend/assets/AgentMetricChart-JPU3MFQ2-pn-oatgo.js.br +0 -0
  7. package/dist/_frontend/assets/AgentMetricChart-JPU3MFQ2-pn-oatgo.js.gz +0 -0
  8. package/dist/_frontend/assets/AgentOverview-EEBHJC32-Bn4qidnv.js +1 -0
  9. package/dist/_frontend/assets/AgentOverview-EEBHJC32-Bn4qidnv.js.br +0 -0
  10. package/dist/_frontend/assets/AgentOverview-EEBHJC32-Bn4qidnv.js.gz +0 -0
  11. package/dist/_frontend/assets/AgentSessionEventTimeline-26Z6IB3B-D_yCZz1m.js +1 -0
  12. package/dist/_frontend/assets/AgentSessionEventTimeline-26Z6IB3B-D_yCZz1m.js.br +0 -0
  13. package/dist/_frontend/assets/AgentSessionEventTimeline-26Z6IB3B-D_yCZz1m.js.gz +0 -0
  14. package/dist/_frontend/assets/AgentSessionEventTimelineChart-CGCU7WBK-JGwv6e5T.js +1 -0
  15. package/dist/_frontend/assets/AgentSessionEventTimelineChart-CGCU7WBK-JGwv6e5T.js.br +0 -0
  16. package/dist/_frontend/assets/AgentSessionEventTimelineChart-CGCU7WBK-JGwv6e5T.js.gz +0 -0
  17. package/dist/_frontend/assets/AgentSessions-3MPDZASK-Dp6vYfGN.js +1 -0
  18. package/dist/_frontend/assets/AgentSessions-3MPDZASK-Dp6vYfGN.js.br +0 -0
  19. package/dist/_frontend/assets/AgentSessions-3MPDZASK-Dp6vYfGN.js.gz +0 -0
  20. package/dist/_frontend/assets/ConnectorSettings-MXFRWWR6-BEwXZbPM.js +1 -0
  21. package/dist/_frontend/assets/ConnectorSettings-MXFRWWR6-BEwXZbPM.js.br +0 -0
  22. package/dist/_frontend/assets/ConnectorSettings-MXFRWWR6-BEwXZbPM.js.gz +0 -0
  23. package/dist/_frontend/assets/{DockLayout-2RWDSUKE-eKoTN8R3.js → DockLayout-LM4AFMFY-DoBwJ3-e.js} +1 -1
  24. package/dist/_frontend/assets/DrawerLayout-JR3O6RRB-BZ9sffvm.js +2 -0
  25. package/dist/_frontend/assets/DrawerLayout-JR3O6RRB-BZ9sffvm.js.br +0 -0
  26. package/dist/_frontend/assets/DrawerLayout-JR3O6RRB-BZ9sffvm.js.gz +0 -0
  27. package/dist/_frontend/assets/ModelSettings-G7IFNC2Y-DxVYHG2m.js +1 -0
  28. package/dist/_frontend/assets/ModelSettings-G7IFNC2Y-DxVYHG2m.js.br +0 -0
  29. package/dist/_frontend/assets/ModelSettings-G7IFNC2Y-DxVYHG2m.js.gz +0 -0
  30. package/dist/_frontend/assets/SandboxSettings-NXAANMAX-DhC28qE6.js +1 -0
  31. package/dist/_frontend/assets/SandboxSettings-NXAANMAX-DhC28qE6.js.br +0 -0
  32. package/dist/_frontend/assets/SandboxSettings-NXAANMAX-DhC28qE6.js.gz +0 -0
  33. package/dist/_frontend/assets/SchedulesPage-KKLUDO6B-CWdrd7KY.js +1 -0
  34. package/dist/_frontend/assets/SchedulesPage-KKLUDO6B-CWdrd7KY.js.br +0 -0
  35. package/dist/_frontend/assets/SchedulesPage-KKLUDO6B-CWdrd7KY.js.gz +0 -0
  36. package/dist/_frontend/assets/SettingsBuilder-L34IQ56S-BQuxGH5w.js +2 -0
  37. package/dist/_frontend/assets/SettingsBuilder-L34IQ56S-BQuxGH5w.js.br +0 -0
  38. package/dist/_frontend/assets/SettingsBuilder-L34IQ56S-BQuxGH5w.js.gz +0 -0
  39. package/dist/_frontend/assets/ShellRouteSync-CEBETGEJ-C4NOyyck.js +1 -0
  40. package/dist/_frontend/assets/ShellRouteSync-CEBETGEJ-C4NOyyck.js.br +0 -0
  41. package/dist/_frontend/assets/ShellRouteSync-CEBETGEJ-C4NOyyck.js.gz +0 -0
  42. package/dist/_frontend/assets/SidebarLayout-A2HJPPHS-kusjDx4J.js +2 -0
  43. package/dist/_frontend/assets/SidebarLayout-A2HJPPHS-kusjDx4J.js.br +0 -0
  44. package/dist/_frontend/assets/SidebarLayout-A2HJPPHS-kusjDx4J.js.gz +0 -0
  45. package/dist/_frontend/assets/SkillSettings-FGGMSUNO-CjrGBX5J.js +1 -0
  46. package/dist/_frontend/assets/SkillSettings-FGGMSUNO-CjrGBX5J.js.br +0 -0
  47. package/dist/_frontend/assets/SkillSettings-FGGMSUNO-CjrGBX5J.js.gz +0 -0
  48. package/dist/_frontend/assets/TrueForgeUIWithRouter-MZVJWJMB-CZ8BOF1k.js +1 -0
  49. package/dist/_frontend/assets/WidgetLayout-6QM45OQQ-Bp0tde9v.js +1 -0
  50. package/dist/_frontend/assets/WidgetLayout-6QM45OQQ-Bp0tde9v.js.br +0 -0
  51. package/dist/_frontend/assets/WidgetLayout-6QM45OQQ-Bp0tde9v.js.gz +0 -0
  52. package/dist/_frontend/assets/chunk-62JRHF6Z-BLb_tkPU.js +12 -0
  53. package/dist/_frontend/assets/chunk-62JRHF6Z-BLb_tkPU.js.br +0 -0
  54. package/dist/_frontend/assets/chunk-62JRHF6Z-BLb_tkPU.js.gz +0 -0
  55. package/dist/_frontend/assets/chunk-DMMZSZTN-BBNhHida.js +1 -0
  56. package/dist/_frontend/assets/chunk-DMMZSZTN-BBNhHida.js.br +0 -0
  57. package/dist/_frontend/assets/chunk-DMMZSZTN-BBNhHida.js.gz +0 -0
  58. package/dist/_frontend/assets/chunk-FJW36PD7-R_XSoO50.js +2 -0
  59. package/dist/_frontend/assets/chunk-FJW36PD7-R_XSoO50.js.br +0 -0
  60. package/dist/_frontend/assets/chunk-FJW36PD7-R_XSoO50.js.gz +0 -0
  61. package/dist/_frontend/assets/chunk-WVE3F724-CL71bP7s.js +1 -0
  62. package/dist/_frontend/assets/chunk-WVE3F724-CL71bP7s.js.br +0 -0
  63. package/dist/_frontend/assets/chunk-WVE3F724-CL71bP7s.js.gz +0 -0
  64. package/dist/_frontend/assets/{cssMode-CvKwYh_L.js → cssMode-CVefs5W-.js} +1 -1
  65. package/dist/_frontend/assets/cssMode-CVefs5W-.js.br +0 -0
  66. package/dist/_frontend/assets/cssMode-CVefs5W-.js.gz +0 -0
  67. package/dist/_frontend/assets/{freemarker2-Bb2yOpT3.js → freemarker2-mt8l8QVE.js} +1 -1
  68. package/dist/_frontend/assets/freemarker2-mt8l8QVE.js.br +0 -0
  69. package/dist/_frontend/assets/freemarker2-mt8l8QVE.js.gz +0 -0
  70. package/dist/_frontend/assets/{handlebars-FL3wsxe0.js → handlebars-C97jT8Zn.js} +1 -1
  71. package/dist/_frontend/assets/handlebars-C97jT8Zn.js.br +0 -0
  72. package/dist/_frontend/assets/handlebars-C97jT8Zn.js.gz +0 -0
  73. package/dist/_frontend/assets/{html-Cb3v_ZRD.js → html-DKtvlaWU.js} +1 -1
  74. package/dist/_frontend/assets/html-DKtvlaWU.js.br +0 -0
  75. package/dist/_frontend/assets/html-DKtvlaWU.js.gz +0 -0
  76. package/dist/_frontend/assets/{htmlMode-JQDvK0Qf.js → htmlMode-BHsrcqlc.js} +1 -1
  77. package/dist/_frontend/assets/htmlMode-BHsrcqlc.js.br +0 -0
  78. package/dist/_frontend/assets/htmlMode-BHsrcqlc.js.gz +0 -0
  79. package/dist/_frontend/assets/{index-DRjgykCE.js → index-BW-oaxAt.js} +3 -3
  80. package/dist/_frontend/assets/index-BW-oaxAt.js.br +0 -0
  81. package/dist/_frontend/assets/index-BW-oaxAt.js.gz +0 -0
  82. package/dist/_frontend/assets/{index-DEKCw40W.css → index-D8eVAzN5.css} +1 -1
  83. package/dist/_frontend/assets/index-D8eVAzN5.css.br +0 -0
  84. package/dist/_frontend/assets/index-D8eVAzN5.css.gz +0 -0
  85. package/dist/_frontend/assets/index-DVCxCjDg.js +923 -0
  86. package/dist/_frontend/assets/index-DVCxCjDg.js.br +0 -0
  87. package/dist/_frontend/assets/index-DVCxCjDg.js.gz +0 -0
  88. package/dist/_frontend/assets/index-DuKoX4ct.js +18 -0
  89. package/dist/_frontend/assets/index-DuKoX4ct.js.br +0 -0
  90. package/dist/_frontend/assets/index-DuKoX4ct.js.gz +0 -0
  91. package/dist/_frontend/assets/{javascript-2WsgEpYV.js → javascript-Cs0N3w-s.js} +1 -1
  92. package/dist/_frontend/assets/{jsonMode-DnbseMlM.js → jsonMode-CqrfFSVA.js} +1 -1
  93. package/dist/_frontend/assets/jsonMode-CqrfFSVA.js.br +0 -0
  94. package/dist/_frontend/assets/jsonMode-CqrfFSVA.js.gz +0 -0
  95. package/dist/_frontend/assets/{liquid-DeE37I1e.js → liquid-C11lKF6J.js} +1 -1
  96. package/dist/_frontend/assets/liquid-C11lKF6J.js.br +0 -0
  97. package/dist/_frontend/assets/liquid-C11lKF6J.js.gz +0 -0
  98. package/dist/_frontend/assets/{lspLanguageFeatures-Bty8j9di.js → lspLanguageFeatures-DBZtnSMo.js} +1 -1
  99. package/dist/_frontend/assets/lspLanguageFeatures-DBZtnSMo.js.br +0 -0
  100. package/dist/_frontend/assets/lspLanguageFeatures-DBZtnSMo.js.gz +0 -0
  101. package/dist/_frontend/assets/{mdx-DfKPZX1Z.js → mdx-CCo4oKJJ.js} +1 -1
  102. package/dist/_frontend/assets/mdx-CCo4oKJJ.js.br +0 -0
  103. package/dist/_frontend/assets/mdx-CCo4oKJJ.js.gz +0 -0
  104. package/dist/_frontend/assets/{python-2i3Kiv75.js → python-627g_SSG.js} +1 -1
  105. package/dist/_frontend/assets/python-627g_SSG.js.br +0 -0
  106. package/dist/_frontend/assets/python-627g_SSG.js.gz +0 -0
  107. package/dist/_frontend/assets/{razor-B0N4vZnc.js → razor-BGDxoA7p.js} +1 -1
  108. package/dist/_frontend/assets/razor-BGDxoA7p.js.br +0 -0
  109. package/dist/_frontend/assets/razor-BGDxoA7p.js.gz +0 -0
  110. package/dist/_frontend/assets/{tsMode-D1Y8xh-o.js → tsMode-gPT7Bbjh.js} +1 -1
  111. package/dist/_frontend/assets/tsMode-gPT7Bbjh.js.br +0 -0
  112. package/dist/_frontend/assets/tsMode-gPT7Bbjh.js.gz +0 -0
  113. package/dist/_frontend/assets/{typescript-2nhip0PT.js → typescript-Cb0PzreF.js} +1 -1
  114. package/dist/_frontend/assets/typescript-Cb0PzreF.js.br +0 -0
  115. package/dist/_frontend/assets/typescript-Cb0PzreF.js.gz +0 -0
  116. package/dist/_frontend/assets/{workers-DSmTvA39.js → workers-BAgwFgJ0.js} +1 -1
  117. package/dist/_frontend/assets/workers-BAgwFgJ0.js.br +0 -0
  118. package/dist/_frontend/assets/workers-BAgwFgJ0.js.gz +0 -0
  119. package/dist/_frontend/assets/{xml-CA4M6Pks.js → xml-BpvCCHF9.js} +1 -1
  120. package/dist/_frontend/assets/xml-BpvCCHF9.js.br +0 -0
  121. package/dist/_frontend/assets/xml-BpvCCHF9.js.gz +0 -0
  122. package/dist/_frontend/assets/{yaml-D5KNk7Ji.js → yaml-f3XKmHoH.js} +1 -1
  123. package/dist/_frontend/assets/yaml-f3XKmHoH.js.br +0 -0
  124. package/dist/_frontend/assets/yaml-f3XKmHoH.js.gz +0 -0
  125. package/dist/_frontend/index.html +2 -31
  126. package/dist/controller-main.js +1259 -0
  127. package/dist/controller-main.js.map +1 -0
  128. package/dist/main.js +10419 -5343
  129. package/dist/main.js.map +1 -1
  130. package/dist/postgres/migrations/20260821_000001_agent_compaction.js +63 -0
  131. package/dist/postgres/migrations/20260821_000001_agent_compaction.js.map +1 -0
  132. package/dist/postgres/migrations/20260827_000001_schedule.js +40 -0
  133. package/dist/postgres/migrations/20260827_000001_schedule.js.map +1 -0
  134. package/dist/postgres/migrations/20260827_000001_session_metrics.js +25 -0
  135. package/dist/postgres/migrations/20260827_000001_session_metrics.js.map +1 -0
  136. package/dist/postgres/migrations/20260828_000001_schedule_name_uq.js +15 -0
  137. package/dist/postgres/migrations/20260828_000001_schedule_name_uq.js.map +1 -0
  138. package/dist/postgres/migrations/20260831_000001_session_external_id.js +26 -0
  139. package/dist/postgres/migrations/20260831_000001_session_external_id.js.map +1 -0
  140. package/dist/postgres/migrations/20260901_000001_agent_metadata.js +18 -0
  141. package/dist/postgres/migrations/20260901_000001_agent_metadata.js.map +1 -0
  142. package/dist/postgres/migrations/20260902_000001_session_metadata.js +15 -0
  143. package/dist/postgres/migrations/20260902_000001_session_metadata.js.map +1 -0
  144. package/dist/postgres/migrations/20260902_000002_agent_external_id.js +26 -0
  145. package/dist/postgres/migrations/20260902_000002_agent_external_id.js.map +1 -0
  146. package/dist/postgres/migrations/20260903_000001_drop_agent_metadata.js +18 -0
  147. package/dist/postgres/migrations/20260903_000001_drop_agent_metadata.js.map +1 -0
  148. package/dist/postgres/migrations/20260903_000002_created_by_subject.js +110 -0
  149. package/dist/postgres/migrations/20260903_000002_created_by_subject.js.map +1 -0
  150. package/dist/postgres/migrations/20260904_000001_schedule_agent_id.js +48 -0
  151. package/dist/postgres/migrations/20260904_000001_schedule_agent_id.js.map +1 -0
  152. package/dist/sqlite/migrations/20260821_000001_agent_compaction.js +69 -0
  153. package/dist/sqlite/migrations/20260821_000001_agent_compaction.js.map +1 -0
  154. package/dist/sqlite/migrations/20260827_000001_schedule.js +69 -0
  155. package/dist/sqlite/migrations/20260827_000001_schedule.js.map +1 -0
  156. package/dist/sqlite/migrations/20260827_000001_session_metrics.js +165 -0
  157. package/dist/sqlite/migrations/20260827_000001_session_metrics.js.map +1 -0
  158. package/dist/sqlite/migrations/20260828_000001_schedule_name_uq.js +20 -0
  159. package/dist/sqlite/migrations/20260828_000001_schedule_name_uq.js.map +1 -0
  160. package/dist/sqlite/migrations/20260831_000001_session_external_id.js +28 -0
  161. package/dist/sqlite/migrations/20260831_000001_session_external_id.js.map +1 -0
  162. package/dist/sqlite/migrations/20260901_000001_agent_metadata.js +92 -0
  163. package/dist/sqlite/migrations/20260901_000001_agent_metadata.js.map +1 -0
  164. package/dist/sqlite/migrations/20260902_000001_session_metadata.js +197 -0
  165. package/dist/sqlite/migrations/20260902_000001_session_metadata.js.map +1 -0
  166. package/dist/sqlite/migrations/20260902_000002_agent_external_id.js +28 -0
  167. package/dist/sqlite/migrations/20260902_000002_agent_external_id.js.map +1 -0
  168. package/dist/sqlite/migrations/20260903_000001_drop_agent_metadata.js +114 -0
  169. package/dist/sqlite/migrations/20260903_000001_drop_agent_metadata.js.map +1 -0
  170. package/dist/sqlite/migrations/20260903_000002_created_by_subject.js +496 -0
  171. package/dist/sqlite/migrations/20260903_000002_created_by_subject.js.map +1 -0
  172. package/dist/sqlite/migrations/20260904_000001_schedule_agent_id.js +131 -0
  173. package/dist/sqlite/migrations/20260904_000001_schedule_agent_id.js.map +1 -0
  174. package/package.json +31 -24
  175. package/dist/_frontend/assets/ConnectorSettings-ODC3LVHN-CAU9MgGN.js +0 -1
  176. package/dist/_frontend/assets/ConnectorSettings-ODC3LVHN-CAU9MgGN.js.br +0 -0
  177. package/dist/_frontend/assets/ConnectorSettings-ODC3LVHN-CAU9MgGN.js.gz +0 -0
  178. package/dist/_frontend/assets/DrawerLayout-CZLJYMIN-DWPAdLZz.js +0 -2
  179. package/dist/_frontend/assets/DrawerLayout-CZLJYMIN-DWPAdLZz.js.br +0 -0
  180. package/dist/_frontend/assets/DrawerLayout-CZLJYMIN-DWPAdLZz.js.gz +0 -0
  181. package/dist/_frontend/assets/ModelSettings-CKQ5CVAC-UBz_ch6T.js +0 -1
  182. package/dist/_frontend/assets/ModelSettings-CKQ5CVAC-UBz_ch6T.js.br +0 -0
  183. package/dist/_frontend/assets/ModelSettings-CKQ5CVAC-UBz_ch6T.js.gz +0 -0
  184. package/dist/_frontend/assets/SandboxSettings-HSCPYUOC-Csl-nC9h.js +0 -1
  185. package/dist/_frontend/assets/SandboxSettings-HSCPYUOC-Csl-nC9h.js.br +0 -0
  186. package/dist/_frontend/assets/SandboxSettings-HSCPYUOC-Csl-nC9h.js.gz +0 -0
  187. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-Ce3OWfa1.js +0 -2
  188. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-Ce3OWfa1.js.br +0 -0
  189. package/dist/_frontend/assets/SettingsBuilder-MYWRFXRI-Ce3OWfa1.js.gz +0 -0
  190. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-B5lyCu4o.js +0 -1
  191. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-B5lyCu4o.js.br +0 -0
  192. package/dist/_frontend/assets/ShellRouteSync-T4WLY57Q-B5lyCu4o.js.gz +0 -0
  193. package/dist/_frontend/assets/SidebarLayout-WVY54TGZ-CIx5jQIC.js +0 -2
  194. package/dist/_frontend/assets/SidebarLayout-WVY54TGZ-CIx5jQIC.js.br +0 -0
  195. package/dist/_frontend/assets/SidebarLayout-WVY54TGZ-CIx5jQIC.js.gz +0 -0
  196. package/dist/_frontend/assets/SkillSettings-ECH6SHZ7-CKWEzdO_.js +0 -1
  197. package/dist/_frontend/assets/SkillSettings-ECH6SHZ7-CKWEzdO_.js.br +0 -0
  198. package/dist/_frontend/assets/SkillSettings-ECH6SHZ7-CKWEzdO_.js.gz +0 -0
  199. package/dist/_frontend/assets/TrueForgeUIWithRouter-RKZ2E7PV-CoVbEgto.js +0 -1
  200. package/dist/_frontend/assets/WidgetLayout-NWWB2SXI-cUmY1p2v.js +0 -1
  201. package/dist/_frontend/assets/WidgetLayout-NWWB2SXI-cUmY1p2v.js.br +0 -0
  202. package/dist/_frontend/assets/WidgetLayout-NWWB2SXI-cUmY1p2v.js.gz +0 -0
  203. package/dist/_frontend/assets/chunk-62JRHF6Z-BftTGWZl.js +0 -12
  204. package/dist/_frontend/assets/chunk-62JRHF6Z-BftTGWZl.js.br +0 -0
  205. package/dist/_frontend/assets/chunk-62JRHF6Z-BftTGWZl.js.gz +0 -0
  206. package/dist/_frontend/assets/chunk-OZTNBS6V-CLmmFX7d.js +0 -4
  207. package/dist/_frontend/assets/chunk-OZTNBS6V-CLmmFX7d.js.br +0 -0
  208. package/dist/_frontend/assets/chunk-OZTNBS6V-CLmmFX7d.js.gz +0 -0
  209. package/dist/_frontend/assets/chunk-TCAVLWYL-DVhtkE3q.js +0 -2
  210. package/dist/_frontend/assets/chunk-TCAVLWYL-DVhtkE3q.js.br +0 -0
  211. package/dist/_frontend/assets/chunk-TCAVLWYL-DVhtkE3q.js.gz +0 -0
  212. package/dist/_frontend/assets/cssMode-CvKwYh_L.js.br +0 -0
  213. package/dist/_frontend/assets/cssMode-CvKwYh_L.js.gz +0 -0
  214. package/dist/_frontend/assets/freemarker2-Bb2yOpT3.js.br +0 -0
  215. package/dist/_frontend/assets/freemarker2-Bb2yOpT3.js.gz +0 -0
  216. package/dist/_frontend/assets/handlebars-FL3wsxe0.js.br +0 -0
  217. package/dist/_frontend/assets/handlebars-FL3wsxe0.js.gz +0 -0
  218. package/dist/_frontend/assets/html-Cb3v_ZRD.js.br +0 -0
  219. package/dist/_frontend/assets/html-Cb3v_ZRD.js.gz +0 -0
  220. package/dist/_frontend/assets/htmlMode-JQDvK0Qf.js.br +0 -0
  221. package/dist/_frontend/assets/htmlMode-JQDvK0Qf.js.gz +0 -0
  222. package/dist/_frontend/assets/index-DEKCw40W.css.br +0 -0
  223. package/dist/_frontend/assets/index-DEKCw40W.css.gz +0 -0
  224. package/dist/_frontend/assets/index-DJ1uWGdt.js +0 -859
  225. package/dist/_frontend/assets/index-DJ1uWGdt.js.br +0 -0
  226. package/dist/_frontend/assets/index-DJ1uWGdt.js.gz +0 -0
  227. package/dist/_frontend/assets/index-DRjgykCE.js.br +0 -0
  228. package/dist/_frontend/assets/index-DRjgykCE.js.gz +0 -0
  229. package/dist/_frontend/assets/jsonMode-DnbseMlM.js.br +0 -0
  230. package/dist/_frontend/assets/jsonMode-DnbseMlM.js.gz +0 -0
  231. package/dist/_frontend/assets/liquid-DeE37I1e.js.br +0 -0
  232. package/dist/_frontend/assets/liquid-DeE37I1e.js.gz +0 -0
  233. package/dist/_frontend/assets/lspLanguageFeatures-Bty8j9di.js.br +0 -0
  234. package/dist/_frontend/assets/lspLanguageFeatures-Bty8j9di.js.gz +0 -0
  235. package/dist/_frontend/assets/mdx-DfKPZX1Z.js.br +0 -0
  236. package/dist/_frontend/assets/mdx-DfKPZX1Z.js.gz +0 -0
  237. package/dist/_frontend/assets/python-2i3Kiv75.js.br +0 -0
  238. package/dist/_frontend/assets/python-2i3Kiv75.js.gz +0 -0
  239. package/dist/_frontend/assets/razor-B0N4vZnc.js.br +0 -0
  240. package/dist/_frontend/assets/razor-B0N4vZnc.js.gz +0 -0
  241. package/dist/_frontend/assets/tsMode-D1Y8xh-o.js.br +0 -0
  242. package/dist/_frontend/assets/tsMode-D1Y8xh-o.js.gz +0 -0
  243. package/dist/_frontend/assets/typescript-2nhip0PT.js.br +0 -0
  244. package/dist/_frontend/assets/typescript-2nhip0PT.js.gz +0 -0
  245. package/dist/_frontend/assets/workers-DSmTvA39.js.br +0 -0
  246. package/dist/_frontend/assets/workers-DSmTvA39.js.gz +0 -0
  247. package/dist/_frontend/assets/xml-CA4M6Pks.js.br +0 -0
  248. package/dist/_frontend/assets/xml-CA4M6Pks.js.gz +0 -0
  249. package/dist/_frontend/assets/yaml-D5KNk7Ji.js.br +0 -0
  250. package/dist/_frontend/assets/yaml-D5KNk7Ji.js.gz +0 -0
  251. package/dist/_frontend/index.html.br +0 -0
  252. package/dist/_frontend/index.html.gz +0 -0
@@ -0,0 +1,1259 @@
1
+ // src/config.ts
2
+ import { existsSync } from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ import envPaths from "env-paths";
7
+ var DEFAULT_PORT = 8790;
8
+ var DEFAULT_HOST = "localhost";
9
+ var DEFAULT_MAX_REQUEST_BODY_BYTES = 30 * 1024 * 1024;
10
+ var PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11
+ var LOCAL_EXECUTOR_ID = "local";
12
+ var ENV_PATHS_APP_NAME = "trueforge";
13
+ var DEFAULT_POSTGRES_USER = "trueforge";
14
+ var DEFAULT_POSTGRES_PASSWORD = "trueforge";
15
+ var DEFAULT_POSTGRES_DB = "trueforge";
16
+ var DEFAULT_POSTGRES_HOST = "localhost";
17
+ var DEFAULT_POSTGRES_PORT = 5432;
18
+ var DEFAULT_REDIS_URL = "redis://localhost:6379";
19
+ var DEFAULT_OIDC_USER_REFERENCE_CLAIM = "sub";
20
+ var DEFAULT_OIDC_USER_DISPLAY_NAME_CLAIM = "name";
21
+ var DEFAULT_OIDC_USER_ROLE_CLAIM = "groups";
22
+ var DEFAULT_OIDC_ADMIN_ROLE_VALUE = "admin";
23
+ var DEFAULT_OIDC_SCOPES = "openid,profile,email";
24
+ function getEnv(key, options) {
25
+ const value = process.env[key];
26
+ if (value !== void 0) {
27
+ return value;
28
+ }
29
+ if (options?.defaultValue !== void 0) {
30
+ return options.defaultValue;
31
+ }
32
+ if (options?.required) {
33
+ throw new Error(`Environment variable ${key} is required but was not specified.`);
34
+ }
35
+ return void 0;
36
+ }
37
+ function randomAlphanumeric(length) {
38
+ return Array.from({ length }, () => Math.floor(Math.random() * 36).toString(36)).join("");
39
+ }
40
+ function parsePort(raw) {
41
+ if (raw === void 0 || raw.trim() === "") {
42
+ return DEFAULT_PORT;
43
+ }
44
+ const port2 = Number(raw);
45
+ if (!Number.isInteger(port2) || port2 < 1 || port2 > 65535) {
46
+ throw new Error(`Environment variable PORT must be an integer between 1 and 65535, got "${raw}"`);
47
+ }
48
+ return port2;
49
+ }
50
+ function parseOidcScopes(raw) {
51
+ const scopes = raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
52
+ if (scopes.length === 0) {
53
+ throw new Error("OIDC_SCOPES must contain at least one scope.");
54
+ }
55
+ return scopes;
56
+ }
57
+ function parseOidcAllowedEmails(raw) {
58
+ if (raw === void 0 || raw.trim() === "") {
59
+ return [];
60
+ }
61
+ return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
62
+ }
63
+ function parsePositiveInt(options) {
64
+ const { envKey, raw, defaultValue } = options;
65
+ if (raw === void 0 || raw.trim() === "") {
66
+ return defaultValue;
67
+ }
68
+ const value = Number(raw);
69
+ if (!Number.isInteger(value) || value < 1) {
70
+ throw new Error(`Environment variable ${envKey} must be a positive integer, got "${raw}"`);
71
+ }
72
+ return value;
73
+ }
74
+ function parseBoolean(options) {
75
+ const { envKey, raw, defaultValue } = options;
76
+ if (raw === void 0 || raw.trim() === "") {
77
+ return defaultValue;
78
+ }
79
+ const value = raw.trim().toLowerCase();
80
+ if (value === "true") {
81
+ return true;
82
+ }
83
+ if (value === "false") {
84
+ return false;
85
+ }
86
+ throw new Error(`Environment variable ${envKey} must be "true" or "false", got "${raw}"`);
87
+ }
88
+ function parsePostgresSslMode(raw) {
89
+ if (!raw) {
90
+ return "";
91
+ }
92
+ const mode = raw.trim();
93
+ if (mode === "") {
94
+ return "";
95
+ }
96
+ switch (mode) {
97
+ case "disable":
98
+ case "prefer":
99
+ case "require":
100
+ case "verify-ca":
101
+ case "verify-full":
102
+ case "no-verify":
103
+ return mode;
104
+ default:
105
+ throw new Error(
106
+ `Environment variable POSTGRES_SSL_MODE must be one of disable, prefer, require, verify-ca, verify-full, no-verify; got "${mode}"`
107
+ );
108
+ }
109
+ }
110
+ function resolveDefaultFrontendDir() {
111
+ const packaged = path.join(PACKAGE_ROOT, "dist", "_frontend");
112
+ if (existsSync(path.join(packaged, "index.html"))) {
113
+ return packaged;
114
+ }
115
+ return path.join(PACKAGE_ROOT, "..", "frontend", "dist");
116
+ }
117
+ function resolveFrontendDir() {
118
+ const override = getEnv("FRONTEND_DIR");
119
+ if (override !== void 0 && override.trim() !== "") {
120
+ return path.resolve(override);
121
+ }
122
+ return resolveDefaultFrontendDir();
123
+ }
124
+ function resolveOptionalPathEnv(envKey) {
125
+ const override = getEnv(envKey);
126
+ if (override === void 0 || override.trim() === "") {
127
+ return void 0;
128
+ }
129
+ return path.resolve(override);
130
+ }
131
+ function resolveSqlitePath(appDataDir2) {
132
+ const override = getEnv("SQLITE_PATH");
133
+ if (override !== void 0 && override.trim() !== "") {
134
+ return path.resolve(override);
135
+ }
136
+ return path.join(appDataDir2, "db", "db.sqlite");
137
+ }
138
+ function resolveLocalSandboxRootParent(appDataDir2) {
139
+ return path.join(appDataDir2, "sandboxes");
140
+ }
141
+ function resolveCodeModeSocketParent() {
142
+ return path.join(os.tmpdir(), "tf_cms");
143
+ }
144
+ function resolveRedisUrl() {
145
+ const raw = getEnv("REDIS_URL", { defaultValue: DEFAULT_REDIS_URL }) ?? DEFAULT_REDIS_URL;
146
+ if (raw.trim() === "") {
147
+ throw new Error("Environment variable REDIS_URL must be non-empty when STANDALONE=false.");
148
+ }
149
+ return raw;
150
+ }
151
+ function resolvePostgresDatabaseUrl() {
152
+ const databaseUrl = getEnv("DATABASE_URL");
153
+ if (databaseUrl !== void 0 && databaseUrl.trim() !== "") {
154
+ return databaseUrl.trim();
155
+ }
156
+ const postgresUser = getEnv("POSTGRES_USER", { defaultValue: DEFAULT_POSTGRES_USER }) ?? DEFAULT_POSTGRES_USER;
157
+ const postgresPassword = getEnv("POSTGRES_PASSWORD", { defaultValue: DEFAULT_POSTGRES_PASSWORD }) ?? DEFAULT_POSTGRES_PASSWORD;
158
+ const postgresDb = getEnv("POSTGRES_DB", { defaultValue: DEFAULT_POSTGRES_DB }) ?? DEFAULT_POSTGRES_DB;
159
+ const postgresHost = getEnv("POSTGRES_HOST", { defaultValue: DEFAULT_POSTGRES_HOST }) ?? DEFAULT_POSTGRES_HOST;
160
+ const postgresPort = parsePositiveInt({
161
+ envKey: "POSTGRES_PORT",
162
+ raw: getEnv("POSTGRES_PORT"),
163
+ defaultValue: DEFAULT_POSTGRES_PORT
164
+ });
165
+ const postgresSslMode = parsePostgresSslMode(getEnv("POSTGRES_SSL_MODE"));
166
+ if (postgresUser.trim() === "" || postgresPassword.trim() === "" || postgresDb.trim() === "" || postgresHost.trim() === "") {
167
+ throw new Error(
168
+ "Set DATABASE_URL, or set non-empty POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, and POSTGRES_HOST when STANDALONE=false."
169
+ );
170
+ }
171
+ return buildPostgresConnectionString({
172
+ user: postgresUser,
173
+ password: postgresPassword,
174
+ host: postgresHost,
175
+ port: postgresPort,
176
+ database: postgresDb,
177
+ sslMode: postgresSslMode
178
+ });
179
+ }
180
+ function buildPostgresConnectionString(parts) {
181
+ let connectionString = `postgres://${encodeURIComponent(parts.user)}:${encodeURIComponent(parts.password)}@${parts.host}:${String(parts.port)}/${encodeURIComponent(parts.database)}`;
182
+ if (parts.sslMode !== "") {
183
+ connectionString += `?sslmode=${encodeURIComponent(parts.sslMode)}`;
184
+ }
185
+ return connectionString;
186
+ }
187
+ function resolveOIDCConfig() {
188
+ const issuerUrl = getEnv("OIDC_ISSUER_URL");
189
+ const clientId = getEnv("OIDC_CLIENT_ID");
190
+ const clientSecret = getEnv("OIDC_CLIENT_SECRET");
191
+ if (!issuerUrl && !clientId && !clientSecret) {
192
+ return void 0;
193
+ }
194
+ if (!issuerUrl || !clientId || !clientSecret) {
195
+ throw new Error(
196
+ "OIDC_ISSUER_URL, OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET must all be set together, or all left unset (unset = fixed local admin identity, no IdP)."
197
+ );
198
+ }
199
+ return {
200
+ OIDC_ISSUER_URL: issuerUrl,
201
+ OIDC_CLIENT_ID: clientId,
202
+ OIDC_CLIENT_SECRET: clientSecret,
203
+ OIDC_USER_REFERENCE_CLAIM: getEnv("OIDC_USER_REFERENCE_CLAIM", { defaultValue: DEFAULT_OIDC_USER_REFERENCE_CLAIM }) ?? DEFAULT_OIDC_USER_REFERENCE_CLAIM,
204
+ OIDC_USER_DISPLAY_NAME_CLAIM: getEnv("OIDC_USER_DISPLAY_NAME_CLAIM", { defaultValue: DEFAULT_OIDC_USER_DISPLAY_NAME_CLAIM }) ?? DEFAULT_OIDC_USER_DISPLAY_NAME_CLAIM,
205
+ OIDC_USER_ROLE_CLAIM: getEnv("OIDC_USER_ROLE_CLAIM", { defaultValue: DEFAULT_OIDC_USER_ROLE_CLAIM }) ?? DEFAULT_OIDC_USER_ROLE_CLAIM,
206
+ OIDC_ADMIN_ROLE_VALUE: getEnv("OIDC_ADMIN_ROLE_VALUE", { defaultValue: DEFAULT_OIDC_ADMIN_ROLE_VALUE }) ?? DEFAULT_OIDC_ADMIN_ROLE_VALUE,
207
+ OIDC_SCOPES: parseOidcScopes(getEnv("OIDC_SCOPES", { defaultValue: DEFAULT_OIDC_SCOPES }) ?? DEFAULT_OIDC_SCOPES),
208
+ OIDC_ALLOWED_EMAILS: parseOidcAllowedEmails(getEnv("OIDC_ALLOWED_EMAILS"))
209
+ };
210
+ }
211
+ var serverExecutionTimeoutSeconds = parsePositiveInt({
212
+ envKey: "SERVER_EXECUTION_TIMEOUT_SECONDS",
213
+ raw: getEnv("SERVER_EXECUTION_TIMEOUT_SECONDS"),
214
+ defaultValue: 600
215
+ });
216
+ var standalone = parseBoolean({
217
+ envKey: "STANDALONE",
218
+ raw: getEnv("STANDALONE"),
219
+ defaultValue: true
220
+ });
221
+ var appDataDirSuffix = getEnv("APP_DATA_DIR_SUFFIX", { defaultValue: "" }) ?? "";
222
+ var appDataDir = envPaths(ENV_PATHS_APP_NAME, { suffix: appDataDirSuffix }).data;
223
+ var port = parsePort(getEnv("PORT"));
224
+ var host = getEnv("HOST", { defaultValue: DEFAULT_HOST }) ?? DEFAULT_HOST;
225
+ var shared = {
226
+ LOG_LEVEL: getEnv("LOG_LEVEL", { defaultValue: "info" }) ?? "info",
227
+ ACCESS_LOGS: parseBoolean({ envKey: "ACCESS_LOGS", raw: getEnv("ACCESS_LOGS"), defaultValue: true }),
228
+ NODE_ENV: getEnv("NODE_ENV"),
229
+ PORT: port,
230
+ HOST: host,
231
+ EXECUTOR_ID: standalone ? LOCAL_EXECUTOR_ID : randomAlphanumeric(6),
232
+ MODEL_CATALOG_PATH: resolveOptionalPathEnv("MODEL_CATALOG_PATH"),
233
+ MCP_CATALOG_PATH: resolveOptionalPathEnv("MCP_CATALOG_PATH"),
234
+ SKILL_CATALOG_PATH: resolveOptionalPathEnv("SKILL_CATALOG_PATH"),
235
+ SANDBOX_CATALOG_PATH: resolveOptionalPathEnv("SANDBOX_CATALOG_PATH"),
236
+ FRONTEND_DIR: resolveFrontendDir(),
237
+ MCP_REQUEST_TIMEOUT_MS: parsePositiveInt({
238
+ envKey: "MCP_REQUEST_TIMEOUT_MS",
239
+ raw: getEnv("MCP_REQUEST_TIMEOUT_MS"),
240
+ defaultValue: 4 * 60 * 1e3
241
+ }),
242
+ MCP_CONNECT_TIMEOUT_MS: parsePositiveInt({
243
+ envKey: "MCP_CONNECT_TIMEOUT_MS",
244
+ raw: getEnv("MCP_CONNECT_TIMEOUT_MS"),
245
+ defaultValue: 30 * 1e3
246
+ }),
247
+ MCP_DCR_OAUTH_CLIENT_NAME: getEnv("MCP_DCR_OAUTH_CLIENT_NAME", { defaultValue: "truefoundry-harness" }) ?? "truefoundry-harness",
248
+ SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD: parsePositiveInt({
249
+ envKey: "SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD",
250
+ raw: getEnv("SANDBOX_FILE_MAX_BYTES_FOR_DOWNLOAD"),
251
+ defaultValue: 20971520
252
+ }),
253
+ MAX_REQUEST_BODY_BYTES: parsePositiveInt({
254
+ envKey: "MAX_REQUEST_BODY_BYTES",
255
+ raw: getEnv("MAX_REQUEST_BODY_BYTES"),
256
+ defaultValue: DEFAULT_MAX_REQUEST_BODY_BYTES
257
+ }),
258
+ GRACEFUL_TIMEOUT_SECONDS: parsePositiveInt({
259
+ envKey: "GRACEFUL_TIMEOUT_SECONDS",
260
+ raw: getEnv("GRACEFUL_TIMEOUT_SECONDS"),
261
+ defaultValue: 30
262
+ }),
263
+ SERVER_EXECUTION_TIMEOUT_SECONDS: serverExecutionTimeoutSeconds,
264
+ TURN_STREAM_TTL_SECONDS: parsePositiveInt({
265
+ envKey: "TURN_STREAM_TTL_SECONDS",
266
+ raw: getEnv("TURN_STREAM_TTL_SECONDS"),
267
+ defaultValue: serverExecutionTimeoutSeconds + 300
268
+ }),
269
+ TURN_STREAM_POST_COMPLETION_TTL_SECONDS: parsePositiveInt({
270
+ envKey: "TURN_STREAM_POST_COMPLETION_TTL_SECONDS",
271
+ raw: getEnv("TURN_STREAM_POST_COMPLETION_TTL_SECONDS"),
272
+ defaultValue: 300
273
+ }),
274
+ TURN_SUBSCRIBE_TIMEOUT_MS: parsePositiveInt({
275
+ envKey: "TURN_SUBSCRIBE_TIMEOUT_MS",
276
+ raw: getEnv("TURN_SUBSCRIBE_TIMEOUT_MS"),
277
+ defaultValue: 6e5
278
+ }),
279
+ REDIS_REQUEST_REPLY_TIMEOUT_MS: parsePositiveInt({
280
+ envKey: "REDIS_REQUEST_REPLY_TIMEOUT_MS",
281
+ raw: getEnv("REDIS_REQUEST_REPLY_TIMEOUT_MS"),
282
+ defaultValue: 6e4
283
+ }),
284
+ REDIS_REQUEST_REPLY_HEARTBEAT_INTERVAL_MS: parsePositiveInt({
285
+ envKey: "REDIS_REQUEST_REPLY_HEARTBEAT_INTERVAL_MS",
286
+ raw: getEnv("REDIS_REQUEST_REPLY_HEARTBEAT_INTERVAL_MS"),
287
+ defaultValue: 5e3
288
+ }),
289
+ REDIS_REQUEST_REPLY_REPLY_TTL_MS: parsePositiveInt({
290
+ envKey: "REDIS_REQUEST_REPLY_REPLY_TTL_MS",
291
+ raw: getEnv("REDIS_REQUEST_REPLY_REPLY_TTL_MS"),
292
+ defaultValue: 12e4
293
+ }),
294
+ REDIS_REQUEST_REPLY_POLL_INTERVAL_MS: parsePositiveInt({
295
+ envKey: "REDIS_REQUEST_REPLY_POLL_INTERVAL_MS",
296
+ raw: getEnv("REDIS_REQUEST_REPLY_POLL_INTERVAL_MS"),
297
+ defaultValue: 500
298
+ }),
299
+ PUBLIC_BASE_URL: getEnv("PUBLIC_BASE_URL", { defaultValue: "" }) ?? "",
300
+ SERVER_URL: getEnv("SERVER_URL", { defaultValue: `http://localhost:${String(port)}` }) ?? `http://localhost:${String(port)}`,
301
+ TRUEFORGE_MTLS_ENABLED: parseBoolean({
302
+ envKey: "TRUEFORGE_MTLS_ENABLED",
303
+ raw: getEnv("TRUEFORGE_MTLS_ENABLED"),
304
+ defaultValue: false
305
+ }),
306
+ TRUEFORGE_MTLS_CERTS_DIR: getEnv("TRUEFORGE_MTLS_CERTS_DIR", { defaultValue: "/etc/tls" }) ?? "/etc/tls"
307
+ };
308
+ var configuration = standalone ? {
309
+ ...shared,
310
+ STANDALONE: true,
311
+ SQLITE_PATH: resolveSqlitePath(appDataDir),
312
+ LOCAL_SANDBOX_ROOT_PARENT: resolveLocalSandboxRootParent(appDataDir),
313
+ CODE_MODE_SOCKET_PARENT: resolveCodeModeSocketParent()
314
+ } : {
315
+ ...shared,
316
+ STANDALONE: false,
317
+ DATABASE_URL: resolvePostgresDatabaseUrl(),
318
+ DATABASE_POOL_MAX: parsePositiveInt({
319
+ envKey: "DATABASE_POOL_MAX",
320
+ raw: getEnv("DATABASE_POOL_MAX"),
321
+ defaultValue: 10
322
+ }),
323
+ POSTGRES_STATEMENT_TIMEOUT_MS: parsePositiveInt({
324
+ envKey: "POSTGRES_STATEMENT_TIMEOUT_MS",
325
+ raw: getEnv("POSTGRES_STATEMENT_TIMEOUT_MS"),
326
+ defaultValue: 6e4
327
+ }),
328
+ POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS: parsePositiveInt({
329
+ envKey: "POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS",
330
+ raw: getEnv("POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS"),
331
+ defaultValue: 6e4
332
+ }),
333
+ REDIS_URL: resolveRedisUrl(),
334
+ OIDC: resolveOIDCConfig(),
335
+ TRUEFOUNDRY_SERVICEFOUNDRY_SERVER_URL: getEnv("TRUEFOUNDRY_SERVICEFOUNDRY_SERVER_URL", { required: false }),
336
+ TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_TIMEOUT_MS: parsePositiveInt({
337
+ envKey: "TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_TIMEOUT_MS",
338
+ raw: getEnv("TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_TIMEOUT_MS"),
339
+ defaultValue: 1e4
340
+ }),
341
+ TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_AGENT_TIMEOUT_MS: parsePositiveInt({
342
+ envKey: "TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_AGENT_TIMEOUT_MS",
343
+ raw: getEnv("TRUEFOUNDRY_SERVICEFOUNDRY_HTTP_AGENT_TIMEOUT_MS"),
344
+ defaultValue: 3e3
345
+ }),
346
+ TRUEFOUNDRY_MTLS_ENABLED: parseBoolean({
347
+ envKey: "TRUEFOUNDRY_MTLS_ENABLED",
348
+ raw: getEnv("TRUEFOUNDRY_MTLS_ENABLED"),
349
+ defaultValue: false
350
+ }),
351
+ TRUEFOUNDRY_MTLS_CERTS_DIR: getEnv("TRUEFOUNDRY_MTLS_CERTS_DIR", { defaultValue: "/etc/tls/truefoundry" }) ?? "/etc/tls/truefoundry"
352
+ };
353
+ function isOidcConfigured(value) {
354
+ return !value.STANDALONE && value.OIDC !== void 0;
355
+ }
356
+ function isTrueFoundryModeEnabled(config = configuration) {
357
+ return !config.STANDALONE && config.TRUEFOUNDRY_SERVICEFOUNDRY_SERVER_URL !== void 0;
358
+ }
359
+ if (isTrueFoundryModeEnabled(configuration) && isOidcConfigured(configuration)) {
360
+ throw new Error(
361
+ "TRUEFOUNDRY_SERVICEFOUNDRY_SERVER_URL (TrueFoundry mode) and OIDC (SSO) cannot both be enabled at once."
362
+ );
363
+ }
364
+ var config_default = configuration;
365
+
366
+ // src/controller.ts
367
+ import { TrueForge } from "@truefoundry/trueforge-sdk";
368
+
369
+ // src/controller/Controller.ts
370
+ var CONTROLLER_STOPPED = "controller-stopped";
371
+ var Controller = class {
372
+ #loops;
373
+ #logger;
374
+ #state = /* @__PURE__ */ new Map();
375
+ #abortController = new AbortController();
376
+ constructor(params) {
377
+ const names = /* @__PURE__ */ new Set();
378
+ for (const loop of params.loops) {
379
+ if (names.has(loop.name)) {
380
+ throw new Error(`Duplicate control loop name: ${loop.name}`);
381
+ }
382
+ names.add(loop.name);
383
+ }
384
+ this.#loops = params.loops;
385
+ this.#logger = params.logger;
386
+ }
387
+ /** Shared abort signal; aborted by {@link stop}. */
388
+ get signal() {
389
+ return this.#abortController.signal;
390
+ }
391
+ /**
392
+ * Starts every loop, each with an immediate first pass so a restart does not leave
393
+ * work waiting a full interval.
394
+ */
395
+ start() {
396
+ if (this.#abortController.signal.aborted || this.#state.size > 0) {
397
+ return;
398
+ }
399
+ for (const loop of this.#loops) {
400
+ const state = { timer: void 0, pass: void 0 };
401
+ this.#state.set(loop.name, state);
402
+ state.timer = setInterval(() => {
403
+ void this.#tick(loop);
404
+ }, loop.intervalMs);
405
+ void this.#tick(loop);
406
+ }
407
+ this.#logger.info("Controller started", { loops: this.#loops.map((loop) => loop.name) });
408
+ }
409
+ /**
410
+ * Stops every loop: clears timers, aborts the shared signal, then waits for
411
+ * in-flight passes to finish. Idempotent.
412
+ */
413
+ async stop() {
414
+ if (this.#abortController.signal.aborted) {
415
+ return;
416
+ }
417
+ this.#abortController.abort(CONTROLLER_STOPPED);
418
+ const passes = [];
419
+ for (const state of this.#state.values()) {
420
+ if (state.timer) {
421
+ clearInterval(state.timer);
422
+ state.timer = void 0;
423
+ }
424
+ if (state.pass) {
425
+ passes.push(state.pass);
426
+ }
427
+ }
428
+ await Promise.all(passes);
429
+ this.#logger.info("Controller stopped");
430
+ }
431
+ /**
432
+ * One pass of one loop: never throws, never overlaps itself.
433
+ *
434
+ * A pass that outlives its interval skips the next tick rather than running twice.
435
+ * Whatever it did not finish is picked up by the following pass — the same path a
436
+ * restart takes.
437
+ */
438
+ async #tick(loop) {
439
+ const state = this.#state.get(loop.name);
440
+ const { signal } = this.#abortController;
441
+ if (!state || signal.aborted || state.pass) {
442
+ return;
443
+ }
444
+ const pass = (async () => {
445
+ try {
446
+ await loop.tick(signal);
447
+ } catch (error) {
448
+ if (signal.aborted) {
449
+ return;
450
+ }
451
+ this.#logger.error("Control loop pass failed", { loop: loop.name, error });
452
+ }
453
+ })();
454
+ state.pass = pass;
455
+ try {
456
+ await pass;
457
+ } finally {
458
+ state.pass = void 0;
459
+ }
460
+ }
461
+ };
462
+
463
+ // src/db/scheduleStore.ts
464
+ import { randomUUID } from "crypto";
465
+
466
+ // src/schemas/schedule.ts
467
+ import { z as z2 } from "@hono/zod-openapi";
468
+ import { CreatedBySubjectSchema, TokenPaginationSchema } from "@truefoundry/trueforge-core/agent-session";
469
+
470
+ // src/schemas/common.ts
471
+ import { z } from "@hono/zod-openapi";
472
+ var NameSchema = z.string().min(2).max(64).regex(
473
+ /^[a-z](?:[a-z0-9._-]{0,62}[a-z0-9])$/,
474
+ 'must be 2\u201364 lowercase chars: start with a letter, end with alphanumeric, optionally separated by ".", "_" or "-"'
475
+ ).openapi("ResourceName");
476
+
477
+ // src/schemas/schedule.ts
478
+ var CRON_FIELD = String.raw`[\d*,\-/]+`;
479
+ var InvalidCronError = class extends Error {
480
+ constructor(message, options) {
481
+ super(message, options);
482
+ this.name = "InvalidCronError";
483
+ }
484
+ };
485
+ var CronExpressionSchema = z2.string().trim().regex(
486
+ new RegExp(`^${CRON_FIELD}(?:\\s+${CRON_FIELD}){4}$`),
487
+ "must be a 5-field cron expression: minute hour day-of-month month day-of-week"
488
+ ).describe("Standard 5-field cron expression, evaluated in `timezone`.").openapi("CronExpression");
489
+ var TimezoneSchema = z2.string().trim().min(1).refine((value) => {
490
+ try {
491
+ new Intl.DateTimeFormat(void 0, { timeZone: value });
492
+ return true;
493
+ } catch {
494
+ return false;
495
+ }
496
+ }, 'must be a valid IANA time zone name, e.g. "America/New_York"').describe("IANA time zone the cron expression is evaluated in.").openapi("Timezone");
497
+ var IsoTimestamp = z2.iso.datetime().openapi({ type: "string", format: "date-time" });
498
+ var NullableIsoTimestamp = z2.iso.datetime().nullable().openapi({ type: ["string", "null"], format: "date-time" });
499
+ var ScheduleTaskSchema = z2.string().trim().min(1).describe("First user message sent to the agent on every run.");
500
+ var ScheduleStatusSchema = z2.enum(["active", "paused"]).openapi("ScheduleStatus");
501
+ var ScheduleManifestObjectSchema = z2.object({
502
+ task: ScheduleTaskSchema,
503
+ cron: CronExpressionSchema,
504
+ timezone: TimezoneSchema.default("UTC"),
505
+ status: ScheduleStatusSchema.default("active")
506
+ }).strict();
507
+ var ScheduleManifestSchema = ScheduleManifestObjectSchema.openapi("ScheduleManifest");
508
+ var ScheduleSchema = z2.object({
509
+ id: z2.string(),
510
+ agent_name: NameSchema,
511
+ name: NameSchema,
512
+ manifest: ScheduleManifestSchema,
513
+ created_by_subject: CreatedBySubjectSchema,
514
+ created_at: IsoTimestamp,
515
+ updated_at: IsoTimestamp
516
+ }).strict().openapi("Schedule");
517
+ var CreateScheduleRequestSchema = z2.object({
518
+ agent_name: NameSchema,
519
+ name: NameSchema,
520
+ manifest: ScheduleManifestSchema
521
+ }).strict().openapi("CreateScheduleRequest");
522
+ var UpdateScheduleRequestSchema = z2.object({
523
+ name: NameSchema,
524
+ manifest: ScheduleManifestSchema
525
+ }).strict().openapi("UpdateScheduleRequest");
526
+ var GetScheduleResponseSchema = z2.object({ data: ScheduleSchema }).openapi("GetScheduleResponse");
527
+ var ListSchedulesResponseSchema = z2.object({
528
+ data: z2.array(ScheduleSchema),
529
+ pagination: TokenPaginationSchema
530
+ }).openapi("ListSchedulesResponse");
531
+ var DeleteScheduleResponseSchema = z2.object({}).openapi("DeleteScheduleResponse");
532
+ var ScheduleRunStatusSchema = z2.enum(["scheduled", "triggered", "failed"]).openapi("ScheduleRunStatus");
533
+ var ScheduleRunSchema = z2.object({
534
+ id: z2.string(),
535
+ schedule_id: z2.string(),
536
+ name: z2.string(),
537
+ scheduled_for: IsoTimestamp,
538
+ status: ScheduleRunStatusSchema,
539
+ created_by_subject: CreatedBySubjectSchema,
540
+ triggered_at: NullableIsoTimestamp,
541
+ created_at: IsoTimestamp,
542
+ updated_at: IsoTimestamp
543
+ }).strict().openapi("ScheduleRun");
544
+ var ListScheduleRunsResponseSchema = z2.object({ data: z2.array(ScheduleRunSchema) }).openapi("ListScheduleRunsResponse");
545
+ var CreateScheduleRunRequestSchema = z2.object({
546
+ schedule_id: z2.string().min(1).max(64).describe("Immutable schedule identifier.")
547
+ }).strict().describe("Trigger an immediate run for the given schedule. The task is taken from the schedule manifest.").openapi("CreateScheduleRunRequest");
548
+ var CreateScheduleRunResponseSchema = z2.object({ data: ScheduleRunSchema }).openapi("CreateScheduleRunResponse");
549
+
550
+ // src/db/scheduleStore.ts
551
+ function cronRunName(scheduledFor) {
552
+ return `sched-${String(Math.floor(scheduledFor.getTime() / 1e3))}`;
553
+ }
554
+ function parseStoredScheduleManifest(manifest) {
555
+ return ScheduleManifestSchema.parse(manifest);
556
+ }
557
+ var ScheduleRunConflictError = class extends Error {
558
+ constructor(message, options) {
559
+ super(message, options);
560
+ this.name = "ScheduleRunConflictError";
561
+ }
562
+ };
563
+ var ScheduleNameConflictError = class extends Error {
564
+ tenant_id;
565
+ agent_name;
566
+ schedule_name;
567
+ constructor({ tenant_id, agent_name, name }, options) {
568
+ super(`Schedule name already exists for agent ${agent_name}: ${name}`, options);
569
+ this.name = "ScheduleNameConflictError";
570
+ this.tenant_id = tenant_id;
571
+ this.agent_name = agent_name;
572
+ this.schedule_name = name;
573
+ }
574
+ };
575
+ function shouldSyncPendingRun(previous, next) {
576
+ return previous.status !== next.status || previous.manifest.cron !== next.manifest.cron || previous.manifest.timezone !== next.manifest.timezone;
577
+ }
578
+
579
+ // src/runtime/cron.ts
580
+ import { CronExpressionParser } from "cron-parser";
581
+ function nextTriggerAfter(input) {
582
+ const { cron, timezone, from } = input;
583
+ try {
584
+ const interval = CronExpressionParser.parse(cron, {
585
+ currentDate: from,
586
+ tz: timezone
587
+ });
588
+ return interval.next().toDate();
589
+ } catch (error) {
590
+ throw new InvalidCronError(`Cron expression "${cron}" has no next trigger time in ${timezone}`, { cause: error });
591
+ }
592
+ }
593
+
594
+ // src/controller/scheduleDispatch.ts
595
+ var DISPATCH_BATCH_LIMIT = 20;
596
+ var SCHEDULE_DISPATCH_INTERVAL_MS = 6e4;
597
+ var SCHEDULE_DISPATCH_LOOP_NAME = "schedule-dispatch";
598
+ function executeScheduledRun(client) {
599
+ return async ({ run, schedule }) => {
600
+ const { data: session } = await client.internal.sessions.getOrCreateByExternalId({
601
+ externalId: run.id,
602
+ agent: { name: schedule.agent_name }
603
+ });
604
+ const turns = await client.sessions.listTurns(session.id, { limit: 1 });
605
+ if (turns.data.length > 0) {
606
+ return;
607
+ }
608
+ await client.sessions.createTurn(session.id, {
609
+ input: [{ type: "user.message", content: schedule.manifest.task }],
610
+ previousTurnId: "none"
611
+ });
612
+ };
613
+ }
614
+ async function finishScheduledRun(params) {
615
+ const { store, withTransaction, run, status, now: now2 } = params;
616
+ await withTransaction(async (txn) => {
617
+ const latest = await store.getScheduleForUpdate({ tenant_id: run.tenant_id, id: run.schedule_id }, txn);
618
+ const updated = await store.updateRunStatus({ tenant_id: run.tenant_id, id: run.id, status }, txn);
619
+ if (updated === void 0) {
620
+ return;
621
+ }
622
+ if (latest?.status !== "active") {
623
+ return;
624
+ }
625
+ const advanceFrom = new Date(Math.max(Date.parse(run.scheduled_for), now2.getTime()));
626
+ let nextTrigger;
627
+ try {
628
+ nextTrigger = nextTriggerAfter({
629
+ cron: latest.manifest.cron,
630
+ timezone: latest.manifest.timezone,
631
+ from: advanceFrom
632
+ });
633
+ } catch (error) {
634
+ if (!(error instanceof InvalidCronError)) {
635
+ throw error;
636
+ }
637
+ return;
638
+ }
639
+ await store.createRun(
640
+ {
641
+ tenant_id: latest.tenant_id,
642
+ schedule_id: latest.id,
643
+ name: cronRunName(nextTrigger),
644
+ scheduled_for: nextTrigger,
645
+ status: "scheduled",
646
+ created_by_subject: latest.created_by_subject
647
+ },
648
+ txn
649
+ );
650
+ });
651
+ }
652
+ async function dispatchScheduledRuns(params) {
653
+ const { store, withTransaction, onTriggered, logger, signal } = params;
654
+ const now2 = /* @__PURE__ */ new Date();
655
+ const scheduled = await store.listScheduledRuns({ limit: DISPATCH_BATCH_LIMIT, until: now2 });
656
+ let dispatched = 0;
657
+ let failed = 0;
658
+ for (const run of scheduled) {
659
+ if (signal?.aborted) {
660
+ break;
661
+ }
662
+ try {
663
+ const schedule = await store.getSchedule({
664
+ tenant_id: run.tenant_id,
665
+ id: run.schedule_id
666
+ });
667
+ if (schedule === void 0) {
668
+ continue;
669
+ }
670
+ try {
671
+ await onTriggered({ run, schedule });
672
+ } catch (error) {
673
+ logger.error("Failed to hand off triggered run", {
674
+ schedule_id: schedule.id,
675
+ run_id: run.id,
676
+ error
677
+ });
678
+ await finishScheduledRun({
679
+ store,
680
+ run,
681
+ now: now2,
682
+ status: "failed",
683
+ withTransaction
684
+ });
685
+ failed += 1;
686
+ continue;
687
+ }
688
+ await finishScheduledRun({
689
+ store,
690
+ run,
691
+ now: now2,
692
+ status: "triggered",
693
+ withTransaction
694
+ });
695
+ dispatched += 1;
696
+ } catch (error) {
697
+ logger.error("Failed to process scheduled run", {
698
+ schedule_id: run.schedule_id,
699
+ run_id: run.id,
700
+ error
701
+ });
702
+ }
703
+ }
704
+ return { dispatched, failed };
705
+ }
706
+ function scheduleDispatchLoop(params) {
707
+ const { scheduleStore, client, withTransaction, logger } = params;
708
+ return {
709
+ name: SCHEDULE_DISPATCH_LOOP_NAME,
710
+ intervalMs: SCHEDULE_DISPATCH_INTERVAL_MS,
711
+ async tick(signal) {
712
+ const result = await dispatchScheduledRuns({
713
+ store: scheduleStore,
714
+ onTriggered: executeScheduledRun(client),
715
+ logger,
716
+ withTransaction,
717
+ signal
718
+ });
719
+ if (result.dispatched > 0 || result.failed > 0) {
720
+ logger.debug("Scheduled runs dispatched or failed", result);
721
+ }
722
+ }
723
+ };
724
+ }
725
+
726
+ // src/http/tls.ts
727
+ import { readFileSync } from "fs";
728
+ import { createServer as createHttpsServer } from "https";
729
+ import { join } from "path";
730
+ import { rootCertificates, TLSSocket } from "tls";
731
+ import { Agent, fetch as undiciFetch } from "undici";
732
+ var TLS_CERT_FILE = "tls.crt";
733
+ var TLS_KEY_FILE = "tls.key";
734
+ var TLS_CA_FILE = "ca.crt";
735
+ function readTlsFile(input) {
736
+ const filePath = join(input.dir, input.fileName);
737
+ try {
738
+ return readFileSync(filePath, "utf8");
739
+ } catch (error) {
740
+ throw new Error(
741
+ `${input.enabledEnvKey} is true but ${filePath} could not be read. Check that the mTLS secret is mounted at the configured certs directory, or set ${input.enabledEnvKey}=false.`,
742
+ { cause: error }
743
+ );
744
+ }
745
+ }
746
+ function normalizeTlsUrl(input) {
747
+ if (!input.enabled) {
748
+ return input.url;
749
+ }
750
+ const parsed = new URL(input.url);
751
+ if (parsed.protocol === "http:") {
752
+ parsed.protocol = "https:";
753
+ }
754
+ return parsed.href;
755
+ }
756
+ function createTlsDispatcher(options) {
757
+ if (!options.enabled) {
758
+ return void 0;
759
+ }
760
+ const read = (fileName) => readTlsFile({ dir: options.dir, fileName, enabledEnvKey: options.enabledEnvKey });
761
+ return new Agent({
762
+ connect: {
763
+ // Appended to the default roots, not replacing them: passing `ca` alone would override Node's
764
+ // entire trust store for this dispatcher (breaks public HTTPS peers on the same agent).
765
+ ca: [...rootCertificates, read(TLS_CA_FILE)],
766
+ cert: read(TLS_CERT_FILE),
767
+ key: read(TLS_KEY_FILE)
768
+ }
769
+ });
770
+ }
771
+ function requestUrlFromFetchInput(input) {
772
+ if (typeof input === "string") {
773
+ return input;
774
+ }
775
+ if (input instanceof URL) {
776
+ return input.href;
777
+ }
778
+ return input.url;
779
+ }
780
+ function createTlsFetch(options) {
781
+ const dispatcher = createTlsDispatcher({
782
+ ...options,
783
+ enabledEnvKey: "TRUEFORGE_MTLS_ENABLED"
784
+ });
785
+ if (dispatcher === void 0) {
786
+ return void 0;
787
+ }
788
+ return (input, init) => undiciFetch(requestUrlFromFetchInput(input), { ...init, dispatcher });
789
+ }
790
+
791
+ // src/controller.ts
792
+ function createScheduleApiClient(params) {
793
+ const baseUrl = normalizeTlsUrl({ url: params.baseUrl, enabled: params.tls.enabled });
794
+ const fetchImpl = createTlsFetch(params.tls);
795
+ return new TrueForge({
796
+ baseUrl,
797
+ auth: false,
798
+ ...fetchImpl !== void 0 ? { fetch: fetchImpl } : {}
799
+ });
800
+ }
801
+ function createController(params) {
802
+ const { scheduleStore, withTransaction, logger, baseUrl } = params;
803
+ const tls = params.tls ?? { enabled: false, dir: "" };
804
+ return new Controller({
805
+ loops: [
806
+ scheduleDispatchLoop({
807
+ scheduleStore,
808
+ client: createScheduleApiClient({ baseUrl, tls }),
809
+ withTransaction,
810
+ logger
811
+ })
812
+ ],
813
+ logger
814
+ });
815
+ }
816
+ function runController(params) {
817
+ const { logger, gracefulTimeoutSeconds, onStopped } = params;
818
+ const controller = createController(params);
819
+ controller.start();
820
+ let shuttingDown = false;
821
+ const shutdown = async (signal) => {
822
+ if (shuttingDown) {
823
+ return;
824
+ }
825
+ shuttingDown = true;
826
+ logger.info(`Received ${signal}, stopping control loops`);
827
+ setTimeout(() => {
828
+ logger.warn(`Controller drain timed out after ${String(gracefulTimeoutSeconds)}s, exiting`);
829
+ process.exit(1);
830
+ }, gracefulTimeoutSeconds * 1e3).unref();
831
+ await controller.stop();
832
+ await onStopped?.();
833
+ process.exit(0);
834
+ };
835
+ process.on("SIGTERM", (signal) => {
836
+ void shutdown(signal);
837
+ });
838
+ process.on("SIGINT", (signal) => {
839
+ void shutdown(signal);
840
+ });
841
+ return controller;
842
+ }
843
+
844
+ // src/db/postgres/client.ts
845
+ import { Kysely, PostgresDialect } from "kysely";
846
+ import pg, { Pool } from "pg";
847
+
848
+ // src/db/postgres/schema.ts
849
+ import { sql } from "kysely";
850
+ var TRUEFORGE_SCHEMA = "trueforge";
851
+
852
+ // src/db/postgres/client.ts
853
+ var INT8_OID = 20;
854
+ var setTypeParserByOid = pg.types.setTypeParser.bind(
855
+ pg.types
856
+ );
857
+ function parseInt8Array(value) {
858
+ if (value === "{}" || value === "") {
859
+ return [];
860
+ }
861
+ return value.slice(1, -1).split(",").map((element) => Number(element));
862
+ }
863
+ function configurePgTypeParsers() {
864
+ pg.types.setTypeParser(INT8_OID, Number);
865
+ setTypeParserByOid(1016, parseInt8Array);
866
+ }
867
+ function createDb(options) {
868
+ const { connectionString, poolMax, statementTimeoutMs, idleInTransactionSessionTimeoutMs } = options;
869
+ configurePgTypeParsers();
870
+ return new Kysely({
871
+ dialect: new PostgresDialect({
872
+ pool: new Pool({
873
+ connectionString,
874
+ max: poolMax,
875
+ statement_timeout: statementTimeoutMs,
876
+ idle_in_transaction_session_timeout: idleInTransactionSessionTimeoutMs,
877
+ options: `-c search_path=${TRUEFORGE_SCHEMA}`
878
+ })
879
+ })
880
+ });
881
+ }
882
+ function isPgErrorCode(err, code) {
883
+ if (typeof err !== "object" || err === null || !("code" in err)) {
884
+ return false;
885
+ }
886
+ return err.code === code;
887
+ }
888
+ function isUniqueViolation(err) {
889
+ return isPgErrorCode(err, "23505");
890
+ }
891
+
892
+ // src/db/postgres/schedule-store/PostgresScheduleStore.ts
893
+ import {
894
+ decodeOffsetPageToken,
895
+ paginateOffsetRows
896
+ } from "@truefoundry/trueforge-core/agent-session/store/OffsetPageToken";
897
+
898
+ // src/utils/id.ts
899
+ import { ulid } from "ulid";
900
+ function newId() {
901
+ return ulid().toLowerCase();
902
+ }
903
+
904
+ // src/db/createdBySubject.ts
905
+ import { CreatedBySubjectSchema as CreatedBySubjectSchema2 } from "@truefoundry/trueforge-core/agent-session";
906
+ function parseStoredCreatedBySubject(value) {
907
+ return CreatedBySubjectSchema2.parse(value);
908
+ }
909
+
910
+ // src/db/postgres/sqlExpressions.ts
911
+ import { sql as sql2 } from "kysely";
912
+ function json(value) {
913
+ return sql2`${JSON.stringify(value)}::jsonb`;
914
+ }
915
+ function now() {
916
+ return sql2`now()`;
917
+ }
918
+ function whereCreatedByOrAgentIds(query, filter) {
919
+ if (filter === void 0) {
920
+ return query;
921
+ }
922
+ if (filter.agent_ids.length === 0) {
923
+ return query.where(sql2`created_by_subject->>'subject_id'`, "=", filter.created_by_subject_id);
924
+ }
925
+ return query.where(
926
+ (eb) => eb.or([
927
+ eb(sql2`created_by_subject->>'subject_id'`, "=", filter.created_by_subject_id),
928
+ eb(sql2`agent_id`, "in", [...filter.agent_ids])
929
+ ])
930
+ );
931
+ }
932
+
933
+ // src/db/postgres/schedule-store/PostgresScheduleStore.ts
934
+ function toScheduleRecord(row) {
935
+ return {
936
+ id: row.id,
937
+ tenant_id: row.tenant_id,
938
+ agent_id: row.agent_id,
939
+ agent_name: row.agent_name,
940
+ name: row.name,
941
+ manifest: parseStoredScheduleManifest(row.manifest),
942
+ status: row.status,
943
+ created_by_subject: parseStoredCreatedBySubject(row.created_by_subject),
944
+ created_at: row.created_at.toISOString(),
945
+ updated_at: row.updated_at.toISOString()
946
+ };
947
+ }
948
+ function toRunRecord(row) {
949
+ return {
950
+ id: row.id,
951
+ tenant_id: row.tenant_id,
952
+ schedule_id: row.schedule_id,
953
+ name: row.name,
954
+ scheduled_for: row.scheduled_for.toISOString(),
955
+ status: row.status,
956
+ created_by_subject: parseStoredCreatedBySubject(row.created_by_subject),
957
+ triggered_at: row.triggered_at === null ? null : row.triggered_at.toISOString(),
958
+ created_at: row.created_at.toISOString(),
959
+ updated_at: row.updated_at.toISOString()
960
+ };
961
+ }
962
+ var PostgresScheduleStore = class {
963
+ #db;
964
+ constructor(db) {
965
+ this.#db = db;
966
+ }
967
+ async #syncPendingRun(schedule, from, transaction) {
968
+ const db = transaction ?? this.#db;
969
+ await db.deleteFrom("schedule_run").where("tenant_id", "=", schedule.tenant_id).where("schedule_id", "=", schedule.id).where("status", "=", "scheduled").execute();
970
+ if (schedule.status !== "active") {
971
+ return void 0;
972
+ }
973
+ const nextTrigger = nextTriggerAfter({
974
+ cron: schedule.manifest.cron,
975
+ timezone: schedule.manifest.timezone,
976
+ from
977
+ });
978
+ return this.createRun(
979
+ {
980
+ tenant_id: schedule.tenant_id,
981
+ schedule_id: schedule.id,
982
+ name: cronRunName(nextTrigger),
983
+ scheduled_for: nextTrigger,
984
+ status: "scheduled",
985
+ created_by_subject: schedule.created_by_subject
986
+ },
987
+ transaction
988
+ );
989
+ }
990
+ async getSchedule(input, transaction) {
991
+ const db = transaction ?? this.#db;
992
+ const row = await db.selectFrom("schedule").selectAll().where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).executeTakeFirst();
993
+ return row === void 0 ? void 0 : toScheduleRecord(row);
994
+ }
995
+ async getScheduleForUpdate(input, transaction) {
996
+ const row = await transaction.selectFrom("schedule").selectAll().where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).forUpdate().executeTakeFirst();
997
+ return row === void 0 ? void 0 : toScheduleRecord(row);
998
+ }
999
+ async createScheduleAndRun(input, transaction) {
1000
+ const db = transaction ?? this.#db;
1001
+ let row;
1002
+ try {
1003
+ row = await db.insertInto("schedule").values({
1004
+ id: newId(),
1005
+ tenant_id: input.tenant_id,
1006
+ agent_id: input.agent_id,
1007
+ agent_name: input.agent_name,
1008
+ name: input.name,
1009
+ manifest: json(input.manifest),
1010
+ // Column mirrors the manifest so the dispatch scan and API reads share one value.
1011
+ status: input.manifest.status,
1012
+ created_by_subject: json(input.created_by_subject),
1013
+ created_at: now(),
1014
+ updated_at: now()
1015
+ }).returningAll().executeTakeFirstOrThrow();
1016
+ } catch (error) {
1017
+ if (isUniqueViolation(error)) {
1018
+ throw new ScheduleNameConflictError(
1019
+ { tenant_id: input.tenant_id, agent_name: input.agent_name, name: input.name },
1020
+ { cause: error }
1021
+ );
1022
+ }
1023
+ throw error;
1024
+ }
1025
+ const schedule = toScheduleRecord(row);
1026
+ const pendingRun = await this.#syncPendingRun(schedule, input.runFrom, transaction);
1027
+ return { schedule, pendingRun };
1028
+ }
1029
+ async updateScheduleAndRun(input, transaction) {
1030
+ const previous = transaction !== void 0 ? await this.getScheduleForUpdate({ tenant_id: input.tenant_id, id: input.id }, transaction) : await this.getSchedule({ tenant_id: input.tenant_id, id: input.id });
1031
+ if (previous === void 0) {
1032
+ return void 0;
1033
+ }
1034
+ const db = transaction ?? this.#db;
1035
+ let row;
1036
+ try {
1037
+ row = await db.updateTable("schedule").set({ name: input.name, manifest: json(input.manifest), status: input.manifest.status, updated_at: now() }).where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).returningAll().executeTakeFirst();
1038
+ } catch (error) {
1039
+ if (isUniqueViolation(error)) {
1040
+ throw new ScheduleNameConflictError(
1041
+ { tenant_id: input.tenant_id, agent_name: previous.agent_name, name: input.name },
1042
+ { cause: error }
1043
+ );
1044
+ }
1045
+ throw error;
1046
+ }
1047
+ if (row === void 0) {
1048
+ return void 0;
1049
+ }
1050
+ const schedule = toScheduleRecord(row);
1051
+ if (!shouldSyncPendingRun(previous, schedule)) {
1052
+ const pendingRun2 = await this.getScheduledRunFor(
1053
+ { tenant_id: schedule.tenant_id, schedule_id: schedule.id },
1054
+ transaction
1055
+ );
1056
+ return { schedule, pendingRun: pendingRun2 };
1057
+ }
1058
+ const pendingRun = await this.#syncPendingRun(schedule, input.runFrom, transaction);
1059
+ return { schedule, pendingRun };
1060
+ }
1061
+ async deleteSchedule(input, transaction) {
1062
+ const db = transaction ?? this.#db;
1063
+ await db.deleteFrom("schedule").where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).execute();
1064
+ }
1065
+ async listSchedules(input, transaction) {
1066
+ const offset = decodeOffsetPageToken(input.page_token);
1067
+ const db = transaction ?? this.#db;
1068
+ let query = db.selectFrom("schedule").selectAll().where("tenant_id", "=", input.tenant_id);
1069
+ if (input.agent_names !== void 0) {
1070
+ query = query.where("agent_name", "in", [...input.agent_names]);
1071
+ }
1072
+ query = whereCreatedByOrAgentIds(query, input.created_by_or_agent_ids);
1073
+ const rows = await query.orderBy("created_at", "desc").orderBy("id").limit(input.limit + 1).offset(offset).execute();
1074
+ const { data, pagination } = paginateOffsetRows(rows, input.limit, offset);
1075
+ return { data: data.map(toScheduleRecord), pagination };
1076
+ }
1077
+ async listRuns(input, transaction) {
1078
+ const db = transaction ?? this.#db;
1079
+ const rows = await db.selectFrom("schedule_run").selectAll().where("tenant_id", "=", input.tenant_id).where("schedule_id", "=", input.schedule_id).orderBy("scheduled_for", "desc").orderBy("id").execute();
1080
+ return rows.map(toRunRecord);
1081
+ }
1082
+ async getRun(input, transaction) {
1083
+ const db = transaction ?? this.#db;
1084
+ const row = await db.selectFrom("schedule_run").selectAll().where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).executeTakeFirst();
1085
+ return row === void 0 ? void 0 : toRunRecord(row);
1086
+ }
1087
+ async getScheduledRunFor(input, transaction) {
1088
+ const db = transaction ?? this.#db;
1089
+ const row = await db.selectFrom("schedule_run").selectAll().where("tenant_id", "=", input.tenant_id).where("schedule_id", "=", input.schedule_id).where("status", "=", "scheduled").executeTakeFirst();
1090
+ return row === void 0 ? void 0 : toRunRecord(row);
1091
+ }
1092
+ async createRun(input, transaction) {
1093
+ const db = transaction ?? this.#db;
1094
+ try {
1095
+ const row = await db.insertInto("schedule_run").values({
1096
+ id: newId(),
1097
+ tenant_id: input.tenant_id,
1098
+ schedule_id: input.schedule_id,
1099
+ name: input.name,
1100
+ scheduled_for: input.scheduled_for,
1101
+ status: input.status,
1102
+ created_by_subject: json(input.created_by_subject),
1103
+ triggered_at: input.triggered_at ?? null,
1104
+ created_at: now(),
1105
+ updated_at: now()
1106
+ }).returningAll().executeTakeFirstOrThrow();
1107
+ return toRunRecord(row);
1108
+ } catch (error) {
1109
+ if (isUniqueViolation(error)) {
1110
+ throw new ScheduleRunConflictError(`Schedule run already exists: ${input.name}`, { cause: error });
1111
+ }
1112
+ throw error;
1113
+ }
1114
+ }
1115
+ async updateRunStatus(input, transaction) {
1116
+ const db = transaction ?? this.#db;
1117
+ const patch = input.status === "triggered" ? { status: input.status, triggered_at: now(), updated_at: now() } : { status: input.status, updated_at: now() };
1118
+ const row = await db.updateTable("schedule_run").set(patch).where("tenant_id", "=", input.tenant_id).where("id", "=", input.id).returningAll().executeTakeFirst();
1119
+ return row === void 0 ? void 0 : toRunRecord(row);
1120
+ }
1121
+ async listScheduledRuns(input, transaction) {
1122
+ const db = transaction ?? this.#db;
1123
+ const rows = await db.selectFrom("schedule_run").selectAll().where("status", "=", "scheduled").where("scheduled_for", "<=", input.until).orderBy("scheduled_for").limit(input.limit).execute();
1124
+ return rows.map(toRunRecord);
1125
+ }
1126
+ };
1127
+
1128
+ // src/logger.ts
1129
+ import winston from "winston";
1130
+ var STANDALONE_META_SKIP = /* @__PURE__ */ new Set(["level", "message", "timestamp", "version", "component", "stack", "splat"]);
1131
+ function shouldColorize() {
1132
+ const noColor = process.env["NO_COLOR"];
1133
+ if (noColor !== void 0 && noColor !== "") {
1134
+ return false;
1135
+ }
1136
+ const forceColor = process.env["FORCE_COLOR"];
1137
+ if (forceColor === "0") {
1138
+ return false;
1139
+ }
1140
+ if (forceColor !== void 0 && forceColor !== "") {
1141
+ return true;
1142
+ }
1143
+ return process.stderr.isTTY;
1144
+ }
1145
+ function standaloneMeta(info) {
1146
+ const copied = { ...info };
1147
+ const meta = {};
1148
+ for (const key of Object.keys(copied)) {
1149
+ if (STANDALONE_META_SKIP.has(key)) {
1150
+ continue;
1151
+ }
1152
+ meta[key] = copied[key];
1153
+ }
1154
+ if (Object.keys(meta).length === 0) {
1155
+ return "";
1156
+ }
1157
+ return ` ${JSON.stringify(meta)}`;
1158
+ }
1159
+ function standaloneFormat(color) {
1160
+ const parts = [
1161
+ winston.format.timestamp({ format: "HH:mm:ss" }),
1162
+ winston.format.errors({ stack: true })
1163
+ ];
1164
+ if (color) {
1165
+ parts.push(winston.format.colorize({ level: true }));
1166
+ }
1167
+ parts.push(
1168
+ winston.format.printf((info) => {
1169
+ const extra = standaloneMeta(info);
1170
+ const stack = typeof info["stack"] === "string" ? `
1171
+ ${info["stack"]}` : "";
1172
+ return `${String(info["timestamp"])} ${info.level} ${String(info.message)}${extra}${stack}`;
1173
+ })
1174
+ );
1175
+ return winston.format.combine(...parts);
1176
+ }
1177
+ function jsonFormat() {
1178
+ return winston.format.combine(
1179
+ winston.format.timestamp(),
1180
+ winston.format.errors({ stack: true }),
1181
+ winston.format.json()
1182
+ );
1183
+ }
1184
+ function serverLogFormat(options) {
1185
+ if (options.standalone) {
1186
+ return standaloneFormat(shouldColorize());
1187
+ }
1188
+ return jsonFormat();
1189
+ }
1190
+ function createLogger(options) {
1191
+ return winston.createLogger({
1192
+ level: options.level,
1193
+ defaultMeta: { version: options.version, component: options.component },
1194
+ format: serverLogFormat({ standalone: options.standalone }),
1195
+ transports: [new winston.transports.Console()]
1196
+ });
1197
+ }
1198
+ function createControllerLogger(options) {
1199
+ return createLogger({ ...options, component: "controller" });
1200
+ }
1201
+
1202
+ // src/packageVersion.ts
1203
+ import { readFileSync as readFileSync2 } from "fs";
1204
+ import path2 from "path";
1205
+ import { fileURLToPath as fileURLToPath2 } from "url";
1206
+ var PACKAGE_ROOT2 = path2.resolve(path2.dirname(fileURLToPath2(import.meta.url)), "..");
1207
+ function readPackageVersion() {
1208
+ const packageJsonPath = path2.join(PACKAGE_ROOT2, "package.json");
1209
+ const parsed = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
1210
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) {
1211
+ throw new Error(`${packageJsonPath} is missing a version field`);
1212
+ }
1213
+ const { version } = parsed;
1214
+ if (typeof version !== "string" || version.length === 0) {
1215
+ throw new Error(`${packageJsonPath} version must be a non-empty string`);
1216
+ }
1217
+ return version;
1218
+ }
1219
+ var PACKAGE_VERSION = readPackageVersion();
1220
+
1221
+ // src/controller-main.ts
1222
+ try {
1223
+ const logger = createControllerLogger({
1224
+ level: config_default.LOG_LEVEL,
1225
+ standalone: config_default.STANDALONE,
1226
+ version: PACKAGE_VERSION
1227
+ });
1228
+ if (config_default.STANDALONE) {
1229
+ logger.warn("Standalone mode (STANDALONE=true): the server runs the controller in-process; nothing to do here.");
1230
+ process.exit(0);
1231
+ }
1232
+ const db = createDb({
1233
+ connectionString: config_default.DATABASE_URL,
1234
+ poolMax: config_default.DATABASE_POOL_MAX,
1235
+ statementTimeoutMs: config_default.POSTGRES_STATEMENT_TIMEOUT_MS,
1236
+ idleInTransactionSessionTimeoutMs: config_default.POSTGRES_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS
1237
+ });
1238
+ const mtls = {
1239
+ enabled: config_default.TRUEFORGE_MTLS_ENABLED,
1240
+ dir: config_default.TRUEFORGE_MTLS_CERTS_DIR
1241
+ };
1242
+ logger.info("Controller starting", {
1243
+ serverUrl: config_default.SERVER_URL,
1244
+ mTlsEnabled: mtls.enabled
1245
+ });
1246
+ runController({
1247
+ scheduleStore: new PostgresScheduleStore(db),
1248
+ withTransaction: (callback) => db.transaction().execute(callback),
1249
+ logger,
1250
+ baseUrl: config_default.SERVER_URL,
1251
+ tls: mtls,
1252
+ gracefulTimeoutSeconds: config_default.GRACEFUL_TIMEOUT_SECONDS,
1253
+ onStopped: () => db.destroy()
1254
+ });
1255
+ } catch (error) {
1256
+ console.error("Failed to start controller:", error instanceof Error ? error.message : error);
1257
+ process.exit(1);
1258
+ }
1259
+ //# sourceMappingURL=controller-main.js.map