@hotmeshio/long-tail 0.1.12 → 0.1.14

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 (282) hide show
  1. package/README.md +1 -1
  2. package/build/api/files.d.ts +13 -0
  3. package/build/api/files.js +44 -0
  4. package/build/api/mcp-runs.d.ts +2 -0
  5. package/build/api/mcp-runs.js +2 -0
  6. package/build/api/workflow-sets.d.ts +11 -0
  7. package/build/api/workflow-sets.js +62 -0
  8. package/build/api/yaml-workflows.d.ts +9 -0
  9. package/build/api/yaml-workflows.js +40 -11
  10. package/build/examples/seed.js +50 -0
  11. package/build/lib/db/schemas/001_schema.sql +281 -106
  12. package/build/lib/db/schemas/002_seed.sql +56 -39
  13. package/build/lib/storage/local.d.ts +15 -0
  14. package/build/lib/storage/local.js +63 -0
  15. package/build/lib/storage/mime.d.ts +4 -0
  16. package/build/lib/storage/mime.js +31 -0
  17. package/build/lib/storage/s3.d.ts +16 -0
  18. package/build/lib/storage/s3.js +70 -0
  19. package/build/lib/storage/types.d.ts +18 -0
  20. package/build/modules/utils.d.ts +73 -0
  21. package/build/modules/utils.js +84 -0
  22. package/build/routes/file-browser.d.ts +2 -0
  23. package/build/routes/file-browser.js +112 -0
  24. package/build/routes/files.js +25 -17
  25. package/build/routes/index.js +2 -0
  26. package/build/routes/mcp-runs.js +2 -0
  27. package/build/routes/workflow-sets.js +9 -0
  28. package/build/routes/yaml-workflows/deployment.js +8 -0
  29. package/build/services/insight/index.d.ts +13 -0
  30. package/build/services/insight/index.js +4 -7
  31. package/build/services/insight/prompts.d.ts +1 -1
  32. package/build/services/insight/prompts.js +1 -1
  33. package/build/services/mcp/server.js +31 -0
  34. package/build/services/mcp-runs/queries.d.ts +2 -0
  35. package/build/services/mcp-runs/queries.js +11 -1
  36. package/build/services/mcp-runs/sql.d.ts +1 -1
  37. package/build/services/mcp-runs/sql.js +2 -2
  38. package/build/services/workflow-sets/db.d.ts +1 -0
  39. package/build/services/workflow-sets/db.js +6 -0
  40. package/build/services/workflow-sets/index.d.ts +1 -1
  41. package/build/services/workflow-sets/index.js +2 -1
  42. package/build/services/workflow-sets/sql.d.ts +1 -0
  43. package/build/services/workflow-sets/sql.js +6 -1
  44. package/build/services/yaml-workflow/db.d.ts +12 -0
  45. package/build/services/yaml-workflow/db.js +18 -0
  46. package/build/services/yaml-workflow/generator.js +4 -4
  47. package/build/services/yaml-workflow/pipeline/build/index.d.ts +2 -1
  48. package/build/services/yaml-workflow/pipeline/build/index.js +3 -2
  49. package/build/services/yaml-workflow/pipeline/build/utils.d.ts +0 -2
  50. package/build/services/yaml-workflow/pipeline/build/utils.js +0 -8
  51. package/build/services/yaml-workflow/sql.d.ts +2 -1
  52. package/build/services/yaml-workflow/sql.js +10 -3
  53. package/build/system/activities/schema-exchange.d.ts +50 -0
  54. package/build/system/activities/schema-exchange.js +210 -0
  55. package/build/system/activities/sql.d.ts +1 -1
  56. package/build/system/activities/sql.js +12 -1
  57. package/build/system/index.js +1 -0
  58. package/build/system/mcp-servers/human-queue.js +31 -0
  59. package/build/system/mcp-servers/knowledge.js +35 -6
  60. package/build/system/mcp-servers/schema-exchange.d.ts +4 -0
  61. package/build/system/mcp-servers/schema-exchange.js +93 -0
  62. package/build/system/seed/server-definitions.d.ts +112 -1
  63. package/build/system/seed/server-definitions.js +37 -0
  64. package/build/system/seed/tool-manifests-data.d.ts +87 -0
  65. package/build/system/seed/tool-manifests-data.js +37 -1
  66. package/build/system/seed/tool-manifests-knowledge.d.ts +9 -1
  67. package/build/system/seed/tool-manifests-knowledge.js +6 -5
  68. package/build/system/workflows/mcp-workflow-builder/prompts.d.ts +1 -1
  69. package/build/system/workflows/mcp-workflow-builder/prompts.js +21 -20
  70. package/build/system/workflows/mcp-workflow-planner/activities/persist.d.ts +1 -1
  71. package/build/system/workflows/mcp-workflow-planner/activities/persist.js +3 -3
  72. package/build/system/workflows/mcp-workflow-planner/index.js +39 -5
  73. package/build/system/workflows/mcp-workflow-planner/prompts.d.ts +1 -1
  74. package/build/system/workflows/mcp-workflow-planner/prompts.js +3 -3
  75. package/build/tsconfig.tsbuildinfo +1 -1
  76. package/dashboard/dist/assets/{AdminDashboard-DUrSBQOl.js → AdminDashboard-Cngijp4Q.js} +2 -2
  77. package/dashboard/dist/assets/{AdminDashboard-DUrSBQOl.js.map → AdminDashboard-Cngijp4Q.js.map} +1 -1
  78. package/dashboard/dist/assets/{AvailableEscalationsPage-Dbd1qUK_.js → AvailableEscalationsPage-CpBfGV1h.js} +2 -2
  79. package/dashboard/dist/assets/{AvailableEscalationsPage-Dbd1qUK_.js.map → AvailableEscalationsPage-CpBfGV1h.js.map} +1 -1
  80. package/dashboard/dist/assets/{BotPicker-Cg5iNEkm.js → BotPicker-B8Uvw9Si.js} +2 -2
  81. package/dashboard/dist/assets/{BotPicker-Cg5iNEkm.js.map → BotPicker-B8Uvw9Si.js.map} +1 -1
  82. package/dashboard/dist/assets/{CollapsibleSection-Kd9UIyeU.js → CollapsibleSection-DiFPuWOY.js} +2 -2
  83. package/dashboard/dist/assets/{CollapsibleSection-Kd9UIyeU.js.map → CollapsibleSection-DiFPuWOY.js.map} +1 -1
  84. package/dashboard/dist/assets/{ConfirmDeleteModal-DZMgmlof.js → ConfirmDeleteModal-CpXG9uyu.js} +2 -2
  85. package/dashboard/dist/assets/{ConfirmDeleteModal-DZMgmlof.js.map → ConfirmDeleteModal-CpXG9uyu.js.map} +1 -1
  86. package/dashboard/dist/assets/{CopyableId-cPFTRm8q.js → CopyableId-DKsTR9lK.js} +2 -2
  87. package/dashboard/dist/assets/{CopyableId-cPFTRm8q.js.map → CopyableId-DKsTR9lK.js.map} +1 -1
  88. package/dashboard/dist/assets/CredentialsPage-DlS7Kf40.js +2 -0
  89. package/dashboard/dist/assets/{CredentialsPage-DJablIbs.js.map → CredentialsPage-DlS7Kf40.js.map} +1 -1
  90. package/dashboard/dist/assets/{CustomDurationPicker-NgIP6YDW.js → CustomDurationPicker-B-9eW3pm.js} +2 -2
  91. package/dashboard/dist/assets/{CustomDurationPicker-NgIP6YDW.js.map → CustomDurationPicker-B-9eW3pm.js.map} +1 -1
  92. package/dashboard/dist/assets/{DataTable-CTRhTAfT.js → DataTable-DkOokbtL.js} +2 -2
  93. package/dashboard/dist/assets/{DataTable-CTRhTAfT.js.map → DataTable-DkOokbtL.js.map} +1 -1
  94. package/dashboard/dist/assets/{ElapsedCell-HcSJ_MMs.js → ElapsedCell-DVtHqM-5.js} +2 -2
  95. package/dashboard/dist/assets/{ElapsedCell-HcSJ_MMs.js.map → ElapsedCell-DVtHqM-5.js.map} +1 -1
  96. package/dashboard/dist/assets/{EmptyState-joNbd4gg.js → EmptyState-C7KIMIbE.js} +2 -2
  97. package/dashboard/dist/assets/{EmptyState-joNbd4gg.js.map → EmptyState-C7KIMIbE.js.map} +1 -1
  98. package/dashboard/dist/assets/{EscalationsOverview-DpXDnQux.js → EscalationsOverview-BMKBlkPx.js} +2 -2
  99. package/dashboard/dist/assets/{EscalationsOverview-DpXDnQux.js.map → EscalationsOverview-BMKBlkPx.js.map} +1 -1
  100. package/dashboard/dist/assets/{EventTable-CYem3v8n.js → EventTable-BYZ5OVdQ.js} +2 -2
  101. package/dashboard/dist/assets/{EventTable-CYem3v8n.js.map → EventTable-BYZ5OVdQ.js.map} +1 -1
  102. package/dashboard/dist/assets/{FilterBar-BiO8SOzc.js → FilterBar-C5r3n6YO.js} +2 -2
  103. package/dashboard/dist/assets/{FilterBar-BiO8SOzc.js.map → FilterBar-C5r3n6YO.js.map} +1 -1
  104. package/dashboard/dist/assets/{ListToolbar-6yRDh2e9.js → ListToolbar-BGUajIsW.js} +2 -2
  105. package/dashboard/dist/assets/{ListToolbar-6yRDh2e9.js.map → ListToolbar-BGUajIsW.js.map} +1 -1
  106. package/dashboard/dist/assets/{McpOverview-CUgSxkQe.js → McpOverview-B_kJYHea.js} +2 -2
  107. package/dashboard/dist/assets/{McpOverview-CUgSxkQe.js.map → McpOverview-B_kJYHea.js.map} +1 -1
  108. package/dashboard/dist/assets/McpQueryDetailPage-Czsmovqw.js +5 -0
  109. package/dashboard/dist/assets/McpQueryDetailPage-Czsmovqw.js.map +1 -0
  110. package/dashboard/dist/assets/McpQueryPage-BgAq_bQg.js +2 -0
  111. package/dashboard/dist/assets/{McpQueryPage-lV6kfDG5.js.map → McpQueryPage-BgAq_bQg.js.map} +1 -1
  112. package/dashboard/dist/assets/McpRunDetailPage-B8c0OszR.js +2 -0
  113. package/dashboard/dist/assets/McpRunDetailPage-B8c0OszR.js.map +1 -0
  114. package/dashboard/dist/assets/McpRunsPage-BY8C6k78.js +2 -0
  115. package/dashboard/dist/assets/McpRunsPage-BY8C6k78.js.map +1 -0
  116. package/dashboard/dist/assets/{Modal-BuTvD0pz.js → Modal-E1yRnCeW.js} +2 -2
  117. package/dashboard/dist/assets/{Modal-BuTvD0pz.js.map → Modal-E1yRnCeW.js.map} +1 -1
  118. package/dashboard/dist/assets/OperatorDashboard-C8MSTzey.js +2 -0
  119. package/dashboard/dist/assets/{OperatorDashboard-C9SSV96T.js.map → OperatorDashboard-C8MSTzey.js.map} +1 -1
  120. package/dashboard/dist/assets/{PageHeader-BcTVF9ul.js → PageHeader-Cm5HBQF_.js} +2 -2
  121. package/dashboard/dist/assets/{PageHeader-BcTVF9ul.js.map → PageHeader-Cm5HBQF_.js.map} +1 -1
  122. package/dashboard/dist/assets/{PageHeaderWithStats-BI7JG5x6.js → PageHeaderWithStats-CNmWJFSN.js} +2 -2
  123. package/dashboard/dist/assets/{PageHeaderWithStats-BI7JG5x6.js.map → PageHeaderWithStats-CNmWJFSN.js.map} +1 -1
  124. package/dashboard/dist/assets/{PriorityBadge-DqVaOU65.js → PriorityBadge-HSI4RVhs.js} +2 -2
  125. package/dashboard/dist/assets/{PriorityBadge-DqVaOU65.js.map → PriorityBadge-HSI4RVhs.js.map} +1 -1
  126. package/dashboard/dist/assets/{ProcessDetailPage-hFMhf9qa.js → ProcessDetailPage-Dln8622H.js} +2 -2
  127. package/dashboard/dist/assets/{ProcessDetailPage-hFMhf9qa.js.map → ProcessDetailPage-Dln8622H.js.map} +1 -1
  128. package/dashboard/dist/assets/{ProcessesListPage-ByVoBCQ3.js → ProcessesListPage-bIsd9N_h.js} +2 -2
  129. package/dashboard/dist/assets/{ProcessesListPage-ByVoBCQ3.js.map → ProcessesListPage-bIsd9N_h.js.map} +1 -1
  130. package/dashboard/dist/assets/{RolePill-D9ZIkYiu.js → RolePill-BVUp2bF0.js} +2 -2
  131. package/dashboard/dist/assets/{RolePill-D9ZIkYiu.js.map → RolePill-BVUp2bF0.js.map} +1 -1
  132. package/dashboard/dist/assets/RolesPage-kH-Njt25.js +2 -0
  133. package/dashboard/dist/assets/{RolesPage-SMedMuqa.js.map → RolesPage-kH-Njt25.js.map} +1 -1
  134. package/dashboard/dist/assets/{RowActions-yDhwwDbU.js → RowActions-DbUJPfaW.js} +2 -2
  135. package/dashboard/dist/assets/{RowActions-yDhwwDbU.js.map → RowActions-DbUJPfaW.js.map} +1 -1
  136. package/dashboard/dist/assets/{StatCard-BrBnQFxh.js → StatCard-Bs3JbyAz.js} +2 -2
  137. package/dashboard/dist/assets/{StatCard-BrBnQFxh.js.map → StatCard-Bs3JbyAz.js.map} +1 -1
  138. package/dashboard/dist/assets/{StatusBadge-xgb-lZku.js → StatusBadge-CakDdsCw.js} +2 -2
  139. package/dashboard/dist/assets/{StatusBadge-xgb-lZku.js.map → StatusBadge-CakDdsCw.js.map} +1 -1
  140. package/dashboard/dist/assets/{StepIndicator-B9ps2SvM.js → StepIndicator-Cd_SG_yA.js} +2 -2
  141. package/dashboard/dist/assets/{StepIndicator-B9ps2SvM.js.map → StepIndicator-Cd_SG_yA.js.map} +1 -1
  142. package/dashboard/dist/assets/{StickyPagination-DTIjBKN3.js → StickyPagination-Bz0C18nC.js} +2 -2
  143. package/dashboard/dist/assets/{StickyPagination-DTIjBKN3.js.map → StickyPagination-Bz0C18nC.js.map} +1 -1
  144. package/dashboard/dist/assets/{SwimlaneTimeline-RK4Yu66z.js → SwimlaneTimeline-Cfe-xQRX.js} +2 -2
  145. package/dashboard/dist/assets/{SwimlaneTimeline-RK4Yu66z.js.map → SwimlaneTimeline-Cfe-xQRX.js.map} +1 -1
  146. package/dashboard/dist/assets/{TagInput-CdNUuqk4.js → TagInput-ClFhXG-U.js} +2 -2
  147. package/dashboard/dist/assets/{TagInput-CdNUuqk4.js.map → TagInput-ClFhXG-U.js.map} +1 -1
  148. package/dashboard/dist/assets/{TaskDetailPage-C-nzaNea.js → TaskDetailPage-SuMBdARt.js} +2 -2
  149. package/dashboard/dist/assets/{TaskDetailPage-C-nzaNea.js.map → TaskDetailPage-SuMBdARt.js.map} +1 -1
  150. package/dashboard/dist/assets/{TaskQueuePill-Lvr2-NzS.js → TaskQueuePill-lJR1JW_W.js} +2 -2
  151. package/dashboard/dist/assets/{TaskQueuePill-Lvr2-NzS.js.map → TaskQueuePill-lJR1JW_W.js.map} +1 -1
  152. package/dashboard/dist/assets/{TasksListPage-DSUmD84y.js → TasksListPage-Dkq1Vtbt.js} +2 -2
  153. package/dashboard/dist/assets/{TasksListPage-DSUmD84y.js.map → TasksListPage-Dkq1Vtbt.js.map} +1 -1
  154. package/dashboard/dist/assets/{TimeAgo-BZdLdrIh.js → TimeAgo-DgfDZ1pl.js} +2 -2
  155. package/dashboard/dist/assets/{TimeAgo-BZdLdrIh.js.map → TimeAgo-DgfDZ1pl.js.map} +1 -1
  156. package/dashboard/dist/assets/{TimestampCell-QX_0i5FK.js → TimestampCell-MpHZ1hMD.js} +2 -2
  157. package/dashboard/dist/assets/{TimestampCell-QX_0i5FK.js.map → TimestampCell-MpHZ1hMD.js.map} +1 -1
  158. package/dashboard/dist/assets/{UserName-DyZMXcBm.js → UserName-DqsosA4B.js} +2 -2
  159. package/dashboard/dist/assets/{UserName-DyZMXcBm.js.map → UserName-DqsosA4B.js.map} +1 -1
  160. package/dashboard/dist/assets/{WorkflowExecutionPage-DjVxfZaF.js → WorkflowExecutionPage-CVlg38C3.js} +2 -2
  161. package/dashboard/dist/assets/{WorkflowExecutionPage-DjVxfZaF.js.map → WorkflowExecutionPage-CVlg38C3.js.map} +1 -1
  162. package/dashboard/dist/assets/WorkflowPill-CRpZhjGR.js +2 -0
  163. package/dashboard/dist/assets/WorkflowPill-CRpZhjGR.js.map +1 -0
  164. package/dashboard/dist/assets/{WorkflowsDashboard-DZjuiFZ0.js → WorkflowsDashboard-Ugzbs8mV.js} +2 -2
  165. package/dashboard/dist/assets/{WorkflowsDashboard-DZjuiFZ0.js.map → WorkflowsDashboard-Ugzbs8mV.js.map} +1 -1
  166. package/dashboard/dist/assets/{WorkflowsOverview-CLnLRpOu.js → WorkflowsOverview-CIp_lTNl.js} +2 -2
  167. package/dashboard/dist/assets/{WorkflowsOverview-CLnLRpOu.js.map → WorkflowsOverview-CIp_lTNl.js.map} +1 -1
  168. package/dashboard/dist/assets/YamlWorkflowsPage-BICF0fRO.js +2 -0
  169. package/dashboard/dist/assets/YamlWorkflowsPage-BICF0fRO.js.map +1 -0
  170. package/dashboard/dist/assets/{bots-DIM6lBoY.js → bots-DPfUpVqI.js} +2 -2
  171. package/dashboard/dist/assets/{bots-DIM6lBoY.js.map → bots-DPfUpVqI.js.map} +1 -1
  172. package/dashboard/dist/assets/{escalation-JOTuOqjq.js → escalation-RrCDbMC3.js} +2 -2
  173. package/dashboard/dist/assets/{escalation-JOTuOqjq.js.map → escalation-RrCDbMC3.js.map} +1 -1
  174. package/dashboard/dist/assets/escalation-columns-CDGa9wsD.js +2 -0
  175. package/dashboard/dist/assets/{escalation-columns-Cyg58nkg.js.map → escalation-columns-CDGa9wsD.js.map} +1 -1
  176. package/dashboard/dist/assets/{helpers-B1BDxBZd.js → helpers-ZSKqdkdS.js} +2 -2
  177. package/dashboard/dist/assets/{helpers-B1BDxBZd.js.map → helpers-ZSKqdkdS.js.map} +1 -1
  178. package/dashboard/dist/assets/helpers-rMEcLwKs.js +2 -0
  179. package/dashboard/dist/assets/helpers-rMEcLwKs.js.map +1 -0
  180. package/dashboard/dist/assets/{index-DDYFpi4l.js → index-ABcJHHlN.js} +2 -2
  181. package/dashboard/dist/assets/{index-DDYFpi4l.js.map → index-ABcJHHlN.js.map} +1 -1
  182. package/dashboard/dist/assets/{index-D1wVX50Z.js → index-B91h_jZ0.js} +2 -2
  183. package/dashboard/dist/assets/{index-D1wVX50Z.js.map → index-B91h_jZ0.js.map} +1 -1
  184. package/dashboard/dist/assets/{index-BcR6PfpY.js → index-BbI2dzhJ.js} +2 -2
  185. package/dashboard/dist/assets/{index-BcR6PfpY.js.map → index-BbI2dzhJ.js.map} +1 -1
  186. package/dashboard/dist/assets/{index-BizfauqT.js → index-BmVCyB6C.js} +4 -4
  187. package/dashboard/dist/assets/{index-BizfauqT.js.map → index-BmVCyB6C.js.map} +1 -1
  188. package/dashboard/dist/assets/index-C1E5GTs9.js +2 -0
  189. package/dashboard/dist/assets/index-C1E5GTs9.js.map +1 -0
  190. package/dashboard/dist/assets/{index-Cf60K3x9.js → index-C90ZPzXk.js} +2 -2
  191. package/dashboard/dist/assets/{index-Cf60K3x9.js.map → index-C90ZPzXk.js.map} +1 -1
  192. package/dashboard/dist/assets/{index-BYZX9tOb.js → index-Cmgrk7PQ.js} +58 -58
  193. package/dashboard/dist/assets/index-Cmgrk7PQ.js.map +1 -0
  194. package/dashboard/dist/assets/{index-Ds0JoXS2.js → index-DNytWfSZ.js} +2 -2
  195. package/dashboard/dist/assets/{index-Ds0JoXS2.js.map → index-DNytWfSZ.js.map} +1 -1
  196. package/dashboard/dist/assets/index-DX6zxr6t.js +2 -0
  197. package/dashboard/dist/assets/{index-Cg5nfiYX.js.map → index-DX6zxr6t.js.map} +1 -1
  198. package/dashboard/dist/assets/index-DeX-ezqf.css +1 -0
  199. package/dashboard/dist/assets/index-K40Qw1tk.js +2 -0
  200. package/dashboard/dist/assets/{index-Di12t56M.js.map → index-K40Qw1tk.js.map} +1 -1
  201. package/dashboard/dist/assets/{index-BUK3qR-1.js → index-lCyNr5Xk.js} +2 -2
  202. package/dashboard/dist/assets/{index-BUK3qR-1.js.map → index-lCyNr5Xk.js.map} +1 -1
  203. package/dashboard/dist/assets/{mcp-B_xbczAt.js → mcp-CNE44TSp.js} +2 -2
  204. package/dashboard/dist/assets/{mcp-B_xbczAt.js.map → mcp-CNE44TSp.js.map} +1 -1
  205. package/dashboard/dist/assets/mcp-query-RQX0uN-5.js +2 -0
  206. package/dashboard/dist/assets/mcp-query-RQX0uN-5.js.map +1 -0
  207. package/dashboard/dist/assets/mcp-runs-0w40bdz-.js +2 -0
  208. package/dashboard/dist/assets/mcp-runs-0w40bdz-.js.map +1 -0
  209. package/dashboard/dist/assets/{namespaces-C3WtdO_9.js → namespaces-BbmdXuPp.js} +2 -2
  210. package/dashboard/dist/assets/{namespaces-C3WtdO_9.js.map → namespaces-BbmdXuPp.js.map} +1 -1
  211. package/dashboard/dist/assets/{roles-BDAsPpZG.js → roles-DoHYlhWH.js} +2 -2
  212. package/dashboard/dist/assets/{roles-BDAsPpZG.js.map → roles-DoHYlhWH.js.map} +1 -1
  213. package/dashboard/dist/assets/{settings-Ife_UwAp.js → settings-BAiJiCHS.js} +2 -2
  214. package/dashboard/dist/assets/{settings-Ife_UwAp.js.map → settings-BAiJiCHS.js.map} +1 -1
  215. package/dashboard/dist/assets/{tasks-BquNDHDI.js → tasks-CvroqHtm.js} +2 -2
  216. package/dashboard/dist/assets/{tasks-BquNDHDI.js.map → tasks-CvroqHtm.js.map} +1 -1
  217. package/dashboard/dist/assets/{useEventHooks-anv_B2Yy.js → useEventHooks-BHMbzR_y.js} +2 -2
  218. package/dashboard/dist/assets/{useEventHooks-anv_B2Yy.js.map → useEventHooks-BHMbzR_y.js.map} +1 -1
  219. package/dashboard/dist/assets/useFilterParams-CGRYFw_A.js +2 -0
  220. package/dashboard/dist/assets/useFilterParams-CGRYFw_A.js.map +1 -0
  221. package/dashboard/dist/assets/useYamlActivityEvents-D56KV14X.js +2 -0
  222. package/dashboard/dist/assets/useYamlActivityEvents-D56KV14X.js.map +1 -0
  223. package/dashboard/dist/assets/{users-CFcxB4v6.js → users-CxIMy_xw.js} +2 -2
  224. package/dashboard/dist/assets/{users-CFcxB4v6.js.map → users-CxIMy_xw.js.map} +1 -1
  225. package/dashboard/dist/assets/{vendor-icons-T4r2DSPD.js → vendor-icons-AFGxSeQS.js} +132 -82
  226. package/dashboard/dist/assets/vendor-icons-AFGxSeQS.js.map +1 -0
  227. package/dashboard/dist/assets/{workflows-CeRci9z3.js → workflows-yR9yais7.js} +2 -2
  228. package/dashboard/dist/assets/{workflows-CeRci9z3.js.map → workflows-yR9yais7.js.map} +1 -1
  229. package/dashboard/dist/assets/yaml-workflows-QVF2MZ0l.js +2 -0
  230. package/dashboard/dist/assets/yaml-workflows-QVF2MZ0l.js.map +1 -0
  231. package/dashboard/dist/index.html +3 -3
  232. package/docs/schema-exchange.md +173 -0
  233. package/docs/self-test.md +106 -0
  234. package/package.json +4 -2
  235. package/build/lib/db/schemas/003_workflow_discovery.sql +0 -39
  236. package/build/lib/db/schemas/004_query_router.sql +0 -38
  237. package/build/lib/db/schemas/004_workflow_sets.sql +0 -29
  238. package/build/lib/db/schemas/005_triage_router.sql +0 -37
  239. package/build/lib/db/schemas/005_unique_graph_topic.sql +0 -7
  240. package/build/lib/db/schemas/006_oauth.sql +0 -50
  241. package/build/lib/db/schemas/007_security.sql +0 -27
  242. package/build/lib/db/schemas/008_bot_accounts.sql +0 -30
  243. package/build/lib/db/schemas/009_audit_trail.sql +0 -7
  244. package/build/lib/db/schemas/010_credential_providers.sql +0 -4
  245. package/build/lib/db/schemas/011_system_workflow_configs.sql +0 -37
  246. package/build/lib/db/schemas/012_drop_modality.sql +0 -6
  247. package/build/lib/db/schemas/013_execute_as.sql +0 -9
  248. package/build/lib/db/schemas/014_ephemeral_credentials.sql +0 -16
  249. package/build/lib/db/schemas/015_knowledge.sql +0 -23
  250. package/build/lib/db/schemas/016_streamable_http.sql +0 -7
  251. package/dashboard/dist/assets/CredentialsPage-DJablIbs.js +0 -2
  252. package/dashboard/dist/assets/McpQueryDetailPage-BWbinTM_.js +0 -5
  253. package/dashboard/dist/assets/McpQueryDetailPage-BWbinTM_.js.map +0 -1
  254. package/dashboard/dist/assets/McpQueryPage-lV6kfDG5.js +0 -2
  255. package/dashboard/dist/assets/McpRunDetailPage-D6gaxH3_.js +0 -2
  256. package/dashboard/dist/assets/McpRunDetailPage-D6gaxH3_.js.map +0 -1
  257. package/dashboard/dist/assets/McpRunsPage-DKvTklh9.js +0 -2
  258. package/dashboard/dist/assets/McpRunsPage-DKvTklh9.js.map +0 -1
  259. package/dashboard/dist/assets/OperatorDashboard-C9SSV96T.js +0 -2
  260. package/dashboard/dist/assets/RolesPage-SMedMuqa.js +0 -2
  261. package/dashboard/dist/assets/WorkflowPill-CZqGslD6.js +0 -2
  262. package/dashboard/dist/assets/WorkflowPill-CZqGslD6.js.map +0 -1
  263. package/dashboard/dist/assets/YamlWorkflowsPage-VjdhnLmO.js +0 -2
  264. package/dashboard/dist/assets/YamlWorkflowsPage-VjdhnLmO.js.map +0 -1
  265. package/dashboard/dist/assets/escalation-columns-Cyg58nkg.js +0 -2
  266. package/dashboard/dist/assets/helpers-BCix9c_m.js +0 -2
  267. package/dashboard/dist/assets/helpers-BCix9c_m.js.map +0 -1
  268. package/dashboard/dist/assets/index-BYZX9tOb.js.map +0 -1
  269. package/dashboard/dist/assets/index-Cg5nfiYX.js +0 -2
  270. package/dashboard/dist/assets/index-DcIKW-cZ.css +0 -1
  271. package/dashboard/dist/assets/index-Di12t56M.js +0 -2
  272. package/dashboard/dist/assets/mcp-query-B8-P_QoG.js +0 -2
  273. package/dashboard/dist/assets/mcp-query-B8-P_QoG.js.map +0 -1
  274. package/dashboard/dist/assets/mcp-runs-CWeZinoF.js +0 -2
  275. package/dashboard/dist/assets/mcp-runs-CWeZinoF.js.map +0 -1
  276. package/dashboard/dist/assets/useFilterParams-BUyLHcx_.js +0 -2
  277. package/dashboard/dist/assets/useFilterParams-BUyLHcx_.js.map +0 -1
  278. package/dashboard/dist/assets/useYamlActivityEvents-DN-PTgVx.js +0 -2
  279. package/dashboard/dist/assets/useYamlActivityEvents-DN-PTgVx.js.map +0 -1
  280. package/dashboard/dist/assets/vendor-icons-T4r2DSPD.js.map +0 -1
  281. package/dashboard/dist/assets/yaml-workflows-DLwd2BOX.js +0 -2
  282. package/dashboard/dist/assets/yaml-workflows-DLwd2BOX.js.map +0 -1
