@stkxp/cli 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/README.md +273 -0
  2. package/bin/stkxp.mjs +198 -0
  3. package/package.json +97 -0
  4. package/src/bootstrap.mjs +37 -0
  5. package/src/bootstrap.test.mjs +73 -0
  6. package/src/deploy.mjs +145 -0
  7. package/src/deploy.test.mjs +131 -0
  8. package/src/export.mjs +30 -0
  9. package/src/export.test.mjs +56 -0
  10. package/src/secret-input.mjs +64 -0
  11. package/src/secret-input.test.mjs +58 -0
  12. package/src/serve.mjs +83 -0
  13. package/src/serve.test.mjs +93 -0
  14. package/vendor/dist-server/asyncapi/generator.js +1 -0
  15. package/vendor/dist-server/asyncapi/messages.js +1 -0
  16. package/vendor/dist-server/asyncapi/viewer.html +43 -0
  17. package/vendor/dist-server/core/app-config/branding.js +1 -0
  18. package/vendor/dist-server/core/app-config/mantine-theme.js +1 -0
  19. package/vendor/dist-server/core/app-config/mermaid-theme.js +2 -0
  20. package/vendor/dist-server/core/app-config/prompt-optimization.js +1 -0
  21. package/vendor/dist-server/core/app-config/settings.js +1 -0
  22. package/vendor/dist-server/core/config.js +1 -0
  23. package/vendor/dist-server/core/graph/a2a-agent-executor.js +2 -0
  24. package/vendor/dist-server/core/graph/app.js +120 -0
  25. package/vendor/dist-server/core/graph/delegated-agent-adapter.js +1 -0
  26. package/vendor/dist-server/core/graph/graph-builder.js +3 -0
  27. package/vendor/dist-server/core/graph/kibana-agent-executor.js +1 -0
  28. package/vendor/dist-server/core/graph/nodes/context/assistants-context.js +5 -0
  29. package/vendor/dist-server/core/graph/nodes/context/compare-context.js +10 -0
  30. package/vendor/dist-server/core/graph/nodes/context/enrich-context.js +8 -0
  31. package/vendor/dist-server/core/graph/nodes/context/inventory-context.js +4 -0
  32. package/vendor/dist-server/core/graph/nodes/context/namespace-context.js +2 -0
  33. package/vendor/dist-server/core/graph/nodes/context/node-types-context.js +4 -0
  34. package/vendor/dist-server/core/graph/nodes/context/relevant-assistants-context.js +5 -0
  35. package/vendor/dist-server/core/graph/nodes/context/relevant-skills-context.js +5 -0
  36. package/vendor/dist-server/core/graph/nodes/context/skills-context.js +8 -0
  37. package/vendor/dist-server/core/graph/nodes/context/state-setter.js +1 -0
  38. package/vendor/dist-server/core/graph/nodes/control/check-reset.js +1 -0
  39. package/vendor/dist-server/core/graph/nodes/control/topic-detection.js +1 -0
  40. package/vendor/dist-server/core/graph/nodes/governance/human-approval.js +16 -0
  41. package/vendor/dist-server/core/graph/nodes/index.js +1 -0
  42. package/vendor/dist-server/core/graph/nodes/orchestration/suggestion-generator.js +17 -0
  43. package/vendor/dist-server/core/graph/nodes/orchestration/team-decider.js +1 -0
  44. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-error.js +4 -0
  45. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-standalone-runner.js +1 -0
  46. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/decider-synthesis.js +29 -0
  47. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-memory.js +2 -0
  48. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/pipeline-runner.js +7 -0
  49. package/vendor/dist-server/core/graph/nodes/orchestration/team-execution/team-assistant-utils.js +1 -0
  50. package/vendor/dist-server/core/graph/nodes/orchestration/team-finder.js +13 -0
  51. package/vendor/dist-server/core/graph/nodes/orchestration/team-invoker.js +3 -0
  52. package/vendor/dist-server/core/graph/nodes/orchestration/team-parallel.js +1 -0
  53. package/vendor/dist-server/core/graph/nodes/orchestration/team-pipeline.js +6 -0
  54. package/vendor/dist-server/core/graph/nodes/orchestration/team-router.js +26 -0
  55. package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/index.js +6 -0
  56. package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/resource-bridge.js +2 -0
  57. package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/sandbox.js +6 -0
  58. package/vendor/dist-server/core/graph/nodes/reasoning/code-executor/tool-bridge.js +1 -0
  59. package/vendor/dist-server/core/graph/nodes/reasoning/local-extractor.js +5 -0
  60. package/vendor/dist-server/core/graph/nodes/reasoning/response-generator.js +47 -0
  61. package/vendor/dist-server/core/graph/nodes/reasoning/static-code-executor/index.js +1 -0
  62. package/vendor/dist-server/core/graph/nodes/reasoning/system.js +54 -0
  63. package/vendor/dist-server/core/graph/nodes/reasoning/tool-executor.js +9 -0
  64. package/vendor/dist-server/core/graph/nodes/tools/raw-output.js +4 -0
  65. package/vendor/dist-server/core/graph/nodes/tools/tool-cleaner.js +7 -0
  66. package/vendor/dist-server/core/graph/nodes/tools/tool-execution/execute-tool-calls.js +3 -0
  67. package/vendor/dist-server/core/graph/nodes/tools/tool-execution/invoke.js +1 -0
  68. package/vendor/dist-server/core/graph/nodes/tools/tool-execution/namespace-guard.js +1 -0
  69. package/vendor/dist-server/core/graph/nodes/tools/tool-execution/result-limits.js +3 -0
  70. package/vendor/dist-server/core/graph/nodes/tools/tool-invoker.js +1 -0
  71. package/vendor/dist-server/core/graph/nodes/tools/tool.js +4 -0
  72. package/vendor/dist-server/core/graph/schemas.js +1 -0
  73. package/vendor/dist-server/core/graph/topic-variants.js +1 -0
  74. package/vendor/dist-server/core/graph/types.js +1 -0
  75. package/vendor/dist-server/core/graph/utils/content-utils.js +17 -0
  76. package/vendor/dist-server/core/graph/utils/edge-jsonata-condition.js +1 -0
  77. package/vendor/dist-server/core/graph/utils/engine-vars.js +1 -0
  78. package/vendor/dist-server/core/graph/utils/logging-utils.js +4 -0
  79. package/vendor/dist-server/core/graph/utils/message-utils.js +5 -0
  80. package/vendor/dist-server/core/graph/utils/node-type-defaults-cache.js +1 -0
  81. package/vendor/dist-server/core/graph/utils/sandbox-catalog.js +1 -0
  82. package/vendor/dist-server/core/graph/utils/schema-utils.js +1 -0
  83. package/vendor/dist-server/core/graph/utils/team-context-policy.js +5 -0
  84. package/vendor/dist-server/core/graph/utils/team-node-resolvers.js +1 -0
  85. package/vendor/dist-server/core/graph/utils/tool-result.js +4 -0
  86. package/vendor/dist-server/core/graph/utils/tool-wrapper.js +14 -0
  87. package/vendor/dist-server/core/llm/init-indices.js +1 -0
  88. package/vendor/dist-server/core/llm/models/index.js +1 -0
  89. package/vendor/dist-server/core/llm/models/model.model.js +1 -0
  90. package/vendor/dist-server/core/llm/models/provider.model.js +1 -0
  91. package/vendor/dist-server/core/llm/models/routing-rule.model.js +1 -0
  92. package/vendor/dist-server/core/llm/providers.js +1 -0
  93. package/vendor/dist-server/core/mcp/client.js +1 -0
  94. package/vendor/dist-server/core/runtime/active-runs-registry.js +1 -0
  95. package/vendor/dist-server/core/runtime/system-prompt-cache.js +1 -0
  96. package/vendor/dist-server/core/runtime/trace-bus.js +1 -0
  97. package/vendor/dist-server/core/schema/cluster_health_report.js +1 -0
  98. package/vendor/dist-server/core/schema/cluster_info.js +1 -0
  99. package/vendor/dist-server/core/schema/cluster_license.js +5 -0
  100. package/vendor/dist-server/core/schema/cluster_stats.js +12 -0
  101. package/vendor/dist-server/core/schema/dashboard.js +1 -0
  102. package/vendor/dist-server/core/schema/indices_settings.js +1 -0
  103. package/vendor/dist-server/core/schema/indices_shards.js +1 -0
  104. package/vendor/dist-server/core/schema/indices_stats.js +1 -0
  105. package/vendor/dist-server/core/schema/nodes_info.js +2 -0
  106. package/vendor/dist-server/core/schema/nodes_stats.js +11 -0
  107. package/vendor/dist-server/core/schema/pricing.js +1 -0
  108. package/vendor/dist-server/core/schema/ui.js +1 -0
  109. package/vendor/dist-server/core/schema/zod_client.js +83 -0
  110. package/vendor/dist-server/core/services/a2a-client.js +2 -0
  111. package/vendor/dist-server/core/services/alerts-service.js +1 -0
  112. package/vendor/dist-server/core/services/api-keys-service.js +1 -0
  113. package/vendor/dist-server/core/services/assistant-resolver.js +1 -0
  114. package/vendor/dist-server/core/services/assistants-index-service.js +1 -0
  115. package/vendor/dist-server/core/services/async-conversations-service.js +22 -0
  116. package/vendor/dist-server/core/services/asyncapi-dispatch.js +1 -0
  117. package/vendor/dist-server/core/services/asyncapi-drivers/driver-manager.js +1 -0
  118. package/vendor/dist-server/core/services/asyncapi-drivers/driver-types.js +0 -0
  119. package/vendor/dist-server/core/services/asyncapi-drivers/http-driver.js +1 -0
  120. package/vendor/dist-server/core/services/asyncapi-drivers/nats-driver.js +1 -0
  121. package/vendor/dist-server/core/services/asyncapi-drivers/websocket-driver.js +1 -0
  122. package/vendor/dist-server/core/services/asyncapi-events-service.js +1 -0
  123. package/vendor/dist-server/core/services/asyncapi-reply-service.js +1 -0
  124. package/vendor/dist-server/core/services/asyncapi-sink.js +1 -0
  125. package/vendor/dist-server/core/services/asyncapi-tools-service.js +1 -0
  126. package/vendor/dist-server/core/services/block-repair-service.js +13 -0
  127. package/vendor/dist-server/core/services/chart-renderer.js +1 -0
  128. package/vendor/dist-server/core/services/chat-llms-service.js +1 -0
  129. package/vendor/dist-server/core/services/chat-runs-service.js +1 -0
  130. package/vendor/dist-server/core/services/chat-tools-service.js +1 -0
  131. package/vendor/dist-server/core/services/chat-traces-service.js +1 -0
  132. package/vendor/dist-server/core/services/chats-service.js +5 -0
  133. package/vendor/dist-server/core/services/comparison-service.js +107 -0
  134. package/vendor/dist-server/core/services/default-model.service.js +1 -0
  135. package/vendor/dist-server/core/services/elastic-stack-sync-service.js +2 -0
  136. package/vendor/dist-server/core/services/elasticsearch-wrapper.js +1 -0
  137. package/vendor/dist-server/core/services/embed-rate-limiter.js +1 -0
  138. package/vendor/dist-server/core/services/error-analytics-service.js +1 -0
  139. package/vendor/dist-server/core/services/es-field-resolver.js +1 -0
  140. package/vendor/dist-server/core/services/gateway-platform-types.js +1 -0
  141. package/vendor/dist-server/core/services/gliner-tagging-service.js +1 -0
  142. package/vendor/dist-server/core/services/golden-questions-scoring.js +1 -0
  143. package/vendor/dist-server/core/services/golden-questions-service.js +1 -0
  144. package/vendor/dist-server/core/services/graph-drilldown-service.js +1 -0
  145. package/vendor/dist-server/core/services/graph-registry-service.js +1 -0
  146. package/vendor/dist-server/core/services/hitl-analytics-service.js +1 -0
  147. package/vendor/dist-server/core/services/ingestion-jobs-service.js +1 -0
  148. package/vendor/dist-server/core/services/ingestion-service.js +5 -0
  149. package/vendor/dist-server/core/services/kibana-client-factory.js +1 -0
  150. package/vendor/dist-server/core/services/kibana-client.js +2 -0
  151. package/vendor/dist-server/core/services/kibana-dashboard-extractor.js +1 -0
  152. package/vendor/dist-server/core/services/kibana-service.js +1 -0
  153. package/vendor/dist-server/core/services/llm-analytics-service.js +1 -0
  154. package/vendor/dist-server/core/services/llm-client-resolver.js +1 -0
  155. package/vendor/dist-server/core/services/llm-models-service.js +1 -0
  156. package/vendor/dist-server/core/services/llm-pricing-pure.js +1 -0
  157. package/vendor/dist-server/core/services/llm-pricing-service.js +1 -0
  158. package/vendor/dist-server/core/services/llm-providers-service.js +1 -0
  159. package/vendor/dist-server/core/services/llm-routing-service.js +1 -0
  160. package/vendor/dist-server/core/services/llm-services.js +1 -0
  161. package/vendor/dist-server/core/services/llm-sync-service.js +1 -0
  162. package/vendor/dist-server/core/services/manifest-loader.js +1 -0
  163. package/vendor/dist-server/core/services/mcp-servers-service.js +1 -0
  164. package/vendor/dist-server/core/services/mcp-sync-service.js +1 -0
  165. package/vendor/dist-server/core/services/mcp-tools-service.js +1 -0
  166. package/vendor/dist-server/core/services/memories-service.js +2 -0
  167. package/vendor/dist-server/core/services/memory-analytics-service.js +1 -0
  168. package/vendor/dist-server/core/services/monitoring-analytics-service.js +1 -0
  169. package/vendor/dist-server/core/services/monitoring-service.js +1 -0
  170. package/vendor/dist-server/core/services/multi-kibana-service.js +1 -0
  171. package/vendor/dist-server/core/services/node-latency-service.js +1 -0
  172. package/vendor/dist-server/core/services/package-policy-service.js +2 -0
  173. package/vendor/dist-server/core/services/pdf-service.js +572 -0
  174. package/vendor/dist-server/core/services/plan-service.js +1 -0
  175. package/vendor/dist-server/core/services/platform-direction.js +1 -0
  176. package/vendor/dist-server/core/services/platform-secrets.js +1 -0
  177. package/vendor/dist-server/core/services/platforms-service.js +1 -0
  178. package/vendor/dist-server/core/services/policy-factory.js +1 -0
  179. package/vendor/dist-server/core/services/prompt-cache-service.js +1 -0
  180. package/vendor/dist-server/core/services/provider-rate-limits.js +1 -0
  181. package/vendor/dist-server/core/services/quota-service.js +1 -0
  182. package/vendor/dist-server/core/services/report-assets-service.js +1 -0
  183. package/vendor/dist-server/core/services/run-analytics-collector.js +1 -0
  184. package/vendor/dist-server/core/services/run-stream-sink.js +1 -0
  185. package/vendor/dist-server/core/services/send_mail.js +460 -0
  186. package/vendor/dist-server/core/services/share-service.js +1 -0
  187. package/vendor/dist-server/core/services/slack-signature.js +1 -0
  188. package/vendor/dist-server/core/services/sources-service.js +6 -0
  189. package/vendor/dist-server/core/services/team-mcp-result.js +4 -0
  190. package/vendor/dist-server/core/services/team-mcp-run-tokens.js +1 -0
  191. package/vendor/dist-server/core/services/team-mcp-runner.js +1 -0
  192. package/vendor/dist-server/core/services/team-mcp-server.js +1 -0
  193. package/vendor/dist-server/core/services/team-mcp-tools.js +1 -0
  194. package/vendor/dist-server/core/services/team-mcp-ui.js +551 -0
  195. package/vendor/dist-server/core/services/team-run-progress.js +1 -0
  196. package/vendor/dist-server/core/services/team-runner-headless.js +7 -0
  197. package/vendor/dist-server/core/services/team-search-service.js +1 -0
  198. package/vendor/dist-server/core/services/teams-service.js +1 -0
  199. package/vendor/dist-server/core/services/token-projection-service.js +1 -0
  200. package/vendor/dist-server/core/services/tool-analytics-service.js +1 -0
  201. package/vendor/dist-server/core/services/tool-history-service.js +1 -0
  202. package/vendor/dist-server/core/services/tool-metrics-service.js +1 -0
  203. package/vendor/dist-server/core/services/tool-scoring.js +1 -0
  204. package/vendor/dist-server/core/services/toolbox-import-mappers.js +1 -0
  205. package/vendor/dist-server/core/services/toolbox-import-service.js +1 -0
  206. package/vendor/dist-server/core/services/trigger-service.js +1 -0
  207. package/vendor/dist-server/core/services/version-snapshot-service.js +1 -0
  208. package/vendor/dist-server/core/services/webhook-calls-service.js +1 -0
  209. package/vendor/dist-server/core/tools/compare-chat.js +46 -0
  210. package/vendor/dist-server/core/tools/enrich-chat.js +50 -0
  211. package/vendor/dist-server/core/tools/variable-encoding.js +1 -0
  212. package/vendor/dist-server/core/types/settings.js +1 -0
  213. package/vendor/dist-server/core/utils/ab-evaluator.js +5 -0
  214. package/vendor/dist-server/core/utils/condition-evaluator.js +1 -0
  215. package/vendor/dist-server/core/utils/http-client.js +1 -0
  216. package/vendor/dist-server/core/utils/json-schema-to-form.js +1 -0
  217. package/vendor/dist-server/core/utils/logger.js +3 -0
  218. package/vendor/dist-server/core/utils/owner-scope.js +1 -0
  219. package/vendor/dist-server/core/utils/ownership.js +1 -0
  220. package/vendor/dist-server/core/utils/parallel-tool-executor.js +1 -0
  221. package/vendor/dist-server/core/utils/performance-tracker.js +3 -0
  222. package/vendor/dist-server/core/utils/prompt-optimizer.js +40 -0
  223. package/vendor/dist-server/core/utils/response-cache.js +1 -0
  224. package/vendor/dist-server/core/utils/schema-validator.js +1 -0
  225. package/vendor/dist-server/core/utils/streaming-optimizer.js +2 -0
  226. package/vendor/dist-server/core/utils/string-helpers.js +1 -0
  227. package/vendor/dist-server/core/utils/test-responses.js +9 -0
  228. package/vendor/dist-server/core/utils/text-utils.js +1 -0
  229. package/vendor/dist-server/core/utils/tool-form-trigger.js +1 -0
  230. package/vendor/dist-server/entrypoints/cli-bootstrap-run.js +1 -0
  231. package/vendor/dist-server/entrypoints/cli-deploy-run.js +1 -0
  232. package/vendor/dist-server/entrypoints/cli-deploy.js +1 -0
  233. package/vendor/dist-server/entrypoints/team-runner.js +1 -0
  234. package/vendor/dist-server/generated/toolbox-catalog.js +1 -0
  235. package/vendor/dist-server/index.js +2 -0
  236. package/vendor/dist-server/middleware/integration-logos.js +1 -0
  237. package/vendor/dist-server/middleware/plan-guard.js +1 -0
  238. package/vendor/dist-server/openapi/generator.js +1 -0
  239. package/vendor/dist-server/openapi/html-tool-spec.js +1 -0
  240. package/vendor/dist-server/routes/a2a-routes.js +1 -0
  241. package/vendor/dist-server/routes/a2a-server-routes.js +5 -0
  242. package/vendor/dist-server/routes/admin.js +1 -0
  243. package/vendor/dist-server/routes/assistants-routes.js +1 -0
  244. package/vendor/dist-server/routes/asyncapi-routes.js +1 -0
  245. package/vendor/dist-server/routes/auth.js +1 -0
  246. package/vendor/dist-server/routes/billing-routes.js +1 -0
  247. package/vendor/dist-server/routes/chat-llms.js +1 -0
  248. package/vendor/dist-server/routes/chat-tools.js +1 -0
  249. package/vendor/dist-server/routes/chat-traces.js +1 -0
  250. package/vendor/dist-server/routes/chats.js +1 -0
  251. package/vendor/dist-server/routes/clusters.js +1 -0
  252. package/vendor/dist-server/routes/compare.js +43 -0
  253. package/vendor/dist-server/routes/connectors-routes.js +1 -0
  254. package/vendor/dist-server/routes/consumptions-routes.js +1 -0
  255. package/vendor/dist-server/routes/data-admin-routes.js +1 -0
  256. package/vendor/dist-server/routes/data-transfer-routes.js +1 -0
  257. package/vendor/dist-server/routes/elastic-tool-execution-routes.js +1 -0
  258. package/vendor/dist-server/routes/geo-proxy-routes.js +1 -0
  259. package/vendor/dist-server/routes/golden-questions-routes.js +1 -0
  260. package/vendor/dist-server/routes/graph-registry.js +1 -0
  261. package/vendor/dist-server/routes/graph-templates-routes.js +1 -0
  262. package/vendor/dist-server/routes/helpdesk-routes.js +35 -0
  263. package/vendor/dist-server/routes/html-routes.js +1 -0
  264. package/vendor/dist-server/routes/index.js +1 -0
  265. package/vendor/dist-server/routes/indices.js +1 -0
  266. package/vendor/dist-server/routes/integrations-routes.js +1 -0
  267. package/vendor/dist-server/routes/langgraph.js +7 -0
  268. package/vendor/dist-server/routes/live-resources-routes.js +1 -0
  269. package/vendor/dist-server/routes/llm-analytics.js +1 -0
  270. package/vendor/dist-server/routes/llm-control-plane.js +1 -0
  271. package/vendor/dist-server/routes/llm.js +1 -0
  272. package/vendor/dist-server/routes/mcp-gateway-routes.js +1 -0
  273. package/vendor/dist-server/routes/mcp-query-routes.js +1 -0
  274. package/vendor/dist-server/routes/mcp-servers-routes.js +1 -0
  275. package/vendor/dist-server/routes/mcp-team-routes.js +1 -0
  276. package/vendor/dist-server/routes/mcp-tools-routes.js +1 -0
  277. package/vendor/dist-server/routes/me-routes.js +63 -0
  278. package/vendor/dist-server/routes/memories-routes.js +1 -0
  279. package/vendor/dist-server/routes/monitoring-analytics.js +12 -0
  280. package/vendor/dist-server/routes/monitoring.js +1 -0
  281. package/vendor/dist-server/routes/node-types-routes.js +171 -0
  282. package/vendor/dist-server/routes/nodes.js +1 -0
  283. package/vendor/dist-server/routes/packages.js +1 -0
  284. package/vendor/dist-server/routes/pdf.js +3 -0
  285. package/vendor/dist-server/routes/plan-routes.js +1 -0
  286. package/vendor/dist-server/routes/platform-requests-routes.js +1 -0
  287. package/vendor/dist-server/routes/platforms-routes.js +1 -0
  288. package/vendor/dist-server/routes/prompts-routes.js +1 -0
  289. package/vendor/dist-server/routes/proxy-logos.js +1 -0
  290. package/vendor/dist-server/routes/quality-routes.js +1 -0
  291. package/vendor/dist-server/routes/resources-ingest-routes.js +1 -0
  292. package/vendor/dist-server/routes/resources-routes.js +1 -0
  293. package/vendor/dist-server/routes/schema-routes.js +1 -0
  294. package/vendor/dist-server/routes/settings-original.js +1 -0
  295. package/vendor/dist-server/routes/settings.js +1 -0
  296. package/vendor/dist-server/routes/share-routes.js +1 -0
  297. package/vendor/dist-server/routes/sources-catalog-routes.js +1 -0
  298. package/vendor/dist-server/routes/sources-routes.js +1 -0
  299. package/vendor/dist-server/routes/team-optimizer-routes.js +1 -0
  300. package/vendor/dist-server/routes/team-schedule-routes.js +1 -0
  301. package/vendor/dist-server/routes/teams-routes.js +1 -0
  302. package/vendor/dist-server/routes/tool-analytics.js +1 -0
  303. package/vendor/dist-server/routes/tool-history-routes.js +1 -0
  304. package/vendor/dist-server/routes/tool-metrics-routes.js +1 -0
  305. package/vendor/dist-server/routes/toolbox-import-routes.js +1 -0
  306. package/vendor/dist-server/routes/tools-routes.js +5 -0
  307. package/vendor/dist-server/routes/transcribe-routes.js +1 -0
  308. package/vendor/dist-server/routes/triggers.js +1 -0
  309. package/vendor/dist-server/routes/versions-routes.js +1 -0
  310. package/vendor/dist-server/routes/webhooks-routes.js +1 -0
  311. package/vendor/dist-server/scripts/add-label-to-tools.js +4 -0
  312. package/vendor/dist-server/scripts/migrate-assistants-to-mcp.js +10 -0
  313. package/vendor/dist-server/scripts/migrate-chat-runs.js +8 -0
  314. package/vendor/dist-server/scripts/migrate-mcp-protocol.js +8 -0
  315. package/vendor/dist-server/scripts/migrate-mcp-to-platforms.js +15 -0
  316. package/vendor/dist-server/services/alert-evaluator.js +3 -0
  317. package/vendor/dist-server/services/auth.js +1 -0
  318. package/vendor/dist-server/services/billing-service.js +1 -0
  319. package/vendor/dist-server/services/chat-title-generator.js +12 -0
  320. package/vendor/dist-server/services/clone/clone-executor.js +1 -0
  321. package/vendor/dist-server/services/clone/closure-resolver.js +3 -0
  322. package/vendor/dist-server/services/clone/entity-graph.js +3 -0
  323. package/vendor/dist-server/services/clone/team-bundle-bootstrap.js +1 -0
  324. package/vendor/dist-server/services/clone/team-bundle-crypto.js +1 -0
  325. package/vendor/dist-server/services/clone/team-bundle-encrypted.js +1 -0
  326. package/vendor/dist-server/services/clone/team-bundle.js +1 -0
  327. package/vendor/dist-server/services/cluster-service.js +1 -0
  328. package/vendor/dist-server/services/connection-adapters.js +1 -0
  329. package/vendor/dist-server/services/connectors-service.js +10 -0
  330. package/vendor/dist-server/services/cost-forecast-service.js +1 -0
  331. package/vendor/dist-server/services/eui-ssr-renderer.js +4 -0
  332. package/vendor/dist-server/services/graph-canvas/full-structure-builder.js +1 -0
  333. package/vendor/dist-server/services/graph-templates-service.js +13 -0
  334. package/vendor/dist-server/services/guest-service.js +1 -0
  335. package/vendor/dist-server/services/html-service.js +1 -0
  336. package/vendor/dist-server/services/langgraph-service.js +2 -0
  337. package/vendor/dist-server/services/leaflet-render-service.js +80 -0
  338. package/vendor/dist-server/services/live-resources-service.js +16 -0
  339. package/vendor/dist-server/services/mcp-app-tester-package.js +1 -0
  340. package/vendor/dist-server/services/mcp-gateway/executors/openapi-executor.js +1 -0
  341. package/vendor/dist-server/services/mcp-gateway/gateway-grant-service.js +2 -0
  342. package/vendor/dist-server/services/team-optimizer-service.js +1 -0
  343. package/vendor/dist-server/services/trace-bus-sink.js +1 -0
  344. package/vendor/dist-server/services/user-provisioning-service.js +3 -0
  345. package/vendor/dist-server/templates/mcp-app-tester/src/mcp-http.js +3 -0
  346. package/vendor/dist-server/templates/mcp-app-tester/src/server.js +1 -0
  347. package/vendor/dist-server/utils.js +1 -0
  348. package/vendor/dist-server/ws/assistant-executor.js +7 -0
  349. package/vendor/dist-server/ws/classify-streamed-json-block.js +1 -0
  350. package/vendor/dist-server/ws/collect-response-generator-node-ids.js +1 -0
  351. package/vendor/dist-server/ws/extractors/blockkit-extractor.js +1 -0
  352. package/vendor/dist-server/ws/extractors/echarts-extractor.js +1 -0
  353. package/vendor/dist-server/ws/extractors/eui-extractor.js +1 -0
  354. package/vendor/dist-server/ws/extractors/form-extractor.js +1 -0
  355. package/vendor/dist-server/ws/extractors/index.js +1 -0
  356. package/vendor/dist-server/ws/extractors/leaflet-extractor.js +1 -0
  357. package/vendor/dist-server/ws/extractors/mantine-extractor.js +1 -0
  358. package/vendor/dist-server/ws/extractors/markdown-extractor.js +7 -0
  359. package/vendor/dist-server/ws/extractors/mermaid-extractor.js +1 -0
  360. package/vendor/dist-server/ws/extractors/recharts-extractor.js +1 -0
  361. package/vendor/dist-server/ws/extractors/remotion-extractor.js +1 -0
  362. package/vendor/dist-server/ws/handler.js +66 -0
  363. package/vendor/dist-server/ws/parsers/anthropic-parser.js +7 -0
  364. package/vendor/dist-server/ws/parsers/base-parser.js +3 -0
  365. package/vendor/dist-server/ws/parsers/gemini-parser.js +8 -0
  366. package/vendor/dist-server/ws/parsers/index.js +1 -0
  367. package/vendor/dist-server/ws/parsers/parse-json-blocks.js +1 -0
  368. package/vendor/dist-server/ws/types.js +0 -0
  369. package/vendor/dist-server/ws/utils.js +1 -0
  370. package/vendor/shared/engine-vars.ts +51 -0
  371. package/vendor/shared/llm-providers-config.ts +69 -0
