@useatlas/create 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (515) hide show
  1. package/README.md +231 -0
  2. package/index.ts +829 -0
  3. package/package.json +38 -0
  4. package/templates/docker/.env.example +67 -0
  5. package/templates/docker/Dockerfile +52 -0
  6. package/templates/docker/bin/__tests__/benchmark.test.ts +598 -0
  7. package/templates/docker/bin/__tests__/duckdb-ingest.test.ts +171 -0
  8. package/templates/docker/bin/__tests__/eval.test.ts +434 -0
  9. package/templates/docker/bin/__tests__/matview-partition.test.ts +615 -0
  10. package/templates/docker/bin/__tests__/multi-source.test.ts +113 -0
  11. package/templates/docker/bin/__tests__/plugin-cli.test.ts +322 -0
  12. package/templates/docker/bin/__tests__/profiler-heuristics.test.ts +608 -0
  13. package/templates/docker/bin/__tests__/query.test.ts +240 -0
  14. package/templates/docker/bin/__tests__/schema-drift.test.ts +542 -0
  15. package/templates/docker/bin/__tests__/view-yaml-generation.test.ts +146 -0
  16. package/templates/docker/bin/atlas.ts +5044 -0
  17. package/templates/docker/bin/benchmark.ts +695 -0
  18. package/templates/docker/bin/enrich.ts +559 -0
  19. package/templates/docker/bin/eval.ts +770 -0
  20. package/templates/docker/bin/smoke.ts +438 -0
  21. package/templates/docker/data/.gitkeep +0 -0
  22. package/templates/docker/data/cybersec.sql +1961 -0
  23. package/templates/docker/data/demo-semantic/catalog.yml +40 -0
  24. package/templates/docker/data/demo-semantic/entities/accounts.yml +170 -0
  25. package/templates/docker/data/demo-semantic/entities/companies.yml +207 -0
  26. package/templates/docker/data/demo-semantic/entities/people.yml +145 -0
  27. package/templates/docker/data/demo-semantic/glossary.yml +22 -0
  28. package/templates/docker/data/demo-semantic/metrics/accounts.yml +38 -0
  29. package/templates/docker/data/demo-semantic/metrics/companies.yml +89 -0
  30. package/templates/docker/data/demo.sql +373 -0
  31. package/templates/docker/data/ecommerce.sql +1690 -0
  32. package/templates/docker/data/init-demo-db.sql +8 -0
  33. package/templates/docker/docker-compose.yml +34 -0
  34. package/templates/docker/docs/deploy.md +390 -0
  35. package/templates/docker/eslint.config.mjs +18 -0
  36. package/templates/docker/gitignore +5 -0
  37. package/templates/docker/next.config.ts +9 -0
  38. package/templates/docker/package.json +59 -0
  39. package/templates/docker/postcss.config.mjs +8 -0
  40. package/templates/docker/public/.gitkeep +0 -0
  41. package/templates/docker/public/favicon.svg +4 -0
  42. package/templates/docker/railway.json +13 -0
  43. package/templates/docker/render.yaml +34 -0
  44. package/templates/docker/semantic/catalog.yml +5 -0
  45. package/templates/docker/semantic/entities/.gitkeep +0 -0
  46. package/templates/docker/semantic/glossary.yml +6 -0
  47. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  48. package/templates/docker/sidecar/Dockerfile +28 -0
  49. package/templates/docker/sidecar/railway.json +14 -0
  50. package/templates/docker/sidecar/server.ts +188 -0
  51. package/templates/docker/src/api/__tests__/actions.test.ts +683 -0
  52. package/templates/docker/src/api/__tests__/admin.test.ts +820 -0
  53. package/templates/docker/src/api/__tests__/auth.test.ts +165 -0
  54. package/templates/docker/src/api/__tests__/chat.test.ts +376 -0
  55. package/templates/docker/src/api/__tests__/conversations.test.ts +555 -0
  56. package/templates/docker/src/api/__tests__/cors.test.ts +135 -0
  57. package/templates/docker/src/api/__tests__/health-plugin.test.ts +169 -0
  58. package/templates/docker/src/api/__tests__/health.test.ts +261 -0
  59. package/templates/docker/src/api/__tests__/query.test.ts +891 -0
  60. package/templates/docker/src/api/__tests__/scheduled-tasks.test.ts +601 -0
  61. package/templates/docker/src/api/__tests__/slack.test.ts +847 -0
  62. package/templates/docker/src/api/index.ts +117 -0
  63. package/templates/docker/src/api/routes/actions.ts +274 -0
  64. package/templates/docker/src/api/routes/admin.ts +757 -0
  65. package/templates/docker/src/api/routes/auth.ts +48 -0
  66. package/templates/docker/src/api/routes/chat.ts +465 -0
  67. package/templates/docker/src/api/routes/conversations.ts +266 -0
  68. package/templates/docker/src/api/routes/health.ts +287 -0
  69. package/templates/docker/src/api/routes/openapi.ts +390 -0
  70. package/templates/docker/src/api/routes/query.ts +318 -0
  71. package/templates/docker/src/api/routes/scheduled-tasks.ts +467 -0
  72. package/templates/docker/src/api/routes/slack.ts +611 -0
  73. package/templates/docker/src/api/server.ts +226 -0
  74. package/templates/docker/src/app/api/[...route]/route.ts +33 -0
  75. package/templates/docker/src/app/error.tsx +24 -0
  76. package/templates/docker/src/app/globals.css +126 -0
  77. package/templates/docker/src/app/layout.tsx +19 -0
  78. package/templates/docker/src/app/page.tsx +14 -0
  79. package/templates/docker/src/global.d.ts +1 -0
  80. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +437 -0
  81. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +114 -0
  82. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
  83. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +514 -0
  84. package/templates/docker/src/lib/__tests__/config-actions.test.ts +166 -0
  85. package/templates/docker/src/lib/__tests__/config.test.ts +1063 -0
  86. package/templates/docker/src/lib/__tests__/conversations.test.ts +589 -0
  87. package/templates/docker/src/lib/__tests__/errors.test.ts +256 -0
  88. package/templates/docker/src/lib/__tests__/logger.test.ts +200 -0
  89. package/templates/docker/src/lib/__tests__/providers.test.ts +99 -0
  90. package/templates/docker/src/lib/__tests__/rls.test.ts +435 -0
  91. package/templates/docker/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
  92. package/templates/docker/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
  93. package/templates/docker/src/lib/__tests__/semantic-index.test.ts +547 -0
  94. package/templates/docker/src/lib/__tests__/semantic-multisource.test.ts +544 -0
  95. package/templates/docker/src/lib/__tests__/semantic.test.ts +363 -0
  96. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +452 -0
  97. package/templates/docker/src/lib/__tests__/startup.test.ts +465 -0
  98. package/templates/docker/src/lib/__tests__/tracing.test.ts +28 -0
  99. package/templates/docker/src/lib/action-types.ts +95 -0
  100. package/templates/docker/src/lib/agent-query.ts +178 -0
  101. package/templates/docker/src/lib/agent.ts +505 -0
  102. package/templates/docker/src/lib/api-url.ts +2 -0
  103. package/templates/docker/src/lib/auth/__tests__/audit.test.ts +418 -0
  104. package/templates/docker/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
  105. package/templates/docker/src/lib/auth/__tests__/byot.test.ts +366 -0
  106. package/templates/docker/src/lib/auth/__tests__/detect.test.ts +190 -0
  107. package/templates/docker/src/lib/auth/__tests__/managed.test.ts +173 -0
  108. package/templates/docker/src/lib/auth/__tests__/middleware.test.ts +456 -0
  109. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +201 -0
  110. package/templates/docker/src/lib/auth/__tests__/permissions.test.ts +225 -0
  111. package/templates/docker/src/lib/auth/__tests__/server.test.ts +34 -0
  112. package/templates/docker/src/lib/auth/__tests__/simple-key.test.ts +176 -0
  113. package/templates/docker/src/lib/auth/__tests__/types.test.ts +44 -0
  114. package/templates/docker/src/lib/auth/audit.ts +89 -0
  115. package/templates/docker/src/lib/auth/byot.ts +158 -0
  116. package/templates/docker/src/lib/auth/client.ts +35 -0
  117. package/templates/docker/src/lib/auth/detect.ts +83 -0
  118. package/templates/docker/src/lib/auth/managed.ts +73 -0
  119. package/templates/docker/src/lib/auth/middleware.ts +208 -0
  120. package/templates/docker/src/lib/auth/migrate.ts +111 -0
  121. package/templates/docker/src/lib/auth/permissions.ts +156 -0
  122. package/templates/docker/src/lib/auth/server.ts +142 -0
  123. package/templates/docker/src/lib/auth/simple-key.ts +92 -0
  124. package/templates/docker/src/lib/auth/types.ts +49 -0
  125. package/templates/docker/src/lib/config.ts +704 -0
  126. package/templates/docker/src/lib/conversation-types.ts +29 -0
  127. package/templates/docker/src/lib/conversations.ts +270 -0
  128. package/templates/docker/src/lib/db/__tests__/connection.test.ts +69 -0
  129. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +141 -0
  130. package/templates/docker/src/lib/db/__tests__/internal.test.ts +387 -0
  131. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +207 -0
  132. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
  133. package/templates/docker/src/lib/db/__tests__/registry.test.ts +595 -0
  134. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +339 -0
  135. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +217 -0
  136. package/templates/docker/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
  137. package/templates/docker/src/lib/db/connection.ts +753 -0
  138. package/templates/docker/src/lib/db/duckdb.ts +122 -0
  139. package/templates/docker/src/lib/db/internal.ts +273 -0
  140. package/templates/docker/src/lib/db/salesforce.ts +342 -0
  141. package/templates/docker/src/lib/db/source-rate-limit.ts +191 -0
  142. package/templates/docker/src/lib/errors.ts +154 -0
  143. package/templates/docker/src/lib/logger.ts +98 -0
  144. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
  145. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +529 -0
  146. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +521 -0
  147. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +346 -0
  148. package/templates/docker/src/lib/plugins/__tests__/tools.test.ts +49 -0
  149. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +585 -0
  150. package/templates/docker/src/lib/plugins/hooks.ts +162 -0
  151. package/templates/docker/src/lib/plugins/index.ts +9 -0
  152. package/templates/docker/src/lib/plugins/migrate.ts +309 -0
  153. package/templates/docker/src/lib/plugins/registry.ts +231 -0
  154. package/templates/docker/src/lib/plugins/tools.ts +39 -0
  155. package/templates/docker/src/lib/plugins/wiring.ts +291 -0
  156. package/templates/docker/src/lib/providers.ts +102 -0
  157. package/templates/docker/src/lib/rls.ts +321 -0
  158. package/templates/docker/src/lib/scheduled-task-types.ts +132 -0
  159. package/templates/docker/src/lib/scheduled-tasks.ts +475 -0
  160. package/templates/docker/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
  161. package/templates/docker/src/lib/scheduler/__tests__/engine.test.ts +248 -0
  162. package/templates/docker/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
  163. package/templates/docker/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
  164. package/templates/docker/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
  165. package/templates/docker/src/lib/scheduler/delivery.ts +248 -0
  166. package/templates/docker/src/lib/scheduler/engine.ts +317 -0
  167. package/templates/docker/src/lib/scheduler/executor.ts +73 -0
  168. package/templates/docker/src/lib/scheduler/format-email.ts +109 -0
  169. package/templates/docker/src/lib/scheduler/format-slack.ts +35 -0
  170. package/templates/docker/src/lib/scheduler/format-webhook.ts +37 -0
  171. package/templates/docker/src/lib/scheduler/index.ts +7 -0
  172. package/templates/docker/src/lib/security.ts +11 -0
  173. package/templates/docker/src/lib/semantic-index.ts +503 -0
  174. package/templates/docker/src/lib/semantic.ts +387 -0
  175. package/templates/docker/src/lib/sidecar-types.ts +16 -0
  176. package/templates/docker/src/lib/slack/__tests__/api.test.ts +160 -0
  177. package/templates/docker/src/lib/slack/__tests__/format.test.ts +237 -0
  178. package/templates/docker/src/lib/slack/__tests__/store.test.ts +188 -0
  179. package/templates/docker/src/lib/slack/__tests__/threads.test.ts +112 -0
  180. package/templates/docker/src/lib/slack/__tests__/verify.test.ts +111 -0
  181. package/templates/docker/src/lib/slack/api.ts +102 -0
  182. package/templates/docker/src/lib/slack/format.ts +209 -0
  183. package/templates/docker/src/lib/slack/store.ts +107 -0
  184. package/templates/docker/src/lib/slack/threads.ts +64 -0
  185. package/templates/docker/src/lib/slack/verify.ts +71 -0
  186. package/templates/docker/src/lib/startup.ts +730 -0
  187. package/templates/docker/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
  188. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
  189. package/templates/docker/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
  190. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
  191. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
  192. package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
  193. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
  194. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
  195. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +235 -0
  196. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
  197. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
  198. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
  199. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
  200. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
  201. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
  202. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +1012 -0
  203. package/templates/docker/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
  204. package/templates/docker/src/lib/tools/actions/__tests__/email.test.ts +378 -0
  205. package/templates/docker/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
  206. package/templates/docker/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
  207. package/templates/docker/src/lib/tools/actions/audit.ts +47 -0
  208. package/templates/docker/src/lib/tools/actions/email.ts +191 -0
  209. package/templates/docker/src/lib/tools/actions/handler.ts +591 -0
  210. package/templates/docker/src/lib/tools/actions/index.ts +23 -0
  211. package/templates/docker/src/lib/tools/actions/jira.ts +220 -0
  212. package/templates/docker/src/lib/tools/explore-nsjail.ts +343 -0
  213. package/templates/docker/src/lib/tools/explore-sandbox.ts +264 -0
  214. package/templates/docker/src/lib/tools/explore-sidecar.ts +163 -0
  215. package/templates/docker/src/lib/tools/explore.ts +379 -0
  216. package/templates/docker/src/lib/tools/registry.ts +221 -0
  217. package/templates/docker/src/lib/tools/salesforce.ts +138 -0
  218. package/templates/docker/src/lib/tools/soql-validation.ts +172 -0
  219. package/templates/docker/src/lib/tools/sql.ts +680 -0
  220. package/templates/docker/src/lib/tracing.ts +40 -0
  221. package/templates/docker/src/lib/utils.ts +6 -0
  222. package/templates/docker/src/test-setup.ts +38 -0
  223. package/templates/docker/src/types/vercel-sandbox.d.ts +54 -0
  224. package/templates/docker/src/ui/components/actions/action-approval-card.tsx +295 -0
  225. package/templates/docker/src/ui/components/actions/action-status-badge.tsx +50 -0
  226. package/templates/docker/src/ui/components/admin/admin-layout.tsx +26 -0
  227. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +96 -0
  228. package/templates/docker/src/ui/components/admin/empty-state.tsx +24 -0
  229. package/templates/docker/src/ui/components/admin/entity-detail.tsx +233 -0
  230. package/templates/docker/src/ui/components/admin/entity-list.tsx +96 -0
  231. package/templates/docker/src/ui/components/admin/error-banner.tsx +22 -0
  232. package/templates/docker/src/ui/components/admin/feature-disabled.tsx +44 -0
  233. package/templates/docker/src/ui/components/admin/health-badge.tsx +30 -0
  234. package/templates/docker/src/ui/components/admin/loading-state.tsx +14 -0
  235. package/templates/docker/src/ui/components/admin/stat-card.tsx +32 -0
  236. package/templates/docker/src/ui/components/atlas-chat.tsx +370 -0
  237. package/templates/docker/src/ui/components/chart/chart-detection.ts +261 -0
  238. package/templates/docker/src/ui/components/chart/result-chart.tsx +375 -0
  239. package/templates/docker/src/ui/components/chat/api-key-bar.tsx +66 -0
  240. package/templates/docker/src/ui/components/chat/copy-button.tsx +25 -0
  241. package/templates/docker/src/ui/components/chat/data-table.tsx +102 -0
  242. package/templates/docker/src/ui/components/chat/error-banner.tsx +32 -0
  243. package/templates/docker/src/ui/components/chat/explore-card.tsx +41 -0
  244. package/templates/docker/src/ui/components/chat/loading-card.tsx +10 -0
  245. package/templates/docker/src/ui/components/chat/managed-auth-card.tsx +116 -0
  246. package/templates/docker/src/ui/components/chat/markdown.tsx +72 -0
  247. package/templates/docker/src/ui/components/chat/sql-block.tsx +30 -0
  248. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +144 -0
  249. package/templates/docker/src/ui/components/chat/starter-prompts.ts +6 -0
  250. package/templates/docker/src/ui/components/chat/tool-part.tsx +40 -0
  251. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +19 -0
  252. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +120 -0
  253. package/templates/docker/src/ui/components/conversations/conversation-list.tsx +66 -0
  254. package/templates/docker/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
  255. package/templates/docker/src/ui/components/conversations/delete-confirmation.tsx +27 -0
  256. package/templates/docker/src/ui/context.tsx +78 -0
  257. package/templates/docker/src/ui/hooks/use-admin-fetch.ts +104 -0
  258. package/templates/docker/src/ui/hooks/use-conversations.ts +184 -0
  259. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -0
  260. package/templates/docker/src/ui/lib/action-types.ts +63 -0
  261. package/templates/docker/src/ui/lib/helpers.ts +104 -0
  262. package/templates/docker/src/ui/lib/types.ts +145 -0
  263. package/templates/docker/tsconfig.json +41 -0
  264. package/templates/docker/vercel.json +3 -0
  265. package/templates/nextjs-standalone/.env.example +68 -0
  266. package/templates/nextjs-standalone/bin/__tests__/benchmark.test.ts +598 -0
  267. package/templates/nextjs-standalone/bin/__tests__/duckdb-ingest.test.ts +171 -0
  268. package/templates/nextjs-standalone/bin/__tests__/eval.test.ts +434 -0
  269. package/templates/nextjs-standalone/bin/__tests__/matview-partition.test.ts +615 -0
  270. package/templates/nextjs-standalone/bin/__tests__/multi-source.test.ts +113 -0
  271. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +322 -0
  272. package/templates/nextjs-standalone/bin/__tests__/profiler-heuristics.test.ts +608 -0
  273. package/templates/nextjs-standalone/bin/__tests__/query.test.ts +240 -0
  274. package/templates/nextjs-standalone/bin/__tests__/schema-drift.test.ts +542 -0
  275. package/templates/nextjs-standalone/bin/__tests__/view-yaml-generation.test.ts +146 -0
  276. package/templates/nextjs-standalone/bin/atlas.ts +5044 -0
  277. package/templates/nextjs-standalone/bin/benchmark.ts +695 -0
  278. package/templates/nextjs-standalone/bin/enrich.ts +559 -0
  279. package/templates/nextjs-standalone/bin/eval.ts +770 -0
  280. package/templates/nextjs-standalone/bin/smoke.ts +438 -0
  281. package/templates/nextjs-standalone/data/.gitkeep +0 -0
  282. package/templates/nextjs-standalone/data/cybersec.sql +1961 -0
  283. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +40 -0
  284. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +170 -0
  285. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +207 -0
  286. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +145 -0
  287. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +22 -0
  288. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +38 -0
  289. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +89 -0
  290. package/templates/nextjs-standalone/data/demo.sql +373 -0
  291. package/templates/nextjs-standalone/data/ecommerce.sql +1690 -0
  292. package/templates/nextjs-standalone/data/init-demo-db.sql +8 -0
  293. package/templates/nextjs-standalone/docs/deploy.md +390 -0
  294. package/templates/nextjs-standalone/eslint.config.mjs +18 -0
  295. package/templates/nextjs-standalone/gitignore +5 -0
  296. package/templates/nextjs-standalone/next.config.ts +10 -0
  297. package/templates/nextjs-standalone/package.json +63 -0
  298. package/templates/nextjs-standalone/postcss.config.mjs +8 -0
  299. package/templates/nextjs-standalone/semantic/catalog.yml +5 -0
  300. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  301. package/templates/nextjs-standalone/semantic/glossary.yml +6 -0
  302. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  303. package/templates/nextjs-standalone/src/api/__tests__/actions.test.ts +683 -0
  304. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +820 -0
  305. package/templates/nextjs-standalone/src/api/__tests__/auth.test.ts +165 -0
  306. package/templates/nextjs-standalone/src/api/__tests__/chat.test.ts +376 -0
  307. package/templates/nextjs-standalone/src/api/__tests__/conversations.test.ts +555 -0
  308. package/templates/nextjs-standalone/src/api/__tests__/cors.test.ts +135 -0
  309. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +169 -0
  310. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +261 -0
  311. package/templates/nextjs-standalone/src/api/__tests__/query.test.ts +891 -0
  312. package/templates/nextjs-standalone/src/api/__tests__/scheduled-tasks.test.ts +601 -0
  313. package/templates/nextjs-standalone/src/api/__tests__/slack.test.ts +847 -0
  314. package/templates/nextjs-standalone/src/api/index.ts +117 -0
  315. package/templates/nextjs-standalone/src/api/routes/actions.ts +274 -0
  316. package/templates/nextjs-standalone/src/api/routes/admin.ts +757 -0
  317. package/templates/nextjs-standalone/src/api/routes/auth.ts +48 -0
  318. package/templates/nextjs-standalone/src/api/routes/chat.ts +465 -0
  319. package/templates/nextjs-standalone/src/api/routes/conversations.ts +266 -0
  320. package/templates/nextjs-standalone/src/api/routes/health.ts +287 -0
  321. package/templates/nextjs-standalone/src/api/routes/openapi.ts +390 -0
  322. package/templates/nextjs-standalone/src/api/routes/query.ts +318 -0
  323. package/templates/nextjs-standalone/src/api/routes/scheduled-tasks.ts +467 -0
  324. package/templates/nextjs-standalone/src/api/routes/slack.ts +611 -0
  325. package/templates/nextjs-standalone/src/api/server.ts +226 -0
  326. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +33 -0
  327. package/templates/nextjs-standalone/src/app/error.tsx +24 -0
  328. package/templates/nextjs-standalone/src/app/global-error.tsx +68 -0
  329. package/templates/nextjs-standalone/src/app/globals.css +126 -0
  330. package/templates/nextjs-standalone/src/app/layout.tsx +19 -0
  331. package/templates/nextjs-standalone/src/app/page.tsx +14 -0
  332. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +437 -0
  333. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +114 -0
  334. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +164 -0
  335. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +514 -0
  336. package/templates/nextjs-standalone/src/lib/__tests__/config-actions.test.ts +166 -0
  337. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +1063 -0
  338. package/templates/nextjs-standalone/src/lib/__tests__/conversations.test.ts +589 -0
  339. package/templates/nextjs-standalone/src/lib/__tests__/errors.test.ts +256 -0
  340. package/templates/nextjs-standalone/src/lib/__tests__/logger.test.ts +200 -0
  341. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +99 -0
  342. package/templates/nextjs-standalone/src/lib/__tests__/rls.test.ts +435 -0
  343. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-task-types.test.ts +124 -0
  344. package/templates/nextjs-standalone/src/lib/__tests__/scheduled-tasks.test.ts +550 -0
  345. package/templates/nextjs-standalone/src/lib/__tests__/semantic-index.test.ts +547 -0
  346. package/templates/nextjs-standalone/src/lib/__tests__/semantic-multisource.test.ts +544 -0
  347. package/templates/nextjs-standalone/src/lib/__tests__/semantic.test.ts +363 -0
  348. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +452 -0
  349. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +465 -0
  350. package/templates/nextjs-standalone/src/lib/__tests__/tracing.test.ts +28 -0
  351. package/templates/nextjs-standalone/src/lib/action-types.ts +95 -0
  352. package/templates/nextjs-standalone/src/lib/agent-query.ts +178 -0
  353. package/templates/nextjs-standalone/src/lib/agent.ts +505 -0
  354. package/templates/nextjs-standalone/src/lib/api-url.ts +3 -0
  355. package/templates/nextjs-standalone/src/lib/auth/__tests__/audit.test.ts +418 -0
  356. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot-integration.test.ts +222 -0
  357. package/templates/nextjs-standalone/src/lib/auth/__tests__/byot.test.ts +366 -0
  358. package/templates/nextjs-standalone/src/lib/auth/__tests__/detect.test.ts +190 -0
  359. package/templates/nextjs-standalone/src/lib/auth/__tests__/managed.test.ts +173 -0
  360. package/templates/nextjs-standalone/src/lib/auth/__tests__/middleware.test.ts +456 -0
  361. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +201 -0
  362. package/templates/nextjs-standalone/src/lib/auth/__tests__/permissions.test.ts +225 -0
  363. package/templates/nextjs-standalone/src/lib/auth/__tests__/server.test.ts +34 -0
  364. package/templates/nextjs-standalone/src/lib/auth/__tests__/simple-key.test.ts +176 -0
  365. package/templates/nextjs-standalone/src/lib/auth/__tests__/types.test.ts +44 -0
  366. package/templates/nextjs-standalone/src/lib/auth/audit.ts +89 -0
  367. package/templates/nextjs-standalone/src/lib/auth/byot.ts +158 -0
  368. package/templates/nextjs-standalone/src/lib/auth/client.ts +23 -0
  369. package/templates/nextjs-standalone/src/lib/auth/detect.ts +83 -0
  370. package/templates/nextjs-standalone/src/lib/auth/managed.ts +73 -0
  371. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +208 -0
  372. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +111 -0
  373. package/templates/nextjs-standalone/src/lib/auth/permissions.ts +156 -0
  374. package/templates/nextjs-standalone/src/lib/auth/server.ts +142 -0
  375. package/templates/nextjs-standalone/src/lib/auth/simple-key.ts +92 -0
  376. package/templates/nextjs-standalone/src/lib/auth/types.ts +49 -0
  377. package/templates/nextjs-standalone/src/lib/config.ts +704 -0
  378. package/templates/nextjs-standalone/src/lib/conversation-types.ts +29 -0
  379. package/templates/nextjs-standalone/src/lib/conversations.ts +270 -0
  380. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +69 -0
  381. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +141 -0
  382. package/templates/nextjs-standalone/src/lib/db/__tests__/internal.test.ts +387 -0
  383. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +207 -0
  384. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +156 -0
  385. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +595 -0
  386. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +339 -0
  387. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +217 -0
  388. package/templates/nextjs-standalone/src/lib/db/__tests__/source-rate-limit.test.ts +130 -0
  389. package/templates/nextjs-standalone/src/lib/db/connection.ts +753 -0
  390. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +122 -0
  391. package/templates/nextjs-standalone/src/lib/db/internal.ts +273 -0
  392. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +342 -0
  393. package/templates/nextjs-standalone/src/lib/db/source-rate-limit.ts +191 -0
  394. package/templates/nextjs-standalone/src/lib/errors.ts +154 -0
  395. package/templates/nextjs-standalone/src/lib/logger.ts +98 -0
  396. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +202 -0
  397. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +529 -0
  398. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +521 -0
  399. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +346 -0
  400. package/templates/nextjs-standalone/src/lib/plugins/__tests__/tools.test.ts +49 -0
  401. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +585 -0
  402. package/templates/nextjs-standalone/src/lib/plugins/hooks.ts +162 -0
  403. package/templates/nextjs-standalone/src/lib/plugins/index.ts +9 -0
  404. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +309 -0
  405. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +231 -0
  406. package/templates/nextjs-standalone/src/lib/plugins/tools.ts +39 -0
  407. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +291 -0
  408. package/templates/nextjs-standalone/src/lib/providers.ts +102 -0
  409. package/templates/nextjs-standalone/src/lib/rls.ts +321 -0
  410. package/templates/nextjs-standalone/src/lib/scheduled-task-types.ts +132 -0
  411. package/templates/nextjs-standalone/src/lib/scheduled-tasks.ts +475 -0
  412. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/delivery.test.ts +192 -0
  413. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/engine.test.ts +248 -0
  414. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-email.test.ts +96 -0
  415. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-slack.test.ts +78 -0
  416. package/templates/nextjs-standalone/src/lib/scheduler/__tests__/format-webhook.test.ts +78 -0
  417. package/templates/nextjs-standalone/src/lib/scheduler/delivery.ts +248 -0
  418. package/templates/nextjs-standalone/src/lib/scheduler/engine.ts +317 -0
  419. package/templates/nextjs-standalone/src/lib/scheduler/executor.ts +73 -0
  420. package/templates/nextjs-standalone/src/lib/scheduler/format-email.ts +109 -0
  421. package/templates/nextjs-standalone/src/lib/scheduler/format-slack.ts +35 -0
  422. package/templates/nextjs-standalone/src/lib/scheduler/format-webhook.ts +37 -0
  423. package/templates/nextjs-standalone/src/lib/scheduler/index.ts +7 -0
  424. package/templates/nextjs-standalone/src/lib/security.ts +11 -0
  425. package/templates/nextjs-standalone/src/lib/semantic-index.ts +503 -0
  426. package/templates/nextjs-standalone/src/lib/semantic.ts +387 -0
  427. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +16 -0
  428. package/templates/nextjs-standalone/src/lib/slack/__tests__/api.test.ts +160 -0
  429. package/templates/nextjs-standalone/src/lib/slack/__tests__/format.test.ts +237 -0
  430. package/templates/nextjs-standalone/src/lib/slack/__tests__/store.test.ts +188 -0
  431. package/templates/nextjs-standalone/src/lib/slack/__tests__/threads.test.ts +112 -0
  432. package/templates/nextjs-standalone/src/lib/slack/__tests__/verify.test.ts +111 -0
  433. package/templates/nextjs-standalone/src/lib/slack/api.ts +102 -0
  434. package/templates/nextjs-standalone/src/lib/slack/format.ts +209 -0
  435. package/templates/nextjs-standalone/src/lib/slack/store.ts +107 -0
  436. package/templates/nextjs-standalone/src/lib/slack/threads.ts +64 -0
  437. package/templates/nextjs-standalone/src/lib/slack/verify.ts +71 -0
  438. package/templates/nextjs-standalone/src/lib/startup.ts +730 -0
  439. package/templates/nextjs-standalone/src/lib/tools/__tests__/action-permissions.test.ts +594 -0
  440. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +238 -0
  441. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-backend.test.ts +267 -0
  442. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +492 -0
  443. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +374 -0
  444. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +82 -0
  445. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +208 -0
  446. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +144 -0
  447. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +235 -0
  448. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +154 -0
  449. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +303 -0
  450. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +225 -0
  451. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +98 -0
  452. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +233 -0
  453. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +225 -0
  454. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +1012 -0
  455. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/audit.test.ts +211 -0
  456. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/email.test.ts +378 -0
  457. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/handler.test.ts +681 -0
  458. package/templates/nextjs-standalone/src/lib/tools/actions/__tests__/jira.test.ts +427 -0
  459. package/templates/nextjs-standalone/src/lib/tools/actions/audit.ts +47 -0
  460. package/templates/nextjs-standalone/src/lib/tools/actions/email.ts +191 -0
  461. package/templates/nextjs-standalone/src/lib/tools/actions/handler.ts +591 -0
  462. package/templates/nextjs-standalone/src/lib/tools/actions/index.ts +23 -0
  463. package/templates/nextjs-standalone/src/lib/tools/actions/jira.ts +220 -0
  464. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +343 -0
  465. package/templates/nextjs-standalone/src/lib/tools/explore-sandbox.ts +264 -0
  466. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +163 -0
  467. package/templates/nextjs-standalone/src/lib/tools/explore.ts +379 -0
  468. package/templates/nextjs-standalone/src/lib/tools/registry.ts +221 -0
  469. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +138 -0
  470. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +172 -0
  471. package/templates/nextjs-standalone/src/lib/tools/sql.ts +680 -0
  472. package/templates/nextjs-standalone/src/lib/tracing.ts +40 -0
  473. package/templates/nextjs-standalone/src/lib/utils.ts +6 -0
  474. package/templates/nextjs-standalone/src/test-setup.ts +38 -0
  475. package/templates/nextjs-standalone/src/ui/components/actions/action-approval-card.tsx +295 -0
  476. package/templates/nextjs-standalone/src/ui/components/actions/action-status-badge.tsx +50 -0
  477. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +26 -0
  478. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +96 -0
  479. package/templates/nextjs-standalone/src/ui/components/admin/empty-state.tsx +24 -0
  480. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +233 -0
  481. package/templates/nextjs-standalone/src/ui/components/admin/entity-list.tsx +96 -0
  482. package/templates/nextjs-standalone/src/ui/components/admin/error-banner.tsx +22 -0
  483. package/templates/nextjs-standalone/src/ui/components/admin/feature-disabled.tsx +44 -0
  484. package/templates/nextjs-standalone/src/ui/components/admin/health-badge.tsx +30 -0
  485. package/templates/nextjs-standalone/src/ui/components/admin/loading-state.tsx +14 -0
  486. package/templates/nextjs-standalone/src/ui/components/admin/stat-card.tsx +32 -0
  487. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +370 -0
  488. package/templates/nextjs-standalone/src/ui/components/chart/chart-detection.ts +261 -0
  489. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +375 -0
  490. package/templates/nextjs-standalone/src/ui/components/chat/api-key-bar.tsx +66 -0
  491. package/templates/nextjs-standalone/src/ui/components/chat/copy-button.tsx +25 -0
  492. package/templates/nextjs-standalone/src/ui/components/chat/data-table.tsx +102 -0
  493. package/templates/nextjs-standalone/src/ui/components/chat/error-banner.tsx +32 -0
  494. package/templates/nextjs-standalone/src/ui/components/chat/explore-card.tsx +41 -0
  495. package/templates/nextjs-standalone/src/ui/components/chat/loading-card.tsx +10 -0
  496. package/templates/nextjs-standalone/src/ui/components/chat/managed-auth-card.tsx +116 -0
  497. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +72 -0
  498. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +30 -0
  499. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +144 -0
  500. package/templates/nextjs-standalone/src/ui/components/chat/starter-prompts.ts +6 -0
  501. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +40 -0
  502. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +19 -0
  503. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +120 -0
  504. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-list.tsx +66 -0
  505. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-sidebar.tsx +78 -0
  506. package/templates/nextjs-standalone/src/ui/components/conversations/delete-confirmation.tsx +27 -0
  507. package/templates/nextjs-standalone/src/ui/context.tsx +78 -0
  508. package/templates/nextjs-standalone/src/ui/hooks/use-admin-fetch.ts +104 -0
  509. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +184 -0
  510. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -0
  511. package/templates/nextjs-standalone/src/ui/lib/action-types.ts +63 -0
  512. package/templates/nextjs-standalone/src/ui/lib/helpers.ts +104 -0
  513. package/templates/nextjs-standalone/src/ui/lib/types.ts +145 -0
  514. package/templates/nextjs-standalone/tsconfig.json +32 -0
  515. package/templates/nextjs-standalone/vercel.json +4 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Email formatter for scheduled task results.