@@ -32,10 +32,15 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  exports.LocalStorageBackend = void 0;
37
40
  const fs = __importStar(require("fs"));
38
41
  const path = __importStar(require("path"));
42
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
43
+ const mime_1 = require("./mime");
39
44
  const BASE_DIR = process.env.LT_FILE_STORAGE_DIR || './data/files';
40
45
  function resolveAndValidate(filePath) {
41
46
  const relative = filePath.replace(/^\/+/, '');
@@ -125,5 +130,63 @@ class LocalStorageBackend {
125
130
  }
126
131
  return fs.createReadStream(resolved);
127
132
  }
133
+ async listWithPrefixes(prefix, pageSize, continuationToken) {
134
+ ensureBaseDir();
135
+ const dir = prefix ? resolveAndValidate(prefix) : path.resolve(BASE_DIR);
136
+ if (!fs.existsSync(dir)) {
137
+ return { files: [], directories: [] };
138
+ }
139
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
140
+ const limit = pageSize || 100;
141
+ const offset = continuationToken ? parseInt(continuationToken, 10) : 0;
142
+ const allDirs = [];
143
+ const allFiles = [];
144
+ for (const entry of entries) {
145
+ const relativePath = path.relative(path.resolve(BASE_DIR), path.join(dir, entry.name));
146
+ if (entry.isDirectory()) {
147
+ allDirs.push(relativePath + '/');
148
+ }
149
+ else if (entry.isFile()) {
150
+ const stat = fs.statSync(path.join(dir, entry.name));
151
+ allFiles.push({
152
+ path: relativePath,
153
+ size: stat.size,
154
+ modified_at: stat.mtime.toISOString(),
155
+ });
156
+ }
157
+ }
158
+ // Directories first, then files — paginate the combined list
159
+ const combined = [...allDirs.map((d) => ({ type: 'dir', value: d })),
160
+ ...allFiles.map((f) => ({ type: 'file', value: f }))];
161
+ const page = combined.slice(offset, offset + limit);
162
+ const hasMore = offset + limit < combined.length;
163
+ const directories = page.filter((e) => e.type === 'dir').map((e) => e.value);
164
+ const files = page.filter((e) => e.type === 'file').map((e) => e.value);
165
+ return {
166
+ files,
167
+ directories,
168
+ nextToken: hasMore ? String(offset + limit) : undefined,
169
+ };
170
+ }
171
+ async getMetadata(key) {
172
+ const resolved = resolveAndValidate(key);
173
+ if (!fs.existsSync(resolved)) {
174
+ throw new Error(`File not found: ${key}`);
175
+ }
176
+ const stat = fs.statSync(resolved);
177
+ return {
178
+ size: stat.size,
179
+ modified_at: stat.mtime.toISOString(),
180
+ content_type: (0, mime_1.mimeFromPath)(key),
181
+ };
182
+ }
183
+ async getSignedUrl(key, expiresInSeconds) {
184
+ const secret = process.env.JWT_SECRET;
185
+ if (!secret) {
186
+ throw new Error('JWT_SECRET not configured — cannot generate signed URLs');
187
+ }
188
+ const token = jsonwebtoken_1.default.sign({ filePath: key.replace(/^\/+/, ''), purpose: 'file-download' }, secret, { expiresIn: expiresInSeconds });
189
+ return `/api/files/${key.replace(/^\/+/, '')}?token=${token}`;
190
+ }
128
191
  }
