@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,559 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * LLM-powered enrichment for auto-generated semantic layer YAMLs.
4
+ *
5
+ * Uses the Vercel AI SDK generateText() to add business context,
6
+ * improved descriptions, query patterns, and derived metrics to
7
+ * the YAML files produced by `bin/atlas.ts`.
8
+ *
9
+ * Called automatically by `bun run atlas -- init --enrich` when
10
+ * an API key is available.
11
+ */
12
+
13
+ import { generateText } from "ai";
14
+ import { getModel } from "@atlas/api/lib/providers";
15
+ import type { TableProfile } from "./atlas.js";
16
+ import * as fs from "fs";
17
+ import * as path from "path";
18
+ import * as yaml from "js-yaml";
19
+
20
+ const SEMANTIC_DIR = path.resolve("semantic");
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Token usage tracking
24
+ // ---------------------------------------------------------------------------
25
+
26
+ interface TokenUsage {
27
+ promptTokens: number;
28
+ completionTokens: number;
29
+ totalTokens: number;
30
+ }
31
+
32
+ function addUsage(accumulator: TokenUsage, usage: Partial<TokenUsage>): void {
33
+ accumulator.promptTokens += usage.promptTokens ?? 0;
34
+ accumulator.completionTokens += usage.completionTokens ?? 0;
35
+ accumulator.totalTokens += usage.totalTokens ?? 0;
36
+ }
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // YAML helpers
40
+ // ---------------------------------------------------------------------------
41
+
42
+ /**
43
+ * Extract YAML content from an LLM response that wraps output in
44
+ * ```yaml ... ``` code blocks.
45
+ */
46
+ function extractYamlBlock(text: string): string {
47
+ const match = text.match(/```yaml\s*\n([\s\S]*?)```/);
48
+ if (match) return match[1].trim();
49
+
50
+ // Fallback: try to parse the whole response as YAML
51
+ console.warn(" Note: LLM response did not contain a ```yaml block, attempting to parse raw response");
52
+ return text.trim();
53
+ }
54
+
55
+ /**
56
+ * Safely parse YAML, returning null on failure.
57
+ */
58
+ function safeParse(text: string): Record<string, unknown> | null {
59
+ try {
60
+ const parsed = yaml.load(text);
61
+ if (parsed && typeof parsed === "object") {
62
+ return parsed as Record<string, unknown>;
63
+ }
64
+ return null;
65
+ } catch (err) {
66
+ console.warn(` YAML parse error: ${err instanceof Error ? err.message : String(err)}`);
67
+ return null;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Deep-merge `source` into `target`. Arrays are replaced, not concatenated.
73
+ * Only merges keys that exist in `source` and are non-null.
74
+ */
75
+ function deepMerge(
76
+ target: Record<string, unknown>,
77
+ source: Record<string, unknown>
78
+ ): Record<string, unknown> {
79
+ const result = { ...target };
80
+ for (const key of Object.keys(source)) {
81
+ const val = source[key];
82
+ if (val === null || val === undefined) continue;
83
+
84
+ if (
85
+ typeof val === "object" &&
86
+ !Array.isArray(val) &&
87
+ typeof result[key] === "object" &&
88
+ !Array.isArray(result[key])
89
+ ) {
90
+ result[key] = deepMerge(
91
+ result[key] as Record<string, unknown>,
92
+ val as Record<string, unknown>
93
+ );
94
+ } else {
95
+ result[key] = val;
96
+ }
97
+ }
98
+ return result;
99
+ }
100
+
101
+ // ---------------------------------------------------------------------------
102
+ // Profile formatting helpers
103
+ // ---------------------------------------------------------------------------
104
+
105
+ function formatTableProfile(profile: TableProfile): string {
106
+ const lines: string[] = [];
107
+ const label = profile.object_type === "view" ? "View" : "Table";
108
+ lines.push(`${label}: ${profile.table_name}`);
109
+ lines.push(`Row count: ${profile.row_count.toLocaleString()}`);
110
+
111
+ if (profile.primary_key_columns.length > 0) {
112
+ lines.push(`Primary key: ${profile.primary_key_columns.join(", ")}`);
113
+ }
114
+
115
+ if (profile.foreign_keys.length > 0) {
116
+ lines.push("Foreign keys:");
117
+ for (const fk of profile.foreign_keys) {
118
+ lines.push(` ${fk.from_column} -> ${fk.to_table}.${fk.to_column}`);
119
+ }
120
+ }
121
+
122
+ lines.push("\nColumns:");
123
+ for (const col of profile.columns) {
124
+ const flags: string[] = [];
125
+ if (col.is_primary_key) flags.push("PK");
126
+ if (col.is_foreign_key) flags.push(`FK -> ${col.fk_target_table}.${col.fk_target_column}`);
127
+ if (col.is_enum_like) flags.push("ENUM-LIKE");
128
+ if (col.nullable) flags.push("nullable");
129
+
130
+ const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
131
+ const samples =
132
+ col.sample_values.length > 0
133
+ ? ` samples: ${col.sample_values.slice(0, 8).join(", ")}`
134
+ : "";
135
+ const stats: string[] = [];
136
+ if (col.unique_count !== null) stats.push(`${col.unique_count} unique`);
137
+ if (col.null_count !== null && col.null_count > 0)
138
+ stats.push(`${col.null_count} nulls`);
139
+ const statsStr = stats.length > 0 ? ` (${stats.join(", ")})` : "";
140
+
141
+ lines.push(` ${col.name}: ${col.type}${flagStr}${statsStr}${samples}`);
142
+ }
143
+
144
+ return lines.join("\n");
145
+ }
146
+
147
+ function formatAllTablesOverview(profiles: TableProfile[]): string {
148
+ const lines: string[] = [];
149
+ for (const p of profiles) {
150
+ const label = p.object_type === "view" ? "View" : "Table";
151
+ lines.push(`\n${label}: ${p.table_name} (${p.row_count} rows)`);
152
+ for (const col of p.columns) {
153
+ const typeInfo = col.is_enum_like ? `${col.type} [ENUM]` : col.type;
154
+ lines.push(` ${col.name}: ${typeInfo}`);
155
+ }
156
+ }
157
+ return lines.join("\n");
158
+ }
159
+
160
+ // ---------------------------------------------------------------------------
161
+ // Entity enrichment
162
+ // ---------------------------------------------------------------------------
163
+
164
+ async function enrichEntity(
165
+ filePath: string,
166
+ profile: TableProfile,
167
+ model: ReturnType<typeof getModel>,
168
+ usage: TokenUsage
169
+ ): Promise<void> {
170
+ const fileName = path.basename(filePath);
171
+ console.log(` Enriching ${fileName}...`);
172
+
173
+ const existingContent = fs.readFileSync(filePath, "utf-8");
174
+ const existingYaml = yaml.load(existingContent) as Record<string, unknown>;
175
+ const profileText = formatTableProfile(profile);
176
+
177
+ try {
178
+ const result = await generateText({
179
+ model,
180
+ maxOutputTokens: 2000,
181
+ prompt: `You are a data analyst enriching a semantic layer YAML file with business context.
182
+
183
+ Here is the table profile from the database:
184
+ ${profileText}
185
+
186
+ Here is the current YAML definition:
187
+ \`\`\`yaml
188
+ ${existingContent}
189
+ \`\`\`
190
+
191
+ Generate ONLY the following improved/new fields as valid YAML. Do not repeat the entire file.
192
+ Output your response inside a single \`\`\`yaml code block.
193
+
194
+ Required output fields:
195
+ 1. **description**: A rich 2-3 sentence business description. Explain what business concept this table represents, what each row means, and how it relates to other tables.
196
+ 2. **use_cases**: A list of 3-4 bullet strings. Include concrete analytical use cases and at least one "Avoid for X — use Y instead" entry.
197
+ 3. **query_patterns**: A list of 2-3 objects, each with "description" (string) and "sql" (multiline SQL string). These should be common, useful queries that analysts would run against this table. Use proper PostgreSQL syntax.
198
+ 4. **virtual_dimensions**: A list of suggested CASE-based bucketing dimensions for numeric columns and date extraction dimensions (year, month) for date/timestamp columns. Each should have: name, sql, type, description, virtual: true, and optionally sample_values. Only include if the table has suitable columns.
199
+
200
+ Output format:
201
+ \`\`\`yaml
202
+ description: |
203
+ ...
204
+ use_cases:
205
+ - ...
206
+ query_patterns:
207
+ - description: ...
208
+ sql: |
209
+ ...
210
+ virtual_dimensions:
211
+ - name: ...
212
+ sql: |
213
+ ...
214
+ type: string
215
+ description: ...
216
+ virtual: true
217
+ \`\`\`
218
+
219
+ Important:
220
+ - Write concrete, actionable descriptions (not generic boilerplate)
221
+ - SQL must be valid PostgreSQL referencing only columns from the profile
222
+ - Do not invent columns that do not exist in the profile
223
+ - Use the table name "${profile.table_name}" in all SQL`,
224
+ });
225
+
226
+ addUsage(usage, result.usage);
227
+
228
+ const yamlText = extractYamlBlock(result.text);
229
+ const enriched = safeParse(yamlText);
230
+
231
+ if (!enriched) {
232
+ console.log(` Warning: Could not parse LLM response for ${fileName}, skipping merge`);
233
+ return;
234
+ }
235
+
236
+ // Merge enriched fields into existing YAML
237
+ const merged = deepMerge(existingYaml, enriched);
238
+
239
+ // Write back
240
+ const output = yaml.dump(merged, { lineWidth: 120, noRefs: true });
241
+ fs.writeFileSync(filePath, output);
242
+ console.log(` Updated ${fileName}`);
243
+ } catch (err) {
244
+ const message = err instanceof Error ? err.message : String(err);
245
+ console.error(` Error enriching ${fileName}: ${message}`);
246
+ }
247
+ }
248
+
249
+ // ---------------------------------------------------------------------------
250
+ // Glossary enrichment
251
+ // ---------------------------------------------------------------------------
252
+
253
+ async function enrichGlossary(
254
+ profiles: TableProfile[],
255
+ model: ReturnType<typeof getModel>,
256
+ usage: TokenUsage,
257
+ semanticDir: string = SEMANTIC_DIR
258
+ ): Promise<void> {
259
+ const glossaryPath = path.join(semanticDir, "glossary.yml");
260
+ if (!fs.existsSync(glossaryPath)) {
261
+ console.log(" Skipping glossary enrichment (file not found)");
262
+ return;
263
+ }
264
+
265
+ console.log(" Enriching glossary.yml...");
266
+
267
+ const existingContent = fs.readFileSync(glossaryPath, "utf-8");
268
+ const existingYaml = yaml.load(existingContent) as Record<string, unknown>;
269
+ const tablesOverview = formatAllTablesOverview(profiles);
270
+
271
+ try {
272
+ const result = await generateText({
273
+ model,
274
+ maxOutputTokens: 1500,
275
+ prompt: `You are a data analyst building a business glossary for a semantic layer.
276
+
277
+ Here are all the tables and columns in the database:
278
+ ${tablesOverview}
279
+
280
+ Here is the current glossary:
281
+ \`\`\`yaml
282
+ ${existingContent}
283
+ \`\`\`
284
+
285
+ Suggest additional glossary terms to add. Focus on:
286
+ 1. **Ambiguous terms** — column names or business concepts that could mean different things depending on context. Mark these with status: "ambiguous" and include a "note" explaining the ambiguity and "possible_mappings" listing the options.
287
+ 2. **Domain-specific definitions** — terms that need clear definitions for analysts. Mark these with status: "defined" and include a "definition".
288
+ 3. **Disambiguation guidance** — for terms that overlap across tables, provide "disambiguation" text and "see_also" references.
289
+
290
+ Do NOT duplicate terms that already exist in the current glossary.
291
+ Output ONLY new terms as valid YAML inside a \`\`\`yaml code block.
292
+
293
+ Output format:
294
+ \`\`\`yaml
295
+ terms:
296
+ term_name:
297
+ status: defined|ambiguous
298
+ definition: ...
299
+ # or for ambiguous:
300
+ note: ...
301
+ possible_mappings:
302
+ - ...
303
+ \`\`\`
304
+
305
+ Important:
306
+ - Only reference columns and tables that actually exist in the database
307
+ - Write concise, actionable definitions
308
+ - Include at least one ambiguous term if any exist`,
309
+ });
310
+
311
+ addUsage(usage, result.usage);
312
+
313
+ const yamlText = extractYamlBlock(result.text);
314
+ const enriched = safeParse(yamlText);
315
+
316
+ if (!enriched) {
317
+ console.log(" Warning: Could not parse LLM response for glossary, skipping merge");
318
+ return;
319
+ }
320
+
321
+ // Merge new terms into existing glossary
322
+ const existingTerms =
323
+ (existingYaml.terms as Record<string, unknown>) ?? {};
324
+ const newTerms =
325
+ (enriched.terms as Record<string, unknown>) ?? {};
326
+
327
+ // Only add terms that don't already exist
328
+ const mergedTerms = { ...existingTerms };
329
+ for (const [key, val] of Object.entries(newTerms)) {
330
+ if (!(key in mergedTerms)) {
331
+ mergedTerms[key] = val;
332
+ }
333
+ }
334
+
335
+ const output = yaml.dump(
336
+ { ...existingYaml, terms: mergedTerms },
337
+ { lineWidth: 120, noRefs: true }
338
+ );
339
+ fs.writeFileSync(glossaryPath, output);
340
+ console.log(" Updated glossary.yml");
341
+ } catch (err) {
342
+ const message = err instanceof Error ? err.message : String(err);
343
+ console.error(` Error enriching glossary: ${message}`);
344
+ }
345
+ }
346
+
347
+ // ---------------------------------------------------------------------------
348
+ // Metrics enrichment
349
+ // ---------------------------------------------------------------------------
350
+
351
+ async function enrichMetric(
352
+ filePath: string,
353
+ profile: TableProfile,
354
+ model: ReturnType<typeof getModel>,
355
+ usage: TokenUsage
356
+ ): Promise<void> {
357
+ const fileName = path.basename(filePath);
358
+ console.log(` Enriching ${fileName}...`);
359
+
360
+ const existingContent = fs.readFileSync(filePath, "utf-8");
361
+ const existingYaml = yaml.load(existingContent) as Record<string, unknown>;
362
+ const profileText = formatTableProfile(profile);
363
+
364
+ try {
365
+ const result = await generateText({
366
+ model,
367
+ maxOutputTokens: 2000,
368
+ prompt: `You are a data analyst enriching metric definitions for a semantic layer.
369
+
370
+ Here is the table profile:
371
+ ${profileText}
372
+
373
+ Here are the current metric definitions:
374
+ \`\`\`yaml
375
+ ${existingContent}
376
+ \`\`\`
377
+
378
+ Suggest improvements and additions. Output ONLY the changes as valid YAML inside a \`\`\`yaml code block.
379
+
380
+ For existing metrics, add any missing fields:
381
+ - "unit" (e.g., "USD", "count", "percentage")
382
+ - "aggregation" (e.g., "sum", "avg", "count_distinct")
383
+ - "objective" (e.g., "maximize", "minimize", "maintain")
384
+
385
+ Also suggest 1-3 NEW derived metrics such as:
386
+ - Ratios (e.g., revenue per employee, value per account)
387
+ - Period-over-period comparisons (if date columns exist)
388
+ - Percentage breakdowns
389
+
390
+ Output format:
391
+ \`\`\`yaml
392
+ metrics:
393
+ - id: existing_metric_id
394
+ unit: USD
395
+ aggregation: sum
396
+ objective: maximize
397
+ - id: new_derived_metric
398
+ label: Descriptive Label
399
+ description: What this metric measures and why it matters.
400
+ type: derived
401
+ sql: |
402
+ SELECT ...
403
+ unit: ...
404
+ aggregation: ...
405
+ objective: ...
406
+ \`\`\`
407
+
408
+ Important:
409
+ - For existing metrics, only output the id plus the NEW fields to add (not the entire metric)
410
+ - For new metrics, include all required fields (id, label, description, type, sql)
411
+ - SQL must be valid PostgreSQL referencing only columns from the profile
412
+ - Use the table name "${profile.table_name}" in all SQL
413
+ - Do not duplicate existing metric IDs for new metrics`,
414
+ });
415
+
416
+ addUsage(usage, result.usage);
417
+
418
+ const yamlText = extractYamlBlock(result.text);
419
+ const enriched = safeParse(yamlText);
420
+
421
+ if (!enriched) {
422
+ console.log(` Warning: Could not parse LLM response for ${fileName}, skipping merge`);
423
+ return;
424
+ }
425
+
426
+ // Merge: update existing metrics with new fields, append new metrics
427
+ const existingMetrics = (existingYaml.metrics as Record<string, unknown>[]) ?? [];
428
+ const enrichedMetrics = (enriched.metrics as Record<string, unknown>[]) ?? [];
429
+
430
+ const existingById = new Map(
431
+ existingMetrics.map((m) => [m.id as string, m])
432
+ );
433
+
434
+ for (const em of enrichedMetrics) {
435
+ const id = em.id as string;
436
+ if (existingById.has(id)) {
437
+ // Merge new fields into existing metric (don't overwrite existing fields)
438
+ const existing = existingById.get(id)!;
439
+ for (const [key, val] of Object.entries(em)) {
440
+ if (key === "id") continue;
441
+ if (!(key in existing) && val !== null && val !== undefined) {
442
+ (existing as Record<string, unknown>)[key] = val;
443
+ }
444
+ }
445
+ } else {
446
+ // Append new metric
447
+ existingMetrics.push(em);
448
+ }
449
+ }
450
+
451
+ const output = yaml.dump(
452
+ { ...existingYaml, metrics: existingMetrics },
453
+ { lineWidth: 120, noRefs: true }
454
+ );
455
+ fs.writeFileSync(filePath, output);
456
+ console.log(` Updated ${fileName}`);
457
+ } catch (err) {
458
+ const message = err instanceof Error ? err.message : String(err);
459
+ console.error(` Error enriching ${fileName}: ${message}`);
460
+ }
461
+ }
462
+
463
+ // ---------------------------------------------------------------------------
464
+ // Main entry point
465
+ // ---------------------------------------------------------------------------
466
+
467
+ export async function enrichSemanticLayer(
468
+ profiles: TableProfile[],
469
+ options?: { semanticDir?: string }
470
+ ): Promise<void> {
471
+ const semanticDir = options?.semanticDir ?? SEMANTIC_DIR;
472
+ const entitiesDir = path.join(semanticDir, "entities");
473
+ const metricsDir = path.join(semanticDir, "metrics");
474
+
475
+ const model = getModel();
476
+ const usage: TokenUsage = {
477
+ promptTokens: 0,
478
+ completionTokens: 0,
479
+ totalTokens: 0,
480
+ };
481
+
482
+ // Build a lookup from table name -> profile
483
+ const profileByTable = new Map(
484
+ profiles.map((p) => [p.table_name, p])
485
+ );
486
+
487
+ // 1. Enrich entity YAMLs
488
+ console.log(" --- Entity enrichment ---\n");
489
+
490
+ if (fs.existsSync(entitiesDir)) {
491
+ const entityFiles = fs
492
+ .readdirSync(entitiesDir)
493
+ .filter((f) => f.endsWith(".yml"));
494
+
495
+ for (const file of entityFiles) {
496
+ const tableName = file.replace(/\.yml$/, "");
497
+ const profile = profileByTable.get(tableName);
498
+ if (!profile) {
499
+ console.log(` Skipping ${file} (no matching profile)`);
500
+ continue;
501
+ }
502
+ await enrichEntity(
503
+ path.join(entitiesDir, file),
504
+ profile,
505
+ model,
506
+ usage
507
+ );
508
+ }
509
+ }
510
+
511
+ // 2. Enrich glossary
512
+ console.log("\n --- Glossary enrichment ---\n");
513
+
514
+ await enrichGlossary(profiles, model, usage, semanticDir);
515
+
516
+ // 3. Enrich metrics
517
+ console.log("\n --- Metrics enrichment ---\n");
518
+
519
+ if (fs.existsSync(metricsDir)) {
520
+ const metricFiles = fs
521
+ .readdirSync(metricsDir)
522
+ .filter((f) => f.endsWith(".yml"));
523
+
524
+ for (const file of metricFiles) {
525
+ // Try to match metric file to a table profile
526
+ const tableName = file.replace(/\.yml$/, "");
527
+ const profile = profileByTable.get(tableName);
528
+
529
+ if (!profile) {
530
+ // Metric files might not map 1:1 to tables (e.g., revenue.yml, engagement.yml).
531
+ // Use the first profile that has relevant columns as a fallback.
532
+ const fallbackProfile = profiles[0];
533
+ if (fallbackProfile) {
534
+ await enrichMetric(
535
+ path.join(metricsDir, file),
536
+ fallbackProfile,
537
+ model,
538
+ usage
539
+ );
540
+ } else {
541
+ console.log(` Skipping ${file} (no profiles available)`);
542
+ }
543
+ continue;
544
+ }
545
+ await enrichMetric(
546
+ path.join(metricsDir, file),
547
+ profile,
548
+ model,
549
+ usage
550
+ );
551
+ }
552
+ }
553
+
554
+ // Print token usage summary
555
+ console.log("\n --- Token usage ---\n");
556
+ console.log(` Prompt tokens: ${usage.promptTokens.toLocaleString()}`);
557
+ console.log(` Completion tokens: ${usage.completionTokens.toLocaleString()}`);
558
+ console.log(` Total tokens: ${usage.totalTokens.toLocaleString()}`);
559
+ }