@@ -0,0 +1 @@
1
+ import i from"express";import{z as a,ZodError as l}from"zod";import{importToolboxYaml as m,refreshToolboxDerived as f}from"../core/services/toolbox-import-service";import{userToken as d}from"../services/auth";const n=i.Router();function u(r){const e=r.auth?.username;if(e)return e;let s=r.cookies?.token;if(!s){const o=r.headers.authorization;o&&o.startsWith("Bearer ")&&(s=o.substring(7))}return s?d(s)?.username??null:null}const y=a.object({yaml:a.string().min(1,"yaml field is required (raw YAML file content)")});n.post("/toolbox-yaml",async(r,e)=>{try{const s=u(r);if(!s)return e.status(401).json({success:!1,message:"Unauthorized"});const t=y.safeParse(r.body);if(!t.success)return e.status(400).json({success:!1,message:"Invalid request body",errors:t.error.errors});const o=r.query.dryRun==="true"||r.query.dryRun==="1"||r.query.dry_run==="true",c=await m(t.data.yaml,s,{dryRun:o});return e.json({success:!0,...c})}catch(s){return s instanceof l?e.status(400).json({success:!1,message:"YAML validation failed",errors:s.errors}):(console.error("[toolbox-import] error:",s),e.status(500).json({success:!1,message:s.message??"Internal error"}))}}),n.post("/platforms/:id/refresh",async(r,e)=>{try{const s=u(r);if(!s)return e.status(401).json({success:!1,message:"Unauthorized"});const{id:t}=r.params;if(!t)return e.status(400).json({success:!1,message:"Missing platform id"});const o=await f(t,s);return e.json({success:!0,...o})}catch(s){const t=s.message??"Internal error",o=/not found/i.test(t)?404:/not owned/i.test(t)?403:/only supported/i.test(t)?400:500;return o>=500&&console.error("[toolbox-refresh] error:",s),e.status(o).json({success:!1,message:t})}});var x=n;export{x as default};
@@ -0,0 +1,5 @@
1
+ import{z as s}from"zod";import{mcpToolsService as me}from"../core/services/mcp-tools-service";import{assertOwner as L}from"../core/utils/ownership";import{makeOwnerScopedClient as ye}from"../core/utils/owner-scope";import V from"axios";import ge from"https";import{generateInputSchema as fe,generateOutputSchema as he}from"../core/services/kibana-dashboard-extractor";import{getPlatformById as G,parseAllowedIndexPatterns as be,isToolIndexPatternAllowed as _e}from"../core/services/platforms-service";import{normalizeCustomHeaders as Se}from"../core/utils/string-helpers";import{aggField as X}from"../core/services/es-field-resolver";const we=process.env.ELASTICSEARCH_HOST||"https://51.159.174.230:9205",Y=process.env.ELASTICSEARCH_USER||"elastic",ee=process.env.ELASTICSEARCH_PASSWORD||"",w=".stkxp_tools",O=".stkxp_api",te=".stkxp_platforms",H=new ge.Agent({rejectUnauthorized:!1});async function U(){const o=(process.env.MCP_URL||"https://localhost:3001/mcp").replace(/\/mcp$/,"");try{await V.post(`${o}/cache/reload`,{},{httpsAgent:H,timeout:5e3}),console.log("[Tools] MCP server cache reloaded")}catch(t){console.warn("[Tools] MCP reload notification failed (non-blocking):",t.message)}}async function se(){const o=process.env.STKXP_API_URL||"http://localhost:4000";try{await V.post(`${o}/api/routes/reload`,{},{timeout:1e4}),console.log("[Tools] stkxp-api routes reloaded")}catch(t){console.warn("[Tools] stkxp-api route reload failed (non-blocking):",t.message)}}const p=ye({node:we,auth:{username:Y,password:ee},tls:{rejectUnauthorized:!1},requestTimeout:6e4,maxRetries:3}),W=s.object({type:s.enum(["none","apiKey","bearer","basic","bearer_internal","platform_es"]),headerName:s.string().optional(),apiKey:s.string().optional(),token:s.string().optional(),username:s.string().optional(),password:s.string().optional()});import{QueryVariableSchema as z,detectQueryVariables as B,encodeVariableForDsl as xe,encodeVariableForEsql as ve,encodeVariableForUrl as Te,applyEsqlVariables as oe,applyUrlVariables as ae,applyDslVariables as Z,mergeVariablesIntoInputSchema as F}from"../core/tools/variable-encoding";const re=s.object({title:s.string().optional(),readOnlyHint:s.boolean().optional(),destructiveHint:s.boolean().optional(),idempotentHint:s.boolean().optional(),openWorldHint:s.boolean().optional()}).strict(),ne=s.object({name:s.string().min(1).transform(ie),label:s.string().optional(),description:s.string().optional(),type:s.enum(["mcp","a2a","mcp_remote","assistant_mapping","asyncapi_publish"]).default("mcp"),system:s.string().nullable().optional(),service:s.string().nullable().optional(),endpoint:s.string().optional(),httpMethod:s.enum(["GET","POST","PUT"]).optional(),authConfig:W.optional(),inputSchema:s.string().optional(),outputSchema:s.string().optional(),enabled:s.boolean().default(!0),tags:s.array(s.string()).optional(),apiDocId:s.string().optional(),platformId:s.string().optional(),indexPattern:s.string().optional(),bodyTemplate:s.string().optional(),variables:s.array(z).optional(),annotations:re.optional()}),je=s.object({name:s.string().min(1),system:s.string().min(1),description:s.string().optional(),query:s.string().min(1),query_language:s.enum(["dsl","esql"]).default("dsl"),index_pattern:s.string().min(1),platformId:s.string().min(1),inputSchema:s.string().optional(),outputSchema:s.string().optional(),variables:s.array(z).optional().default([])}),ke=s.object({search:s.string().optional().describe('Hybrid lexical + semantic search across name, label, description, endpoint, system, tags. The semantic leg queries `search_semantic` (semantic_text, fed via copy_to), so a query like "DRH ressources humaines" can match a tool described in English.'),type:s.enum(["mcp","a2a","mcp_remote","assistant_mapping","asyncapi_publish"]).optional(),system:s.string().optional().describe("Filter by exact integration system"),systems:s.string().optional().describe("Comma-separated list of systems (alternative to system)"),mcpServerId:s.string().optional().describe("Filter by remote MCP server id"),platformId:s.string().optional().describe("Filter by OpenAPI platform id"),service:s.string().optional(),endpoint:s.string().optional(),owner:s.string().optional(),owners:s.string().optional().describe("Comma-separated list of owners (OR semantics)"),tags:s.string().optional().describe("Comma-separated list of tags (OR semantics)"),enabled:s.string().optional().describe("'true' or 'false'"),noSystem:s.string().optional().describe("When 'true', return only tools with no system field set"),from:s.string().optional().describe("Pagination offset (default 0)"),size:s.string().optional().describe("Page size (default 10000)"),sortField:s.string().optional().describe("'name' or 'createdAt' (default 'name')"),sortOrder:s.enum(["asc","desc"]).optional()});function M(o){return o.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"").slice(0,40)}function ie(o){const t=o.replace(/[^a-zA-Z0-9_-]+/g,"_").replace(/^_+|_+$/g,"").slice(0,128);return t.length>0?t:"tool"}function ce(o){let t=0;for(let e=0;e<o.length;e++)t=Math.imul(31,t)+o.charCodeAt(e)|0;return Math.abs(t).toString(36).slice(0,6).padStart(6,"0")}const le=s.object({name:s.string().min(1).transform(ie).optional(),label:s.string().optional(),description:s.string().optional(),type:s.enum(["mcp","a2a","mcp_remote","assistant_mapping","asyncapi_publish"]).optional(),system:s.string().nullable().optional(),service:s.string().nullable().optional(),endpoint:s.string().optional(),httpMethod:s.enum(["GET","POST","PUT"]).optional(),authConfig:W.optional(),inputSchema:s.string().optional(),outputSchema:s.string().optional(),enabled:s.boolean().optional(),tags:s.array(s.string()).optional(),owner:s.string().optional(),apiDocId:s.string().optional(),updatedQuery:s.string().optional(),updatedVariables:s.array(z).optional(),bodyTemplate:s.string().nullable().optional(),variables:s.array(z).nullable().optional(),annotations:re.nullable().optional()});async function Pe(){try{if(!await p.indices.exists({index:w}))await p.indices.create({index:w,body:{mappings:{properties:{name:{type:"keyword",copy_to:"search_semantic"},label:{type:"text",copy_to:"search_semantic"},description:{type:"text",copy_to:"search_semantic"},type:{type:"keyword"},system:{type:"keyword",copy_to:"search_semantic"},service:{type:"keyword"},endpoint:{type:"text"},inputSchema:{type:"text"},outputSchema:{type:"text"},enabled:{type:"boolean"},tags:{type:"keyword",copy_to:"search_semantic"},owner:{type:"keyword"},search_semantic:{type:"semantic_text",inference_id:".multilingual-e5-small-elasticsearch"},annotations:{type:"object",properties:{title:{type:"keyword"},readOnlyHint:{type:"boolean"},destructiveHint:{type:"boolean"},idempotentHint:{type:"boolean"},openWorldHint:{type:"boolean"}}},mcpServerId:{type:"keyword"},mcpServerName:{type:"keyword"},createdAt:{type:"date"},updatedAt:{type:"date"},createdBy:{type:"keyword"},updatedBy:{type:"keyword"}}}}}),console.log(`Index ${w} created successfully`);else{await p.indices.putMapping({index:w,body:{properties:{mcpServerId:{type:"keyword"},mcpServerName:{type:"keyword"},annotations:{type:"object",properties:{title:{type:"keyword"},readOnlyHint:{type:"boolean"},destructiveHint:{type:"boolean"},idempotentHint:{type:"boolean"},openWorldHint:{type:"boolean"}}}}}});try{await p.indices.putMapping({index:w,body:{properties:{search_semantic:{type:"semantic_text",inference_id:".multilingual-e5-small-elasticsearch"},name:{type:"keyword",copy_to:"search_semantic"},label:{type:"text",copy_to:"search_semantic"},description:{type:"text",copy_to:"search_semantic"},system:{type:"keyword",copy_to:"search_semantic"},tags:{type:"text",copy_to:"search_semantic"}}}})}catch(t){String(t?.message||"").includes("illegal_argument_exception")||console.warn("[Tools API] putMapping warning for search_semantic field:",t?.message)}}}catch(o){console.error("Error ensuring index:",o)}}Pe();async function Ie(o,t){try{const{search:e,type:a,system:n,systems:r,mcpServerId:i,platformId:c,service:g,endpoint:f,owner:h,owners:u,tags:k,enabled:b,noSystem:x,from:P="0",size:T="10000"}=o.query,v=u?u.split(",").map(m=>m.trim()).filter(Boolean):[],I=v.includes("stkxp")||h==="stkxp"?[]:[{term:{owner:"stkxp"}}],d={bool:{must:[],must_not:I}};if(e){const m=e.toLowerCase();d.bool.must.push({bool:{should:[{multi_match:{query:e,fields:["label^2","description","endpoint"]}},{wildcard:{name:{value:`*${m}*`,case_insensitive:!0}}},{wildcard:{system:{value:`*${m}*`,case_insensitive:!0}}},{wildcard:{service:{value:`*${m}*`,case_insensitive:!0}}},{wildcard:{tags:{value:`*${m}*`,case_insensitive:!0}}},{semantic:{field:"search_semantic",query:e}}],minimum_should_match:1}})}if(a&&d.bool.must.push({term:{type:a}}),n&&d.bool.must.push({term:{system:n}}),i&&d.bool.must.push({term:{mcpServerId:i}}),c&&d.bool.must.push({term:{platformId:c}}),r&&!n){const m={stack_expert:"clusters"},y=r.split(",").map(j=>j.trim()).filter(Boolean).flatMap(j=>{const Q=m[j];return Q?[j,Q]:[j]});y.length>0&&d.bool.must.push({bool:{should:[{terms:{system:y}},{term:{type:"mcp_remote"}},{term:{type:"mcp"}},{term:{type:"assistant_mapping"}},{term:{type:"asyncapi_publish"}}],minimum_should_match:1}})}if(g&&d.bool.must.push({term:{service:g}}),f&&d.bool.must.push({match_phrase:{endpoint:f}}),h&&d.bool.must.push({term:{owner:h}}),v.length>0&&d.bool.must.push({bool:{should:v.map(m=>({term:{owner:m}})),minimum_should_match:1}}),k){const m=k.split(",").map(l=>l.trim()).filter(Boolean);if(m.length>0){const l=await X(w,"tags");d.bool.must.push({terms:{[l]:m}})}}b!==void 0&&d.bool.must.push({term:{enabled:b==="true"}}),x==="true"&&(d.bool.must_not||(d.bool.must_not=[]),d.bool.must_not.push({exists:{field:"system"}})),console.log("@@@@@@@@@@",JSON.stringify(d));const _={name:"name",createdAt:"createdAt"},A=String(o.query.sortField||"name"),$=_[A]||"name",R=o.query.sortOrder==="desc"?"desc":"asc",D={index:w,body:{query:d,from:parseInt(P),size:parseInt(T),sort:[{[$]:{order:R}}]}};n&&(console.log("[Tools API] Filtering by system:",n),console.log("[Tools API] Elasticsearch query:",JSON.stringify(D.body.query,null,2)));const C=await p.search(D);let S=C.hits.hits.map(m=>({id:m._id,...m._source}));const q=S.filter(m=>m.type==="mcp_remote"&&m.mcpServerId&&!m.mcpServerUrl);if(q.length>0){const m=[...new Set(q.map(l=>l.mcpServerId))];try{const l=await p.mget({index:".stkxp_platforms",body:{ids:m}}),y={};l.docs.forEach(j=>{j.found&&(y[j._id]=j._source.url)}),S=S.map(j=>j.type==="mcp_remote"&&j.mcpServerId&&!j.mcpServerUrl?{...j,mcpServerUrl:y[j.mcpServerId]}:j)}catch{}}const E=[...new Set(S.map(m=>m.platformId).filter(Boolean))];if(E.length>0)try{const m=await p.mget({index:te,body:{ids:E}}),l=new Set(m.docs.filter(y=>y.found&&y._source?.config?.serverType==="gateway").map(y=>y._id));S=S.map(y=>({...y,isGatewayLinked:!!y.platformId&&l.has(y.platformId)}))}catch{S=S.map(l=>({...l,isGatewayLinked:!1}))}else S=S.map(m=>({...m,isGatewayLinked:!1}));const N=typeof C.hits.total=="number"?C.hits.total:C.hits.total?.value||0;n&&(console.log("[Tools API] Found",N,"tools matching system:",n),S.length>0&&console.log("[Tools API] First tool sample:",{name:S[0].name,system:S[0].system,service:S[0].service,type:S[0].type})),t.json({success:!0,total:N,from:parseInt(P),size:S.length,tools:S})}catch(e){console.error("Error fetching tools:",e),t.status(500).json({success:!1,error:"Failed to fetch tools",message:e.message})}}async function Ae(o,t){try{const{owner:e,owners:a}=o.query,n=a?a.split(",").map(u=>u.trim()).filter(Boolean):[],r=n.includes("stkxp")||e==="stkxp"?[]:[{term:{owner:"stkxp"}}],i={bool:{must:[],must_not:r}};e&&i.bool.must.push({term:{owner:e}}),n.length>0&&i.bool.must.push({bool:{should:n.map(u=>({term:{owner:u}})),minimum_should_match:1}});const c=await X(w,"tags"),h=((await p.search({index:w,body:{query:i,size:0,aggs:{all_tags:{terms:{field:c,size:1e3,order:{_key:"asc"}}}}}})).aggregations?.all_tags?.buckets||[]).map(u=>u.key).filter(Boolean);t.json({success:!0,tags:h})}catch(e){console.error("[Tools API] Error fetching tags:",e),t.status(500).json({success:!1,error:"Failed to fetch tags",message:e.message})}}async function Re(o,t){try{const{id:e}=o.params,a=await p.get({index:w,id:e});t.json({success:!0,tool:{id:a._id,...a._source}})}catch(e){if(e.meta?.statusCode===404){t.status(404).json({success:!1,error:"Tool not found"});return}console.error("Error fetching tool:",e),t.status(500).json({success:!1,error:"Failed to fetch tool",message:e.message})}}async function ue(o,t,e){if(!t||!o)return null;try{const a=await G(o,e,!0,!1);if(!a)return null;const n=be(a.allowedIndexPatterns),r=_e(t,n);return r.allowed?null:`Index pattern "${r.rejectedEntry}" is not allowed by platform "${a.name}" (allowed: ${n.join(", ")}). Edit the platform's allowedIndexPatterns to grant access.`}catch(a){return console.warn("[Tools] validateToolIndexPattern failed (non-blocking):",a.message),null}}async function qe(o,t){console.log(`[Tools] POST or PUT /api/tools \u2014 handler reached, body keys: ${Object.keys(o.body||{}).join(",")}`);try{const e=ne.parse(o.body);console.log(`[Tools] POST or PUT /api/tools \u2014 schema validated, name=${e.name} platformId=${e.platformId} indexPattern=${e.indexPattern}`);const a=o.auth?.username||"system";console.log("[Tools] POST or PUT /api/tools \u2014 calling validateToolIndexPattern");const n=await ue(e.platformId,e.indexPattern,a);if(console.log(`[Tools] POST or PUT /api/tools \u2014 validateToolIndexPattern returned: ${n??"OK"}`),n){t.status(400).json({success:!1,error:n});return}if((await p.search({index:w,body:{query:{term:{name:e.name}}}})).hits.hits.length>0){t.status(409).json({success:!1,error:"Tool with this name already exists"});return}const i=new Date().toISOString(),c=typeof o.body?.name=="string"?o.body.name:e.name,g={...e,label:e.label||c,owner:a,createdAt:i,updatedAt:i,createdBy:a,updatedBy:a},f=await p.index({index:w,body:g,refresh:!0});U(),t.status(201).json({success:!0,tool:{id:f._id,...g}})}catch(e){if(e instanceof s.ZodError){t.status(400).json({success:!1,error:"Validation error",details:e.errors});return}console.error("Error creating tool:",e),t.status(500).json({success:!1,error:"Failed to create tool",message:e.message})}}async function Ee(o,t){try{console.log("updateTool called for id:",o.params.id),console.log("updateTool body:",o.body);const{id:e}=o.params,a=le.parse(o.body),{apiDocId:n,updatedQuery:r,updatedVariables:i,...c}=a,g=await L(o,t,p,w,e);if(!g)return;const f=o.auth?.username||"system",h=g.source,u=c.platformId!==void 0?c.platformId:h?.platformId,k=c.indexPattern!==void 0?c.indexPattern:h?.indexPattern;if(c.platformId!==void 0||c.indexPattern!==void 0){const T=await ue(u,k,f);if(T){t.status(400).json({success:!1,error:T});return}}const b=[],x={updatedAt:new Date().toISOString(),updatedBy:f};for(const[T,v]of Object.entries(c))v===null?b.push(T):x[T]=v;if(console.log("Updating Elasticsearch document with:",x,"removing:",b),b.length>0){const T=[...Object.keys(x).map(v=>`ctx._source['${v}'] = params.doc['${v}']`),...b.map(v=>`ctx._source.remove('${v}')`)];await p.update({index:w,id:e,body:{script:{source:T.join("; "),params:{doc:x}}},refresh:!0})}else await p.update({index:w,id:e,body:{doc:x},refresh:!0});console.log("Document updated, fetching updated version");const P=await p.get({index:w,id:e});if(console.log("Update successful, sending response"),U(),n&&(r||i!==void 0))try{const T={updated_at:new Date().toISOString()};if(r&&(T.query=r,T.aggs=null),i!==void 0){let v="";if(r)try{const I=JSON.parse(r);v=typeof I.query=="string"?I.query:JSON.stringify(I.query??I)}catch{v=r}if(v){const I=new Set(i.map(_=>_.name)),d=B(v).filter(_=>!I.has(_));if(d.length>0){t.status(400).json({success:!1,error:`Query references undeclared variables: ${d.map(_=>`{{${_}}}`).join(", ")}`});return}}T.variables=i,T.use_variable_substitution=i.length>0}await p.update({index:O,id:n,body:{doc:T},refresh:!0}),console.log(`[Tools] Updated .stkxp_api doc ${n}`)}catch(T){console.warn(`[Tools] Failed to update .stkxp_api doc ${n}:`,T.message)}t.json({success:!0,tool:{id:P._id,...P._source}})}catch(e){if(console.error("Error in updateTool:",e),e instanceof s.ZodError){t.status(400).json({success:!1,error:"Validation error",details:e.errors});return}t.status(500).json({success:!1,error:"Failed to update tool",message:e.message})}}async function $e(o,t){try{const{id:e}=o.params;if(!await L(o,t,p,w,e))return;try{const r=(await p.get({index:w,id:e}))._source?.apiDocId;r&&(await p.get({index:O,id:r}))._source?.category==="custom_query"&&(await p.delete({index:O,id:r,refresh:!0}),console.log(`[Tools] Cascade-deleted custom api-service doc ${r}`))}catch(n){console.warn("[Tools] Cascade delete api-service failed (non-blocking):",n.message)}await p.delete({index:w,id:e,refresh:!0}),U(),t.json({success:!0,message:"Tool deleted successfully"})}catch(e){if(e.meta?.statusCode===404){t.status(404).json({success:!1,error:"Tool not found"});return}console.error("Error deleting tool:",e),t.status(500).json({success:!1,error:"Failed to delete tool",message:e.message})}}async function Oe(o,t){try{const{id:e}=o.params,{enabled:a}=o.body;if(typeof a!="boolean"){t.status(400).json({success:!1,error:"enabled field must be a boolean"});return}if(!await L(o,t,p,w,e))return;const r=o.auth?.username||"system";await p.update({index:w,id:e,body:{doc:{enabled:a,updatedAt:new Date().toISOString(),updatedBy:r}},refresh:!0});const i=await p.get({index:w,id:e});U(),t.json({success:!0,tool:{id:i._id,...i._source}})}catch(e){if(e.meta?.statusCode===404){t.status(404).json({success:!1,error:"Tool not found"});return}console.error("Error toggling tool status:",e),t.status(500).json({success:!1,error:"Failed to toggle tool status",message:e.message})}}async function Ce(o,t){try{const e=o.auth?.username||"system",a=await me.listTools();if(!a.success||!a.tools){t.status(500).json({success:!1,error:"Failed to fetch tools from MCP server"});return}const n=a.tools,r={total:n.length,migrated:0,skipped:0,errors:[]},i=new Date().toISOString();for(const c of n)try{if((await p.search({index:w,body:{query:{term:{name:c.name}}}})).hits.hits.length>0){r.skipped++,console.log(`Tool "${c.name}" already exists, skipping`);continue}const f=typeof c.inputSchema=="string"?c.inputSchema:JSON.stringify(c.inputSchema||{}),h=typeof c.outputSchema=="string"?c.outputSchema:JSON.stringify(c.outputSchema||{}),u=c.name.match(/^([^_]+)_/),k=u?u[1]:c.name.split("_")[0],b={name:c.name,description:c.description||"",type:"mcp",system:k,inputSchema:f,outputSchema:h,enabled:!0,owner:e,createdAt:i,updatedAt:i,createdBy:e,updatedBy:e};await p.index({index:w,body:b,refresh:!0}),r.migrated++,console.log(`Migrated tool: ${c.name}`)}catch(g){r.errors.push({tool:c.name,error:g.message}),console.error(`Error migrating tool "${c.name}":`,g)}t.json({success:!0,results:r})}catch(e){console.error("Error during migration:",e),t.status(500).json({success:!1,error:"Migration failed",message:e.message})}}function de(o,t){return{id:o,query:t.query,aggs:t.aggs,control_panels:t.control_panels,query_file_path:t.query_file_path,has_template:t.has_template,dashboard_title:t.dashboard_title,index_pattern:t.index_pattern}}async function Ne(o,t){const{system:e,service:a}=o.query;if(!e||!a){t.status(400).json({success:!1,error:"system and service required"});return}try{try{const i=await p.get({index:O,id:a});if(i.found&&i._source?.system===e){t.json({success:!0,doc:de(i._id,i._source)});return}}catch{}const r=(await p.search({index:O,size:1,body:{query:{bool:{must:[{term:{system:e}},{term:{"name.keyword":a}}]}}}})).hits.hits[0];if(!r){t.json({success:!0,doc:null});return}t.json({success:!0,doc:de(r._id,r._source)})}catch(n){console.error("[Tools] getApiQuery error:",n),t.status(500).json({success:!1,error:n.message})}}function pe(o){try{return JSON.parse(o)}catch(t){const e=o.replace(/,\s*,+/g,",").replace(/,(\s*[}\]])/g,"$1");try{const a=JSON.parse(e);return console.warn("[Tools] parseQueryJsonLenient: recovered after comma cleanup. strict error:",t.message),a}catch{throw t}}}const De=new Set(["bool","term","terms","match","match_all","match_none","match_phrase","multi_match","range","exists","prefix","wildcard","regexp","fuzzy","ids","query_string","simple_query_string","nested","has_child","has_parent","geo_distance","geo_bounding_box","geo_polygon","script","constant_score","dis_max","function_score","boosting","span_term","terms_set","distance_feature","percolate","wrapper"]);function Qe(o){return!o||typeof o!="object"||Array.isArray(o)?!1:Object.keys(o).some(t=>De.has(t))}async function Ue(o,t){const{platformId:e,unifiedQuery:a,indexPattern:n,query_language:r,esqlParams:i,variables:c,variableValues:g}=o.body;if(!e||!a){t.status(400).json({success:!1,error:"platformId and unifiedQuery required"});return}try{const u=(await p.get({index:te,id:e}))._source?.config?.endpoints?.elasticsearch;if(!u?.url){t.status(400).json({success:!1,error:"Platform has no Elasticsearch endpoint configured"});return}const k=u.port?`:${u.port}`:"",b=u.url.replace(/\/$/,""),x=u.basePath?`/${String(u.basePath).replace(/^\/+|\/+$/g,"")}`:"",P=`${b}${k}${x}`,T=u.username||Y,v=u.password||ee,I=`Basic ${Buffer.from(`${T}:${v}`).toString("base64")}`;if(r==="esql"){let q=a,E;if(c&&c.length>0)try{q=oe(a,c,g||{})}catch(y){t.status(400).json({success:!1,error:y.message});return}else if(i)try{const y=JSON.parse(i);Array.isArray(y)&&y.length>0&&(E=y)}catch{}const N={query:q};E&&(N.params=E);const m=Date.now(),l=await V.post(`${P}/_query`,N,{headers:{"Content-Type":"application/json",Authorization:I},httpsAgent:H,timeout:3e4,validateStatus:()=>!0});t.json({success:l.status<400,statusCode:l.status,durationMs:Date.now()-m,data:l.data,query_language:"esql"});return}let d=a;if(c&&c.length>0)try{d=Z(a,c,g||{})}catch(q){t.status(400).json({success:!1,error:q.message});return}let _;try{console.log("[Tools] testToolQuery: parsing unifiedQuery after variable substitution:",d),_=pe(d),console.log("[Tools] testToolQuery: parsing unifiedQuery after variable substitution:",_)}catch(q){const E=q?.message||String(q);console.error("[Tools] testToolQuery: invalid JSON in unifiedQuery (after variable substitution).",`
2
+ parse error :`,E,`
3
+ rendered query :`,d),t.status(400).json({success:!1,error:"Invalid JSON in unifiedQuery (after variable substitution)",detail:E});return}let A={};try{_.query!==void 0?A=typeof _.query=="string"?JSON.parse(_.query):_.query||{}:Qe(_)&&(A=_)}catch{A={}}let $={};try{$=typeof _.aggs=="string"?JSON.parse(_.aggs):_.aggs||{}}catch{$={}}const R={query:A,size:10,sort:[{"@timestamp":{order:"desc"}}]};Object.keys($).length>0&&(R.aggs=$);const D=n&&n.trim()?n.trim():"logs-*,metrics-*",C=Date.now(),S=await V.post(`${P}/${D}/_search`,R,{headers:{"Content-Type":"application/json",Authorization:I},httpsAgent:H,timeout:3e4,validateStatus:()=>!0});t.json({success:S.status<400,statusCode:S.status,durationMs:Date.now()-C,data:S.data,query_language:"dsl"})}catch(f){console.error("[Tools] testToolQuery error:",f),t.status(500).json({success:!1,error:f.message})}}const ze=s.object({url:s.string().min(1),httpMethod:s.enum(["GET","POST","PUT"]).default("POST"),authConfig:W.optional(),customHeaders:s.record(s.union([s.string(),s.boolean(),s.number()])).optional(),bodyTemplate:s.string().optional(),variables:s.array(z).optional().default([]),variableValues:s.record(s.unknown()).optional().default({}),pathParams:s.record(s.union([s.string(),s.number()])).optional().default({}),platformId:s.string().optional(),dryRun:s.boolean().optional().default(!1)});async function Be(o,t){try{const e=ze.parse(o.body),{url:a,httpMethod:n,authConfig:r,customHeaders:i,bodyTemplate:c,variables:g,variableValues:f,pathParams:h,platformId:u,dryRun:k}=e,b=o.auth?.username||"system",x={},P={};for(const[l,y]of Object.entries(f||{}))l.startsWith("__")?x[l]=y:P[l]=y;x.__username===void 0&&(x.__username=b),x.__now===void 0&&(x.__now=new Date().toISOString());const T=new Set([...B(a),...c?B(c):[]]),v=new Set(g.map(l=>l.name)),I=Array.from(T).filter(l=>!l.startsWith("__")&&!v.has(l));if(I.length>0){t.status(400).json({success:!1,error:`Template references undeclared variables: ${I.map(l=>`{{${l}}}`).join(", ")}`});return}let d,_;try{d=ae(a,g,P,x)}catch(l){t.status(400).json({success:!1,error:`URL render failed: ${l.message}`});return}if(d=d.replace(/:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(l,y,j)=>{const J=h[y||j];return J==null||J===""?l:encodeURIComponent(String(J))}),n!=="GET"&&c){let l;try{l=Z(c,g,P,x)}catch(y){t.status(400).json({success:!1,error:`Body render failed: ${y.message}`});return}try{_=JSON.parse(l)}catch(y){t.status(400).json({success:!1,error:`Rendered body is not valid JSON: ${y.message}`,rendered:{url:d,body:l}});return}}const A={Accept:"application/json",...Se(i)};if(r){if(r.type==="bearer"&&r.token)A.Authorization=`Bearer ${r.token}`;else if(r.type==="apiKey"&&r.apiKey)A[r.headerName||"X-API-Key"]=r.apiKey;else if(r.type==="basic"&&r.username){const l=`${r.username}:${r.password||""}`;A.Authorization=`Basic ${Buffer.from(l).toString("base64")}`}else if(r.type==="platform_es"){if(!u){t.status(400).json({success:!1,error:"authConfig.type='platform_es' requires a platformId in the test body"});return}const l=await G(u,b,!0,!1),y=l?.config,j=y?.endpoints?.elasticsearch?.username,Q=y?.endpoints?.elasticsearch?.password;if(!l||l.type!=="ElasticStack"||!j||!Q){t.status(400).json({success:!1,error:`platform_es: platform "${u}" not found or has no Elasticsearch credentials`});return}A.Authorization=`Basic ${Buffer.from(`${j}:${Q}`).toString("base64")}`}}n!=="GET"&&_!==void 0&&(A["Content-Type"]="application/json");const $={url:d,method:n,headers:{...A,...A.Authorization?{Authorization:"\u2022\u2022\u2022 (redacted)"}:{}},body:_};if(k){t.json({success:!0,dryRun:!0,rendered:$});return}const R=(()=>{const l=d.match(/^([a-z][a-z0-9+.-]*):/i);return l?l[1].toLowerCase():""})();if(R&&R!=="http"&&R!=="https"){t.status(400).json({success:!1,error:`Cannot test "${R}://" URL with the HTTP tester.`,hint:R==="nats"||R==="ws"||R==="wss"?`This tool resolves to an AsyncAPI V2.4 ${R} broker. The "Test" button only supports HTTP \u2014 invoke the tool through the assistant chat (which routes via driverManager.publish) or use the V2.4 demo scripts under scripts/asyncapi-v24-test/.`:"The external-tool tester only supports http:// and https:// URLs.",rendered:$});return}const D={method:n,headers:A};_!==void 0&&(D.body=JSON.stringify(_));const C=Date.now(),S=await fetch(d,D),q=Date.now()-C,E=await S.text();let N=E;const m=S.headers.get("content-type");if(m&&m.includes("application/json"))try{N=JSON.parse(E)}catch{}t.json({success:S.ok,rendered:$,response:{status:S.status,statusText:S.statusText,durationMs:q,body:N}})}catch(e){if(e instanceof s.ZodError){t.status(400).json({success:!1,error:"Validation error",details:e.errors});return}console.error("[Tools] testExternalTool error:",e),t.status(500).json({success:!1,error:e.message})}}function K(o,t=0){if(t>6)return{};if(o===null)return{type:"null"};if(Array.isArray(o)){if(o.length===0)return{type:"array",items:{}};const a=o[0];return{type:"array",items:K(a,t+1)}}const e=typeof o;if(e==="string")return{type:"string"};if(e==="number")return Number.isInteger(o)?{type:"integer"}:{type:"number"};if(e==="boolean")return{type:"boolean"};if(e==="object"){const a=o,n={};for(const[r,i]of Object.entries(a))n[r]=K(i,t+1);return{type:"object",properties:n}}return{}}async function Je(o,t){const{variables:e,sampleResponse:a}=o.body;try{const n=Array.isArray(e)?e:[],r=F("{}",n)||JSON.stringify({type:"object",properties:{}},null,2);let i;if(a==null)i=JSON.stringify({type:"object",additionalProperties:!0},null,2);else{let c=a;if(typeof c=="string"){const f=c.trim();if(f.startsWith("{")||f.startsWith("["))try{c=JSON.parse(f)}catch{}}const g=K(c,0);i=JSON.stringify(g,null,2)}t.json({success:!0,inputSchema:r,outputSchema:i})}catch(n){console.error("[Tools] generateExternalToolSchemas error:",n),t.status(500).json({success:!1,error:n.message})}}async function Ve(o,t){const{unifiedQuery:e,controlPanels:a,includeTimeRange:n=!0,variables:r,query_language:i}=o.body;if(!e){t.status(400).json({success:!1,error:"unifiedQuery required"});return}try{if(i==="esql"){const b=F("{}",r||[]),x=JSON.stringify({type:"object",properties:{columns:{type:"array",items:{type:"object"}},rows:{type:"array",items:{type:"array"}}}},null,2);t.json({success:!0,inputSchema:b,outputSchema:x});return}const c=e.replace(/\{\{\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\}\}/g,"null");let g;try{g=pe(c)}catch(b){const x=b?.message||String(b);console.error("[Tools] deriveSchema: invalid JSON in unifiedQuery.",`
4
+ parse error :`,x,`
5
+ sanitized query :`,c),t.status(400).json({success:!1,error:"Invalid JSON in unifiedQuery",detail:x});return}let f={};try{f=typeof g.aggs=="string"?JSON.parse(g.aggs):g.aggs||{}}catch{f={}}let h=[];if(a)try{h=JSON.parse(a),Array.isArray(h)||(h=[])}catch{h=[]}let u=fe(h,f,n);if(r&&r.length>0){const b=F(JSON.stringify(u),r);if(b)try{u=JSON.parse(b)}catch{}}const k=he(f);t.json({success:!0,inputSchema:JSON.stringify(u,null,2),outputSchema:JSON.stringify(k,null,2)})}catch(c){console.error("[Tools] generateToolSchemas error:",c),t.status(500).json({success:!1,error:c.message})}}async function Fe(o,t){try{const e=o.auth?.username||"system",r=((await p.search({index:O,body:{size:0,query:{term:{owner:e}},aggs:{systems:{terms:{field:"system",size:200},aggs:{top:{top_hits:{size:1,_source:["index_pattern","platformId"]}}}}}}})).aggregations?.systems?.buckets||[]).map(i=>{const c=i.top?.hits?.hits?.[0]?._source||{};return{system:i.key,index_pattern:c.index_pattern||"",platformId:c.platformId||""}});t.json({success:!0,systems:r})}catch(e){console.error("[Tools] getApiServiceSystems error:",e),t.status(500).json({success:!1,error:e.message})}}async function Me(o,t){try{const{id:e}=o.params,a=await p.get({index:O,id:e});if(!a.found){t.status(404).json({success:!1,error:"API service not found"});return}t.json({success:!0,apiService:{id:a._id,...a._source}})}catch(e){if(e.meta?.statusCode===404){t.status(404).json({success:!1,error:"API service not found"});return}console.error("[Tools] getApiService error:",e),t.status(500).json({success:!1,error:e.message})}}async function Le(o,t){try{const e=je.parse(o.body),a=o.auth?.username||"system",n=new Date().toISOString(),r=`${M(e.system)}_${M(e.name)}_${ce(e.system+e.name+n)}`,i=e.query,c=null,g=new Set((e.variables||[]).map(b=>b.name)),h=B(e.query).filter(b=>!g.has(b));if(h.length>0){t.status(400).json({success:!1,error:`Query references undeclared variables: ${h.map(b=>`{{${b}}}`).join(", ")}`});return}const u={name:r,system:e.system,description:e.description||"",status:"active",category:"custom_query",unique_path:r,query:i,query_language:e.query_language,index_pattern:e.index_pattern,platformId:e.platformId,has_template:!!e.outputSchema,owner:a,createdAt:n,updatedAt:n,createdBy:a,updatedBy:a};c&&(u.aggs=c),e.outputSchema&&(u.index_template=e.outputSchema),e.variables&&e.variables.length>0&&(u.variables=e.variables,u.use_variable_substitution=!0);const k=await p.index({index:O,id:r,body:u,refresh:!0});se(),t.status(201).json({success:!0,apiDocId:k._id,uniquePath:r})}catch(e){if(e instanceof s.ZodError){t.status(400).json({success:!1,error:"Validation error",details:e.errors});return}console.error("[Tools] createApiService error:",e),t.status(500).json({success:!1,error:e.message})}}async function He(o,t){try{const{id:e}=o.params,a=o.auth?.username||"system",n=new Date().toISOString(),r=await p.get({index:w,id:e});if(!r.found){t.status(404).json({success:!1,error:"Tool not found"});return}const i=r._source,c=Math.random().toString(16).slice(2,8).padEnd(6,"0"),f=`${i.name.replace(/_[a-f0-9]{6}$/,"")}_${c}`;let h=i.service,u=i.endpoint;const k=i.service||i.apiDocId;if(k&&i.system)try{const v=await p.get({index:O,id:k});if(v.found){const I=v._source,d=`${M(i.system)}_${M(f)}_${ce(i.system+f+n)}`,_={...I,name:d,unique_path:d,owner:a,createdAt:n,updatedAt:n,createdBy:a,updatedBy:a};await p.index({index:O,id:d,body:_,refresh:!0}),h=d,u=`/stack_expert/${i.system}/:namespace/${d}`,se()}}catch{console.warn(`[cloneTool] .stkxp_api doc "${k}" not found, skipping API doc clone`)}const{path:b,...x}=i,P={...x,name:f,service:h,endpoint:u,path:h!==i.service&&i.system?`/api/stack_expert/${i.system}/:namespace/${h}`:i.path,owner:a,createdAt:n,updatedAt:n,createdBy:a,updatedBy:a};h!==(i.service||i.apiDocId)&&(P.apiDocId=h);const T=await p.index({index:w,body:P,refresh:!0});U(),t.status(201).json({success:!0,tool:{id:T._id,...P}})}catch(e){if(e.meta?.statusCode===404){t.status(404).json({success:!1,error:"Tool not found"});return}console.error("Error cloning tool:",e),t.status(500).json({success:!1,error:"Failed to clone tool",message:e.message})}}const ct=[{method:"get",path:"/api/stack_expert/settings/tools",handler:Ie,validate:{query:ke},openapi:{summary:"List tools for the caller",description:"Returns tools from `.stkxp_tools`. `search` runs a hybrid lexical + semantic query (semantic_text field `search_semantic`) alongside filters by type/system/owner/tags/enabled.",tags:["tools"]}},{method:"get",path:"/api/stack_expert/settings/tools/api-query",handler:Ne},{method:"get",path:"/api/stack_expert/settings/tools/tags",handler:Ae},{method:"get",path:"/api/stack_expert/settings/tools/:id",handler:Re},{method:"post",path:"/api/stack_expert/settings/tools/:id/clone",handler:He},{method:"post",path:"/api/stack_expert/settings/tools",handler:qe,validate:{body:ne}},{method:"get",path:"/api/stack_expert/settings/api-services/systems",handler:Fe},{method:"get",path:"/api/stack_expert/settings/api-services/:id",handler:Me},{method:"post",path:"/api/stack_expert/settings/api-services",handler:Le},{method:"post",path:"/api/stack_expert/settings/tools/migrate",handler:Ce},{method:"post",path:"/api/stack_expert/settings/tools/test-query",handler:Ue},{method:"post",path:"/api/stack_expert/settings/tools/test-external",handler:Be},{method:"post",path:"/api/stack_expert/settings/tools/generate-schemas",handler:Ve},{method:"post",path:"/api/stack_expert/settings/tools/generate-external-schemas",handler:Je},{method:"put",path:"/api/stack_expert/settings/tools/:id",handler:Ee,validate:{body:le}},{method:"delete",path:"/api/stack_expert/settings/tools/:id",handler:$e},{method:"patch",path:"/api/stack_expert/settings/tools/:id/status",handler:Oe}];export{Z as applyDslVariables,oe as applyEsqlVariables,ae as applyUrlVariables,B as detectQueryVariables,xe as encodeVariableForDsl,ve as encodeVariableForEsql,Te as encodeVariableForUrl,F as mergeVariablesIntoInputSchema,ct as routes};
@@ -0,0 +1 @@
1
+ import p from"express";const R=process.env.WHISPER_URL||"http://127.0.0.1:3742",g=process.env.WHISPER_API_KEY||"",b=Number(process.env.WHISPER_MAX_UPLOAD_BYTES||26214400),E=Number(process.env.WHISPER_TIMEOUT_MS||6e5),m=p.Router();m.post("/transcribe",p.raw({type:()=>!0,limit:b}),async(t,n)=>{try{const e=t.body;if(!e||!Buffer.isBuffer(e)||e.length===0)return n.status(400).json({success:!1,message:"Empty or missing audio body"});const r=typeof t.query.quality=="string"?t.query.quality:"",i=typeof t.query.language=="string"?t.query.language:"",s=t.headers["content-type"]||"audio/webm",d=String(s).includes("ogg")?"ogg":String(s).includes("wav")?"wav":String(s).includes("mp4")||String(s).includes("m4a")?"m4a":String(s).includes("mpeg")||String(s).includes("mp3")?"mp3":"webm",o=new URLSearchParams;r&&o.set("quality",r),i&&o.set("language",i);const y=`${R}/transcribe${o.toString()?`?${o.toString()}`:""}`,u=new FormData;u.append("audio",new Blob([e],{type:String(s)}),`audio.${d}`);const c=new AbortController,f=setTimeout(()=>c.abort(),E);let a;try{a=await fetch(y,{method:"POST",headers:g?{"X-API-Key":g}:void 0,body:u,signal:c.signal})}finally{clearTimeout(f)}const l=await a.text();if(!a.ok)return n.status(a.status).json({success:!1,message:"Transcription service error",detail:l});const S=JSON.parse(l);return n.json({success:!0,...S})}catch(e){const r=e?.name==="AbortError";return console.error("[transcribe] proxy error:",e?.message||e),n.status(r?504:502).json({success:!1,message:r?"Transcription timed out":"Failed to reach transcription service"})}});var I=m;export{I as default};
@@ -0,0 +1 @@
1
+ import{createTrigger as c,getTrigger as i,listTriggers as d,updateTrigger as l,deleteTrigger as p,updateTriggerStatus as h,setTriggerTarget as y,setTriggerReplyChannel as m,rotateReplyHmacSecret as f,setTriggerStreaming as j,recordTriggerExecution as T,ensureIndex as b}from"../core/services/trigger-service";import{driverManager as w}from"../core/services/asyncapi-drivers/driver-manager";b().catch(s=>{console.error("[Triggers] Failed to initialize index:",s)});function u(s,e){w.reconcileTrigger(s).then(r=>{r.ok?r.action!=="noop"&&console.log(`[Triggers API] reconcile after ${e} on ${s}: ${r.action}`):console.warn(`[Triggers API] reconcile after ${e} on ${s} failed: ${r.error}`)}).catch(r=>{console.error(`[Triggers API] reconcile after ${e} on ${s} threw:`,r)})}const $=[{path:"/api/triggers",method:"get",handler:async(s,e)=>{try{const r=s.auth,{type:t,enabled:n,owner:o}=s.query,a={};t&&(a.type=t),n!==void 0&&(a.enabled=n==="true"),r.roles?.includes("superuser")?o&&(a.owner=o):a.owner=r.username;const g=await d(a);return e.json({success:!0,count:g.length,triggers:g})}catch(r){return console.error("[Triggers API] List triggers error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id",method:"get",handler:async(s,e)=>{try{const{id:r}=s.params;if(!r)return e.status(400).json({error:"Bad request: Trigger ID is required"});const t=await i(r);return t?e.json({success:!0,trigger:t}):e.status(404).json({error:"Not found: Trigger not found",id:r})}catch(r){return console.error("[Triggers API] Get trigger error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers",method:"post",handler:async(s,e)=>{try{const r=s.auth,t=s.body;if(!t.id||!t.name||!t.type||!t.target)return e.status(400).json({error:"Bad request: id, name, type, and target are required"});if(t.type==="cron"&&!t.schedule)return e.status(400).json({error:"Bad request: schedule is required for cron triggers"});t.owner=r.username;const n=await c(t);return u(n,"create"),e.status(201).json({success:!0,id:n,message:"Trigger created successfully"})}catch(r){return console.error("[Triggers API] Create trigger error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id",method:"put",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params,n=s.body;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});const o=await i(t);if(!o)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(o.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to update this trigger"});delete n.owner,delete n.createdAt,delete n.updatedAt,delete n.runCount,delete n.lastRun,await l(t,n),u(t,"update");const a=await i(t);return e.json({success:!0,trigger:a,message:"Trigger updated successfully"})}catch(r){return console.error("[Triggers API] Update trigger error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/status",method:"patch",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params,{enabled:n}=s.body;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});if(typeof n!="boolean")return e.status(400).json({error:"Bad request: enabled must be a boolean"});const o=await i(t);if(!o)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(o.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to update this trigger"});await h(t,n),u(t,`status:${n?"enabled":"disabled"}`);const a=await i(t);return e.json({success:!0,trigger:a,message:`Trigger ${n?"enabled":"disabled"} successfully`})}catch(r){return console.error("[Triggers API] Update trigger status error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id",method:"delete",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});const n=await i(t);return n?n.owner!==r.username&&!r.roles?.includes("superuser")?e.status(403).json({error:"Forbidden: You don't have permission to delete this trigger"}):(await p(t),u(t,"delete"),e.json({success:!0,id:t,message:"Trigger deleted successfully"})):e.status(404).json({error:"Not found: Trigger not found",id:t})}catch(r){return console.error("[Triggers API] Delete trigger error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/target",method:"patch",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params,{targetTeamId:n}=s.body??{};if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});if(n!==null&&(typeof n!="string"||n.trim()===""))return e.status(400).json({error:"Bad request: targetTeamId must be a non-empty string or null"});const o=await i(t);if(!o)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(o.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to update this trigger"});if(o.type!=="webhook")return e.status(400).json({error:"Bad request: targetTeamId only applies to webhook triggers",type:o.type});await y(t,n??null),u(t,"set-target");const a=await i(t);return e.json({success:!0,trigger:a})}catch(r){return console.error("[Triggers API] Set trigger target error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/reply-channel",method:"patch",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params,{replyChannel:n}=s.body??{};if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});if(n!==null&&(typeof n!="string"||n.trim()===""))return e.status(400).json({error:"Bad request: replyChannel must be a non-empty string or null"});const o=await i(t);if(!o)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(o.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to update this trigger"});if(o.type!=="webhook")return e.status(400).json({error:"Bad request: replyChannel only applies to webhook triggers",type:o.type});await m(t,n??null),u(t,"set-reply-channel");const a=await i(t);return e.json({success:!0,trigger:a})}catch(r){return console.error("[Triggers API] Set trigger reply channel error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/reply-secret",method:"get",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});const n=await i(t);return n?n.owner!==r.username&&!r.roles?.includes("superuser")?e.status(403).json({error:"Forbidden: You don't have permission to view this trigger's secret"}):n.replyHmacSecret?(console.log(`[Triggers API] reply-secret revealed for ${t} by ${r.username}`),e.json({success:!0,replyHmacSecret:n.replyHmacSecret,replyChannel:n.replyChannel??null})):e.status(404).json({error:"Not found: This trigger has no reply HMAC secret yet (set a reply channel first)"}):e.status(404).json({error:"Not found: Trigger not found",id:t})}catch(r){return console.error("[Triggers API] Get reply secret error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/reply-secret/rotate",method:"post",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});const n=await i(t);if(!n)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(n.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to rotate this trigger's secret"});const o=await f(t);return console.log(`[Triggers API] reply-secret rotated for ${t} by ${r.username}`),e.json({success:!0,replyHmacSecret:o})}catch(r){return console.error("[Triggers API] Rotate reply secret error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/streaming",method:"patch",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params,{enabled:n,batchMs:o}=s.body??{};if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});if(typeof n!="boolean")return e.status(400).json({error:"Bad request: `enabled` must be a boolean"});if(o!==void 0&&(typeof o!="number"||o<0||o>5e3))return e.status(400).json({error:"Bad request: `batchMs` must be a number between 0 and 5000"});const a=await i(t);if(!a)return e.status(404).json({error:"Not found: Trigger not found",id:t});if(a.owner!==r.username&&!r.roles?.includes("superuser"))return e.status(403).json({error:"Forbidden: You don't have permission to update this trigger"});if(a.type!=="webhook")return e.status(400).json({error:"Bad request: streaming only applies to webhook triggers",type:a.type});if(n&&(!a.replyChannel||!a.replyHmacSecret))return e.status(400).json({error:"Bad request: streaming requires a reply channel + HMAC secret to be set first",hint:"Wire the Reply channel column for this subscriber, then enable streaming"});await j(t,n,o),u(t,"set-streaming");const g=await i(t);return e.json({success:!0,trigger:g})}catch(r){return console.error("[Triggers API] Set trigger streaming error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}},{path:"/api/triggers/:id/test",method:"post",handler:async(s,e)=>{try{const r=s.auth,{id:t}=s.params;if(!t)return e.status(400).json({error:"Bad request: Trigger ID is required"});const n=await i(t);return n?n.owner!==r.username&&!r.roles?.includes("superuser")?e.status(403).json({error:"Forbidden: You don't have permission to test this trigger"}):(await T(t),e.json({success:!0,message:"Trigger test executed successfully",note:"Graph execution not yet implemented - execution recorded only"})):e.status(404).json({error:"Not found: Trigger not found",id:t})}catch(r){return console.error("[Triggers API] Test trigger error:",r),e.status(500).json({error:"Internal server error",message:r.message})}}}];export{$ as routes};
@@ -0,0 +1 @@
1
+ import{Client as c}from"@elastic/elasticsearch";import{z as e}from"zod";import{listVersions as a}from"../core/services/version-snapshot-service";import{getAuthUsername as u}from"../core/utils/ownership";const m=process.env.ELASTICSEARCH_HOST||"https://51.159.174.230:9205",d=new c({node:m,auth:{username:process.env.ELASTICSEARCH_USER||"elastic",password:process.env.ELASTICSEARCH_PASSWORD||""},tls:{rejectUnauthorized:!1}}),l={team:".stkxp_teams",assistant:".stkxp_assistants",graph:".stkxp_graphs",routing_rule:".stkxp_llm_routing_rules"};async function g(s,n){try{const t=s.params.entityType,r=s.params.entityId,o=await a(t,r);n.status(200).json({success:!0,versions:o})}catch(t){n.status(500).json({success:!1,error:"Failed to list versions",message:t.message})}}async function f(s,n){try{const t=s.params.entityType,r=s.params.entityId,o=Number(s.params.version),i=(await a(t,r)).find(y=>y.version===o);if(!i)return n.status(404).json({success:!1,error:`Version ${o} not found for ${t}/${r}`});const p=u(s)||"system";await d.update({index:l[t],id:r,body:{doc:i.payload},refresh:"wait_for"}),console.log(`[Versions API] ${p} restored ${t}/${r} to version ${o}`),n.status(200).json({success:!0,restored:!0})}catch(t){n.status(500).json({success:!1,error:"Failed to restore version",message:t.message})}}const x=[{path:"/api/versions/:entityType/:entityId",method:"get",handler:g,validate:{params:e.object({entityType:e.enum(["team","assistant","graph","routing_rule"]),entityId:e.string().min(1)})}},{path:"/api/versions/:entityType/:entityId/:version/restore",method:"post",handler:f,validate:{params:e.object({entityType:e.enum(["team","assistant","graph","routing_rule"]),entityId:e.string().min(1),version:e.string().regex(/^\d+$/)})}}];export{g as listVersionsHandler,f as restoreVersionHandler,x as routes};
@@ -0,0 +1 @@
1
+ import{z as S}from"zod";import{randomUUID as w,timingSafeEqual as T}from"crypto";import{getTeamWebhookConfig as v}from"../core/services/teams-service";import{createChat as C}from"../core/services/chats-service";import{createChatRun as _}from"../core/services/chat-runs-service";import{logWebhookCall as A,updateWebhookCall as l,sanitiseHeaders as N,hashPayload as D}from"../core/services/webhook-calls-service";import{runTeamHeadless as W}from"../core/services/team-runner-headless";function $(t){const e={};t.teamId&&(e.teamId=t.teamId),t.threadId&&(e.threadId=t.threadId),t.chatId&&(e.chatId=t.chatId),t.name&&(e.name=t.name);const n=(t.assistants??[]).map(a=>({id:a?.id,name:a?.name})).filter(a=>a.id||a.name);return n.length>0&&(e.assistants=n),e}function O(t,e){if(!t||typeof t!="object"||Array.isArray(t)||Object.keys(e).length===0)return t;const n=t,a=n.teamContext&&typeof n.teamContext=="object"&&!Array.isArray(n.teamContext)?n.teamContext:{};return{...n,teamContext:{...e,...a}}}function P(t,e){const n=Buffer.from(t,"utf8"),a=Buffer.from(e,"utf8");return n.length!==a.length?!1:T(n,a)}async function M(t,e){const n=Date.now(),{teamId:a}=t.params,m=t.headers["x-stkxp-webhook-token"]??"",d=t.body??{},h=new Date().toISOString(),u=t.ip??t.socket?.remoteAddress??null,r=w();await A({webhookCallId:r,receivedAt:h,teamId:a,owner:null,sourceIp:u,status:"pending",payload:d,payloadHash:D(d),headers:N(t.headers)});try{const o=await v(a);if(!o||!o.webhookEnabled||!o.webhookToken)return await l(r,{status:"rejected_team_disabled",rejectionReason:o?"webhook_disabled":"team_not_found",durationMs:Date.now()-n}),e.status(401).json({success:!1,error:"Invalid webhook credentials"});if(!m||!P(m,o.webhookToken))return await l(r,{owner:o.owner??null,status:"rejected_token",rejectionReason:m?"token_mismatch":"token_missing",durationMs:Date.now()-n}),e.status(401).json({success:!1,error:"Invalid webhook credentials"});if(!o.owner)return console.error(`[Webhooks] Team ${a} has no owner \u2014 refusing run`),await l(r,{status:"failed",error:"Team owner not configured",durationMs:Date.now()-n}),e.status(500).json({success:!1,error:"Team owner not configured"});const s=w(),i=w(),b=new Date().toISOString(),j=$({teamId:a,threadId:i,chatId:i,name:o.name,assistants:o.assistants}),y=O(d,j),c=U(d),I=typeof c.ruleName=="string"&&c.ruleName.trim()||typeof c.message=="string"&&c.message.trim().slice(0,60)||typeof c.severity=="string"&&`${c.severity} alert`||"Event",g={};for(const f of["ruleId","alertId","hostName"]){const p=c[f];typeof p=="string"&&p&&(g[f]=p)}await C({id:i,title:`${o.name??a} \xB7 ${I}`,teamId:a,teamName:o.name??a,status:"draft",messages:[],assistants:[],metadata:{source:"webhook",webhookCallId:r,webhookSummary:c,...Object.keys(g).length>0?{correlationKeys:g}:{}},username:o.owner,createdAt:b,updatedAt:b}),await _(s,i,o.owner,{teamId:a,teamName:o.name??a,assistantId:"__webhook_pending__",assistantName:`${I} (running\u2026)`,graphId:o.graphId,userMessage:JSON.stringify(y).slice(0,2e3),metadata:{webhookCallId:r,webhookSourceIp:u}});const x=Date.now()-n;await l(r,{owner:o.owner,status:"accepted",runId:s,chatId:i,durationMs:x}),console.log(`[Webhooks] Accepted call ${r} for team ${a} \u2192 runId=${s} chatId=${i} (${x}ms)`);const k=parseInt(String(t.headers["x-stkxp-webhook-depth"]??"0"),10),R=Number.isFinite(k)&&k>=0?k:0;return setImmediate(()=>{W({teamId:a,runId:s,chatId:i,webhookCallId:r,payload:y,depth:R,channel:"webhook"}).catch(f=>{console.error(`[Webhooks] Unexpected throw from runTeamHeadless (runId=${s}):`,f)})}),e.status(202).json({success:!0,runId:s,chatId:i,teamId:a,webhookCallId:r,message:"Accepted \u2014 team graph executing in the background."})}catch(o){return console.error("[Webhooks] Failed to handle webhook call:",o),await l(r,{status:"failed",error:String(o?.message??o).slice(0,1e3),durationMs:Date.now()-n}),e.status(500).json({success:!1,error:"Failed to handle webhook",message:o?.message})}}function U(t){if(!t||typeof t!="object")return{};const e=t,n={},a=e.rule?.id??e.ruleId??e.rule_id??e.alert?.type;a&&(n.ruleId=String(a));const m=e.rule?.name??e.ruleName??e.rule_name;m&&(n.ruleName=String(m));const d=e.alert?.id??e.alertId??e.alert_id;d&&(n.alertId=String(d));const h=e.alert?.uuid??e.alertUuid;h&&(n.alertUuid=String(h));const u=e.host?.name??e.host?.hostname??e.hostName??e.hostname??e.context?.group;u&&(n.hostName=String(u));const r=e.params?.index;r&&(n.indexPattern=Array.isArray(r)?r.join(","):String(r));const o=e.context?.message??e.message??e.context?.title??e.title;o&&(n.message=String(o).slice(0,500));const s=e.severity??e.alert?.severity??e.rule?.severity;return s&&(n.severity=String(s)),e.stkxp&&typeof e.stkxp=="object"&&(n.stkxp=e.stkxp),n}const B=S.object({teamId:S.string().min(1)}),G=[{method:"post",path:"/api/webhooks/team/:teamId",handler:M,validate:{params:B},openapi:{summary:"Trigger a team run from an inbound webhook",description:"Public endpoint authenticated by the per-team `X-Stkxp-Webhook-Token` header (not JWT). Accepts an arbitrary JSON body, creates a draft chat that captures the payload, queues a run, and returns 202 immediately. The team graph executes asynchronously in the background.",tags:["webhooks"],security:"none",audience:"public"}}];export{$ as buildTeamContext,O as enrichPayloadWithTeamContext,G as routes};
@@ -0,0 +1,4 @@
1
+ import{Client as x}from"@elastic/elasticsearch";import S from"dotenv";S.config();const h=process.env.ES_NODE||"https://localhost:9200",$=process.env.ES_USERNAME||"elastic",b=process.env.ES_PASSWORD||"",r=".stkxp_tools";function f(o){if(o.length!==5)return!1;const e=/[a-zA-Z]/.test(o),a=/[0-9]/.test(o);return e&&a}function m(o){const e=o.split("_"),a=e[e.length-1];return(f(a)?e.slice(0,-1):e).map(n=>n.charAt(0).toUpperCase()+n.slice(1).toLowerCase()).join(" ")}async function y(){const o=new x({node:h,auth:{username:$,password:b},tls:{rejectUnauthorized:!1}});try{console.log(`\u{1F50D} Connecting to Elasticsearch at ${h}...`),await o.indices.exists({index:r})||(console.error(`\u274C Index ${r} does not exist!`),process.exit(1)),console.log("\u2705 Connected to Elasticsearch"),console.log(`\u{1F4CB} Fetching all tools from ${r}...`);const s=(await o.search({index:r,body:{query:{match_all:{}},size:1e4}})).hits.hits;if(console.log(`\u{1F4CA} Found ${s.length} tools to process`),s.length===0){console.log("\u2705 No tools to update");return}let n=0,i=0,c=0;for(const d of s){const E=d._id,t=d._source,p=t.label!==void 0,g=t.key!==void 0;p&&g&&(console.log(`\u23ED\uFE0F Skipping ${t.name} - label and key already exist`),i++);const u=m(t.name);try{const l={};p||(l.label=u),g||(l.key=t.name),await o.update({index:r,id:E,body:{doc:l}}),console.log(`\u2705 Updated: ${t.name} -> label: "${u}" | key: "${t.name}"`),n++}catch(l){console.error(`\u274C Error updating ${t.name}:`,l),c++}}console.log(`
2
+ \u{1F4C8} Migration Summary:`),console.log(` \u2705 Updated: ${n}`),console.log(` \u23ED\uFE0F Skipped: ${i}`),console.log(` \u274C Errors: ${c}`),console.log(` \u{1F4CA} Total: ${s.length}`),c===0?console.log(`
3
+ \u{1F389} Migration completed successfully!`):(console.log(`
4
+ \u26A0\uFE0F Migration completed with errors`),process.exit(1))}catch(e){console.error("\u274C Fatal error during migration:",e),process.exit(1)}finally{await o.close()}}y().catch(o=>{console.error("\u274C Unhandled error:",o),process.exit(1)});export{y as addLabelToTools,f as isValidKey,m as nameToLabel};
@@ -0,0 +1,10 @@
1
+ import{Client as _}from"@elastic/elasticsearch";const u=process.env.ELASTICSEARCH_HOST||"https://51.159.174.230:9205",m=process.env.ELASTICSEARCH_USER||"elastic",S=process.env.ELASTICSEARCH_PASSWORD||"",i=".stkxp_assistants",f=".stkxp_mcp_servers",r=new _({node:u,auth:{username:m,password:S},tls:{rejectUnauthorized:!1},requestTimeout:6e4,maxRetries:3}),y={stack_expert:"clusters",clusters:"clusters",mysql:"mysql",postgresql:"postgresql",apache:"apache"};async function h(o){const t=y[o?.toLowerCase()]||o;try{return(await r.search({index:f,body:{query:{term:{enabled:!0}},size:100}})).hits.hits.map(s=>({id:s._id,...s._source})).find(s=>s.packageName?.toLowerCase()===t?.toLowerCase()||s.name.toLowerCase().includes(t?.toLowerCase()))||null}catch(n){return console.error(`Error finding MCP server for package "${o}":`,n),null}}async function E(o=!0){console.log(`
2
+ ========================================`),console.log("MCP TOOLS MIGRATION SCRIPT"),console.log(`========================================
3
+ `),console.log(`Mode: ${o?"DRY RUN (no changes)":"LIVE MIGRATION"}
4
+ `);try{const n=(await r.search({index:i,body:{query:{match_all:{}},size:1e3}})).hits.hits.map(e=>({id:e._id,...e._source}));console.log(`Found ${n.length} assistants
5
+ `);let l=0,c=0,s=0;for(const e of n){const g=e.tools_policy?.packageName,d=e.mcp_servers_policy?.servers?.length>0;if(!g||d){console.log(`\u2713 SKIP: ${e.name} (already migrated or no legacy config)`),c++;continue}console.log(`
6
+ \u2192 MIGRATING: ${e.name}`),console.log(` Package: ${e.tools_policy.packageName}`);const a=await h(e.tools_policy.packageName);if(!a){console.log(` \u2717 FAILED: No MCP server found for package "${e.tools_policy.packageName}"`),s++;continue}console.log(` \u2713 Found MCP server: ${a.name} (${a.id})`);const p={...e,mcp_servers_policy:{servers:[{id:a.id,name:a.name,enabled:!0,excluded_tools:[]}],auto_tool_calling:e.tools_policy?.auto_tool_calling||"dynamic",conflict_resolution:"first"},tools_policy:{custom_tools:e.tools_policy?.custom_tools||void 0,packageName:void 0,tools_raw:void 0,allowed_tools:void 0,preferred_tools:void 0,_deprecated:!0,_migrated_at:new Date().toISOString()}};o?console.log(` \u2713 WOULD MIGRATE: ${e.name}`):(await r.update({index:i,id:e.id,body:{doc:p},refresh:"wait_for"}),console.log(` \u2713 MIGRATED: ${e.name}`)),l++}console.log(`
7
+ ========================================`),console.log("MIGRATION SUMMARY"),console.log("========================================"),console.log(`Total assistants: ${n.length}`),console.log(`Migrated: ${l}`),console.log(`Skipped (already migrated): ${c}`),console.log(`Failed (no matching server): ${s}`),console.log(`========================================
8
+ `),o?(console.log("\u{1F538} DRY RUN COMPLETE - No changes made"),console.log(`\u{1F538} Run with --live flag to apply changes
9
+ `)):console.log(`\u2705 LIVE MIGRATION COMPLETE
10
+ `)}catch(t){console.error("Migration failed:",t.message),process.exit(1)}}const C=process.argv.includes("--live");E(!C).then(()=>process.exit(0)).catch(o=>{console.error("Script error:",o),process.exit(1)});
@@ -0,0 +1,8 @@
1
+ import{Client as C}from"@elastic/elasticsearch";import{config as R}from"../core/config";import{createChatRun as f,completeChatRun as w,getChatRunByRunId as k}from"../core/services/chat-runs-service";import{calculateCost as _}from"../core/services/llm-pricing-service";const c=new C(R.elasticsearch),I=".stkxp_chats",M=".stkxp_chat_tools";async function y(t){for(const r of t.messages){if(r.id&&r.id.startsWith("run-"))return r.id.replace("run-","");if(r.toolsRunId)return r.toolsRunId}return null}async function $(t,r){try{const o=await y(t);if(!o)return console.warn(`No runId found for chat ${t.id}`),!1;if(await k(o))return console.log(`Run ${o} already exists, skipping`),!1;const a=t.messages[0]?.timestamp||t.createdAt,i=t.messages[t.messages.length-1]?.timestamp,l=new Date(a).getTime(),s=(i?new Date(i).getTime():l)-l;let n="success";i?r?.tools?.some(e=>e.status==="error"||e.status==="failed")&&(n="error"):n="running";const u=t.metadata?.tokenUsage?.details?.map(e=>({provider:e.provider||"unknown",model:e.model||"unknown",inputTokens:e.inputTokens||0,outputTokens:e.outputTokens||0,totalTokens:e.totalTokens||0}))||[];let d=0;for(const e of u){const x=await _(e.provider,e.model,e.inputTokens,e.outputTokens);d+=x}const h=r?.tools?.map(e=>e.name)||[],T=Array.from(new Set(h));return await f(o,t.id||o,t.username,t.metadata),await w(o,n,{endTime:i,duration:s,llmUsage:u,totalTokens:t.metadata?.tokenUsage?.totalTokens||0,toolsUsed:T,toolCallsCount:r?.tools?.length||0,messageCount:t.messages.length,estimatedCost:d}),console.log(`\u2713 Migrated run ${o} (${n})`),!0}catch(o){return console.error(`Error migrating chat ${t.id}:`,o),!1}}async function b(){console.log("="+"=".repeat(69)),console.log("Chat Runs Migration"),console.log("="+"=".repeat(69));try{if(console.log(`
2
+ Initializing .stkxp_chat_runs index...`),await c.indices.exists({index:".stkxp_chat_runs"}))console.log("Index already exists");else{const s="test-init-run";await f(s,"test-chat","system",{}),await c.deleteByQuery({index:".stkxp_chat_runs",body:{query:{term:{runId:s}}},refresh:!0}),console.log("Index created successfully")}console.log(`
3
+ Fetching all chats...`);const o=(await c.search({index:I,body:{query:{match_all:{}},size:1e3,sort:[{createdAt:"desc"}]}})).hits.hits.map(s=>({id:s._id,...s._source}));console.log(`Found ${o.length} chats`),console.log("Fetching all chat tools records...");const m=await c.search({index:M,body:{query:{match_all:{}},size:1e3}}),a=new Map;m.hits.hits.forEach(s=>{const n={id:s._id,...s._source};a.set(n.runId,n),a.set(n.chatId,n)}),console.log(`Found ${a.size} chat tools records`),console.log(`
4
+ Migrating chats to runs...`);let g=0,i=0,l=0;for(const s of o){const n=await y(s),u=n?a.get(n):a.get(s.id||"");await $(s,u)?g++:await k(n||"")?i++:l++}console.log(`
5
+ `+"=".repeat(70)),console.log("Migration Summary"),console.log("=".repeat(70)),console.log(`Total chats: ${o.length}`),console.log(`Migrated: ${g}`),console.log(`Skipped (already exists): ${i}`),console.log(`Errors: ${l}`),console.log("=".repeat(70));const p=await c.count({index:".stkxp_chat_runs"});console.log(`
6
+ Total runs in .stkxp_chat_runs: ${p.count}`)}catch(t){throw console.error("Migration failed:",t),t}}b().then(()=>{console.log(`
7
+ Migration completed successfully!`),process.exit(0)}).catch(t=>{console.error(`
8
+ Migration failed:`,t),process.exit(1)});
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ts-node
2
+ import{Client as i}from"@elastic/elasticsearch";const a=process.env.ELASTICSEARCH_HOST||"https://51.159.174.230:9205",d=process.env.ELASTICSEARCH_USER||"elastic",p=process.env.ELASTICSEARCH_PASSWORD||"",o=".stkxp_mcp_servers",n=new i({node:a,auth:{username:d,password:p},tls:{rejectUnauthorized:!1},requestTimeout:6e4,maxRetries:3});async function u(){console.log(`=== MCP Protocol Field Migration ===
3
+ `);try{if(!await n.indices.exists({index:o})){console.log(`Index ${o} does not exist. No migration needed.`);return}const r=(await n.count({index:o,body:{query:{bool:{must_not:{exists:{field:"protocol"}}}}}})).count;if(r===0){console.log("\u2713 All MCP servers already have the protocol field. No migration needed.");return}console.log(`Found ${r} MCP server(s) without protocol field.`),console.log(`Updating documents...
4
+ `);const l=await n.updateByQuery({index:o,refresh:!0,body:{script:{source:'if (ctx._source.protocol == null) { ctx._source.protocol = "http" }',lang:"painless"},query:{bool:{must_not:{exists:{field:"protocol"}}}}}});console.log("\u2713 Migration completed successfully!"),console.log(` - Documents updated: ${l.updated}`),console.log(` - Time taken: ${l.took}ms
5
+ `);const s=await n.search({index:o,body:{query:{match_all:{}},size:100,_source:["name","protocol"]}});console.log("=== Verification ==="),console.log(`Total MCP servers: ${s.hits.hits.length}`);const c=s.hits.hits.filter(t=>t._source.protocol);console.log(`Servers with protocol field: ${c.length}`),c.length===s.hits.hits.length?console.log(`\u2713 All servers now have the protocol field!
6
+ `):console.warn(`\u26A0 Warning: Some servers still missing protocol field
7
+ `),console.log("Sample of updated servers:"),s.hits.hits.slice(0,5).forEach(t=>{console.log(` - ${t._source.name}: protocol=${t._source.protocol||"MISSING"}`)})}catch(e){console.error("\u2717 Migration failed:",e.message),process.exit(1)}}u().then(()=>{console.log(`
8
+ === Migration complete ===`),process.exit(0)}).catch(e=>{console.error("Fatal error:",e),process.exit(1)});
@@ -0,0 +1,15 @@
1
+ import{Client as S}from"@elastic/elasticsearch";import*as $ from"dotenv";$.config();const w=process.env.ELASTICSEARCH_HOST||"https://51.159.174.230:9205",x=process.env.ELASTICSEARCH_USER||"elastic",v=process.env.ELASTICSEARCH_PASSWORD||"",c=".stkxp_mcp_servers",l=".stkxp_platforms",r=new S({node:w,auth:{username:x,password:v},tls:{rejectUnauthorized:!1},requestTimeout:6e4,maxRetries:3});function E(e,i){const d=new Date().toISOString();return{id:i,name:e.name,description:e.description||"",type:"MCPServer",managedType:e.owner==="stkxp"?"managed":"self-hosted",owner:e.owner,enabled:e.enabled??!0,created:e.createdAt??e.created??d,updated:d,config:{url:e.url,protocol:e.protocol||"http",serverType:e.type||"remote",authKey:e.authKey,packageName:e.packageName,namespace:e.namespace,headers:e.headers||{},queryParams:e.queryParams||{}}}}async function C(e){const i=[],d=await r.search({index:e,scroll:"2m",size:100,body:{query:{match_all:{}}}});let t=d._scroll_id,a=d.hits.hits;for(i.push(...a.map(s=>({_id:s._id,_source:s._source})));a.length>0;){const s=await r.scroll({scroll_id:t,scroll:"2m"});t=s._scroll_id,a=s.hits.hits,i.push(...a.map(g=>({_id:g._id,_source:g._source})))}return t&&await r.clearScroll({scroll_id:t}).catch(()=>{}),i}async function A(){const e=process.argv.includes("--apply"),i=process.argv.includes("--verify");console.log(`
2
+ ${"=".repeat(60)}`),console.log(" MCP Servers \u2192 Platforms migration"),console.log(` Mode: ${i?"VERIFY":e?"APPLY":"DRY-RUN"}`),console.log(`${"=".repeat(60)}
3
+ `),await r.indices.exists({index:c})||(console.error(`\u274C Source index ${c} does not exist \u2014 nothing to migrate.`),process.exit(1));const t=(await r.count({index:c})).count;if(console.log(`\u{1F4E6} Source: ${c} \u2192 ${t} documents`),i){const n=(await r.count({index:l,body:{query:{term:{type:"MCPServer"}}}})).count;console.log(`\u2705 Already in ${l} as MCPServer: ${n}`);const o=t-n;o===0?console.log(`
4
+ \u2705 All ${t} documents migrated.`):console.warn(`
5
+ \u26A0\uFE0F ${o} documents not yet migrated (or source has grown).`),process.exit(0)}const a=await C(c);console.log(`\u{1F4D6} Loaded ${a.length} docs from ${c}
6
+ `);const s=a.map(({_id:n,_source:o})=>({esId:n,platform:E(o,n)}));console.log("Sample (first 3 transforms):"),s.slice(0,3).forEach(({esId:n,platform:o})=>{console.log(` [${n}] ${o.owner}/${o.name} \u2192 type=${o.type} serverType=${o.config.serverType} url=${o.config.url}`)}),e||(console.log(`
7
+ \u{1F50D} Dry-run complete \u2014 ${s.length} docs would be written to ${l}.`),console.log(` Run with --apply to execute, --verify to check post-migration counts.
8
+ `),process.exit(0)),console.log(`
9
+ \u2699\uFE0F Inserting ${s.length} docs into ${l}...`);const g=50;let m=0,y=0;for(let n=0;n<s.length;n+=g){const o=s.slice(n,n+g),_=o.flatMap(({esId:u,platform:p})=>[{index:{_index:l,_id:u}},p]),h=await r.bulk({operations:_,refresh:!1});if(h.errors){const u=h.items.filter(p=>p.index?.error);u.forEach(p=>{console.error(` \u274C [${p.index?._id}] ${JSON.stringify(p.index?.error)}`)}),y+=u.length,m+=o.length-u.length}else m+=o.length}await r.indices.refresh({index:l}),console.log(`
10
+ \u2705 Inserted: ${m} \u274C Errors: ${y}`);const f=(await r.count({index:l,body:{query:{term:{type:"MCPServer"}}}})).count;console.log(`
11
+ \u{1F4CA} Verification: ${f} MCPServer docs in ${l} (expected ${t})`),f>=t&&y===0?(console.log(`
12
+ \u2705 Migration successful.`),console.log(`
13
+ Next step: block writes on ${c}:`),console.log(` PUT ${c}/_settings { "index.blocks.write": true }`)):(console.warn(`
14
+ \u26A0\uFE0F Migration completed with issues. Review errors above before proceeding.`),process.exit(1))}A().catch(e=>{console.error(`
15
+ \u274C Fatal error:`,e),process.exit(1)});
@@ -0,0 +1,3 @@
1
+ import{Client as _}from"@elastic/elasticsearch";import{config as b}from"../core/config";import{WINDOW_TO_MS as w,listEnabledAlerts as A,patchAlertEvaluationFields as g}from"../core/services/alerts-service";const c=new _(b.elasticsearch),d=".stkxp_chat_runs",p=".stkxp_chat_tools";function f(t,e=[]){const r=[{term:{username:t.alert.owner}},{range:{startTime:{gte:t.windowStartIso,lte:t.windowEndIso}}},...e];return t.alert.filters?.assistantId&&r.push({term:{assistantId:t.alert.filters.assistantId}}),t.alert.filters?.teamId&&r.push({term:{teamId:t.alert.filters.teamId}}),{bool:{must:r}}}async function I(t){return(await c.count({index:d,body:{query:f(t,[{term:{status:"error"}}])}})).count}async function S(t){const[e,r]=await Promise.all([c.count({index:d,body:{query:f(t)}}),c.count({index:d,body:{query:f(t,[{term:{status:"error"}}])}})]);return e.count===0?0:r.count/e.count*100}async function v(t){const n=(await c.search({index:d,body:{query:f(t),size:0,aggs:{p95:{percentiles:{field:"duration",percents:[95]}}}}})).aggregations?.p95?.values||{},o=n["95.0"]??n[95]??0;return typeof o=="number"&&!Number.isNaN(o)?o:0}async function C(t){const r=(await c.search({index:d,body:{query:f(t),size:0,aggs:{total:{sum:{field:"estimatedCost"}}}}})).aggregations?.total?.value??0,n=w[t.alert.window],o=Math.max(n/(1440*60*1e3),1/24);return r/o}async function E(t){const e=[{term:{username:t.alert.owner}},{range:{createdAt:{gte:t.windowStartIso,lte:t.windowEndIso}}}],r=await c.search({index:p,body:{query:{bool:{must:e}},size:5e3,_source:["tools"]}});let n=0;for(const o of r.hits.hits){const s=Array.isArray(o._source.tools)?o._source.tools:[];for(const i of s)i?.error&&(t.alert.filters?.toolName&&i.name!==t.alert.filters.toolName||(n+=1))}return n}async function $(t){const e=[{term:{username:t.alert.owner}},{range:{createdAt:{gte:t.windowStartIso,lte:t.windowEndIso}}}],r=await c.search({index:p,body:{query:{bool:{must:e}},size:5e3,_source:["tools"]}});let n=0,o=0;for(const s of r.hits.hits){const i=Array.isArray(s._source.tools)?s._source.tools:[];for(const u of i)t.alert.filters?.toolName&&u.name!==t.alert.filters.toolName||(n+=1,u?.error&&(o+=1))}return n===0?0:o/n*100}async function N(t){switch(t.alert.metric){case"run_failure_count":return I(t);case"run_failure_rate":return S(t);case"tool_error_count":return E(t);case"tool_error_rate":return $(t);case"avg_run_duration_p95_ms":return v(t);case"total_cost_per_day_usd":return C(t);default:throw new Error(`Unknown metric: ${t.alert.metric}`)}}function R(t,e,r){switch(e){case"gt":return t>r;case"gte":return t>=r;case"lt":return t<r;case"lte":return t<=r}}function y(t,e){return t==="run_failure_rate"||t==="tool_error_rate"?`${e.toFixed(1)}%`:t==="avg_run_duration_p95_ms"?`${Math.round(e)} ms`:t==="total_cost_per_day_usd"?`$${e.toFixed(2)}/day`:String(Math.round(e))}const O={gt:">",gte:"\u2265",lt:"<",lte:"\u2264"};async function P(t,e,r){const n=t.notify?.webhook?.url;if(!n)return;const o=y(t.metric,r),s=y(t.metric,t.threshold),a=`${e==="firing"?"\u{1F6A8}":"\u2705"} *Alert ${e==="firing"?"FIRING":"RECOVERED"}*: ${t.name}
2
+ Metric: \`${t.metric}\` ${O[t.operator]} ${s} (window: ${t.window})
3
+ Current value: *${o}*`;try{const l=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:a,alertId:t.id,alertName:t.name,transition:e,metric:t.metric,operator:t.operator,threshold:t.threshold,window:t.window,value:r,filters:t.filters||{},timestamp:new Date().toISOString()})});l.ok||console.warn(`[alerts] webhook ${n} returned ${l.status} for alert ${t.id}`)}catch(l){console.warn(`[alerts] webhook dispatch failed for alert ${t.id}: ${l.message}`)}}async function T(t){const e=new Date,r=new Date(e.getTime()-w[t.window]),n={alert:t,windowStartIso:r.toISOString(),windowEndIso:e.toISOString()};try{const o=await N(n),s=R(o,t.operator,t.threshold),i=t.status,u=s?"firing":"ok";let a;i!=="firing"&&u==="firing"?a="firing":i==="firing"&&u==="ok"&&(a="recovered");const l={status:u,lastValue:o,lastEvaluatedAt:e.toISOString(),lastError:void 0};return a==="firing"&&(l.lastFiredAt=e.toISOString()),a==="recovered"&&(l.lastRecoveredAt=e.toISOString()),await g(t.id,l),a&&await P(t,a,o),{alertId:t.id,status:u,value:o,transition:a}}catch(o){const s=o?.message||String(o);return await g(t.id,{status:"error",lastEvaluatedAt:new Date().toISOString(),lastError:s.slice(0,500)}),console.error(`[alerts] evaluation failed for ${t.id}: ${s}`),{alertId:t.id,status:"error",value:NaN,error:s}}}function D(t,e){if(!t.enabled)return!1;if(!t.lastEvaluatedAt)return!0;const r=Date.parse(t.lastEvaluatedAt);return Number.isNaN(r)?!0:e-r>=w[t.window]}async function h(){const t=await A(),e=Date.now(),r=[];for(const n of t)D(n,e)&&r.push(await T(n));return r}let m=null;function z(t=6e4){if(m){console.warn("[alerts] scheduler already running");return}console.log(`[alerts] scheduler started \u2014 tick every ${t/1e3}s`),setTimeout(()=>{h().catch(e=>console.error("[alerts] initial evaluation failed:",e))},1e4),m=setInterval(()=>{h().catch(e=>console.error("[alerts] tick failed:",e))},t)}function j(){m&&(clearInterval(m),m=null,console.log("[alerts] scheduler stopped"))}export{T as evaluateAlert,h as evaluateAllDueAlerts,z as startAlertScheduler,j as stopAlertScheduler};
@@ -0,0 +1 @@
1
+ import{config as i}from"../core/config";import l from"jsonwebtoken";import{Client as c}from"@elastic/elasticsearch";import{provisionPlatform as d}from"./user-provisioning-service";import{initTrialMetadata as g}from"../core/services/plan-service";var y=i.jwtSecret,f=i.issuer;const $=function(r){try{return l.verify(r,y,{issuer:f})}catch(e){return console.error("JWT verification error:",e),null}},B=function(r,e,t){function s(){return r.res.status(403).json({message:"Error: Access Denied"})}if(e&&e.indexOf("Bearer ")==0){var n=e.split(" ")[1];l.verify(n,y,function(o,a){if(o==null&&a){var u=!0,p=a.iss==f;return u&&p?(r.auth=a,t(null,a)):(console.error("Role or issuer mismatch"),t(s(),null))}else return console.error("JWT verification failed:",o),t(s(),null)})}else return console.error("Authorization header is missing or malformed"),t(s(),null)},M=function(r,e,t,s){var n=l.sign({username:r,iss:f,roles:e,enabled:s},y);return n},O=function(r,e,t,s){return l.sign({username:r,iss:f,roles:e,enabled:!0,type:"apikey",jti:t,...s?{scopes:s}:{}},y)},h=async function(r){try{return await new c({...i.elasticsearch}).security.getUser({username:r})}catch(e){return e}},S=async function(r){try{const t=await new c({...i.elasticsearch}).security.getUser(),s=t.body??t;return Object.values(s).some(n=>n.email===r)}catch(e){return console.error("Error checking email existence:",e),!1}},_=async function(r,e,t,s){try{const n=new c({...i.elasticsearch}),o=[r];return await n.security.putUser({username:r,email:e,password:t,roles:o,enabled:!1,metadata:{emailToken:s}})}catch(n){return n}},z=async function(r){try{const e=new c({...i.elasticsearch}),t=await e.security.enableUser({username:r});try{await d(r)}catch(s){console.error(`[activateUser] Platform provisioning failed for ${r}:`,s)}try{const s=g(),o=(await e.security.getUser({username:r}))[r];await e.security.putUser({username:r,body:{...o,metadata:{...o?.metadata??{},...s}}}),console.log(`[activateUser] Trial plan initialised for ${r} (expires ${s.planExpiresAt})`)}catch(s){console.error(`[activateUser] Plan initialisation failed for ${r}:`,s)}return t}catch(e){return e}},G=async function(r,e){console.log("userClient config",{...i.elasticsearch,auth:{username:r,password:e}});try{const s=await new c({...i.elasticsearch,auth:{username:r,password:e}}).security.authenticate(),n=s?.body||s;return console.log("authenticate response authData:",n),{username:n.username,roles:n.roles||[],enabled:n.enabled!==!1,email:n.email,full_name:n.full_name,metadata:n.metadata||{}}}catch(t){return console.error("Authentication error authenticate:",t),null}},J=async function(r,e,t,s,n,o){try{const a=new c({...i.elasticsearch}),u={};return e!==void 0&&(u.email=e),t!==void 0&&(u.password=t),s!==void 0&&(u.roles=s),n!==void 0&&(u.enabled=n),o!==void 0&&(u.metadata=o),await a.security.putUser({username:r,...u})}catch(a){return console.error("Error updating user:",a),a}},L=async function(r){try{return await new c({...i.elasticsearch}).security.putRole({name:r,cluster:["all"],indices:[],run_as:[]})}catch(e){return console.error("Error initializing roles:",e),e}},W=async function(r){try{return await new c({...i.elasticsearch}).security.deleteUser({username:r}),!0}catch(e){return console.error("Error deleting user:",e),!1}},F=async function(r){try{const t=await new c({...i.elasticsearch}).security.getUser({username:r});return(t.body??t)[r]?.email??null}catch{return null}},K=async function(r){try{const t=await new c({...i.elasticsearch}).security.getUser(),s=t.body??t,n=Object.entries(s).find(([,o])=>o.email===r);return n?{username:n[0],userRecord:n[1]}:null}catch(e){return console.error("[getUserByEmail] Error:",e),null}},H=async function(r){try{const e=await h(r),t=e.body?.[r]||e[r];return t?t.metadata?.providers||null:(console.warn(`[getUserProviders] User not found: ${r}`),null)}catch(e){return console.error("Error getting user providers:",e),null}};export{z as activateUser,G as authenticate,W as deleteUser,K as getUserByEmail,F as getUserEmailByUsername,H as getUserProviders,L as initRole,S as isEmailExists,h as isUsernameExists,O as issueApiKey,M as issueToken,_ as registerUser,J as updateUser,$ as userToken,B as verifyToken};
@@ -0,0 +1 @@
1
+ import m from"stripe";import{Client as b}from"@elastic/elasticsearch";import{config as n}from"../core/config";const o=new m(n.stripeSecretKey,{apiVersion:"2024-06-20"}),l=new b(n.elasticsearch),d={basic:n.stripePrices?.basic||"",enterprise:n.stripePrices?.enterprise||"",premium:n.stripePrices?.premium||""};async function u(e){return(await l.security.getUser({username:e}))[e]??null}async function c(e,r){const t=await u(e);if(!t)throw new Error(`User ${e} not found`);await l.security.putUser({username:e,body:{...t,metadata:{...t.metadata??{},...r}}})}async function g(e){const r=await u(e),t=r?.metadata?.stripeCustomerId;if(t)return t;const s=await o.customers.create({email:r?.email||`${e}@stackexpert.local`,metadata:{username:e}});return await c(e,{stripeCustomerId:s.id}),s.id}async function P(e,r){const t=d[r];if(!t)throw new Error(`No Stripe price configured for plan: ${r}. Set STRIPE_PRICE_${r.toUpperCase()} env var.`);const s=await g(e);return(await o.checkout.sessions.create({customer:s,mode:"subscription",payment_method_types:["card"],currency:"eur",line_items:[{price:t,quantity:1}],success_url:"https://app.erretegia.com/account#billing?success=1",cancel_url:"https://app.erretegia.com/account#plan?cancelled=1",metadata:{username:e,plan:r},subscription_data:{metadata:{username:e,plan:r}}})).url}async function h(e){const t=(await u(e))?.metadata?.stripeCustomerId;if(!t)throw new Error("No Stripe customer found for this user");return(await o.billingPortal.sessions.create({customer:t,return_url:"https://app.erretegia.com/account#billing"})).url}async function k(e,r){n.stripeWebhookSecret||console.warn("[Stripe] No webhook secret configured \u2014 skipping signature verification");let t;try{t=n.stripeWebhookSecret?o.webhooks.constructEvent(e,r,n.stripeWebhookSecret):JSON.parse(e.toString())}catch(s){throw new Error(`Webhook signature verification failed: ${s.message}`)}switch(console.log(`[Stripe] Webhook event: ${t.type}`),t.type){case"checkout.session.completed":{const s=t.data.object,a=s.metadata?.username,i=s.metadata?.plan,p=s.subscription;if(!a||!i)break;await S(a,i,p,s.customer);break}case"invoice.payment_succeeded":{const s=t.data.object;if(!s.subscription)break;const a=await o.subscriptions.retrieve(s.subscription),i=a.metadata?.username;if(!i)break;const p=new Date(a.current_period_end*1e3).toISOString();await c(i,{planStatus:"active",planExpiresAt:p}),console.log(`[Stripe] Renewed plan for ${i} until ${p}`);break}case"invoice.payment_failed":{const s=t.data.object;if(!s.subscription)break;const i=(await o.subscriptions.retrieve(s.subscription)).metadata?.username;if(!i)break;await c(i,{planStatus:"past_due"}),console.warn(`[Stripe] Payment failed for ${i} \u2014 plan set to past_due`);break}case"customer.subscription.deleted":{const a=t.data.object.metadata?.username;if(!a)break;await c(a,{planStatus:"cancelled"}),console.log(`[Stripe] Subscription cancelled for ${a}`);break}default:break}}async function S(e,r,t,s){const a=await o.subscriptions.retrieve(t),i=new Date(a.current_period_end*1e3).toISOString();await c(e,{plan:r,planStatus:"active",planActivatedAt:new Date().toISOString(),planExpiresAt:i,stripeCustomerId:s,stripeSubscriptionId:t,stripePriceId:d[r]||""}),console.log(`[Stripe] Activated plan '${r}' for user '${e}' until ${i}`)}export{P as createCheckoutSession,h as createPortalSession,g as getOrCreateStripeCustomer,k as handleWebhookEvent};
@@ -0,0 +1,12 @@
1
+ import{createLLMInstance as s}from"../core/llm/providers";import{getOwnerDefaultLLMConfig as c}from"../core/services/default-model.service";async function u(e,n){try{const t=await c(n);if(!t)return console.warn(`[chat-title-generator] No usable LLM key for owner '${n??"(none)"}', using fallback title`),e.substring(0,50).trim();console.log(`[chat-title-generator] Using owner '${n}' model: ${t.provider}:${t.model}`);const i=s({provider:t.provider,model:t.model,apiKey:t.apiKey,baseURL:t.baseURL,temperature:.3,streaming:!1}),a=`Generate a concise, descriptive title (maximum 8 words) for a chat conversation that starts with this user question:
2
+
3
+ "${e}"
4
+
5
+ Requirements:
6
+ - Maximum 8 words
7
+ - Descriptive and specific
8
+ - Focus on the main topic or question
9
+ - No quotes or punctuation at the end
10
+ - Start with a capital letter
11
+
12
+ Return ONLY the title, nothing else.`,o=await i.invoke(a);let r=typeof o.content=="string"?o.content.trim():String(o.content).trim();return r=r.replace(/^["']|["']$/g,"").replace(/\.$/,"").substring(0,100),r.length<3?e.substring(0,50).trim():r}catch(t){return console.error("Error generating chat title:",t),e.substring(0,50).trim()}}export{u as generateChatTitle};
@@ -0,0 +1 @@
1
+ import{v4 as R}from"uuid";import{getEntitySpec as A,parseFieldPath as K,blankSecretField as S}from"./entity-graph";import{SHARED_OWNERS as V}from"./closure-resolver";function F(l,o){if(o.length===0)return null;let r=l;for(let i=0;i<o.length-1;i++){if(r==null||typeof r!="object")return null;r=r[o[i]]}return r==null||typeof r!="object"?null:{parent:r,key:o[o.length-1]}}function v(l,o){let r=l;for(const i of o){if(r==null)return;r=r[i]}return r}function O(l,o,r){const i=K(o.field),y=[],I=t=>typeof t=="string"&&t.length>0;switch(i.kind){case"scalar":{const t=F(l,i.prefix);if(!t)break;const p=t.parent[t.key];if(I(p)){const s=r(p);s.mapped?t.parent[t.key]=s.newVal:(t.parent[t.key]="",y.push(p))}break}case"scalarArray":{const t=F(l,i.prefix),p=t?.parent[t.key];if(!t||!Array.isArray(p))break;const s=[];for(const c of p){if(!I(c))continue;const u=r(c);u.mapped?s.push(u.newVal):y.push(c)}t.parent[t.key]=s;break}case"objectArray":{const t=F(l,i.prefix),p=t?.parent[t.key];if(!t||!Array.isArray(p))break;const s=[];for(const c of p){const u=c?.[i.leaf];if(!I(u)){s.push(c);continue}const g=r(u);g.mapped?(c[i.leaf]=g.newVal,s.push(c)):y.push(u)}t.parent[t.key]=s;break}case"mapValues":{const t=v(l,i.prefix);if(!t||typeof t!="object")break;for(const p of Object.keys(t)){const s=t[p];if(!I(s))continue;const c=r(s);c.mapped?t[p]=c.newVal:(delete t[p],y.push(s))}break}}return y}async function $(l,o,r,i,y={}){const I=y.blankSecrets!==!1,t=y.genId??R,p=y.now??new Date().toISOString(),s={targetOwner:o,created:[],skipped:[],referenced:[],secretsBlanked:[],droppedRefs:[]},c=(e,n)=>{const a=A(e).ownerPath==="metadata.owner"?n?.metadata?.owner:n?.owner;return typeof a=="string"?a:void 0},u=new Map,g=e=>{let n=u.get(e);return n||(n=new Map,u.set(e,n)),n},b=new Map;for(const e of l.resolutions)b.set(`${e.fromEsId}|${e.field}|${e.value}`,{targetKey:e.targetKey,targetOldEsId:e.targetOldEsId});const C=[];for(const e of l.docs){const n=A(e.key),f=n.nameField?e.source[n.nameField]:void 0,a=c(e.key,e.source);if(a&&V.includes(a)){g(e.key).set(e.esId,{newEsId:e.esId,newAppId:n.appIdField?e.source[n.appIdField]:void 0,skipped:!0}),s.referenced.push({key:e.key,index:n.index,esId:e.esId,name:f,owner:a});continue}let d=null;if(n.nameField&&typeof f=="string"&&f.length>0){const k=await r.findByName(n.index,n.nameField,f,[o]);d=k.length?[...k].sort((m,w)=>m._id.localeCompare(w._id))[0]:null}if(d)g(e.key).set(e.esId,{newEsId:d._id,newAppId:n.appIdField?d._source[n.appIdField]:void 0,skipped:!0}),s.skipped.push({key:e.key,index:n.index,oldEsId:e.esId,existingEsId:d._id,name:f});else{const k=t(),m=n.appIdField&&typeof e.source[n.appIdField]=="string"&&e.source[n.appIdField].length>0;g(e.key).set(e.esId,{newEsId:k,newAppId:m?t():void 0,skipped:!1}),C.push(e)}}for(const e of C){const n=A(e.key),f=g(e.key).get(e.esId),a=JSON.parse(JSON.stringify(e.source));for(const d of n.edges){const m=O(a,d,w=>{const h=b.get(`${e.esId}|${d.field}|${w}`);if(!h)return{mapped:!1};const E=g(h.targetKey).get(h.targetOldEsId);if(!E)return{mapped:!1};const x=d.scheme==="appId"?E.newAppId:d.scheme==="esId"?E.newEsId:E.newAppId??E.newEsId;return typeof x=="string"&&x.length>0?{mapped:!0,newVal:x}:{mapped:!1}});for(const w of m)s.droppedRefs.push({fromKey:e.key,fromNewEsId:f.newEsId,field:d.field,oldValue:w})}n.ownerPath==="metadata.owner"?a.metadata={...a.metadata??{},owner:o}:a.owner=o;for(const d of n.extraOwnerFields??[])a[d]=o;if(n.appIdField&&f.newAppId&&(a[n.appIdField]=f.newAppId),I&&n.secretFields?.length){for(const d of n.secretFields)S(a,d);s.secretsBlanked.push({key:e.key,newEsId:f.newEsId,fields:n.secretFields})}for(const d of["createdAt","updatedAt","created","updated","timestamp"])d in a&&(a[d]=p);await i.create(n.index,f.newEsId,a),s.created.push({key:e.key,index:n.index,oldEsId:e.esId,newEsId:f.newEsId,name:n.nameField?e.source[n.nameField]:void 0})}return s}function W(l){return{async create(o,r,i){await l.index({index:o,id:r,document:i,refresh:!0})}}}export{W as createEsCloneWriter,$ as executeClone};
@@ -0,0 +1,3 @@
1
+ import{getEntityByIndex as A,getEntitySpec as h,parseFieldPath as E}from"./entity-graph";import{aggField as $}from"../../core/services/es-field-resolver";const D=["stkxp","kibana","system"],N="assistant.mcp_servers_policy.servers[].id.__personal_tools__";function I(r,a){let o=r;for(const l of a){if(o==null)return;o=o[l]}return o}function O(r,a){const o=E(a.field),l=a.nameFallbackField?E(a.nameFallbackField):void 0,n=[],e=t=>typeof t=="string"&&t.length>0;switch(o.kind){case"scalar":{const t=I(r,o.prefix);if(e(t)){const s=l?I(r,l.prefix):void 0;n.push({value:t,fallbackName:e(s)?s:void 0})}break}case"scalarArray":{const t=I(r,o.prefix);if(Array.isArray(t))for(const s of t)e(s)&&n.push({value:s});break}case"objectArray":{const t=I(r,o.prefix);if(Array.isArray(t))for(const s of t){const y=s?.[o.leaf];if(e(y)){const p=l?s?.[l.leaf]:void 0;n.push({value:y,fallbackName:e(p)?p:void 0})}}break}case"mapValues":{const t=I(r,o.prefix);if(t&&typeof t=="object")for(const s of Object.values(t))e(s)&&n.push({value:s});break}}return n}function T(r){const a=new Map;for(const e of r)a.set(e,new Set);for(const e of r)for(const t of h(e).edges)t.target!==e&&r.has(t.target)&&a.get(e).add(t.target);const o=[],l=[...r].filter(e=>a.get(e).size===0).sort(),n=new Map([...a].map(([e,t])=>[e,new Set(t)]));for(;l.length;){const e=l.shift();o.push(e),n.delete(e);for(const[t,s]of n)s.delete(e)&&s.size===0&&(l.push(t),l.sort())}for(const e of r)o.includes(e)||o.push(e);return o}async function M(r,a,o){const l=new Set,n=[],e=new Map,t=[],s=[],y=new Set,p=r.map(c=>({index:c.index,esId:c.esId,via:"root"}));async function k(c){for(const u of[[a],D,void 0]){const i=await c(u);if(i.length)return{doc:[...i].sort((g,w)=>g._id.localeCompare(w._id))[0],ambiguous:i.length>1}}return{doc:null,ambiguous:!1}}async function P(c,u,i){const f=h(c);let g=null,w=!1;if(u.scheme==="esId")g=await o.getById(f.index,i.value);else{const d=await k(m=>o.findByAppId(f.index,f.appIdField,i.value,m));g=d.doc,w=d.ambiguous,!g&&u.scheme==="appIdThenEsId"&&(g=await o.getById(f.index,i.value))}if(!g&&i.fallbackName&&f.nameField){const d=await k(m=>o.findByName(f.index,f.nameField,i.fallbackName,m??D));g=d.doc,w=d.ambiguous}return{doc:g,reason:w?"ambiguous":"missing"}}for(;p.length;){const c=p.shift(),u=`${c.index}:${c.esId}`;if(l.has(u)){e.get(u)?.reachedVia.push(c.via);continue}l.add(u);const i=A(c.index);if(!i)continue;const f=await o.getById(c.index,c.esId);if(!f){t.push({from:{key:i.key,esId:c.esId},field:"(self)",target:i.key,value:c.esId,reason:"missing",blocking:!1});continue}const g={key:i.key,index:i.index,esId:f._id,appId:i.appIdField?f._source[i.appIdField]:void 0,source:f._source,reachedVia:[c.via]};n.push(g),e.set(u,g),y.add(i.key);const w=i.nameField?f._source[i.nameField]:void 0;for(const d of i.edges){const m=O(f._source,d);for(const v of m){const x=/^__personal_tools__:(.+)$/.exec(v.value);if(x){const b=x[1],B=await o.findPersonalTools(b),C=h("tool");for(const K of B)p.push({index:C.index,esId:K._id,via:N});continue}const{doc:_,reason:F}=await P(d.target,d,v);if(_){const b=h(d.target);s.push({fromEsId:f._id,field:d.field,value:v.value,targetKey:d.target,targetOldEsId:_._id}),p.push({index:b.index,esId:_._id,via:`${i.key}.${d.field}`})}else t.push({from:{key:i.key,esId:f._id,name:w},field:d.field,target:d.target,value:v.value,reason:F,blocking:!!d.required})}}for(const d of i.reverseEdges??[]){const m=h(d.from),v=await o.findByField(m.index,d.field,f._id,a);for(const x of v)p.push({index:m.index,esId:x._id,via:`${i.key}\u2190${d.from}.${d.field}`})}}const R=t.filter(c=>c.blocking);if(R.length){const c=R.map(u=>` ${u.from.key}(${u.from.esId}).${u.field} \u2192 ${u.target} "${u.value}" (${u.reason})`);throw new Error(`[clone] Required dependencies could not be resolved \u2014 clone blocked:
2
+ ${c.join(`
3
+ `)}`)}return{sourceOwner:a,roots:r,docs:n,order:T(y),unresolved:t,resolutions:s}}function S(r){return r?.body??r}function U(r){async function a(n,e){return $(n,e)}async function o(n,e){return!e||!e.length?[]:[{terms:{[await a(n,"owner")]:e}}]}async function l(n,e){const t=await r.search({index:n,size:50,body:{query:{bool:{must:e}}}});return(S(t).hits?.hits??[]).map(y=>({_id:y._id,_source:y._source}))}return{async getById(n,e){try{const t=await r.get({index:n,id:e}),s=S(t);return s?.found===!1?null:{_id:s._id,_source:s._source}}catch(t){if(t?.meta?.statusCode===404||t?.statusCode===404)return null;throw t}},async findByAppId(n,e,t,s){return l(n,[{term:{[await a(n,e)]:t}},...await o(n,s)])},async findByName(n,e,t,s){return l(n,[{term:{[await a(n,e)]:t}},...await o(n,s)])},async findByField(n,e,t,s){return l(n,[{term:{[await a(n,e)]:t}},{term:{[await a(n,"owner")]:s}}])},async findPersonalTools(n){const e=h("tool").index;return l(e,[{term:{[await a(e,"owner")]:n}},{term:{[await a(e,"type")]:"mcp"}},{bool:{must_not:[{exists:{field:"system"}}]}}])}}}export{N as PERSONAL_TOOLS_REACHED_VIA,D as SHARED_OWNERS,U as createEsStore,O as extractEdgeRefs,M as resolveClosure,T as topoOrder};
@@ -0,0 +1,3 @@
1
+ const d={assistant:{key:"assistant",index:".stkxp_assistants",ownerPath:"owner",nameField:"name",edges:[{field:"graphId",target:"graph",scheme:"appId"},{field:"promptId",target:"prompt",scheme:"appIdThenEsId"},{field:"mcp_servers_policy.servers[].id",target:"platform",scheme:"esId",nameFallbackField:"mcp_servers_policy.servers[].name"},{field:"llm_overrides.*",target:"routingRule",scheme:"appId"}]},team:{key:"team",index:".stkxp_teams",ownerPath:"owner",nameField:"name",secretFields:["webhookToken","mcpSigningSecret"],edges:[{field:"assistantIds[]",target:"assistant",scheme:"esId"},{field:"assistants[].id",target:"assistant",scheme:"esId"},{field:"graphId",target:"graph",scheme:"appId"}]},graph:{key:"graph",index:".stkxp_graphs",ownerPath:"owner",appIdField:"id",nameField:"name",edges:[{field:"nodes[].graphId",target:"graph",scheme:"appId",required:!0},{field:"nodes[].templateId",target:"nodeTemplate",scheme:"appId"},{field:"nodes[].llm_routing_rule_id",target:"routingRule",scheme:"appId"}]},prompt:{key:"prompt",index:".stkxp_prompts",ownerPath:"owner",appIdField:"id",nameField:"name",edges:[]},routingRule:{key:"routingRule",index:".stkxp_llm_routing_rules",ownerPath:"owner",appIdField:"id",nameField:"name",edges:[{field:"modelId",target:"model",scheme:"appId"}]},model:{key:"model",index:".stkxp_llm_models",ownerPath:"owner",appIdField:"id",nameField:"name",edges:[{field:"providerId",target:"provider",scheme:"esId"}]},provider:{key:"provider",index:".stkxp_llm_providers",ownerPath:"owner",appIdField:"id",nameField:"name",secretFields:["apiKey"],edges:[]},platform:{key:"platform",index:".stkxp_platforms",ownerPath:"owner",appIdField:"id",nameField:"name",secretFields:["config.authKey","config.headers","config.queryParams","config.auth.bearerToken","config.auth.password","config.auth.apiKeyValue","config.auth.apiKeySecret","config.auth.clientSecret"],edges:[],reverseEdges:[{from:"tool",field:"platformId",scheme:"esId"}]},tool:{key:"tool",index:".stkxp_tools",ownerPath:"owner",extraOwnerFields:["createdBy","updatedBy"],nameField:"name",secretFields:["authConfig.token","authConfig.apiKey","authConfig.password","authConfig.clientSecret","authConfig.clientId","broker.auth.token","broker.auth.apiKey","broker.auth.password","customHeaders"],edges:[{field:"platformId",target:"platform",scheme:"esId"},{field:"apiDocId",target:"apiDoc",scheme:"esId"},{field:"mcpServerId",target:"platform",scheme:"esId",nameFallbackField:"mcpServerName"}]},apiDoc:{key:"apiDoc",index:".stkxp_api",ownerPath:"owner",nameField:"name",edges:[]},nodeTemplate:{key:"nodeTemplate",index:".stkxp_node_templates",ownerPath:"owner",appIdField:"id",nameField:"type",edges:[]}},o=Object.fromEntries(Object.values(d).map(t=>[t.index,t.key]));function l(t){const a=d[t];if(!a)throw new Error(`[entity-graph] No spec for entity "${t}"`);return a}function c(t){const a=o[t];return a?d[a]:void 0}function p(t){if(t.endsWith(".*"))return{kind:"mapValues",prefix:t.slice(0,-2).split("."),leaf:""};const a=t.indexOf("[]");if(a===-1)return{kind:"scalar",prefix:t.split("."),leaf:""};const r=t.slice(0,a),e=t.slice(a+2),n=r.split(".");return e===""?{kind:"scalarArray",prefix:n,leaf:""}:{kind:"objectArray",prefix:n,leaf:e.replace(/^\./,"")}}function m(){const t=[],a=new Set(Object.keys(d));for(const r of Object.values(d)){r.key!==o[r.index]&&t.push(`${r.key}: key/index mismatch (index ${r.index})`);for(const e of r.edges){a.has(e.target)||t.push(`${r.key}.${e.field} \u2192 unknown target "${e.target}"`);let n;try{n=p(e.field)}catch(i){t.push(`${r.key}.${e.field}: unparseable (${i.message})`)}if(e.nameFallbackField&&n){const i=p(e.nameFallbackField);i.kind!==n.kind&&t.push(`${r.key}.${e.field}: nameFallbackField kind "${i.kind}" does not match field kind "${n.kind}"`)}(e.scheme==="appId"||e.scheme==="appIdThenEsId")&&!d[e.target].appIdField&&t.push(`${r.key}.${e.field}: scheme "${e.scheme}" but target "${e.target}" has no appIdField`)}for(const e of r.reverseEdges??[])a.has(e.from)||t.push(`${r.key} reverseEdge \u2192 unknown from "${e.from}"`)}if(t.length)throw new Error(`[entity-graph] validation failed:
2
+ ${t.join(`
3
+ `)}`)}function f(t,a){const r=a.split(".");let e=t;for(let s=0;s<r.length-1;s++){if(e==null||typeof e!="object")return;e=e[r[s]]}if(e==null||typeof e!="object")return;const n=r[r.length-1];if(!(n in e))return;const i=e[n];Array.isArray(i)?e[n]=[]:i!=null&&typeof i=="object"?e[n]={}:e[n]=""}export{d as ENTITY_GRAPH,o as INDEX_TO_ENTITY,f as blankSecretField,c as getEntityByIndex,l as getEntitySpec,p as parseFieldPath,m as validateEntityGraph};
@@ -0,0 +1 @@
1
+ function t(n){return n?.body??n}async function c(n,s){const a=[...new Set(s.docs.map(e=>e.index))],o=[];for(const e of a)t(await n.indices.exists({index:e}))||(await n.indices.create({index:e}),o.push(e));if(s.docs.length===0)return{indicesCreated:o,docsIndexed:0};const d=s.docs.flatMap(e=>[{index:{_index:e.index,_id:e.esId}},e.source]),i=t(await n.bulk({operations:d,refresh:"wait_for"}));if(i.errors){const e=(i.items??[]).filter(r=>r.index?.error).map(r=>`${r.index._id}: ${r.index.error.reason}`);throw new Error(`Bulk index failed for ${e.length} doc(s): ${e.join("; ")}`)}return{indicesCreated:o,docsIndexed:s.docs.length}}export{c as bootstrapClosureToEs};
@@ -0,0 +1 @@
1
+ import{randomBytes as h,scryptSync as B,createCipheriv as m,createDecipheriv as y}from"crypto";const l="aes-256-gcm",v=32,x=16,S=12,d="v2",i={N:65536,r:8,p:1},w=128*i.N*i.r*2;function E(){return h(x).toString("hex")}class o extends Error{}function A(t,r){let e;try{e=Buffer.from(r,"hex")}catch{throw new o("Malformed bundle key-derivation salt")}if(e.length!==x)throw new o("Malformed bundle key-derivation salt");return B(t,e,v,{...i,maxmem:w})}function M(t,r){const e=h(S),n=m(l,r,e),f=Buffer.from(JSON.stringify(t),"utf8"),a=Buffer.concat([n.update(f),n.final()]),c=n.getAuthTag();return[d,e.toString("hex"),c.toString("hex"),a.toString("hex")].join(":")}function N(t,r){const e=t.split(":");if(e.length!==4||e[0]!==d)throw new o("Malformed encrypted value envelope");const[,n,f,a]=e;let c,s,p;try{c=Buffer.from(n,"hex"),s=Buffer.from(f,"hex"),p=Buffer.from(a,"hex")}catch{throw new o("Malformed encrypted value envelope")}try{const u=y(l,r,c);u.setAuthTag(s);const g=Buffer.concat([u.update(p),u.final()]);return JSON.parse(g.toString("utf8"))}catch{throw new o("Wrong passphrase or corrupted bundle")}}export{o as BundleDecryptError,i as SCRYPT_PARAMS,N as decryptValue,A as deriveBundleKey,M as encryptValue,E as generateBundleSalt};
@@ -0,0 +1 @@
1
+ import{getEntitySpec as f}from"./entity-graph";import{encryptValue as p,decryptValue as g,deriveBundleKey as m,generateBundleSalt as k,BundleDecryptError as N}from"./team-bundle-crypto";const u="stkxp-team-bundle-encrypted",w=1;function E(r,n){const t=n.split(".");let e=r;for(let c=0;c<t.length-1;c++){if(e==null||typeof e!="object")return null;e=e[t[c]]}if(e==null||typeof e!="object")return null;const a=t[t.length-1];return a in e?{parent:e,leaf:a}:null}function S(r,n,t){const e=E(r,n);e&&(e.parent[e.leaf]=p(e.parent[e.leaf],t))}function b(r,n,t){const e=E(r,n);!e||typeof e.parent[e.leaf]!="string"||(e.parent[e.leaf]=g(e.parent[e.leaf],t))}function B(r,n){const t=JSON.parse(JSON.stringify(r)),e={},a=k(),c=m(n.passphrase,a);for(const s of t.docs){e[s.key]=(e[s.key]??0)+1;const o=f(s.key);for(const l of o.secretFields??[])S(s.source,l,c);s.key==="team"&&(s.source.webhookEnabled=!1,delete s.source.webhookCreatedAt)}return{kind:u,bundleVersion:w,exportedAt:n.exportedAt,sourceOwner:r.sourceOwner,rootName:n.rootName,summary:{totalDocs:t.docs.length,byEntity:e},kdfSalt:a,closure:t,encryptedGatewaySecret:n.gatewaySecret?p(n.gatewaySecret,c):void 0}}class i extends Error{}function D(r,n){if(r==null||typeof r!="object")throw new i("Bundle is not a JSON object");const t=r;if(t.kind!==u)throw new i(`Not an encrypted team bundle (expected kind "${u}", got "${t.kind}")`);if(t.bundleVersion!==w)throw new i(`Unsupported bundle version ${t.bundleVersion}`);const e=t.closure;if(!e||typeof e!="object"||!Array.isArray(e.docs))throw new i("Bundle is missing a well-formed closure");if(typeof t.kdfSalt!="string"||t.kdfSalt.length===0)throw new i("Bundle is missing its key-derivation salt (kdfSalt)");let a;try{a=m(n,t.kdfSalt)}catch(o){throw new i(`Bundle is missing a usable key-derivation salt: ${o instanceof Error?o.message:"unknown error"}`)}const c=JSON.parse(JSON.stringify(e));for(const o of c.docs){const l=f(o.key);for(const y of l.secretFields??[])try{b(o.source,y,a)}catch(d){throw d instanceof N?new i(`Failed to decrypt ${o.key}.${y}: ${d.message}`):d}}let s;if(typeof t.encryptedGatewaySecret=="string")try{s=g(t.encryptedGatewaySecret,a)}catch(o){throw new i(`Failed to decrypt gateway secret: ${o instanceof Error?o.message:"unknown error"}`)}return{closure:c,rootName:typeof t.rootName=="string"?t.rootName:"(unnamed team)",sourceOwner:typeof t.sourceOwner=="string"?t.sourceOwner:"",mcpGateway:t.mcpGateway,gatewaySecret:s}}export{u as ENCRYPTED_BUNDLE_KIND,w as ENCRYPTED_BUNDLE_VERSION,i as TeamBundleDecryptError,D as parseAndDecryptTeamBundle,B as serializeTeamBundleEncrypted};
@@ -0,0 +1 @@
1
+ import{getEntitySpec as d,blankSecretField as l}from"./entity-graph";const c="stkxp-team-bundle",i=1;function m(t,e){const r=JSON.parse(JSON.stringify(t)),n={};for(const o of r.docs){n[o.key]=(n[o.key]??0)+1;const a=d(o.key);for(const u of a.secretFields??[])l(o.source,u);o.key==="team"&&(o.source.webhookEnabled=!1,delete o.source.webhookCreatedAt)}return{kind:c,bundleVersion:i,exportedAt:e.exportedAt,sourceOwner:t.sourceOwner,rootName:e.rootName,summary:{totalDocs:r.docs.length,byEntity:n},closure:r}}class s extends Error{}function p(t){if(t==null||typeof t!="object")throw new s("Bundle is not a JSON object");const e=t;if(e.kind!==c)throw new s(`Not a team bundle (expected kind "${c}", got "${e.kind}")`);if(e.bundleVersion!==i)throw new s(`Unsupported bundle version ${e.bundleVersion} (this server reads version ${i})`);const r=e.closure;if(!r||typeof r!="object"||!Array.isArray(r.docs)||!Array.isArray(r.resolutions)||!Array.isArray(r.order)||!Array.isArray(r.roots))throw new s("Bundle is missing a well-formed closure");if(r.docs.length===0)throw new s("Bundle closure contains no documents");const n=new Set;for(const a of r.docs)try{d(a.key)}catch{n.add(String(a.key))}if(n.size)throw new s(`Bundle references unknown entity types: ${[...n].join(", ")}`);const o=e.mcpGateway&&typeof e.mcpGateway=="object"&&typeof e.mcpGateway.grantId=="string"&&Array.isArray(e.mcpGateway.platformIds)?{grantId:e.mcpGateway.grantId,platformIds:e.mcpGateway.platformIds}:void 0;return{kind:c,bundleVersion:i,exportedAt:typeof e.exportedAt=="string"?e.exportedAt:"",sourceOwner:typeof e.sourceOwner=="string"?e.sourceOwner:"",rootName:typeof e.rootName=="string"?e.rootName:"(unnamed team)",summary:e.summary&&typeof e.summary=="object"?e.summary:{totalDocs:r.docs.length,byEntity:{}},closure:r,mcpGateway:o}}export{c as BUNDLE_KIND,i as BUNDLE_VERSION,s as TeamBundleParseError,p as parseTeamBundle,m as serializeTeamBundle};
@@ -0,0 +1 @@
1
+ import{HttpsClient as h}from"../core/utils/http-client";import{settingsConfig as u}from"../core/app-config/settings";class k{httpsClient;constructor(){this.httpsClient=new h(u.certificates,u.defaults.timeout)}async checkCluster(e){const s=new URL(e.api_url),n=s.hostname,i=s.port||"443",a=s.pathname||"";if(console.log("Creating checkCluster for cluster:",{hostname:n,port:i,path:a},"with params:",JSON.stringify({...e,api_key:e.api_key?"***":void 0})),console.log("\u{1F50D} api_key value:",e.api_key),console.log("\u{1F50D} api_key type:",typeof e.api_key),console.log("\u{1F50D} username:",e.username),console.log("\u{1F50D} password:",e.password?"***":void 0),e.api_key&&e.api_key!=="undefined"&&typeof e.api_key=="string"&&e.api_key.trim().length>0){console.log("\u2705 Using API Key authentication");const l="ApiKey "+e.api_key,c={hostname:n,port:i,path:a,method:"GET",headers:{Authorization:l,"Content-Type":"application/json"}};try{const t=await this.httpsClient.request(c);if(console.log("checkCluster with API Key - success"),!t.error)return t.data;if(!(t.error?.status===401||t.error?.statusCode===401||typeof t.error=="object"&&t.error.error?.status===401))return console.log("checkCluster with API Key - non-auth error:",t.error),{error:t.error};console.log("checkCluster with API Key - auth failed, trying Basic Auth...")}catch(t){console.log("checkCluster with API Key - exception:",t)}}const o=e;if(o.username&&o.password){console.log("\u2705 Using Basic Auth authentication");const c=`Basic ${Buffer.from(`${o.username}:${o.password}`).toString("base64")}`,t={hostname:n,port:i,path:a,method:"GET",headers:{Authorization:c,"Content-Type":"application/json"}};try{const r=await this.httpsClient.request(t);return console.log("checkCluster with Basic Auth - result:",r.error?"error":"success"),r.error?{error:r.error}:r.data}catch(r){return console.log("checkCluster with Basic Auth - exception:",r),{error:r}}}return{error:{message:"Authentication failed. Please provide valid API key or username/password credentials.",status:401}}}}export{k as ClusterService};
@@ -0,0 +1 @@
1
+ import{HttpsClient as m}from"../core/utils/http-client";import{settingsConfig as h}from"../core/app-config/settings";import g from"ioredis";import C from"mysql2/promise";import{Client as w}from"pg";class f{httpsClient;constructor(){this.httpsClient=new m(h.certificates,h.defaults.timeout)}}class _ extends f{async testConnection(e){try{let s=e.api_url,t=e.api_key,n=e.username,i=e.password;if(e.vars&&(e.vars.api_url&&(s=e.vars.api_url),e.vars.api_key&&(t=e.vars.api_key),e.vars.resource_url&&(s=e.vars.resource_url),e.vars.username&&(n=e.vars.username),e.vars.password&&(i=e.vars.password),e.vars.hosts&&Array.isArray(e.vars.hosts)&&(s=e.vars.hosts[0])),e.inputs)for(const[d,r]of Object.entries(e.inputs))r.enabled&&r.vars&&(r.vars.api_url&&(s=r.vars.api_url),r.vars.api_key&&(t=r.vars.api_key),r.vars.resource_url&&(s=r.vars.resource_url),r.vars.username&&(n=r.vars.username),r.vars.password&&(i=r.vars.password),r.vars.hosts&&Array.isArray(r.vars.hosts)&&(s=r.vars.hosts[0]));if(!s)return{success:!1,error:"Missing required connection parameter: api_url or resource_url",serviceType:"elasticsearch"};if(!t&&!n)return{success:!1,error:"Missing authentication: provide either api_key or username/password",serviceType:"elasticsearch"};const u=new URL(s);let a;t?a=`ApiKey ${t}`:n&&i?a=`Basic ${Buffer.from(`${n}:${i}`).toString("base64")}`:a="";const l={hostname:u.hostname,port:u.port||"443",path:u.pathname||"/",method:"GET",headers:{Authorization:a,"Content-Type":"application/json"}},c=await this.httpsClient.request(l);return c.error?{success:!1,error:c.error,serviceType:"elasticsearch"}:{success:!0,data:c.data,serviceType:"elasticsearch",connectionInfo:{cluster_name:c.data?.cluster_name,version:c.data?.version?.number}}}catch(s){return{success:!1,error:s,serviceType:"elasticsearch"}}}async getServiceInfo(e){return(await this.testConnection(e)).data}}class P extends f{async testConnection(e){let s=null;try{let t=["127.0.0.1:6379"],n="",i="",u=null;if(e.inputs){for(const[p,o]of Object.entries(e.inputs))if(o.enabled&&o.vars&&(o.vars.hosts&&Array.isArray(o.vars.hosts)&&(t=o.vars.hosts),o.vars.password&&(n=o.vars.password),o.vars.username&&(i=o.vars.username),o.vars.ssl&&typeof o.vars.ssl=="string"&&o.vars.ssl.trim()))try{u={}}catch(v){console.warn("Could not parse SSL configuration:",v)}}const[a,l]=t[0].split(":"),c={host:a,port:parseInt(l||"6379"),connectTimeout:5e3,lazyConnect:!0};n&&(c.password=n),i&&(c.username=i),u&&(c.tls=u),s=new g(c),await s.connect();const r=(await s.info("server")).match(/redis_version:(.+)/)?.[1]?.trim();return{success:!0,serviceType:"redis",data:{service:"Redis",version:r,host:`${a}:${l}`},connectionInfo:{service:"Redis",version:r,host:`${a}:${l}`}}}catch(t){return{success:!1,error:t,serviceType:"redis"}}finally{s&&await s.disconnect()}}async getServiceInfo(e){return(await this.testConnection(e)).data}}class S extends f{async testConnection(e){let s=null;try{let t=["127.0.0.1:3306"],n="root",i="",u="";if(e.inputs)for(const[o,v]of Object.entries(e.inputs))v.enabled&&v.vars&&(v.vars.hosts&&Array.isArray(v.vars.hosts)&&(t=v.vars.hosts),v.vars.username&&(n=v.vars.username),v.vars.password&&(i=v.vars.password),v.vars.database&&(u=v.vars.database));let a=t[0],l="127.0.0.1",c="3306";const d=a.match(/tcp\(([^:)]+):?(\d+)?\)/);if(d){l=d[1],c=d[2]||"3306";const o=a.match(/tcp\([^)]+\)\/([^/\s]+)/);o&&!u&&(u=o[1])}else if(a.includes(":")){const o=a.split(":");l=o[0],c=o[1]||"3306"}else l=a;console.log(`[MySQL] Connecting to ${l}:${c} as ${n}, database: ${u||"(none)"}`),s=await C.createConnection({host:l,port:parseInt(c),user:n,password:i,database:u||void 0,connectTimeout:5e3});const[r]=await s.execute("SELECT VERSION() as version"),p=r[0]?.version;return{success:!0,serviceType:"mysql",data:{service:"MySQL",version:p,host:`${l}:${c}`},connectionInfo:{service:"MySQL",version:p,host:`${l}:${c}`}}}catch(t){return{success:!1,error:t,serviceType:"mysql"}}finally{s&&await s.end()}}async getServiceInfo(e){return(await this.testConnection(e)).data}}class b extends f{async testConnection(e){let s=null;try{let t=["127.0.0.1:5432"],n="postgres",i="",u="postgres";if(e.inputs)for(const[r,p]of Object.entries(e.inputs))p.enabled&&p.vars&&(p.vars.hosts&&Array.isArray(p.vars.hosts)&&(t=p.vars.hosts),p.vars.username&&(n=p.vars.username),p.vars.password&&(i=p.vars.password),p.vars.database&&(u=p.vars.database));const[a,l]=t[0].split(":");s=new w({host:a,port:parseInt(l||"5432"),user:n,password:i,database:u,connectTimeoutMillis:5e3}),await s.connect();const d=(await s.query("SELECT version()")).rows[0]?.version;return{success:!0,serviceType:"postgresql",data:{service:"PostgreSQL",version:d,host:`${a}:${l}`},connectionInfo:{service:"PostgreSQL",version:d,host:`${a}:${l}`}}}catch(t){return{success:!1,error:t,serviceType:"postgresql"}}finally{s&&await s.end()}}async getServiceInfo(e){return(await this.testConnection(e)).data}}class k{adapters;constructor(){this.adapters=new Map([["elasticsearch",new _],["redis",new P],["mysql",new S],["postgresql",new b]])}detectServiceType(e){const s={redis:"redis",mysql:"mysql",postgresql:"postgresql",postgres:"postgresql",elasticsearch:"elasticsearch",stack_expert:"elasticsearch"};if(s[e.packageName.toLowerCase()])return s[e.packageName.toLowerCase()];if(e.api_key&&e.api_url)return"elasticsearch";if(e.inputs)for(const[t,n]of Object.entries(e.inputs)){const i=t.toLowerCase();if(i.includes("redis"))return"redis";if(i.includes("mysql"))return"mysql";if(i.includes("postgres"))return"postgresql";if(i.includes("elastic"))return"elasticsearch"}return"elasticsearch"}async testConnection(e){const s=this.detectServiceType(e),t=this.adapters.get(s);if(!t)return{success:!1,error:`Unsupported service type: ${s}`,serviceType:s};console.log(`Testing connection for service type: ${s}`),console.log("Connection params:",JSON.stringify(e,null,2));try{return{...await t.testConnection(e),serviceType:s}}catch(n){return{success:!1,error:n,serviceType:s}}}async getServiceInfo(e){const s=this.detectServiceType(e),t=this.adapters.get(s);if(!t)throw new Error(`Unsupported service type: ${s}`);return await t.getServiceInfo(e)}getSupportedServices(){return Array.from(this.adapters.keys())}}export{f as BaseConnectionAdapter,k as DynamicConnectionService,_ as ElasticsearchConnectionAdapter,S as MySQLConnectionAdapter,b as PostgreSQLConnectionAdapter,P as RedisConnectionAdapter};
@@ -0,0 +1,10 @@
1
+ import*as I from"js-yaml";import{config as E}from"../core/config";import{getPlatformById as D}from"../core/services/platforms-service";import{makeOwnerScopedClient as M}from"../core/utils/owner-scope";const g=M(E.elasticsearch),S=".stkxp_connectors",O=".stkxp_tools",de=".stkxp_platforms",q=".stkxp_assistants",H=".stkxp_teams";async function b(){try{await g.indices.exists({index:S})||(await g.indices.create({index:S,body:{mappings:{properties:{id:{type:"keyword"},name:{type:"text",fields:{keyword:{type:"keyword"}}},namespace:{type:"keyword"},description:{type:"text"},domain:{type:"keyword"},tags:{type:"keyword"},platformId:{type:"keyword"},platformName:{type:"keyword"},spec:{type:"object",enabled:!0},analysis:{type:"object",enabled:!0},toolStrategy:{type:"keyword"},selectedGroups:{type:"keyword"},selectedOperationIds:{type:"keyword"},bodyFormat:{type:"keyword"},customHeaders:{type:"object",enabled:!1},owner:{type:"keyword"},created:{type:"date"},updated:{type:"date"},enabled:{type:"boolean"}}},settings:{number_of_shards:1,number_of_replicas:1}}}),console.log(`\u2705 Created index: ${S}`))}catch(t){throw console.error("Failed to ensure connectors index:",t),t}}async function le(t){await b();const e=`connector_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,n=new Date().toISOString(),s={id:e,created:n,updated:n,...t};return await g.index({index:S,id:e,body:s,refresh:"wait_for"}),s}async function ue(t){return await b(),(await g.search({index:S,body:{query:{term:{owner:t}},sort:[{created:{order:"desc"}}],size:200}})).hits.hits.map(n=>n._source)}async function P(t,e){await b();const s=(await g.search({index:S,body:{query:{bool:{must:[{term:{id:t}},{term:{owner:e}}]}},size:1}})).hits.hits[0];return s?s._source:null}async function L(t,e,n){await b();const p=(await g.search({index:S,body:{query:{bool:{must:[{term:{id:t}},{term:{owner:e}}]}},size:1}})).hits.hits[0];if(!p)return null;const o=p._source,d={...o,...n,id:t,owner:e,created:o.created,updated:new Date().toISOString()};return await g.index({index:S,id:p._id,body:d,refresh:"wait_for"}),d}async function me(t,e){await b();const s=(await g.search({index:S,body:{query:{bool:{must:[{term:{id:t}},{term:{owner:e}}]}},size:1}})).hits.hits[0];return s?(await g.delete({index:S,id:s._id,refresh:"wait_for"}),!0):!1}async function fe(t,e,n){if(n)return n;if(!e)throw new Error("url is required when content is not provided");const p=await fetch(e,{headers:{Accept:"application/json, text/yaml, text/plain, */*"},signal:AbortSignal.timeout(12e4)});if(!p.ok)throw new Error(`Failed to fetch spec: HTTP ${p.status} ${p.statusText}`);return p.text()}function ge(t){let e;try{e=I.load(t)}catch{throw new Error("Unable to parse spec \u2014 not valid YAML or JSON")}if(!e||typeof e!="object")throw new Error("Spec content is empty or not an object");let n="";if(e.openapi&&typeof e.openapi=="string")n=e.openapi;else if(e.swagger&&typeof e.swagger=="string")n=e.swagger;else throw new Error('Not a valid OpenAPI spec \u2014 missing "openapi" or "swagger" field');const s=n.startsWith("3"),p=e.info?.title,o=[];if(s&&Array.isArray(e.servers))for(const c of e.servers)c?.url&&o.push(c.url);else if(!s&&e.host){const c=e.schemes?.[0]??"https",l=e.basePath??"";o.push(`${c}://${e.host}${l}`)}const d=[],u={},y=(c,l)=>{if(c.type&&typeof c.type=="string")return c.type;if(c.openIdConnectUrl)return"openIdConnect";if(c.flows||c.authorizationUrl||c.tokenUrl)return"oauth2";if(c.scheme&&typeof c.scheme=="string")return"http";if(c.in||c.name)return"apiKey";const h=l.toLowerCase();return h.includes("bearer")||h.includes("basic")?"http":h.includes("oauth")?"oauth2":"apiKey"};if(s&&e.components?.securitySchemes)for(const[c,l]of Object.entries(e.components.securitySchemes))!l||typeof l!="object"||(d.push(c),u[c]={type:y(l,c),in:l.in,name:l.name,scheme:l.scheme,description:l.description});else if(!s&&e.securityDefinitions)for(const[c,l]of Object.entries(e.securityDefinitions))!l||typeof l!="object"||(d.push(c),u[c]={type:y(l,c),in:l.in,name:l.name,scheme:l.scheme,description:l.description});const m=[],f=["get","post","put","patch","delete","options","head","trace"],i=e.paths??{};for(const[c,l]of Object.entries(i))if(!(!l||typeof l!="object"))for(const h of f){const w=l[h];if(!w)continue;const C=w.operationId??`${h.toUpperCase()}_${c.replace(/[^a-zA-Z0-9]/g,"_")}`;m.push({operationId:C,method:h.toUpperCase(),path:c,summary:w.summary,tags:Array.isArray(w.tags)?w.tags:[]})}const r=new Set;for(const c of m)for(const l of c.tags??[])r.add(l);const a=Array.from(r).sort();return{openApiVersion:n,title:p,servers:o,securitySchemes:d,securitySchemeDetails:u,operationsCount:m.length,operations:m,suggestedGroups:a}}const z=new Set(["get","post","put","delete","patch","options","head","trace"]);function U(t){return!!t&&typeof t=="object"&&"$ref"in t}function A(t){return t.replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&nbsp;/g," ").replace(/&#(\d+);/g,(e,n)=>String.fromCharCode(parseInt(n,10)))}function B(t){if(!t)return"";if(!t.includes("<"))return A(t).trim();let e=t;e=e.replace(/<pre[^>]*>\s*<code[^>]*>([\s\S]*?)<\/code>\s*<\/pre>/gi,(n,s)=>"\n```\n"+A(s.replace(/<[^>]+>/g,""))+"\n```\n"),e=e.replace(/<code[^>]*>(.*?)<\/code>/gi,(n,s)=>"`"+A(s.replace(/<[^>]+>/g,""))+"`");for(let n=6;n>=1;n--)e=e.replace(new RegExp(`<h${n}[^>]*>([\\s\\S]*?)<\\/h${n}>`,"gi"),(s,p)=>`
2
+ `+"#".repeat(n)+" "+p.replace(/<[^>]+>/g,"").trim()+`
3
+ `);return e=e.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi,"**$1**"),e=e.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi,"*$1*"),e=e.replace(/<a[^>]+href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi,"[$2]($1)"),e=e.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi,`
4
+ - $1`),e=e.replace(/<\/[uo]l>/gi,`
5
+ `),e=e.replace(/<\/p>/gi,`
6
+ `),e=e.replace(/<br\s*\/?>/gi,`
7
+ `),e=e.replace(/<p[^>]*>/gi,`
8
+ `),e=e.replace(/<[^>]+>/g,""),e=A(e),e=e.replace(/\n{3,}/g,`
9
+
10
+ `),e.trim()}function _(t,e,n=new Set,s=0,p={nodes:2e3}){if(s>15||p.nodes<=0||!t||typeof t!="object")return t;if(Array.isArray(t))return t.map(d=>_(d,e,n,s+1,p));if("$ref"in t){const d=t.$ref;if(!d.startsWith("#/"))return t;if(n.has(d))return{type:"object",description:`[Circular: ${d}]`};const u=T(e,d);return u?(p.nodes--,_(u,e,new Set(n).add(d),s+1,p)):t}const o={};for(const[d,u]of Object.entries(t)){if(p.nodes<=0){o[d]=u;continue}p.nodes--,u&&typeof u=="object"?o[d]=_(u,e,n,s+1,p):o[d]=u}return o}function T(t,e){if(!e.startsWith("#/"))return;const n=e.slice(2).split("/").map(p=>p.replace(/~1/g,"/").replace(/~0/g,"~"));let s=t;for(const p of n){if(s==null||typeof s!="object")return;s=s[p]}return s}function K(t,e){if(e){if(U(e)){const n=T(t,e.$ref);return!n?.name||!n?.in?void 0:n}if(!(!e.name||!e.in))return e}}function J(t,e,n){const s=new Map;for(const p of[...e,...n]){const o=K(t,p);o&&s.set(`${o.in}:${o.name.toLowerCase()}`,o)}return[...s.values()]}function x(t){if(!t)return;const e=["application/json","application/*+json","multipart/form-data","application/x-www-form-urlencoded","text/plain"];for(const n of e)if(t[n]?.schema)return t[n].schema;for(const n of Object.values(t))if(n?.schema)return n.schema}function F(t){const e=t.schema??x(t.content)??{type:"string"},n=typeof e=="object"&&e!==null?{...e}:{type:"string"};return t.description&&!n.description&&(n.description=t.description),t.deprecated&&(n.deprecated=!0),n["x-openapi-in"]=t.in,n["x-openapi-name"]=t.name,n}function G(t){if(!t)return;const e=x(t.content);if(!e)return{type:"object",description:t.description??"Request body",additionalProperties:!0};const n=typeof e=="object"&&e!==null?{...e}:e;return typeof n=="object"&&t.description&&!n.description&&(n.description=t.description),n}function Z(t,e){const n=new Set;for(const s of e)for(const p of Object.keys(s)){const o=t[p];o&&(o.type==="apiKey"&&o.in==="header"&&o.name&&n.add(String(o.name).toLowerCase()),o.type==="http"&&(o.scheme==="bearer"||o.scheme==="basic")&&n.add("authorization"))}return n}function V(t,e,n,s,p){const o={},d=new Set,u=Z(n.securitySchemes,n.activeSecurity),y=new Set;for(const i of t){if(i.in==="header"&&u.has(i.name.toLowerCase()))continue;const r=i.name.replace(/[.[\]]+/g,"_").replace(/[^a-zA-Z0-9_]+/g,"_").replace(/^_+|_+$/g,"");o[r]=F(i),i.required&&d.add(r),i.in==="path"&&y.add(i.name)}if(p){const i=/\{([^}]+)\}/g;let r;for(;(r=i.exec(p))!==null;){const a=r[1];if(y.has(a))continue;const c=a.replace(/[.[\]]+/g,"_").replace(/[^a-zA-Z0-9_]+/g,"_").replace(/^_+|_+$/g,"");o[c]||(o[c]={type:"string",description:`Path parameter \`${a}\` (required by the URL path).`,"x-openapi-in":"path","x-openapi-name":a},d.add(c))}}const m=G(e),f=m&&s?_(m,s):m;if(f)if(typeof f=="object"&&f.type==="object"&&f.properties){for(const[i,r]of Object.entries(f.properties))o[i]=r;for(const i of f.required??[])d.add(String(i))}else o.body=f,e?.required&&d.add("body");return{type:"object",properties:o,required:[...d],additionalProperties:!1}}function W(t){for(const n of["200","201","202","203","204","default"]){const s=t[n];if(s)return{schema:x(s.content),description:s.description}}const e=Object.values(t)[0];return e?{schema:x(e.content),description:e.description}:{}}function $(t){const e=new Set;for(const n of t??[])for(const s of Object.keys(n))e.add(s);return[...e]}function X(t,e){const n=t.toLowerCase();return{readOnlyHint:n==="get"||n==="head"||n==="options",destructiveHint:n==="delete",idempotentHint:n==="get"||n==="put"||n==="delete"||n==="head",openWorldHint:/\{.+\}/.test(e)}}function Q(t){return t.trim().replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[^a-zA-Z0-9_]+/g,"_").replace(/_+/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function Y(t){return t.trim().replace(/[^a-zA-Z0-9_]+/g,"_").replace(/_+/g,"_").replace(/^_+|_+$/g,"")}function ee(t,e,n){const s={get:"get",post:"create",put:"replace",patch:"update",delete:"delete",options:"options",head:"head",trace:"trace"},p=e.replace(/[{}]/g,"").split("/").filter(Boolean).map(u=>u.replace(/[^a-zA-Z0-9]+/g," ").trim().replace(/\b\w/g,y=>y.toUpperCase()).replace(/\s+/g,"")).join(""),o=s[t]||t,d=n?n.replace(/[^a-zA-Z0-9 ]+/g," ").trim().replace(/\b\w/g,u=>u.toUpperCase()).replace(/\s+/g,""):p;return`${o}${d}`}function te(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").trim().replace(/\b\w/g,e=>e.toUpperCase())}function ne(t){return t.replace(/\{([^}]+)\}/g,":$1")}function re(t){return[...new Set(t.filter(Boolean).map(e=>e.trim()))]}function se(t,e={}){const n=[],s=$(t.security??[]),p=(t.servers??[]).map(o=>o.url);for(const[o,d]of Object.entries(t.paths??{})){const u=d??{},y=Array.isArray(u.parameters)?u.parameters:[];for(const[m,f]of Object.entries(u).filter(([i])=>z.has(i.toLowerCase()))){const i=m.toLowerCase(),r=f??{};if(!r||typeof r!="object"||r.deprecated&&!e.includeDeprecated)continue;const a=J(t,y,Array.isArray(r.parameters)?r.parameters:[]),c=V(a,r.requestBody,{securitySchemes:t.components?.securitySchemes??{},activeSecurity:r.security??t.security??[]},t,o),l=Y(r.operationId??ee(i,o,r.summary??r.tags?.[0]))||`tool_${n.length+1}`,h=(r.summary??te(l)).replace(/\s+/g," ").trim(),w=r.description??r.summary??`${i.toUpperCase()} ${o}`,C=B(w),j=Q(r.operationId??l),{schema:k,description:N}=W(r.responses??{}),v=k!=null?_(k,t):void 0,R=$(r.security??t.security??[]);n.push({name:j,title:h,description:C,inputSchema:c,annotations:X(i,o),meta:{method:i.toUpperCase(),path:ne(o),operationId:l,tags:re(r.tags??[]),deprecated:!!r.deprecated,servers:p,security:R.length?R:s,responseSchema:v,responseDescription:N,group:r.tags?.[0]}})}}return n.sort((o,d)=>o.name.localeCompare(d.name))}async function oe(){try{await g.indices.putMapping({index:O,body:{properties:{connectorId:{type:"keyword"},platformId:{type:"keyword"},platformName:{type:"keyword"},method:{type:"keyword"},httpMethod:{type:"keyword"},authConfig:{type:"object",enabled:!1},path:{type:"keyword"},openApiMeta:{type:"text",index:!1}}}})}catch{}}async function ye(t,e){const n=await P(t,e);if(!n)throw new Error("Connector not found");let s;try{s=I.load(n.spec.rawContent)}catch{throw new Error("Unable to parse stored spec")}if(!s||typeof s!="object")throw new Error("Invalid spec content");let p="",o;try{const i=await D(n.platformId,e,!0,!0);if(i&&i.type==="OpenAPI"){const r=i.config;p=r.baseUrl??"";const a=r.auth;if(a&&a.type!=="none")if(a.type==="bearer"&&a.bearerToken)o={type:"bearer",token:a.bearerToken};else if(a.type==="basic"&&a.username)o={type:"basic",username:a.username,password:a.password??""};else if(a.type==="apiKey"&&a.apiKeyHeader&&a.apiKeyValue){const c=a.apiKeySecret?`${a.apiKeyValue}:${a.apiKeySecret}`:a.apiKeyValue;o={type:"apiKey",headerName:a.apiKeyHeader,apiKey:c}}else a.type==="oauth2_cc"&&a.tokenUrl&&a.clientId&&a.clientSecret&&(o={type:"oauth2_cc",tokenUrl:a.tokenUrl,clientId:a.clientId,clientSecret:a.clientSecret,scope:a.scope,audience:a.audience,authStyle:a.authStyle,tokenHeaderName:a.tokenHeaderName})}}catch{}const d=se(s,{includeDeprecated:!1});let u=d;if(n.toolStrategy==="grouped"&&n.selectedGroups?.length){const i=new Set(n.selectedGroups);u=d.filter(r=>r.meta.group&&i.has(r.meta.group))}else if(n.toolStrategy==="custom"&&n.selectedOperationIds?.length){const i=new Set(n.selectedOperationIds);u=d.filter(r=>i.has(r.meta.operationId))}if(u.length===0)throw new Error("No tools to generate after applying strategy filter");await oe();try{await g.deleteByQuery({index:O,refresh:!0,body:{query:{bool:{must:[{term:{connectorId:t}},{term:{owner:e}}]}}}})}catch{}const y=new Date().toISOString(),m=n.platformId,f=[];for(const i of u){const r=`openapi_${t}_${i.name}`,a=i.meta.path,c=p||i.meta.servers[0]||"",l=c?c.replace(/\/+$/,"")+"/"+a.replace(/^\/+/,""):"",h={name:i.name,label:i.title,description:i.description,type:"mcp",system:n.name,method:i.meta.method,path:a,endpoint:l,inputSchema:JSON.stringify(i.inputSchema),outputSchema:(()=>{if(i.meta.responseSchema)try{const w=JSON.stringify(i.meta.responseSchema);return w.length<=2e5?w:void 0}catch{return}})(),enabled:!0,tags:i.meta.tags,owner:e,connectorId:t,platformId:m,platformName:n.platformName,httpMethod:i.meta.method,authConfig:o,bodyFormat:n.bodyFormat??void 0,customHeaders:n.customHeaders??void 0,openApiMeta:JSON.stringify({method:i.meta.method,path:i.meta.path,servers:p?[p,...i.meta.servers]:i.meta.servers,platformId:m,security:i.meta.security,annotations:i.annotations}),createdAt:y,updatedAt:y,createdBy:e,updatedBy:e};f.push({index:{_index:O,_id:r}},h)}return await g.bulk({body:f,refresh:"wait_for"}),await L(t,e,{}),{created:u.length,toolNames:u.map(i=>i.name)}}async function he(t,e){const n=await P(t,e);if(!n)return{assistants:[],teams:[]};const s=[...new Set([n.name,n.platformName].filter(Boolean))],o=(await g.search({index:q,body:{query:{bool:{must:[{term:{owner:e}}],filter:[{bool:{should:s.map(r=>({term:{"mcp_servers_policy.servers.name.keyword":r}})),minimum_should_match:1}}]}},size:500,_source:["id","name","topic","enabled"]}})).hits.hits.map(r=>({id:r._id,name:r._source?.name??r._id,topic:r._source?.topic,enabled:r._source?.enabled!==!1}));if(o.length===0)return{assistants:[],teams:[]};const d=o.map(r=>r.id),u=new Map(o.map(r=>[r.id,r])),m=(await g.search({index:H,body:{query:{bool:{must:[{term:{enabled:!0}},{terms:{assistantIds:d}}]}},size:200,_source:["name","assistantIds","enabled"]}})).hits.hits.map(r=>{const c=(r._source?.assistantIds??[]).map(l=>u.get(l)).filter(l=>!!l);return{id:r._id,name:r._source?.name??r._id,assistants:c}}),f=new Set(m.flatMap(r=>r.assistants.map(a=>a.id)));return{assistants:o.filter(r=>!f.has(r.id)),teams:m}}export{ge as analyzeOpenApiSpec,le as createConnector,me as deleteConnector,b as ensureConnectorsIndex,fe as fetchSpecContent,ye as generateConnectorTools,se as generateMcpTools,P as getConnectorById,he as getConnectorLinked,ue as getConnectors,L as updateConnector};
@@ -0,0 +1 @@
1
+ import{Client as f}from"@elastic/elasticsearch";import{config as S}from"../core/config";import{PLAN_PRICES_EUR as w,PLAN_LABELS as _}from"../core/services/plan-service";import{aggField as b}from"../core/services/es-field-resolver";const D=new f(S.elasticsearch),u=".stkxp_chat_runs";function z(){const t=new Date;return new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate()))}function T(t){return t.toISOString().slice(0,10)}async function v(t,r){const s=new Date,e=new Date(s.getTime()-(r-1)*24*60*60*1e3);e.setUTCHours(0,0,0,0);const n=await b(u,"username");return((await D.search({index:u,body:{size:0,query:{bool:{must:[{term:{[n]:t}},{range:{startTime:{gte:e.toISOString(),lte:s.toISOString()}}}]}},aggs:{per_day:{date_histogram:{field:"startTime",calendar_interval:"day",time_zone:"UTC",extended_bounds:{min:e.toISOString(),max:s.toISOString()},min_doc_count:0},aggs:{cost:{sum:{field:"estimatedCost"}}}}}}})).aggregations?.per_day?.buckets??[]).map(c=>({date:T(new Date(c.key)),costUsd:Number(c.cost?.value||0),runs:Number(c.doc_count||0)}))}async function I(t,r){const s=new Date,e=new Date(s.getTime()-r*24*60*60*1e3),n=await b(u,"username"),i=await b(u,"assistantId"),c=((await D.search({index:u,body:{size:0,query:{bool:{must:[{term:{[n]:t}},{range:{startTime:{gte:e.toISOString(),lte:s.toISOString()}}}]}},aggs:{by_assistant:{terms:{field:i,size:5,order:{cost:"desc"}},aggs:{cost:{sum:{field:"estimatedCost"}},name:{top_hits:{size:1,_source:["assistantName"]}}}}}}})).aggregations?.by_assistant?.buckets??[]).map(o=>({key:o.key,label:o.name?.hits?.hits?.[0]?._source?.assistantName||o.key,costUsd:Number(o.cost?.value||0),runs:Number(o.doc_count||0)})),l=await b(u,"llmUsage.provider"),g=await b(u,"llmUsage.model"),a=(await D.search({index:u,body:{size:0,query:{bool:{must:[{term:{[n]:t}},{range:{startTime:{gte:e.toISOString(),lte:s.toISOString()}}}]}},aggs:{llm:{nested:{path:"llmUsage"},aggs:{by_model:{terms:{script:{source:`doc['${l}'].value + ':' + doc['${g}'].value`},size:5,order:{_count:"desc"}},aggs:{tokens:{sum:{field:"llmUsage.totalTokens"}}}}}}}}})).aggregations?.llm?.by_model?.buckets??[],m=a.reduce((o,y)=>o+Number(y.tokens?.value||0),0),U=(await D.search({index:u,body:{size:0,query:{bool:{must:[{term:{[n]:t}},{range:{startTime:{gte:e.toISOString(),lte:s.toISOString()}}}]}},aggs:{total:{sum:{field:"estimatedCost"}}}}})).aggregations,h=Number(U?.total?.value||0),C=a.map(o=>{const y=Number(o.tokens?.value||0),k=m>0?y/m:0;return{key:o.key,label:o.key,costUsd:h*k,runs:Number(o.doc_count||0)}});return{topByAssistant:c,topByModel:C}}function B(t,r){const s=t.slice(-r);return s.length===0?0:s.reduce((n,i)=>n+i.costUsd,0)/s.length}function M(t,r){const s=t.slice(-r);if(s.length<2)return{slope:0,intercept:s[0]?.costUsd??0};const e=s.map((a,m)=>m),n=s.map(a=>a.costUsd),i=e.reduce((a,m)=>a+m,0)/e.length,d=n.reduce((a,m)=>a+m,0)/n.length;let c=0,l=0;for(let a=0;a<e.length;a++)c+=(e[a]-i)*(n[a]-d),l+=(e[a]-i)**2;const g=l===0?0:c/l,p=d-g*i;return{slope:g,intercept:p}}function N(){const t=new Date,r=t.getUTCFullYear(),s=t.getUTCMonth(),e=new Date(Date.UTC(r,s+1,0)).getUTCDate(),n=t.getUTCDate();return{days:e,elapsed:n,remaining:Math.max(e-n,0)}}function P(t){const s=new Date().toISOString().slice(0,7);return t.filter(e=>e.date.startsWith(s)).reduce((e,n)=>e+n.costUsd,0)}async function x(t){try{return((await D.security.getUser({username:t}))[t]?.metadata??{}).plan??"trial"}catch{return"trial"}}async function E(t,r={}){const s=r.windowDays??30,[e,n,i]=await Promise.all([v(t,s),I(t,s),x(t)]),d=P(e),{elapsed:c,remaining:l}=N(),g=B(e,7),{slope:p,intercept:a}=M(e,14),U=Math.min(e.length,14);let h=0;for(let y=0;y<l;y++){const k=U+y;h+=Math.max(a+p*k,0)}const C=d+h,o=d+g*l;return{windowDays:s,lookback:e,monthToDateUsd:d,daysElapsedInMonth:c,daysRemainingInMonth:l,trailing7dAvgUsd:g,linearSlopeUsdPerDay:p,projectionLinearUsd:C,projectionMaUsd:o,topByAssistant:n.topByAssistant,topByModel:n.topByModel,plan:{name:i,label:_[i],monthlyPriceEur:w[i]}}}export{E as getCostForecastReport};
@@ -0,0 +1,4 @@
1
+ import{jsx as i,jsxs as o}from"react/jsx-runtime";import{renderToString as R}from"react-dom/server";import{CacheProvider as A}from"@emotion/react";import w from"@emotion/server/create-instance";import v from"@emotion/cache";import{EuiProvider as T,EuiPanel as d,EuiMarkdownFormat as P,EuiBasicTable as D,EuiText as p,EuiCodeBlock as I,EuiFlexGroup as S,EuiFlexItem as B,EuiStat as F,EuiCard as z}from"@elastic/eui";import{ChartRenderer as y}from"../core/services/chart-renderer";const U=({blocks:e})=>i("div",{className:"pdf-blocks-container",children:e.map((t,r)=>i("div",{className:"pdf-block",children:N(t)},t.id||r))});function N(e){if(!e||!e.type)return null;switch(e.type){case"markdown":return M(e);case"echarts":return E(e);case"recharts":return E(e);case"mermaid":return E(e);case"eui":return $(e);case"stats":return C(e);case"table":return G(e);case"remotion":return _(e);default:return J(e)}}function M(e){return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.body&&i(P,{children:e.body})]})}function E(e){return e.chartImage?o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",color:"subdued",children:e.description}),i("div",{style:{textAlign:"center",marginTop:"16px"},children:i("img",{src:e.chartImage,alt:e.title||"Chart",style:{maxWidth:"100%",height:"auto",border:"1px solid #e1e4e8",borderRadius:"6px"}})})]}):o(d,{paddingSize:"m",hasBorder:!0,color:"subdued",children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",color:"subdued",children:e.description}),i(p,{textAlign:"center",color:"subdued",children:i("p",{children:"\u{1F4CA} Chart rendering failed"})})]})}function C(e){return!e.stats||!Array.isArray(e.stats)?null:o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",color:"subdued",children:e.description}),i(S,{gutterSize:"l",style:{marginTop:"16px"},children:e.stats.map((t,r)=>i(B,{children:i(F,{title:t.value||t.title,description:t.label||t.description,titleColor:t.color||t.titleColor||"primary",titleSize:t.titleSize||"l",textAlign:t.textAlign||"center"})},r))})]})}function L(e,t){return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",color:"subdued",children:e.description}),i(S,{gutterSize:"m",wrap:!0,style:{marginTop:"16px"},children:t.map((r,a)=>i(B,{style:{minWidth:"220px"},children:i(z,{title:r.title||"",description:r.description||"",image:r.image})},a))})]})}function O(e){const t=[],r=/<EuiCard\b([^>]*)\/?>/g;let a;for(;(a=r.exec(e))!==null;){const n=a[1],s=l=>{const u=new RegExp(`${l}=["']([^"']*)["']`).exec(n);return u?u[1]:void 0};t.push({title:s("title"),description:s("description"),image:s("image")})}return t}function $(e){if(e.stats&&Array.isArray(e.stats))return C(e);if(e.body&&typeof e.body=="string"){const t=e.body.includes("EuiStat"),r=e.body.includes("EuiCard");if(t){const a=W(e.body);if(a.length>0)return C({...e,stats:a})}if(r){const a=O(e.body);if(a.length>0)return L(e,a)}}return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",children:e.description}),e.body&&i("div",{dangerouslySetInnerHTML:{__html:e.body}})]})}function W(e){const t=[],r=/<EuiStat[^>]*title=["']([^"']+)["'][^>]*description=["']([^"']+)["'][^>]*(?:titleColor=["']([^"']+)["'])?[^>]*\/?>/g,a=/<EuiStat[^>]*title={([^}]+)}[^>]*description=["']([^"']+)["'][^>]*(?:titleColor=["']([^"']+)["'])?[^>]*\/?>/g;let n;for(;(n=r.exec(e))!==null;)t.push({value:n[1],label:n[2],color:n[3]||"primary"});for(;(n=a.exec(e))!==null;)t.push({value:n[1].replace(/["']/g,""),label:n[2],color:n[3]||"primary"});return t}function G(e){if(!e.data||!Array.isArray(e.data)||e.data.length===0)return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),i("p",{children:"No data available"})]});let t=[];if(e.columns&&Array.isArray(e.columns))t=e.columns.map(r=>({field:r.field||r.key,name:r.name||r.label,sortable:r.sortable||!1,width:r.width}));else{const r=e.data[0];t=Object.keys(r).map(a=>({field:a,name:a.charAt(0).toUpperCase()+a.slice(1).replace(/_/g," ")}))}return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i("p",{children:e.description}),i(D,{items:e.data,columns:t,tableLayout:"auto",responsiveBreakpoint:!1})]})}function J(e){return o(d,{paddingSize:"m",hasBorder:!0,color:"subdued",children:[e.title&&i("h3",{children:e.title}),i(I,{language:"json",isCopyable:!1,children:JSON.stringify(e.content||e,null,2)})]})}function _(e){return o(d,{paddingSize:"m",hasBorder:!0,children:[e.title&&i("h3",{children:e.title}),e.description&&i(p,{size:"s",color:"subdued",children:e.description}),i(p,{size:"s",color:"subdued",children:o("p",{children:["\u{1F3AC} Animation (",e.templateId??"remotion",") \u2014 disponible dans la version web"]})})]})}function j(e){if(!e.data||!Array.isArray(e.data)||e.data.length===0)return null;const t=e.data,r=e.component||"BarChart",a=t[0],n=Object.keys(a),s=n[0],l=n.slice(1),u=t.map(h=>h[s]),g=l.map(h=>{const x=t.map(m=>m[h]);let c={name:h,data:x,type:"bar"};switch(r){case"LineChart":c.type="line",c.smooth=!0;break;case"AreaChart":c.type="line",c.areaStyle={},c.smooth=!0;break;case"BarChart":c.type="bar";break;case"PieChart":return{type:"pie",data:t.map(m=>({name:m[s],value:m[l[0]]})),radius:"50%"};default:c.type="bar"}return c});return{tooltip:{trigger:"axis",axisPointer:{type:r==="BarChart"?"shadow":"line"}},legend:{data:l,top:10},grid:{left:"3%",right:"4%",bottom:"3%",top:60,containLabel:!0},xAxis:r==="PieChart"?void 0:{type:"category",data:u},yAxis:r==="PieChart"?void 0:{type:"value"},series:g}}async function H(e){return console.log("[EUI SSR] Preprocessing",e.length,"blocks for chart rendering"),await Promise.all(e.map(async r=>{if(r.type==="echarts"&&(r.options||r.option)){!r.options&&r.option&&(r.options=r.option);try{if(y.validateChartOptions(r.options)){const a=await y.renderChartToBase64(r.options,{width:800,height:400,backgroundColor:"#ffffff"});return{...r,chartImage:a}}else return console.warn("[EUI SSR] Invalid echarts options:",r.title),r}catch(a){return console.error("[EUI SSR] Error rendering echarts:",a),r}}if(r.type==="recharts")try{const a=j(r);if(a&&y.validateChartOptions(a)){const n=await y.renderChartToBase64(a,{width:800,height:400,backgroundColor:"#ffffff"});return{...r,chartImage:n,type:"echarts"}}else return console.warn("[EUI SSR] Failed to convert recharts to echarts:",r.title),r}catch(a){return console.error("[EUI SSR] Error rendering recharts:",a),r}if(r.type==="mermaid"&&r.body)try{const a=(await import("mermaid")).default;a.initialize({startOnLoad:!1,theme:"base",themeVariables:{primaryColor:"#0077CC",primaryTextColor:"#343741",primaryBorderColor:"#D3DAE6",lineColor:"#69707D",secondaryColor:"#017D73",tertiaryColor:"#DD0A73",background:"#ffffff",mainBkg:"#F5F7FA",secondaryBkg:"#D3DAE6",tertiaryBkg:"#FFF4E0",textColor:"#343741",nodeBorder:"#D3DAE6",clusterBorder:"#98A2B3",errorBkgColor:"#BD271E",errorTextColor:"#ffffff",classText:"#343741",labelColor:"#343741",actorBorder:"#D3DAE6",actorBkg:"#F5F7FA",actorTextColor:"#343741",actorLineColor:"#69707D",signalColor:"#343741",signalTextColor:"#343741",gridColor:"#D3DAE6",todayLineColor:"#BD271E",git0:"#0077CC",git1:"#017D73",git2:"#F5A700",git3:"#DD0A73",git4:"#9170B8",git5:"#54B399",git6:"#E7664C",git7:"#DA8B45",pie1:"#0077CC",pie2:"#017D73",pie3:"#F5A700",pie4:"#DD0A73",pie5:"#9170B8",pie6:"#54B399",pie7:"#E7664C",pie8:"#DA8B45"},fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif',securityLevel:"strict",logLevel:"error"});const n=`mermaid-ssr-${r.id||Date.now()}-${Math.random().toString(36).substr(2,9)}`,{svg:s}=await a.render(n,r.body),u=`data:image/svg+xml;base64,${Buffer.from(s).toString("base64")}`;return console.log("[EUI SSR] Mermaid diagram rendered:",r.title||"untitled"),{...r,chartImage:u}}catch(a){return console.error("[EUI SSR] Error rendering mermaid:",a),console.error("[EUI SSR] Mermaid body:",r.body?.substring(0,200)),r}return r}))}async function f(e){try{const t=await H(e);console.log("[EUI SSR] Preprocessed",t.length,"blocks");const r=v({key:"eui"}),{extractCriticalToChunks:a,constructStyleTagsFromChunks:n}=w(r);console.log("[EUI SSR] Rendering",t.length,"blocks with Emotion extraction");const s=R(i(A,{value:r,children:i(T,{colorMode:"light",children:i(U,{blocks:t})})}));console.log("[EUI SSR] HTML rendered, length:",s.length);const l=s.replace(/[↵↦✄]|\u{10602}|\u{10617}/gu,""),u=a(l),g=n(u);return console.log("[EUI SSR] Styles extracted, length:",g.length),console.log("[EUI SSR] Number of style chunks:",u.styles.length),{html:l,styles:g}}catch(t){return console.error("[EUI SSR] Error during rendering:",t),{html:`<div class="error">
2
+ <h3>SSR Rendering Error</h3>
3
+ <p>${t instanceof Error?t.message:String(t)}</p>
4
+ </div>`,styles:"<style>.error { color: red; padding: 20px; }</style>"}}}async function ee(e){return Array.isArray(e)?await f(e):e&&typeof e=="object"&&e.blocks?await f(e.blocks):typeof e=="string"?await f([{type:"markdown",body:e}]):await f([{type:"raw",content:e}])}export{f as renderEuiBlocks,ee as renderMessageContent};
@@ -0,0 +1 @@
1
+ import{getEntitySpec as N}from"../clone/entity-graph";const v=8;function R(g){const $=new Map,S=new Map,F=new Map;for(const e of g.docs){$.set(`${e.key}:${e.esId}`,e);const t=N(e.key);t.appIdField&&e.source[t.appIdField]!=null&&S.set(`${e.key}:${e.source[t.appIdField]}`,e),t.nameField&&e.source[t.nameField]!=null&&F.set(`${e.key}:${e.source[t.nameField]}`,e)}function u(e,t){return $.get(`${e}:${t}`)||S.get(`${e}:${t}`)||F.get(`${e}:${t}`)}const l=[],f=[],p=[],_=new Set,b=new Set,d=g.docs.find(e=>e.key==="team");if(!d)return{nodes:l,edges:f,groups:p};l.push({id:d.esId,type:"team",label:d.source.name||d.esId,entityKey:"team",entityId:d.esId});function m(e){const t=`${e.from}->${e.to}:${e.condition??""}`;b.has(t)||(b.add(t),f.push(e))}function a(e,t,n){const r=u(e,t);r&&(_.has(`${e}:${r.esId}`)||(_.add(`${e}:${r.esId}`),l.push({id:r.esId,type:e,label:r.source.name||r.source.label||r.esId,entityKey:e,entityId:r.esId,groupId:void 0})),m({id:`e-${n}-${r.esId}`,from:n,to:r.esId,shared:!0}))}function G(e,t){a("routingRule",t,e);const n=u("routingRule",t);if(!n?.source.modelId)return;a("model",n.source.modelId,n.esId);const r=u("model",n.source.modelId);if(!r)return;let s;return r.source.providerId&&(a("provider",r.source.providerId,r.esId),s=u("provider",r.source.providerId)?.source.name),{modelBadge:{model:r.source.name,provider:s}}}function y(e,t,n,r){const s=u("graph",e);if(!s||r>v||n.has(s.esId))return;n.add(s.esId);const h=s.source.nodes||[],I=s.source.edges||[],c=o=>`${s.esId}:${o}`;for(const o of h){const D={};if(o.llm_routing_rule_id){const i=G(c(o.id),o.llm_routing_rule_id);i&&Object.assign(D,i)}l.push({id:c(o.id),type:o.type,label:o.name||o.id,entityKey:"graph",entityId:s.esId,groupId:t,data:D}),o.toolName&&a("tool",o.toolName,c(o.id));for(const i of o.toolCalls||[])a("tool",i.toolName,c(o.id));if(o.type==="subgraph"&&o.graphId){const i=u("graph",o.graphId);if(i){const E=`runtime-group-${i.esId}`;p.push({id:E,kind:"runtime",label:i.source.name||i.esId,parentGroupId:t,entityKey:"graph",entityId:i.esId}),y(o.graphId,E,n,r+1)}}}for(const o of I)o.from==="__start__"||o.to==="__end__"||m({id:`e-${c(o.from)}-${c(o.to)}`,from:c(o.from),to:c(o.to),condition:o.condition})}function K(e,t){const n=t.source.mcp_servers_policy?.servers||[];for(const r of n){a("platform",r.id,e);const s=u("platform",r.id);if(s)for(const h of g.docs.filter(I=>I.key==="tool"&&I.source.platformId===s.esId))a("tool",h.esId,e)}}for(const e of g.docs.filter(t=>t.key==="assistant")){const t=`asst-group-${e.esId}`;if(p.push({id:t,kind:"assistant",label:e.source.name||e.esId,entityKey:"assistant",entityId:e.esId}),l.push({id:e.esId,type:"assistant",label:e.source.name||e.esId,entityKey:"assistant",entityId:e.esId,groupId:t}),m({id:`e-${d.esId}-${e.esId}`,from:d.esId,to:e.esId}),K(e.esId,e),e.source.graphId){const n=u("graph",e.source.graphId);if(n){const r=`runtime-group-${n.esId}`;p.push({id:r,kind:"runtime",label:n.source.name||n.esId,parentGroupId:t,entityKey:"graph",entityId:n.esId}),y(e.source.graphId,r,new Set,0)}}}return d.source.graphId&&y(d.source.graphId,void 0,new Set,0),{nodes:l,edges:f,groups:p}}export{R as buildFullStructureGraph};
@@ -0,0 +1,13 @@
1
+ import{Client as I}from"@elastic/elasticsearch";import{HumanMessage as b}from"@langchain/core/messages";import{config as _}from"../core/config";import{createLLMInstance as G}from"../core/llm/providers";import{listGraphs as L}from"../core/services/graph-registry-service";import{provisionGraphs as v}from"./user-provisioning-service";const g=".stkxp_graph_templates",u="__test_provisioning__",$=".stkxp_graphs",d=new I(_.elasticsearch);async function h(){await d.indices.exists({index:g})||await d.indices.create({index:g,body:{mappings:{properties:{id:{type:"keyword"},name:{type:"text",fields:{keyword:{type:"keyword"}}},category:{type:"keyword"},description:{type:"text"},nodes:{type:"object",enabled:!1},edges:{type:"object",enabled:!1},sourceGraphId:{type:"keyword"},createdAt:{type:"date"},updatedAt:{type:"date"}}}}})}async function S(){return await h(),(await d.search({index:g,body:{query:{match_all:{}},sort:[{"name.keyword":{order:"asc"}}],size:200}})).hits.hits.map(a=>a._source)}async function T(i){try{const c=(await d.search({index:".stkxp_llm_routing_rules",body:{query:{bool:{must:[{term:{owner:i}},{term:{isDefault:!0}}]}},size:1}})).hits.hits[0]?._source;if(!c)return null;const r=c.modelId||c.llmModelId;if(!r)return null;const s=(await d.search({index:".stkxp_llm_models",body:{query:{bool:{must:[{term:{id:r}}]}},size:1}})).hits.hits[0]?._source;if(!s)return null;let n=null;try{const o=await d.get({index:".stkxp_llm_providers",id:s.providerId});o.found!==!1&&(n=o._source)}catch{n=(await d.search({index:".stkxp_llm_providers",body:{query:{bool:{must:[{term:{id:s.providerId}}]}},size:1}})).hits.hits[0]?._source??null}return n?.apiKey?{provider:n.type,model:s.modelId,apiKey:n.apiKey,baseURL:n.endpoint}:null}catch{return null}}async function R(i,a,c,r,p){const s=c.map(e=>`${e.id} (${e.type})`).join(", ")||"(none)",n=r.map(e=>`${e.from} \u2192 ${e.to}${e.condition?` [${e.condition}]`:""}`).join(", ")||"(none)",o=`You are writing a concise product description for a LangGraph Runtime template in an AI platform.
2
+
3
+ Runtime name: "${i}"
4
+ Existing description: "${a||"(none)"}"
5
+ Nodes: ${s}
6
+ Edges: ${n}
7
+
8
+ Write a clear, professional 2-3 sentence description explaining:
9
+ 1. What orchestration pattern this Runtime implements
10
+ 2. The main use case (what kind of AI agent would use it)
11
+ 3. Any notable behaviour (e.g. HITL approval, parallel execution, topic detection)
12
+
13
+ Return ONLY the description text. No quotes, no labels, no markdown.`;try{const t=await G({...p,streaming:!1,temperature:0}).invoke([new b(o)]);return(typeof t.content=="string"?t.content.trim():Array.isArray(t.content)?t.content.map(l=>typeof l=="string"?l:l.text??"").join("").trim():"")||a}catch(e){return console.warn(`[graph-templates] LLM description generation failed for "${i}":`,e),a}}async function q(i){await h();const c=(await d.search({index:$,body:{query:{term:{owner:u}},size:200}})).hits.hits.map(t=>({id:t._id,...t._source})),r=await T(i);r||console.warn(`[graph-templates] No default LLM config found for "${i}" \u2014 using existing descriptions`);const p=await d.search({index:g,body:{query:{match_all:{}},size:200}}),s=new Map(p.hits.hits.map(t=>[t._source.sourceGraphId,t]));let n=0,o=0;const e=[];for(const t of c)try{const m=t.name.split("/")[0].trim(),l=s.get(t.id),f=r?await R(t.name,t.description||"",t.nodes||[],t.edges||[],r):t.description||"",y=`tpl-${t.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}`,w={id:y,name:t.name,category:m,description:f,nodes:t.nodes||[],edges:t.edges||[],sourceGraphId:t.id,createdAt:l?._source.createdAt||new Date().toISOString(),updatedAt:new Date().toISOString()},x=l?._id||y;await d.index({index:g,id:x,body:w,refresh:"wait_for"}),l?o++:n++}catch(m){console.error(`[graph-templates] Failed to seed graph "${t.name}":`,m),e.push(`${t.name}: ${m.message||String(m)}`)}return{seeded:n,updated:o,errors:e}}async function k(i){const a=await L({owner:u}),c=new Map(a.map(s=>[s.id,s])),r=new Set,p=[...i];for(;p.length>0;){const s=p.shift();if(r.has(s))continue;r.add(s);const n=c.get(s);if(n)for(const o of n.nodes??[])o.type==="subgraph"&&o.graphId&&!r.has(o.graphId)&&p.push(o.graphId)}return Array.from(r)}async function C(i,a){await h();const r=(await d.search({index:g,body:{query:{term:{id:i}},size:1}})).hits.hits[0]?._source;if(!r)throw new Error(`Graph template "${i}" not found`);const p=(r.nodes??[]).filter(e=>e.type==="subgraph"&&e.graphId).map(e=>e.graphId);if(p.length===0)return{nodes:r.nodes,edges:r.edges};const s=await k(p);console.log(`[graph-templates] apply "${i}" for "${a}": provisioning ${s.length} child graph(s)`);const n=await v(a,{sourceOwner:u,graphIds:s});return{nodes:(r.nodes??[]).map(e=>e.type==="subgraph"&&e.graphId&&n.has(e.graphId)?{...e,graphId:n.get(e.graphId)}:{...e}),edges:r.edges}}export{C as applyGraphTemplate,h as ensureGraphTemplatesIndex,S as listGraphTemplates,q as seedGraphTemplatesFromProvisioning};
@@ -0,0 +1 @@
1
+ import{Client as y}from"@elastic/elasticsearch";import{config as k}from"../core/config";import{randomUUID as x}from"node:crypto";import{sendMagicLinkEmail as h}from"../core/services/send_mail";import{issueGuestJWT as w,getShareLinkById as m}from"../core/services/share-service";const i=new y(k.elasticsearch),s=".stkxp_guests",I=900*1e3;async function A(){try{await i.indices.exists({index:s})||(await i.indices.create({index:s,body:{settings:{number_of_shards:1,number_of_replicas:0},mappings:{properties:{email:{type:"keyword"},name:{type:"keyword"},ownerId:{type:"keyword"},status:{type:"keyword"},createdAt:{type:"date"},lastAccessAt:{type:"date"},shareLinkIds:{type:"keyword"},notes:{type:"text"},pendingToken:{type:"keyword"},pendingTokenExpiresAt:{type:"date"},pendingShareLinkId:{type:"keyword"}}}}}),console.log("[GuestService] Index created:",s))}catch(e){console.error("[GuestService] ensureIndex error:",e)}}A().catch(()=>{});const g=(e,n)=>Buffer.from(`${e.toLowerCase()}::${n}`).toString("base64url");async function p(e,n){try{const t=g(e,n),r=await i.get({index:s,id:t});return{id:t,...r._source}}catch{return null}}async function l(e){try{const n=await i.get({index:s,id:e});return{id:e,...n._source}}catch{return null}}async function _(e){try{return(await i.search({index:s,size:500,body:{query:{term:{ownerId:e}},sort:[{createdAt:{order:"desc"}}]}})).hits.hits.map(t=>({id:t._id,...t._source}))}catch{return[]}}async function P(e,n,t){const r=g(e,n),a=await p(e,n),c=new Date().toISOString();if(a){const o=a.shareLinkIds.includes(t)?a.shareLinkIds:[...a.shareLinkIds,t];return await i.update({index:s,id:r,body:{doc:{shareLinkIds:o}},refresh:!0}),{...a,shareLinkIds:o}}const d={email:e.toLowerCase(),ownerId:n,status:"active",createdAt:c,shareLinkIds:[t]};return await i.index({index:s,id:r,document:d,refresh:!0}),{id:r,...d}}async function D(e,n,t,r){const a=g(e,n),c=await p(e,n);if(c){const o={};return t!==void 0&&(o.name=t),r!==void 0&&(o.notes=r),Object.keys(o).length>0&&await i.update({index:s,id:a,body:{doc:o},refresh:!0}),{guest:{...c,...o},created:!1}}const d={email:e.toLowerCase(),ownerId:n,status:"active",createdAt:new Date().toISOString(),shareLinkIds:[],...t?{name:t}:{},...r?{notes:r}:{}};return await i.index({index:s,id:a,document:d,refresh:!0}),{guest:{id:a,...d},created:!0}}async function G(e,n,t){try{const r=await l(e);return!r||r.ownerId!==n?!1:(await i.update({index:s,id:e,body:{doc:t},refresh:!0}),!0)}catch{return!1}}async function O(e,n){return G(e,n,{status:"revoked"})}async function E(e,n){try{const t=await l(e);return!t||t.ownerId!==n?!1:(await i.delete({index:s,id:e,refresh:!0}),!0)}catch{return!1}}async function M(e,n){try{const t=g(e,n);await i.update({index:s,id:t,body:{doc:{lastAccessAt:new Date().toISOString()}},refresh:!1})}catch{}}async function C(e,n,t,r,a){const c=await p(e,n);if(c?.status==="revoked")return{sent:!1,error:"Access has been revoked for this email address"};const d=x(),o=new Date(Date.now()+I).toISOString(),u=g(e,n);if(c)await i.update({index:s,id:u,body:{doc:{pendingToken:d,pendingTokenExpiresAt:o,pendingShareLinkId:t}},refresh:!0});else{const f={email:e.toLowerCase(),ownerId:n,status:"active",createdAt:new Date().toISOString(),shareLinkIds:[t],pendingToken:d,pendingTokenExpiresAt:o,pendingShareLinkId:t};await i.index({index:s,id:u,document:f,refresh:!0})}return await h(e,r,a,d),{sent:!0}}async function U(e){const t=(await i.search({index:s,size:1,body:{query:{term:{pendingToken:e}}}})).hits.hits[0];if(!t)return{valid:!1,error:"Invalid or expired magic link"};const r={id:t._id,...t._source};if(!r.pendingTokenExpiresAt||new Date(r.pendingTokenExpiresAt)<new Date)return{valid:!1,error:"Magic link has expired \u2014 please request a new one"};if(r.status==="revoked")return{valid:!1,error:"Access has been revoked for this email address"};const a=r.pendingShareLinkId;await i.update({index:s,id:t._id,body:{doc:{pendingToken:null,pendingTokenExpiresAt:null,pendingShareLinkId:null,lastAccessAt:new Date().toISOString()}},refresh:!0});const c=w(r.email,r.ownerId,a,t._id);let d="dashboard",o;try{const u=await m(a);u&&(d=u.type,o=u.teamId)}catch{}return{valid:!0,guestJWT:c,redirectUrl:a,shareLinkType:d,teamId:o}}export{D as createGuest,E as deleteGuest,C as generateAndSendMagicToken,p as getGuest,l as getGuestById,_ as getGuestsByOwner,M as recordAccess,O as revokeGuest,G as updateGuest,P as upsertGuest,U as validateMagicToken};
@@ -0,0 +1 @@
1
+ import{Window as i}from"happy-dom";import m from"juice";import{PDFService as u}from"../core/services/pdf-service";import{getChatById as f}from"../core/services/chats-service";import{renderLeafletScreenshot as y}from"./leaflet-render-service";import{saveAsset as d}from"../core/services/report-assets-service";function g(t){if(Array.isArray(t))return t;if(t&&typeof t=="object"&&Array.isArray(t.blocks))return t.blocks;if(typeof t=="string")try{const r=JSON.parse(t);if(Array.isArray(r))return r;if(r&&Array.isArray(r.blocks))return r.blocks}catch{}return null}async function h(t){const r=g(t);return r?Promise.all(r.map(async e=>{if(e?.type==="leaflet"&&!e.chartImage)try{const s=await y(e);return{...e,chartImage:s}}catch(s){return console.error("[HtmlService] Leaflet screenshot failed:",s),e}return e})):t}async function p(t){const r=new i;r.document.write(t);const e=Array.from(r.document.querySelectorAll('img[src^="data:"]'));await Promise.all(e.map(async n=>{const o=n.getAttribute("src"),a=await d(o);n.setAttribute("src",a)}));const s=r.document.documentElement.outerHTML;return s.toLowerCase().startsWith("<!doctype")?s:"<!DOCTYPE html>"+s}function w(t){const r=new i;r.document.write(t);const{document:e}=r;e.querySelectorAll("script").forEach(n=>n.remove()),e.querySelectorAll("style").forEach(n=>n.remove()),e.querySelectorAll("link[rel]").forEach(n=>{(n.getAttribute("rel")||"").toLowerCase().split(/\s+/).includes("stylesheet")&&n.remove()});const s=e.documentElement.outerHTML;return s.toLowerCase().startsWith("<!doctype")?s:"<!DOCTYPE html>"+s}function A(t,r){return r?t.messages.find(e=>e.id===r):[...t.messages].reverse().find(e=>e.role==="assistant"||e.role==="agent")}async function I(t){const r=await f(t.chatId,t.username);if(!r)return{error:"not_found"};const e=A(r,t.messageId);if(!e)return{error:"no_message"};if(e.role==="system")return{error:"system_message"};const s=e.role,n=await h(e.content),o={id:e.id,content:n,role:s,timestamp:new Date(e.timestamp)},a=await u.generateHTML(o,{title:r.title,includeTimestamp:!1}),l=await p(a),c=m(l,{removeStyleTags:!0});return{html:w(c)}}export{I as exportChatToEmailHtml,p as externalizeImages,w as sanitizeForEmail};