129
192
  exports.LocalStorageBackend = LocalStorageBackend;
@@ -0,0 +1,4 @@
1
+ /** Shared MIME type map used by file serving routes and storage backends. */
2
+ export declare const MIME_TYPES: Record<string, string>;
3
+ /** Resolve MIME type from file extension. */
4
+ export declare function mimeFromPath(filePath: string): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MIME_TYPES = void 0;
4
+ exports.mimeFromPath = mimeFromPath;
5
+ /** Shared MIME type map used by file serving routes and storage backends. */
6
+ exports.MIME_TYPES = {
7
+ '.png': 'image/png',
8
+ '.jpg': 'image/jpeg',
9
+ '.jpeg': 'image/jpeg',
10
+ '.gif': 'image/gif',
11
+ '.svg': 'image/svg+xml',
12
+ '.webp': 'image/webp',
13
+ '.pdf': 'application/pdf',
14
+ '.json': 'application/json',
15
+ '.txt': 'text/plain',
16
+ '.html': 'text/html',
17
+ '.css': 'text/css',
18
+ '.js': 'application/javascript',
19
+ '.csv': 'text/csv',
20
+ '.xml': 'application/xml',
21
+ '.yaml': 'text/yaml',
22
+ '.yml': 'text/yaml',
23
+ '.md': 'text/markdown',
24
+ '.zip': 'application/zip',
25
+ '.gz': 'application/gzip',
26
+ };
27
+ /** Resolve MIME type from file extension. */
28
+ function mimeFromPath(filePath) {
29
+ const ext = filePath.includes('.') ? '.' + filePath.split('.').pop().toLowerCase() : '';
30
+ return exports.MIME_TYPES[ext] || 'application/octet-stream';
31
+ }
@@ -1,6 +1,7 @@
1
1
  import type { StorageBackend } from './types';