3
+ *
4
+ * Produces inline-styled HTML suitable for email clients (no external CSS).
5
+ */
6
+
7
+ import type { ScheduledTask } from "@atlas/api/lib/scheduled-tasks";
8
+ import type { AgentQueryResult } from "@atlas/api/lib/agent-query";
9
+
10
+ const MAX_DATA_ROWS = 50;
11
+
12
+ export function formatEmailReport(
13
+ task: ScheduledTask,
14
+ result: AgentQueryResult,
15
+ ): { subject: string; body: string } {
16
+ const subject = `Atlas Report: ${task.name}`;
17
+
18
+ const sections: string[] = [];
19
+
20
+ // Header
21
+ sections.push(`
22
+ <div style="background:#f8f9fa;padding:16px 24px;border-bottom:2px solid #e9ecef;">
23
+ <h2 style="margin:0;color:#212529;font-size:20px;">${escapeHtml(task.name)}</h2>
24
+ <p style="margin:4px 0 0;color:#6c757d;font-size:14px;">Question: ${escapeHtml(task.question)}</p>
25
+ </div>
26
+ `);
27
+
28
+ // Answer
29
+ const answer = result.answer || "No answer generated.";
30
+ sections.push(`
31
+ <div style="padding:16px 24px;">
32
+ <h3 style="margin:0 0 8px;color:#495057;font-size:16px;">Answer</h3>
33
+ <p style="margin:0;color:#212529;font-size:14px;line-height:1.6;white-space:pre-wrap;">${escapeHtml(answer)}</p>
34
+ </div>
35
+ `);
36
+
37
+ // Data tables
38
+ for (const dataset of result.data) {
39
+ if (!dataset.columns.length || !dataset.rows.length) continue;
40
+
41
+ const displayRows = dataset.rows.slice(0, MAX_DATA_ROWS);
42
+ const truncated = dataset.rows.length > MAX_DATA_ROWS;
43
+
44
+ const headerCells = dataset.columns
45
+ .map((col) => `<th style="padding:8px 12px;text-align:left;border-bottom:2px solid #dee2e6;background:#f8f9fa;font-size:12px;color:#495057;">${escapeHtml(col)}</th>`)
46
+ .join("");
47
+
48
+ const bodyRows = displayRows
49
+ .map((row) => {
50
+ const cells = dataset.columns
51
+ .map((col) => `<td style="padding:6px 12px;border-bottom:1px solid #e9ecef;font-size:13px;color:#212529;">${escapeHtml(String(row[col] ?? ""))}</td>`)
52
+ .join("");
53
+ return `<tr>${cells}</tr>`;
54
+ })
55
+ .join("");
56
+
57
+ let tableHtml = `
58
+ <div style="padding:0 24px 16px;">
59
+ <table style="border-collapse:collapse;width:100%;font-family:monospace;">
60
+ <thead><tr>${headerCells}</tr></thead>
61
+ <tbody>${bodyRows}</tbody>
62
+ </table>
63
+ `;
64
+ if (truncated) {
65
+ tableHtml += `<p style="margin:4px 0 0;color:#6c757d;font-size:12px;">Showing first ${MAX_DATA_ROWS} of ${dataset.rows.length} rows</p>`;
66
+ }
67
+ tableHtml += `</div>`;
68
+ sections.push(tableHtml);
69
+ }
70
+
71
+ // SQL
72
+ if (result.sql.length > 0) {
73
+ const sqlText = result.sql.join("\n\n");
74
+ sections.push(`
75
+ <div style="padding:0 24px 16px;">
76
+ <h3 style="margin:0 0 8px;color:#495057;font-size:14px;">SQL</h3>
77
+ <pre style="background:#f1f3f5;padding:12px;border-radius:4px;overflow-x:auto;font-size:12px;color:#495057;margin:0;">${escapeHtml(sqlText)}</pre>
78
+ </div>
79
+ `);
80
+ }
81
+
82
+ // Footer
83
+ sections.push(`
84
+ <div style="border-top:1px solid #e9ecef;padding:12px 24px;color:#adb5bd;font-size:12px;">
85
+ ${result.steps} steps &middot; ${result.usage.totalTokens.toLocaleString()} tokens &middot; ${new Date().toISOString()}
86
+ </div>
87
+ `);
88
+
89
+ const body = `
90
+ <!DOCTYPE html>
91
+ <html>
92
+ <body style="margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#ffffff;">
93
+ <div style="max-width:700px;margin:0 auto;border:1px solid #e9ecef;border-radius:8px;overflow:hidden;">
94
+ ${sections.join("")}
95
+ </div>
96
+ </body>
97
+ </html>
98
+ `;
99
+
100
+ return { subject, body };
101
+ }
102
+
103
+ function escapeHtml(text: string): string {
104
+ return text
105
+ .replace(/&/g, "&amp;")
106
+ .replace(/</g, "&lt;")
107
+ .replace(/>/g, "&gt;")
108
+ .replace(/"/g, "&quot;");
109
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Slack formatter for scheduled task results.
3
+ *
4
+ * Reuses formatQueryResponse() from the Slack module and prepends a header
5
+ * block with the task name and question.
6
+ */
7
+
8
+ import type { ScheduledTask } from "@atlas/api/lib/scheduled-tasks";
9
+ import type { AgentQueryResult } from "@atlas/api/lib/agent-query";
10
+ import { formatQueryResponse, type SlackBlock } from "@atlas/api/lib/slack/format";
11
+
12
+ export function formatSlackReport(
13
+ task: ScheduledTask,
14
+ result: AgentQueryResult,
15
+ ): { text: string; blocks: SlackBlock[] } {
16
+ const headerBlock: SlackBlock = {
17
+ type: "section",
18
+ text: {
19
+ type: "mrkdwn",
20
+ text: `:chart_with_upwards_trend: *${task.name}*\n_${truncate(task.question, 200)}_`,
21
+ },
22
+ };
23
+
24
+ const resultBlocks = formatQueryResponse(result);
25
+
26
+ return {
27
+ text: `Atlas Report: ${task.name} — ${truncate(result.answer || "No answer", 100)}`,
28
+ blocks: [headerBlock, ...resultBlocks],
29
+ };
30
+ }
31
+
32
+ function truncate(text: string, maxLength: number): string {
33
+ if (text.length <= maxLength) return text;
34
+ return text.slice(0, maxLength - 3) + "...";
35
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Webhook formatter for scheduled task results.
3
+ *
4
+ * Produces a structured JSON payload with all query data.
5
+ */
6
+
7
+ import type { ScheduledTask } from "@atlas/api/lib/scheduled-tasks";
8
+ import type { AgentQueryResult } from "@atlas/api/lib/agent-query";
9
+
10
+ export interface WebhookPayload {
11
+ taskId: string;
12
+ taskName: string;
13
+ question: string;
14
+ answer: string;
15
+ sql: string[];
16
+ data: { columns: string[]; rows: Record<string, unknown>[] }[];
17
+ steps: number;
18
+ usage: { totalTokens: number };
19
+ timestamp: string;
20
+ }
21
+
22
+ export function formatWebhookPayload(
23
+ task: ScheduledTask,
24
+ result: AgentQueryResult,
25
+ ): WebhookPayload {
26
+ return {
27
+ taskId: task.id,
28
+ taskName: task.name,
29
+ question: task.question,
30
+ answer: result.answer || "",
31
+ sql: result.sql,
32
+ data: result.data,
33
+ steps: result.steps,
34
+ usage: result.usage,
35
+ timestamp: new Date().toISOString(),
36
+ };
37
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Scheduler barrel — re-exports for clean imports.
3
+ */
4
+
5
+ export { getScheduler, triggerTask, runTick, _resetScheduler, type TickResult } from "./engine";
6
+ export { executeScheduledTask, type ExecutionResult } from "./executor";
7
+ export { deliverResult, type DeliverySummary } from "./delivery";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared sensitive-pattern regex.
3
+ *
4
+ * Used by both the SQL tool (to scrub error messages before returning
5
+ * them to the agent) and the audit logger (to scrub error strings before
6
+ * persisting them). Keeping a single source of truth prevents the two
7
+ * lists from drifting apart.
8
+ */
9
+
10
+ export const SENSITIVE_PATTERNS =
11
+ /password|secret|credential|connection.?string|pg_hba\.conf|SSL|certificate|Access denied for user|ER_ACCESS_DENIED_ERROR|ER_DBACCESS_DENIED_ERROR|ER_BAD_HOST_ERROR|ER_HOST_NOT_PRIVILEGED|ER_SPECIFIC_ACCESS_DENIED_ERROR|PROTOCOL_CONNECTION_LOST|Can't connect to MySQL server|Authentication failed|DB::Exception.*Authentication|UNKNOWN_USER|WRONG_PASSWORD|REQUIRED_PASSWORD|IP_ADDRESS_NOT_ALLOWED|ALL_CONNECTION_TRIES_FAILED|CLIENT_HAS_CONNECTED_TO_WRONG_PORT|AUTHENTICATION_FAILED|INVALID_SESSION_ID|LOGIN_MUST_USE_SECURITY_TOKEN|INVALID_LOGIN|INVALID_CLIENT_ID/i;
@@ -0,0 +1,503 @@
1
+ /**
2
+ * Pre-indexed semantic layer summary.
3
+ *
4
+ * Reads all entity YAMLs, metrics YAMLs, catalog, and glossary at boot
5
+ * (or on cache invalidation) and builds a compressed text summary that
6
+ * the agent can use without calling the explore tool.
7
+ *
8
+ * Two modes based on entity count:
9
+ * - Small (< 20 entities): full column details in prompt
10
+ * - Large (20+ entities): table-level summaries only
11
+ */
12
+
13
+ import * as fs from "fs";
14
+ import * as path from "path";
15
+ import * as yaml from "js-yaml";
16
+ import { createLogger } from "@atlas/api/lib/logger";
17
+
18
+ const log = createLogger("semantic-index");
19
+
20
+ /** Threshold: layers with fewer entities get full column detail. */
21
+ const SMALL_LAYER_THRESHOLD = 20;
22
+
23
+ /** Approximate characters per token (conservative estimate for English). */
24
+ const CHARS_PER_TOKEN = 4;
25
+
26
+ // --- Types for parsed YAML ---
27
+
28
+ interface EntityDimension {
29
+ name?: string;
30
+ sql?: string;
31
+ type?: string;
32
+ description?: string;
33
+ sample_values?: unknown[];
34
+ primary_key?: boolean;
35
+ }
36
+
37
+ interface EntityMeasure {
38
+ name?: string;
39
+ sql?: string;
40
+ type?: string;
41
+ description?: string;
42
+ aggregation?: string;
43
+ }
44
+
45
+ interface EntityJoin {
46
+ target_entity?: string;
47
+ relationship?: string;
48
+ description?: string;
49
+ join_columns?: Record<string, string>;
50
+ }
51
+
52
+ interface EntityQueryPattern {
53
+ name?: string;
54
+ description?: string;
55
+ sql?: string;
56
+ }
57
+
58
+ interface ParsedEntity {
59
+ name?: string;
60
+ table: string;
61
+ type?: string;
62
+ connection?: string;
63
+ grain?: string;
64
+ description?: string;
65
+ dimensions?: EntityDimension[];
66
+ measures?: EntityMeasure[];
67
+ joins?: EntityJoin[];
68
+ query_patterns?: EntityQueryPattern[];
69
+ }
70
+
71
+ interface ParsedMetric {
72
+ name?: string;
73
+ description?: string;
74
+ sql?: string;
75
+ type?: string;
76
+ entity?: string;
77
+ aggregation?: string;
78
+ unit?: string;
79
+ }
80
+
81
+ interface GlossaryTerm {
82
+ term?: string;
83
+ definition?: string;
84
+ status?: string;
85
+ disambiguation?: string;
86
+ }
87
+
88
+ interface CatalogEntry {
89
+ name?: string;
90
+ description?: string;
91
+ use_for?: string[];
92
+ common_questions?: string[];
93
+ }
94
+
95
+ interface ParsedCatalog {
96
+ version?: string;
97
+ entities?: CatalogEntry[];
98
+ }
99
+
100
+ // --- Index cache ---
101
+
102
+ let _cachedIndex: string | null = null;
103
+ let _cachedEntityCount = 0;
104
+
105
+ /**
106
+ * Build or retrieve the cached semantic index.
107
+ *
108
+ * @param semanticRoot - Override for the semantic root directory (DI for tests).
109
+ */
110
+ export function getSemanticIndex(semanticRoot?: string): string {
111
+ if (_cachedIndex !== null) return _cachedIndex;
112
+
113
+ const root = semanticRoot ?? path.resolve(process.cwd(), "semantic");
114
+ _cachedIndex = buildSemanticIndex(root);
115
+ return _cachedIndex;
116
+ }
117
+
118
+ /** Returns the entity count from the last index build. */
119
+ export function getIndexedEntityCount(): number {
120
+ return _cachedEntityCount;
121
+ }
122
+
123
+ /** Clear the cached index (called on semantic layer changes). */
124
+ export function invalidateSemanticIndex(): void {
125
+ _cachedIndex = null;
126
+ _cachedEntityCount = 0;
127
+ }
128
+
129
+ /**
130
+ * Build a compressed text summary of the entire semantic layer.
131
+ */
132
+ export function buildSemanticIndex(semanticRoot: string): string {
133
+ const entities = loadEntities(semanticRoot);
134
+ const metrics = loadMetrics(semanticRoot);
135
+ const glossary = loadGlossary(semanticRoot);
136
+ const catalog = loadCatalog(semanticRoot);
137
+
138
+ _cachedEntityCount = entities.length;
139
+
140
+ if (entities.length === 0) {
141
+ log.info("No entities found — semantic index is empty");
142
+ return "";
143
+ }
144
+
145
+ const isSmall = entities.length < SMALL_LAYER_THRESHOLD;
146
+ const mode = isSmall ? "full" : "summary";
147
+
148
+ const sections: string[] = [];
149
+
150
+ // Header
151
+ sections.push(
152
+ `## Semantic Layer Reference (${entities.length} entities, mode: ${mode})`,
153
+ );
154
+
155
+ // Entity summaries
156
+ sections.push("");
157
+ sections.push("### Tables & Columns");
158
+ for (const entity of entities) {
159
+ sections.push("");
160
+ sections.push(formatEntity(entity, isSmall, catalog));
161
+ }
162
+
163
+ // Metrics
164
+ if (metrics.length > 0) {
165
+ sections.push("");
166
+ sections.push("### Metrics");
167
+ for (const metric of metrics) {
168
+ sections.push(formatMetric(metric));
169
+ }
170
+ }
171
+
172
+ // Glossary (always include — important for disambiguation)
173
+ if (glossary.length > 0) {
174
+ sections.push("");
175
+ sections.push("### Glossary");
176
+ for (const term of glossary) {
177
+ sections.push(formatGlossaryTerm(term));
178
+ }
179
+ }
180
+
181
+ const index = sections.join("\n");
182
+
183
+ const tokenEstimate = Math.ceil(index.length / CHARS_PER_TOKEN);
184
+ log.info(
185
+ {
186
+ entityCount: entities.length,
187
+ metricCount: metrics.length,
188
+ glossaryTermCount: glossary.length,
189
+ indexChars: index.length,
190
+ tokenEstimate,
191
+ mode,
192
+ },
193
+ "Semantic index built (%d entities, ~%dk tokens)",
194
+ entities.length,
195
+ Math.round(tokenEstimate / 1000),
196
+ );
197
+
198
+ return index;
199
+ }
200
+
201
+ // --- Formatters ---
202
+
203
+ function formatEntity(
204
+ entity: ParsedEntity,
205
+ full: boolean,
206
+ catalog: ParsedCatalog | null,
207
+ ): string {
208
+ const lines: string[] = [];
209
+ const conn = entity.connection ? ` [${entity.connection}]` : "";
210
+ const entityType = entity.type ? ` (${entity.type})` : "";
211
+
212
+ lines.push(`**${entity.table}**${entityType}${conn}`);
213
+
214
+ if (entity.description) {
215
+ // Truncate long descriptions
216
+ const desc =
217
+ entity.description.length > 200
218
+ ? entity.description.slice(0, 197) + "..."
219
+ : entity.description;
220
+ lines.push(desc);
221
+ }
222
+
223
+ if (entity.grain) {
224
+ lines.push(`Grain: ${entity.grain}`);
225
+ }
226
+
227
+ // Catalog use_for hints
228
+ const catalogEntry = catalog?.entities?.find(
229
+ (e) => e.name === entity.name || e.name === entity.table,
230
+ );
231
+ if (catalogEntry?.use_for && catalogEntry.use_for.length > 0) {
232
+ lines.push(`Use for: ${catalogEntry.use_for.join("; ")}`);
233
+ }
234
+
235
+ if (full) {
236
+ // Full mode: list all columns with types
237
+ if (entity.dimensions && entity.dimensions.length > 0) {
238
+ lines.push("Columns:");
239
+ for (const dim of entity.dimensions) {
240
+ const name = dim.name ?? dim.sql ?? "?";
241
+ const type = dim.type ?? "unknown";
242
+ const pk = dim.primary_key ? " PK" : "";
243
+ const desc = dim.description ? ` — ${dim.description}` : "";
244
+ lines.push(` - ${name} (${type}${pk})${desc}`);
245
+ }
246
+ }
247
+
248
+ // Measures
249
+ if (entity.measures && entity.measures.length > 0) {
250
+ lines.push("Measures:");
251
+ for (const m of entity.measures) {
252
+ const name = m.name ?? "?";
253
+ const agg = m.aggregation ?? m.type ?? "";
254
+ const desc = m.description ? ` — ${m.description}` : "";
255
+ lines.push(` - ${name} [${agg}]${desc}`);
256
+ }
257
+ }
258
+
259
+ // Joins
260
+ if (entity.joins && entity.joins.length > 0) {
261
+ lines.push("Joins:");
262
+ for (const j of entity.joins) {
263
+ const target = j.target_entity ?? "?";
264
+ const rel = j.relationship ?? "?";
265
+ lines.push(` - → ${target} (${rel})`);
266
+ }
267
+ }
268
+
269
+ // Query patterns (just names — agent can explore for full SQL)
270
+ if (entity.query_patterns && entity.query_patterns.length > 0) {
271
+ const patternNames = entity.query_patterns
272
+ .map((p) => p.name ?? p.description)
273
+ .filter(Boolean);
274
+ if (patternNames.length > 0) {
275
+ lines.push(`Query patterns: ${patternNames.join(", ")}`);
276
+ }
277
+ }
278
+ } else {
279
+ // Summary mode: column count + key columns only
280
+ const dims = entity.dimensions ?? [];
281
+ const pks = dims.filter((d) => d.primary_key);
282
+ const colCount = dims.length;
283
+ const measureCount = entity.measures?.length ?? 0;
284
+ const joinCount = entity.joins?.length ?? 0;
285
+
286
+ const parts: string[] = [`${colCount} columns`];
287
+ if (pks.length > 0)
288
+ parts.push(`PK: ${pks.map((p) => p.name ?? p.sql).join(", ")}`);
289
+ if (measureCount > 0) parts.push(`${measureCount} measures`);
290
+ if (joinCount > 0)
291
+ parts.push(
292
+ `joins: ${entity.joins!.map((j) => j.target_entity).join(", ")}`,
293
+ );
294
+ lines.push(parts.join(" | "));
295
+ }
296
+
297
+ return lines.join("\n");
298
+ }
299
+
300
+ function formatMetric(metric: ParsedMetric): string {
301
+ const name = metric.name ?? "unnamed";
302
+ const desc = metric.description ? ` — ${metric.description}` : "";
303
+ const entity = metric.entity ? ` (${metric.entity})` : "";
304
+ return `- **${name}**${entity}${desc}`;
305
+ }
306
+
307
+ function formatGlossaryTerm(term: GlossaryTerm): string {
308
+ const name = term.term ?? "?";
309
+ const status = term.status === "ambiguous" ? " **[AMBIGUOUS]**" : "";
310
+ const def = term.definition ? `: ${term.definition}` : "";
311
+ const disambig = term.disambiguation
312
+ ? ` → ${term.disambiguation}`
313
+ : "";
314
+ return `- **${name}**${status}${def}${disambig}`;
315
+ }
316
+
317
+ // --- Loaders ---
318
+
319
+ function loadEntities(semanticRoot: string): ParsedEntity[] {
320
+ const entities: ParsedEntity[] = [];
321
+
322
+ // Default entities
323
+ loadEntitiesFromDir(path.join(semanticRoot, "entities"), entities);
324
+
325
+ // Per-source subdirectories
326
+ if (fs.existsSync(semanticRoot)) {
327
+ let entries: fs.Dirent[];
328
+ try {
329
+ entries = fs.readdirSync(semanticRoot, { withFileTypes: true });
330
+ } catch (err) {
331
+ log.warn({ semanticRoot, err: err instanceof Error ? err.message : String(err) }, "Failed to scan semantic root for per-source entity directories");
332
+ return entities;
333
+ }
334
+ const reserved = new Set(["entities", "metrics"]);
335
+ for (const entry of entries) {
336
+ if (!entry.isDirectory() || reserved.has(entry.name)) continue;
337
+ const subEntities = path.join(semanticRoot, entry.name, "entities");
338
+ if (fs.existsSync(subEntities)) {
339
+ loadEntitiesFromDir(subEntities, entities, entry.name);
340
+ }
341
+ }
342
+ }
343
+
344
+ return entities;
345
+ }
346
+
347
+ function loadEntitiesFromDir(
348
+ dir: string,
349
+ out: ParsedEntity[],
350
+ connectionId?: string,
351
+ ): void {
352
+ if (!fs.existsSync(dir)) return;
353
+
354
+ let files: string[];
355
+ try {
356
+ files = fs.readdirSync(dir).filter((f) => f.endsWith(".yml"));
357
+ } catch (err) {
358
+ log.warn({ dir, err: err instanceof Error ? err.message : String(err) }, "Failed to read entities directory for semantic index");
359
+ return;
360
+ }
361
+
362
+ for (const file of files) {
363
+ try {
364
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
365
+ const raw = yaml.load(content) as Record<string, unknown> | null;
366
+ if (!raw || typeof raw !== "object" || !raw.table) continue;
367
+
368
+ const entity: ParsedEntity = {
369
+ name: raw.name as string | undefined,
370
+ table: raw.table as string,
371
+ type: raw.type as string | undefined,
372
+ connection: (raw.connection as string | undefined) ?? connectionId,
373
+ grain: raw.grain as string | undefined,
374
+ description: raw.description as string | undefined,
375
+ dimensions: Array.isArray(raw.dimensions) ? (raw.dimensions as EntityDimension[]) : undefined,
376
+ measures: Array.isArray(raw.measures) ? (raw.measures as EntityMeasure[]) : undefined,
377
+ joins: Array.isArray(raw.joins) ? (raw.joins as EntityJoin[]) : undefined,
378
+ query_patterns: Array.isArray(raw.query_patterns) ? (raw.query_patterns as EntityQueryPattern[]) : undefined,
379
+ };
380
+ out.push(entity);
381
+ } catch (err) {
382
+ log.warn({ file, dir, err: err instanceof Error ? err.message : String(err) }, "Skipping entity file in semantic index — failed to read or parse");
383
+ }
384
+ }
385
+ }
386
+
387
+ function loadMetrics(semanticRoot: string): ParsedMetric[] {
388
+ const metrics: ParsedMetric[] = [];
389
+
390
+ // Default metrics
391
+ loadMetricsFromDir(path.join(semanticRoot, "metrics"), metrics);
392
+
393
+ // Per-source subdirectories
394
+ if (fs.existsSync(semanticRoot)) {
395
+ let entries: fs.Dirent[];
396
+ try {
397
+ entries = fs.readdirSync(semanticRoot, { withFileTypes: true });
398
+ } catch (err) {
399
+ log.warn({ semanticRoot, err: err instanceof Error ? err.message : String(err) }, "Failed to scan semantic root for per-source metric directories");
400
+ return metrics;
401
+ }
402
+ const reserved = new Set(["entities", "metrics"]);
403
+ for (const entry of entries) {
404
+ if (!entry.isDirectory() || reserved.has(entry.name)) continue;
405
+ const subMetrics = path.join(semanticRoot, entry.name, "metrics");
406
+ if (fs.existsSync(subMetrics)) {
407
+ loadMetricsFromDir(subMetrics, metrics);
408
+ }
409
+ }
410
+ }
411
+
412
+ return metrics;
413
+ }
414
+
415
+ function loadMetricsFromDir(dir: string, out: ParsedMetric[]): void {
416
+ if (!fs.existsSync(dir)) return;
417
+
418
+ let files: string[];
419
+ try {
420
+ files = fs.readdirSync(dir).filter((f) => f.endsWith(".yml"));
421
+ } catch (err) {
422
+ log.warn({ dir, err: err instanceof Error ? err.message : String(err) }, "Failed to read metrics directory for semantic index");
423
+ return;
424
+ }
425
+
426
+ for (const file of files) {
427
+ try {
428
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
429
+ const raw = yaml.load(content) as Record<string, unknown> | null;
430
+ if (!raw || typeof raw !== "object") continue;
431
+
432
+ // Metric files may contain a top-level array of metrics or a single metric
433
+ if (Array.isArray(raw.metrics)) {
434
+ for (const m of raw.metrics as ParsedMetric[]) {
435
+ if (m && typeof m === "object") out.push(m);
436
+ }
437
+ } else if (raw.name) {
438
+ out.push(raw as ParsedMetric);
439
+ }
440
+ } catch (err) {
441
+ log.warn({ file, dir, err: err instanceof Error ? err.message : String(err) }, "Skipping metric file in semantic index — failed to read or parse");
442
+ }
443
+ }
444
+ }
445
+
446
+ function loadGlossary(semanticRoot: string): GlossaryTerm[] {
447
+ const terms: GlossaryTerm[] = [];
448
+
449
+ // Try root glossary
450
+ loadGlossaryFile(path.join(semanticRoot, "glossary.yml"), terms);
451
+
452
+ // Per-source glossaries
453
+ if (fs.existsSync(semanticRoot)) {
454
+ let entries: fs.Dirent[];
455
+ try {
456
+ entries = fs.readdirSync(semanticRoot, { withFileTypes: true });
457
+ } catch (err) {
458
+ log.warn({ semanticRoot, err: err instanceof Error ? err.message : String(err) }, "Failed to scan semantic root for per-source glossary files");
459
+ return terms;
460
+ }
461
+ const reserved = new Set(["entities", "metrics"]);
462
+ for (const entry of entries) {
463
+ if (!entry.isDirectory() || reserved.has(entry.name)) continue;
464
+ loadGlossaryFile(
465
+ path.join(semanticRoot, entry.name, "glossary.yml"),
466
+ terms,
467
+ );
468
+ }
469
+ }
470
+
471
+ return terms;
472
+ }
473
+
474
+ function loadGlossaryFile(filePath: string, out: GlossaryTerm[]): void {
475
+ if (!fs.existsSync(filePath)) return;
476
+
477
+ try {
478
+ const content = fs.readFileSync(filePath, "utf-8");
479
+ const raw = yaml.load(content) as Record<string, unknown> | null;
480
+ if (!raw || typeof raw !== "object") return;
481
+
482
+ if (Array.isArray(raw.terms)) {
483
+ for (const t of raw.terms as GlossaryTerm[]) {
484
+ if (t && typeof t === "object") out.push(t);
485
+ }
486
+ }
487
+ } catch (err) {
488
+ log.warn({ filePath, err: err instanceof Error ? err.message : String(err) }, "Failed to load glossary file for semantic index");
489
+ }
490
+ }
491
+
492
+ function loadCatalog(semanticRoot: string): ParsedCatalog | null {
493
+ const catalogPath = path.join(semanticRoot, "catalog.yml");
494
+ if (!fs.existsSync(catalogPath)) return null;
495
+
496
+ try {
497
+ const content = fs.readFileSync(catalogPath, "utf-8");
498
+ return yaml.load(content) as ParsedCatalog | null;
499
+ } catch (err) {
500
+ log.warn({ catalogPath, err: err instanceof Error ? err.message : String(err) }, "Failed to load catalog for semantic index");
501
+ return null;
502
+ }
503
+ }