2
2
  export declare class S3StorageBackend implements StorageBackend {
3
3
  private client;
4
+ private signingClient;
4
5
  private bucket;
5
6
  private bucketReady;
6
7
  constructor();
@@ -28,4 +29,19 @@ export declare class S3StorageBackend implements StorageBackend {
28
29
  size: number;
29
30
  }>;
30
31
  createReadStream(key: string): Promise<NodeJS.ReadableStream>;
32
+ listWithPrefixes(prefix?: string, pageSize?: number, continuationToken?: string): Promise<{
33
+ files: Array<{
34
+ path: string;
35
+ size: number;
36
+ modified_at: string;
37
+ }>;
38
+ directories: string[];
39
+ nextToken?: string;
40
+ }>;
41
+ getMetadata(key: string): Promise<{
42
+ size: number;
43
+ modified_at: string;
44
+ content_type: string;
45
+ }>;
46
+ getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
31
47
  }
@@ -38,10 +38,14 @@ const fs = __importStar(require("fs"));
38
38
  const os = __importStar(require("os"));
39
39
  const path = __importStar(require("path"));
40
40
  const client_s3_1 = require("@aws-sdk/client-s3");
41
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
42
+ const mime_1 = require("./mime");
41
43
  const STAGING_DIR = path.join(os.tmpdir(), 'lt-staging');
42
44
  class S3StorageBackend {
43
45
  constructor() {
46
+ this.signingClient = null;
44
47
  const endpoint = process.env.LT_S3_ENDPOINT;
48
+ const publicEndpoint = process.env.LT_S3_PUBLIC_ENDPOINT;
45
49
  const region = process.env.LT_S3_REGION || 'us-east-1';
46
50
  const forcePathStyle = process.env.LT_S3_FORCE_PATH_STYLE === 'true';
47
51
  this.bucket = process.env.LT_S3_BUCKET || 'long-tail-files';
@@ -63,6 +67,12 @@ class S3StorageBackend {
63
67
  };
64
68
  }
65
69
  this.client = new client_s3_1.S3Client(clientConfig);
70
+ // Signed URLs need the public-facing endpoint so browsers can reach them.
71
+ // In Docker, LT_S3_ENDPOINT is the internal hostname (e.g. http://minio:9000)
72
+ // while LT_S3_PUBLIC_ENDPOINT is the host-accessible URL (e.g. http://localhost:9000).
73
+ if (publicEndpoint && publicEndpoint !== endpoint) {
74
+ this.signingClient = new client_s3_1.S3Client({ ...clientConfig, endpoint: publicEndpoint });
75
+ }
66
76
  this.bucketReady = this.ensureBucket();
67
77
  }
68
78
  async ensureBucket() {
@@ -168,6 +178,66 @@ class S3StorageBackend {
168
178
  }));
169
179
  return resp.Body;
170
180
  }
181
+ async listWithPrefixes(prefix, pageSize, continuationToken) {
182
+ await this.bucketReady;
183
+ const normalizedPrefix = prefix ? normalizeKey(prefix) : undefined;
184
+ const listPrefix = normalizedPrefix
185
+ ? (normalizedPrefix.endsWith('/') ? normalizedPrefix : normalizedPrefix + '/')
186
+ : undefined;
187
+ const resp = await this.client.send(new client_s3_1.ListObjectsV2Command({
188
+ Bucket: this.bucket,
189
+ Prefix: listPrefix,
190
+ Delimiter: '/',
191
+ MaxKeys: pageSize || 100,
192
+ ContinuationToken: continuationToken || undefined,
193
+ }));
194
+ const files = [];
195
+ for (const obj of resp.Contents || []) {
196
+ if (!obj.Key)
197
+ continue;
198
+ // Skip the prefix itself if it appears as a "file"
199
+ if (obj.Key === listPrefix)
200
+ continue;
201
+ files.push({
202
+ path: obj.Key,
203
+ size: obj.Size || 0,
204
+ modified_at: obj.LastModified?.toISOString() || new Date().toISOString(),
205
+ });
206
+ }
207
+ const directories = [];
208
+ for (const cp of resp.CommonPrefixes || []) {
209
+ if (cp.Prefix) {
210
+ directories.push(cp.Prefix);
211
+ }
212
+ }
213
+ return {
214
+ files,
215
+ directories,
216
+ nextToken: resp.NextContinuationToken || undefined,
217
+ };
218
+ }
219
+ async getMetadata(key) {
220
+ await this.bucketReady;
221
+ const resp = await this.client.send(new client_s3_1.HeadObjectCommand({
222
+ Bucket: this.bucket,
223
+ Key: normalizeKey(key),
224
+ }));
225
+ return {
226
+ size: resp.ContentLength || 0,
227
+ modified_at: resp.LastModified?.toISOString() || new Date().toISOString(),
228
+ content_type: resp.ContentType || (0, mime_1.mimeFromPath)(key),
229
+ };
230
+ }
231
+ async getSignedUrl(key, expiresInSeconds) {
232
+ await this.bucketReady;
233
+ const command = new client_s3_1.GetObjectCommand({
234
+ Bucket: this.bucket,
235
+ Key: normalizeKey(key),
236
+ });
237
+ // Use the public-facing client so the signed URL hostname is reachable from browsers
238
+ const client = this.signingClient || this.client;
239
+ return (0, s3_request_presigner_1.getSignedUrl)(client, command, { expiresIn: expiresInSeconds });
240
+ }
171
241
  }
172
242
  exports.S3StorageBackend = S3StorageBackend;
173
243
  /** Strip leading slashes to create a valid S3 key; reject traversal. */
@@ -38,4 +38,22 @@ export interface StorageBackend {
38
38
  }>;
39
39
  /** Create a readable stream for HTTP serving. */
40
40
  createReadStream(key: string): Promise<NodeJS.ReadableStream>;
41
+ /** List files and directory prefixes under a path (for directory browsing). */
42
+ listWithPrefixes(prefix?: string, pageSize?: number, continuationToken?: string): Promise<{
43
+ files: Array<{
44
+ path: string;
45
+ size: number;
46
+ modified_at: string;
47
+ }>;
48
+ directories: string[];
49
+ nextToken?: string;
50
+ }>;
51
+ /** Get file metadata without reading content. */
52
+ getMetadata(key: string): Promise<{
53
+ size: number;
54
+ modified_at: string;
55
+ content_type: string;
56
+ }>;
57
+ /** Generate a time-limited signed URL for unauthenticated file access. */
58
+ getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
41
59
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Sanitize a value for use as an MCP tool name or HotMesh graph topic
3
+ * (the `subscribes` field in a YAML DAG).
4
+ *
5
+ * ## Why snake_case
6
+ *
7
+ * MCP tool names become the `subscribes` topic in a HotMesh YAML DAG.
8
+ * That topic is how the system routes incoming messages to the correct
9
+ * workflow. The same value also appears in `worker` activity `topic`
10
+ * fields and in the `mcp_<server>_<tool>` activity type encoding.
11
+ *
12
+ * Because the activity type uses underscores to delimit server from tool
13
+ * (`mcp_longtail_take_screenshot`), both the server name (letters only)
14
+ * and the tool name (snake_case) must avoid dashes, dots, or other
15
+ * separators that would create ambiguity when parsing activity types.
16
+ *
17
+ * ## Risks if violated
18
+ *
19
+ * - Dashes in tool names cause `parseMcpActivityType()` to mis-split
20
+ * the server/tool boundary in activity type strings.
21
+ * - Dots or special chars can produce invalid HotMesh topic subscriptions
22
+ * that silently fail to route.
23
+ * - Mixed conventions across entry points (builder, planner, discovery)
24
+ * cause topic collisions or deployment failures when merging workflows
25
+ * into a single app namespace.
26
+ *
27
+ * ## Contract
28
+ *
29
+ * Input: any string (LLM output, user input, URL slug, etc.)
30
+ * Output: lowercase letters, digits, and underscores only.
31
+ * Runs of non-alphanumeric chars become a single underscore.
32
+ * No leading or trailing underscores.
33
+ *
34
+ * This is the ONE canonical backend implementation. The dashboard has an
35
+ * identical copy at `dashboard/src/lib/sanitize.ts`. No other file in
36
+ * the platform may inline this logic.
37
+ */
38
+ export declare function sanitizeToolName(value: string): string;
39
+ /**
40
+ * Sanitize a value for use as an MCP server name (the HotMesh `app.id`
41
+ * and Postgres schema name that isolates one server's workflows from another).
42
+ *
43
+ * ## Why lowercase alphanumeric, leading letter
44
+ *
45
+ * The server name becomes:
46
+ * 1. A Postgres schema name — must start with a letter; letters and digits
47
+ * are safe without quoting.
48
+ * 2. The first segment in the `mcp_<server>_<tool>` activity type encoding.
49
+ * Because underscores delimit server from tool, the server name itself
50
+ * must never contain underscores (or dashes, dots, etc.).
51
+ *
52
+ * ## Risks if violated
53
+ *
54
+ * - Underscores or dashes in the server name make `parseMcpActivityType()`
55
+ * split incorrectly — it uses the first `_` after `mcp_` as the boundary.
56
+ * - A leading digit produces an invalid Postgres schema name that requires
57
+ * quoting and breaks HotMesh's unquoted SQL paths.
58
+ * - Special characters can cause silent deployment failures or schema
59
+ * creation errors.
60
+ *
61
+ * ## Contract
62
+ *
63
+ * Input: any string (LLM suggestion, user input, etc.)
64
+ * Output: lowercase letters and digits only, guaranteed to start with a letter.
65
+ * All non-alphanumeric chars are stripped (not replaced).
66
+ * Leading digits are stripped so the result starts with a letter.
67
+ * Default: 'longtail' if the result is empty after sanitization.
68
+ *
69
+ * This is the ONE canonical backend implementation. The dashboard has an
70
+ * identical copy at `dashboard/src/lib/sanitize.ts`. No other file in
71
+ * the platform may inline this logic.
72
+ */
73
+ export declare function sanitizeServerName(value: string): string;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeToolName = sanitizeToolName;
4
+ exports.sanitizeServerName = sanitizeServerName;
5
+ /**
6
+ * Sanitize a value for use as an MCP tool name or HotMesh graph topic
7
+ * (the `subscribes` field in a YAML DAG).
8
+ *
9
+ * ## Why snake_case
10
+ *
11
+ * MCP tool names become the `subscribes` topic in a HotMesh YAML DAG.
12
+ * That topic is how the system routes incoming messages to the correct
13
+ * workflow. The same value also appears in `worker` activity `topic`
14
+ * fields and in the `mcp_<server>_<tool>` activity type encoding.
15
+ *
16
+ * Because the activity type uses underscores to delimit server from tool
17
+ * (`mcp_longtail_take_screenshot`), both the server name (letters only)
18
+ * and the tool name (snake_case) must avoid dashes, dots, or other
19
+ * separators that would create ambiguity when parsing activity types.
20
+ *
21
+ * ## Risks if violated
22
+ *
23
+ * - Dashes in tool names cause `parseMcpActivityType()` to mis-split
24
+ * the server/tool boundary in activity type strings.
25
+ * - Dots or special chars can produce invalid HotMesh topic subscriptions
26
+ * that silently fail to route.
27
+ * - Mixed conventions across entry points (builder, planner, discovery)
28
+ * cause topic collisions or deployment failures when merging workflows
29
+ * into a single app namespace.
30
+ *
31
+ * ## Contract
32
+ *
33
+ * Input: any string (LLM output, user input, URL slug, etc.)
34
+ * Output: lowercase letters, digits, and underscores only.
35
+ * Runs of non-alphanumeric chars become a single underscore.
36
+ * No leading or trailing underscores.
37
+ *
38
+ * This is the ONE canonical backend implementation. The dashboard has an
39
+ * identical copy at `dashboard/src/lib/sanitize.ts`. No other file in
40
+ * the platform may inline this logic.
41
+ */
42
+ function sanitizeToolName(value) {
43
+ return value
44
+ .toLowerCase()
45
+ .replace(/[^a-z0-9]+/g, '_')
46
+ .replace(/^_|_$/g, '');
47
+ }
48
+ /**
49
+ * Sanitize a value for use as an MCP server name (the HotMesh `app.id`
50
+ * and Postgres schema name that isolates one server's workflows from another).
51
+ *
52
+ * ## Why lowercase alphanumeric, leading letter
53
+ *
54
+ * The server name becomes:
55
+ * 1. A Postgres schema name — must start with a letter; letters and digits
56
+ * are safe without quoting.
57
+ * 2. The first segment in the `mcp_<server>_<tool>` activity type encoding.
58
+ * Because underscores delimit server from tool, the server name itself
59
+ * must never contain underscores (or dashes, dots, etc.).
60
+ *
61
+ * ## Risks if violated
62
+ *
63
+ * - Underscores or dashes in the server name make `parseMcpActivityType()`
64
+ * split incorrectly — it uses the first `_` after `mcp_` as the boundary.
65
+ * - A leading digit produces an invalid Postgres schema name that requires
66
+ * quoting and breaks HotMesh's unquoted SQL paths.
67
+ * - Special characters can cause silent deployment failures or schema
68
+ * creation errors.
69
+ *
70
+ * ## Contract
71
+ *
72
+ * Input: any string (LLM suggestion, user input, etc.)
73
+ * Output: lowercase letters and digits only, guaranteed to start with a letter.
74
+ * All non-alphanumeric chars are stripped (not replaced).
75
+ * Leading digits are stripped so the result starts with a letter.
76
+ * Default: 'longtail' if the result is empty after sanitization.
77
+ *
78
+ * This is the ONE canonical backend implementation. The dashboard has an
79
+ * identical copy at `dashboard/src/lib/sanitize.ts`. No other file in
80
+ * the platform may inline this logic.
81
+ */
82
+ function sanitizeServerName(value) {
83
+ return value.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/^[0-9]+/, '');
84
+ }
@@ -0,0 +1,2 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const express_1 = require("express");
40
+ const path_1 = __importDefault(require("path"));
41
+ const api = __importStar(require("../api/files"));
42
+ const storage_1 = require("../lib/storage");
43
+ const mime_1 = require("../lib/storage/mime");
44
+ const router = (0, express_1.Router)();
45
+ /**
46
+ * GET /api/file-browser/browse
47
+ * List files and directories at a given prefix.
48
+ * Query: ?prefix=screenshots/&pageSize=100&continuationToken=...
49
+ */
50
+ router.get('/browse', async (req, res) => {
51
+ const result = await api.browseFiles({
52
+ prefix: req.query.prefix,
53
+ pageSize: req.query.pageSize ? parseInt(req.query.pageSize, 10) : undefined,
54
+ continuationToken: req.query.continuationToken,
55
+ });
56
+ res.status(result.status).json(result.data ?? { error: result.error });
57
+ });
58
+ /**
59
+ * GET /api/file-browser/metadata/*
60
+ * Get metadata for a single file.
61
+ */
62
+ router.get('/metadata/{*filePath}', async (req, res) => {
63
+ const raw = req.params.filePath;
64
+ const filePath = Array.isArray(raw) ? raw.join('/') : raw;
65
+ if (!filePath) {
66
+ res.status(400).json({ error: 'File path required' });
67
+ return;
68
+ }
69
+ const result = await api.getFileMetadata({ filePath });
70
+ res.status(result.status).json(result.data ?? { error: result.error });
71
+ });
72
+ /**
73
+ * POST /api/file-browser/signed-url
74
+ * Generate a time-limited signed URL for sharing.
75
+ * Body: { path, expiresIn } — expiresIn in seconds (3600, 21600, 86400, 604800, 2592000)
76
+ */
77
+ router.post('/signed-url', async (req, res) => {
78
+ const { path: filePath, expiresIn } = req.body;
79
+ if (!filePath || !expiresIn) {
80
+ res.status(400).json({ error: 'path and expiresIn are required' });
81
+ return;
82
+ }
83
+ const result = await api.generateSignedUrl({
84
+ filePath,
85
+ expiresIn: typeof expiresIn === 'number' ? expiresIn : parseInt(expiresIn, 10),
86
+ });
87
+ res.status(result.status).json(result.data ?? { error: result.error });
88
+ });
89
+ /**
90
+ * GET /api/file-browser/download/*
91
+ * Download a file with Content-Disposition: attachment.
92
+ */
93
+ router.get('/download/{*filePath}', async (req, res) => {
94
+ const raw = req.params.filePath;
95
+ const filePath = Array.isArray(raw) ? raw.join('/') : raw;
96
+ if (!filePath) {
97
+ res.status(400).json({ error: 'File path required' });
98
+ return;
99
+ }
100
+ try {
101
+ const stream = await (0, storage_1.getStorageBackend)().createReadStream(filePath);
102
+ const fileName = path_1.default.basename(filePath);
103
+ const contentType = (0, mime_1.mimeFromPath)(filePath);
104
+ res.setHeader('Content-Type', contentType);
105
+ res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
106
+ stream.pipe(res);
107
+ }
108
+ catch {
109
+ res.status(404).json({ error: 'File not found' });
110
+ }
111
+ });
112
+ exports.default = router;
@@ -4,26 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const express_1 = require("express");
7
- const path_1 = __importDefault(require("path"));
7
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
8
  const storage_1 = require("../lib/storage");
9
+ const mime_1 = require("../lib/storage/mime");
9
10
  const router = (0, express_1.Router)();
10
- const MIME_TYPES = {
11
- '.png': 'image/png',
12
- '.jpg': 'image/jpeg',
13
- '.jpeg': 'image/jpeg',
14
- '.gif': 'image/gif',
15
- '.svg': 'image/svg+xml',
16
- '.webp': 'image/webp',
17
- '.pdf': 'application/pdf',
18
- '.json': 'application/json',
19
- '.txt': 'text/plain',
20
- '.html': 'text/html',
21
- '.csv': 'text/csv',
22
- '.xml': 'application/xml',
23
- };
24
11
  /**
25
12
  * GET /api/files/*
26
13
  * Serve files from managed file storage.
14
+ * Supports optional signed token (?token=<jwt>) for authenticated access
15
+ * to locally-generated signed URLs.
27
16
  */
28
17
  router.get('/{*filePath}', async (req, res) => {
29
18
  const raw = req.params.filePath;
@@ -32,10 +21,29 @@ router.get('/{*filePath}', async (req, res) => {
32
21
  res.status(400).json({ error: 'File path required' });
33
22
  return;
34
23
  }
24
+ // Validate signed token if provided
25
+ const token = req.query.token;
26
+ if (token) {
27
+ const secret = process.env.JWT_SECRET;
28
+ if (!secret) {
29
+ res.status(500).json({ error: 'Server not configured for signed URLs' });
30
+ return;
31
+ }
32
+ try {
33
+ const decoded = jsonwebtoken_1.default.verify(token, secret);
34
+ if (decoded.purpose !== 'file-download' || decoded.filePath !== filePath.replace(/^\/+/, '')) {
35
+ res.status(403).json({ error: 'Token does not match requested file' });
36
+ return;
37
+ }
38
+ }
39
+ catch {
40
+ res.status(403).json({ error: 'Invalid or expired token' });
41
+ return;
42
+ }
43
+ }
35
44
  try {
36
45
  const stream = await (0, storage_1.getStorageBackend)().createReadStream(filePath);
37
- const ext = path_1.default.extname(filePath).toLowerCase();
38
- const contentType = MIME_TYPES[ext] || 'application/octet-stream';
46
+ const contentType = (0, mime_1.mimeFromPath)(filePath);
39
47
  res.setHeader('Content-Type', contentType);
40
48
  res.setHeader('Cache-Control', 'public, max-age=300');
41
49
  stream.pipe(res);
@@ -23,6 +23,7 @@ const settings_1 = __importDefault(require("./settings"));
23
23
  const mcp_runs_1 = __importDefault(require("./mcp-runs"));
24
24
  const namespaces_1 = __importDefault(require("./namespaces"));
25
25
  const files_1 = __importDefault(require("./files"));
26
+ const file_browser_1 = __importDefault(require("./file-browser"));
26
27
  const controlplane_1 = __importDefault(require("./controlplane"));
27
28
  const bot_accounts_1 = __importDefault(require("./bot-accounts"));
28
29
  const docs_1 = __importDefault(require("./docs"));
@@ -49,6 +50,7 @@ router.use('/insight', insight_1.default);
49
50
  router.use('/yaml-workflows', yaml_workflows_1.default);
50
51
  router.use('/mcp-runs', mcp_runs_1.default);
51
52
  router.use('/namespaces', namespaces_1.default);
53
+ router.use('/file-browser', file_browser_1.default);
52
54
  router.use('/controlplane', controlplane_1.default);
53
55
  router.use('/bot-accounts', bot_accounts_1.default);
54
56
  router.use('/docs', docs_1.default);
@@ -60,6 +60,8 @@ router.get('/', async (req, res) => {
60
60
  entity: req.query.entity || undefined,
61
61
  search: req.query.search || undefined,
62
62
  status: req.query.status || undefined,
63
+ sort_by: req.query.sort_by || undefined,
64
+ order: req.query.order || undefined,
63
65
  });
64
66
  res.status(result.status).json(result.data ?? { error: result.error });
65
67
  });
@@ -79,6 +79,15 @@ router.put('/:id/plan', async (req, res) => {
79
79
  });
80
80
  res.status(result.status).json(result.data ?? { error: result.error });
81
81
  });
82
+ /**
83
+ * POST /api/workflow-sets/:id/add
84
+ * Add additional workflows to an existing set from a new specification.
85
+ */
86
+ router.post('/:id/add', async (req, res) => {
87
+ const { specification } = req.body;
88
+ const result = await api.addToWorkflowSet({ id: req.params.id, specification }, req.auth ? { userId: req.auth.userId } : undefined);
89
+ res.status(result.status).json(result.data ?? { error: result.error });
90
+ });
82
91
  /**
83
92
  * POST /api/workflow-sets/:id/build
84
93
  * Trigger the build phase (resume the planner workflow).
@@ -76,4 +76,12 @@ router.post('/:id/archive', async (req, res) => {
76
76
  const result = await api.archiveYamlWorkflow({ id: req.params.id });
77
77
  res.status(result.status).json(result.data ?? { error: result.error });
78
78
  });
79
+ /**
80
+ * POST /api/yaml-workflows/:id/restore
81
+ * Restore an archived YAML workflow back to draft status for redeployment.
82
+ */
83
+ router.post('/:id/restore', async (req, res) => {
84
+ const result = await api.restoreYamlWorkflow({ id: req.params.id });
85
+ res.status(result.status).json(result.data ?? { error: result.error });
86
+ });
79
87
  exports.default = router;