@useatlas/create 0.0.1 → 0.0.3

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 (298) hide show
  1. package/README.md +4 -18
  2. package/index.ts +191 -31
  3. package/package.json +1 -1
  4. package/templates/docker/.env.example +3 -3
  5. package/templates/docker/Dockerfile.sidecar +28 -0
  6. package/templates/docker/bin/__tests__/plugin-cli.test.ts +11 -11
  7. package/templates/docker/bin/atlas.ts +120 -56
  8. package/templates/docker/data/demo-semantic/catalog.yml +51 -27
  9. package/templates/docker/data/demo-semantic/entities/accounts.yml +95 -103
  10. package/templates/docker/data/demo-semantic/entities/companies.yml +88 -152
  11. package/templates/docker/data/demo-semantic/entities/people.yml +82 -95
  12. package/templates/docker/data/demo-semantic/glossary.yml +104 -8
  13. package/templates/docker/data/demo-semantic/metrics/accounts.yml +62 -23
  14. package/templates/docker/data/demo-semantic/metrics/companies.yml +52 -78
  15. package/templates/docker/docker-compose.yml +1 -1
  16. package/templates/docker/docs/deploy.md +4 -41
  17. package/templates/docker/package.json +17 -1
  18. package/templates/docker/semantic/catalog.yml +62 -3
  19. package/templates/docker/semantic/entities/accounts.yml +162 -0
  20. package/templates/docker/semantic/entities/companies.yml +143 -0
  21. package/templates/docker/semantic/entities/people.yml +132 -0
  22. package/templates/docker/semantic/glossary.yml +116 -4
  23. package/templates/docker/semantic/metrics/accounts.yml +77 -0
  24. package/templates/docker/semantic/metrics/companies.yml +63 -0
  25. package/templates/docker/sidecar/Dockerfile +5 -6
  26. package/templates/docker/sidecar/railway.json +1 -2
  27. package/templates/docker/src/api/__tests__/admin.test.ts +7 -7
  28. package/templates/docker/src/api/__tests__/health-plugin.test.ts +7 -0
  29. package/templates/docker/src/api/__tests__/health.test.ts +30 -8
  30. package/templates/docker/src/api/routes/admin.ts +549 -8
  31. package/templates/docker/src/api/routes/chat.ts +5 -20
  32. package/templates/docker/src/api/routes/health.ts +39 -27
  33. package/templates/docker/src/api/routes/openapi.ts +1329 -74
  34. package/templates/docker/src/api/routes/query.ts +2 -1
  35. package/templates/docker/src/api/server.ts +27 -0
  36. package/templates/docker/src/app/api/[...route]/route.ts +2 -2
  37. package/templates/docker/src/app/globals.css +13 -12
  38. package/templates/docker/src/app/layout.tsx +9 -2
  39. package/templates/docker/src/components/ui/alert-dialog.tsx +196 -0
  40. package/templates/docker/src/components/ui/badge.tsx +48 -0
  41. package/templates/docker/src/components/ui/button.tsx +64 -0
  42. package/templates/docker/src/components/ui/card.tsx +92 -0
  43. package/templates/docker/src/components/ui/collapsible.tsx +33 -0
  44. package/templates/docker/src/components/ui/command.tsx +184 -0
  45. package/templates/docker/src/components/ui/dialog.tsx +158 -0
  46. package/templates/docker/src/components/ui/dropdown-menu.tsx +257 -0
  47. package/templates/docker/src/components/ui/input.tsx +21 -0
  48. package/templates/docker/src/components/ui/scroll-area.tsx +58 -0
  49. package/templates/docker/src/components/ui/select.tsx +190 -0
  50. package/templates/docker/src/components/ui/separator.tsx +28 -0
  51. package/templates/docker/src/components/ui/sheet.tsx +143 -0
  52. package/templates/docker/src/components/ui/sidebar.tsx +726 -0
  53. package/templates/docker/src/components/ui/skeleton.tsx +13 -0
  54. package/templates/docker/src/components/ui/table.tsx +116 -0
  55. package/templates/docker/src/components/ui/tabs.tsx +91 -0
  56. package/templates/docker/src/components/ui/toggle-group.tsx +83 -0
  57. package/templates/docker/src/components/ui/toggle.tsx +47 -0
  58. package/templates/docker/src/components/ui/tooltip.tsx +57 -0
  59. package/templates/docker/src/hooks/use-mobile.ts +19 -0
  60. package/templates/docker/src/lib/__tests__/agent-cache.test.ts +2 -0
  61. package/templates/docker/src/lib/__tests__/agent-dialect.test.ts +17 -0
  62. package/templates/docker/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  63. package/templates/docker/src/lib/__tests__/agent-integration.test.ts +2 -0
  64. package/templates/docker/src/lib/__tests__/config.test.ts +69 -19
  65. package/templates/docker/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  66. package/templates/docker/src/lib/__tests__/providers.test.ts +32 -1
  67. package/templates/docker/src/lib/__tests__/startup-actions.test.ts +9 -0
  68. package/templates/docker/src/lib/__tests__/startup-first-run.test.ts +429 -0
  69. package/templates/docker/src/lib/__tests__/startup.test.ts +5 -0
  70. package/templates/docker/src/lib/agent-query.ts +5 -23
  71. package/templates/docker/src/lib/agent.ts +32 -112
  72. package/templates/docker/src/lib/auth/__tests__/migrate.test.ts +5 -3
  73. package/templates/docker/src/lib/auth/middleware.ts +30 -4
  74. package/templates/docker/src/lib/auth/migrate.ts +97 -0
  75. package/templates/docker/src/lib/auth/server.ts +12 -1
  76. package/templates/docker/src/lib/config.ts +38 -40
  77. package/templates/docker/src/lib/db/__tests__/connection.test.ts +89 -14
  78. package/templates/docker/src/lib/db/__tests__/registry-health.test.ts +1 -18
  79. package/templates/docker/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  80. package/templates/docker/src/lib/db/__tests__/registry.test.ts +11 -208
  81. package/templates/docker/src/lib/db/connection.ts +87 -265
  82. package/templates/docker/src/lib/db/internal.ts +6 -1
  83. package/templates/docker/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  84. package/templates/docker/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  85. package/templates/docker/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  86. package/templates/docker/src/lib/plugins/__tests__/registry.test.ts +32 -5
  87. package/templates/docker/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  88. package/templates/docker/src/lib/plugins/index.ts +4 -1
  89. package/templates/docker/src/lib/plugins/migrate.ts +104 -1
  90. package/templates/docker/src/lib/plugins/registry.ts +14 -8
  91. package/templates/docker/src/lib/plugins/wiring.ts +113 -4
  92. package/templates/docker/src/lib/providers.ts +6 -1
  93. package/templates/docker/src/lib/security.ts +24 -0
  94. package/templates/docker/src/lib/semantic.ts +2 -0
  95. package/templates/docker/src/lib/sidecar-types.ts +12 -1
  96. package/templates/docker/src/lib/startup.ts +71 -101
  97. package/templates/docker/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  98. package/templates/docker/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  99. package/templates/docker/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  100. package/templates/docker/src/lib/tools/__tests__/explore-sdk-compat.test.ts +1 -1
  101. package/templates/docker/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  102. package/templates/docker/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  103. package/templates/docker/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  104. package/templates/docker/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  105. package/templates/docker/src/lib/tools/__tests__/python.test.ts +331 -0
  106. package/templates/docker/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  107. package/templates/docker/src/lib/tools/__tests__/registry.test.ts +38 -31
  108. package/templates/docker/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  109. package/templates/docker/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  110. package/templates/docker/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  111. package/templates/docker/src/lib/tools/__tests__/sql.test.ts +5 -308
  112. package/templates/docker/src/lib/tools/explore-nsjail.ts +17 -12
  113. package/templates/docker/src/lib/tools/explore-sidecar.ts +25 -0
  114. package/templates/docker/src/lib/tools/explore.ts +28 -32
  115. package/templates/docker/src/lib/tools/python-nsjail.ts +396 -0
  116. package/templates/docker/src/lib/tools/python-sandbox.ts +476 -0
  117. package/templates/docker/src/lib/tools/python-sidecar.ts +150 -0
  118. package/templates/docker/src/lib/tools/python.ts +367 -0
  119. package/templates/docker/src/lib/tools/registry.ts +49 -22
  120. package/templates/docker/src/lib/tools/sql.ts +88 -88
  121. package/templates/docker/src/types/vercel-sandbox.d.ts +7 -0
  122. package/templates/docker/src/ui/components/admin/admin-layout.tsx +77 -8
  123. package/templates/docker/src/ui/components/admin/admin-sidebar.tsx +25 -17
  124. package/templates/docker/src/ui/components/admin/change-password-dialog.tsx +128 -0
  125. package/templates/docker/src/ui/components/admin/entity-detail.tsx +3 -3
  126. package/templates/docker/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  127. package/templates/docker/src/ui/components/atlas-chat.tsx +64 -12
  128. package/templates/docker/src/ui/components/chart/result-chart.tsx +25 -15
  129. package/templates/docker/src/ui/components/chat/markdown.tsx +88 -42
  130. package/templates/docker/src/ui/components/chat/python-result-card.tsx +244 -0
  131. package/templates/docker/src/ui/components/chat/sql-block.tsx +39 -15
  132. package/templates/docker/src/ui/components/chat/sql-result-card.tsx +6 -1
  133. package/templates/docker/src/ui/components/chat/tool-part.tsx +12 -3
  134. package/templates/docker/src/ui/components/chat/typing-indicator.tsx +5 -2
  135. package/templates/docker/src/ui/components/conversations/conversation-item.tsx +25 -20
  136. package/templates/docker/src/ui/context.tsx +1 -1
  137. package/templates/docker/src/ui/hooks/use-conversations.ts +3 -3
  138. package/templates/docker/src/ui/hooks/use-dark-mode.ts +17 -10
  139. package/templates/docker/tsconfig.json +2 -2
  140. package/templates/nextjs-standalone/.env.example +1 -1
  141. package/templates/nextjs-standalone/bin/__tests__/plugin-cli.test.ts +11 -11
  142. package/templates/nextjs-standalone/bin/atlas.ts +120 -56
  143. package/templates/nextjs-standalone/data/demo-semantic/catalog.yml +51 -27
  144. package/templates/nextjs-standalone/data/demo-semantic/entities/accounts.yml +95 -103
  145. package/templates/nextjs-standalone/data/demo-semantic/entities/companies.yml +88 -152
  146. package/templates/nextjs-standalone/data/demo-semantic/entities/people.yml +82 -95
  147. package/templates/nextjs-standalone/data/demo-semantic/glossary.yml +104 -8
  148. package/templates/nextjs-standalone/data/demo-semantic/metrics/accounts.yml +62 -23
  149. package/templates/nextjs-standalone/data/demo-semantic/metrics/companies.yml +52 -78
  150. package/templates/nextjs-standalone/docs/deploy.md +4 -41
  151. package/templates/nextjs-standalone/package.json +11 -2
  152. package/templates/nextjs-standalone/scripts/migrate-auth.ts +25 -0
  153. package/templates/nextjs-standalone/scripts/seed-demo.ts +94 -0
  154. package/templates/nextjs-standalone/semantic/catalog.yml +62 -3
  155. package/templates/nextjs-standalone/semantic/entities/accounts.yml +162 -0
  156. package/templates/nextjs-standalone/semantic/entities/companies.yml +143 -0
  157. package/templates/nextjs-standalone/semantic/entities/people.yml +132 -0
  158. package/templates/nextjs-standalone/semantic/glossary.yml +116 -4
  159. package/templates/nextjs-standalone/semantic/metrics/accounts.yml +77 -0
  160. package/templates/nextjs-standalone/semantic/metrics/companies.yml +63 -0
  161. package/templates/nextjs-standalone/src/api/__tests__/admin.test.ts +7 -7
  162. package/templates/nextjs-standalone/src/api/__tests__/health-plugin.test.ts +7 -0
  163. package/templates/nextjs-standalone/src/api/__tests__/health.test.ts +30 -8
  164. package/templates/nextjs-standalone/src/api/routes/admin.ts +549 -8
  165. package/templates/nextjs-standalone/src/api/routes/chat.ts +5 -20
  166. package/templates/nextjs-standalone/src/api/routes/health.ts +39 -27
  167. package/templates/nextjs-standalone/src/api/routes/openapi.ts +1329 -74
  168. package/templates/nextjs-standalone/src/api/routes/query.ts +2 -1
  169. package/templates/nextjs-standalone/src/api/server.ts +27 -0
  170. package/templates/nextjs-standalone/src/app/api/[...route]/route.ts +2 -2
  171. package/templates/nextjs-standalone/src/app/globals.css +13 -12
  172. package/templates/nextjs-standalone/src/app/layout.tsx +9 -2
  173. package/templates/nextjs-standalone/src/components/ui/alert-dialog.tsx +196 -0
  174. package/templates/nextjs-standalone/src/components/ui/badge.tsx +48 -0
  175. package/templates/nextjs-standalone/src/components/ui/button.tsx +64 -0
  176. package/templates/nextjs-standalone/src/components/ui/card.tsx +92 -0
  177. package/templates/nextjs-standalone/src/components/ui/collapsible.tsx +33 -0
  178. package/templates/nextjs-standalone/src/components/ui/command.tsx +184 -0
  179. package/templates/nextjs-standalone/src/components/ui/dialog.tsx +158 -0
  180. package/templates/nextjs-standalone/src/components/ui/dropdown-menu.tsx +257 -0
  181. package/templates/nextjs-standalone/src/components/ui/input.tsx +21 -0
  182. package/templates/nextjs-standalone/src/components/ui/scroll-area.tsx +58 -0
  183. package/templates/nextjs-standalone/src/components/ui/select.tsx +190 -0
  184. package/templates/nextjs-standalone/src/components/ui/separator.tsx +28 -0
  185. package/templates/nextjs-standalone/src/components/ui/sheet.tsx +143 -0
  186. package/templates/nextjs-standalone/src/components/ui/sidebar.tsx +726 -0
  187. package/templates/nextjs-standalone/src/components/ui/skeleton.tsx +13 -0
  188. package/templates/nextjs-standalone/src/components/ui/table.tsx +116 -0
  189. package/templates/nextjs-standalone/src/components/ui/tabs.tsx +91 -0
  190. package/templates/nextjs-standalone/src/components/ui/toggle-group.tsx +83 -0
  191. package/templates/nextjs-standalone/src/components/ui/toggle.tsx +47 -0
  192. package/templates/nextjs-standalone/src/components/ui/tooltip.tsx +57 -0
  193. package/templates/nextjs-standalone/src/hooks/use-mobile.ts +19 -0
  194. package/templates/nextjs-standalone/src/lib/__tests__/agent-cache.test.ts +2 -0
  195. package/templates/nextjs-standalone/src/lib/__tests__/agent-dialect.test.ts +17 -0
  196. package/templates/nextjs-standalone/src/lib/__tests__/agent-health-annotations.test.ts +2 -0
  197. package/templates/nextjs-standalone/src/lib/__tests__/agent-integration.test.ts +2 -0
  198. package/templates/nextjs-standalone/src/lib/__tests__/config.test.ts +69 -19
  199. package/templates/nextjs-standalone/src/lib/__tests__/plugin-aware-validation.test.ts +321 -0
  200. package/templates/nextjs-standalone/src/lib/__tests__/providers.test.ts +32 -1
  201. package/templates/nextjs-standalone/src/lib/__tests__/startup-actions.test.ts +9 -0
  202. package/templates/nextjs-standalone/src/lib/__tests__/startup-first-run.test.ts +429 -0
  203. package/templates/nextjs-standalone/src/lib/__tests__/startup.test.ts +5 -0
  204. package/templates/nextjs-standalone/src/lib/agent-query.ts +5 -23
  205. package/templates/nextjs-standalone/src/lib/agent.ts +32 -112
  206. package/templates/nextjs-standalone/src/lib/auth/__tests__/migrate.test.ts +5 -3
  207. package/templates/nextjs-standalone/src/lib/auth/middleware.ts +30 -4
  208. package/templates/nextjs-standalone/src/lib/auth/migrate.ts +97 -0
  209. package/templates/nextjs-standalone/src/lib/auth/server.ts +12 -1
  210. package/templates/nextjs-standalone/src/lib/config.ts +38 -40
  211. package/templates/nextjs-standalone/src/lib/db/__tests__/connection.test.ts +89 -14
  212. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-health.test.ts +1 -18
  213. package/templates/nextjs-standalone/src/lib/db/__tests__/registry-pool-limits.test.ts +0 -19
  214. package/templates/nextjs-standalone/src/lib/db/__tests__/registry.test.ts +11 -208
  215. package/templates/nextjs-standalone/src/lib/db/connection.ts +87 -265
  216. package/templates/nextjs-standalone/src/lib/db/internal.ts +6 -1
  217. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks-integration.test.ts +3 -1
  218. package/templates/nextjs-standalone/src/lib/plugins/__tests__/hooks.test.ts +2 -2
  219. package/templates/nextjs-standalone/src/lib/plugins/__tests__/migrate.test.ts +355 -1
  220. package/templates/nextjs-standalone/src/lib/plugins/__tests__/registry.test.ts +32 -5
  221. package/templates/nextjs-standalone/src/lib/plugins/__tests__/wiring.test.ts +228 -14
  222. package/templates/nextjs-standalone/src/lib/plugins/index.ts +4 -1
  223. package/templates/nextjs-standalone/src/lib/plugins/migrate.ts +104 -1
  224. package/templates/nextjs-standalone/src/lib/plugins/registry.ts +14 -8
  225. package/templates/nextjs-standalone/src/lib/plugins/wiring.ts +113 -4
  226. package/templates/nextjs-standalone/src/lib/providers.ts +6 -1
  227. package/templates/nextjs-standalone/src/lib/security.ts +24 -0
  228. package/templates/nextjs-standalone/src/lib/semantic.ts +2 -0
  229. package/templates/nextjs-standalone/src/lib/sidecar-types.ts +12 -1
  230. package/templates/nextjs-standalone/src/lib/startup.ts +71 -101
  231. package/templates/nextjs-standalone/src/lib/tools/__tests__/custom-validation.test.ts +2 -0
  232. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-nsjail.test.ts +32 -18
  233. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-plugin.test.ts +14 -14
  234. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sdk-compat.test.ts +1 -1
  235. package/templates/nextjs-standalone/src/lib/tools/__tests__/explore-sidecar.test.ts +5 -3
  236. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-nsjail.test.ts +515 -0
  237. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sandbox.test.ts +397 -0
  238. package/templates/nextjs-standalone/src/lib/tools/__tests__/python-sidecar.test.ts +365 -0
  239. package/templates/nextjs-standalone/src/lib/tools/__tests__/python.test.ts +331 -0
  240. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry-actions.test.ts +1 -13
  241. package/templates/nextjs-standalone/src/lib/tools/__tests__/registry.test.ts +38 -31
  242. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-audit.test.ts +2 -0
  243. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-connection-whitelist.test.ts +2 -0
  244. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-ratelimit.test.ts +2 -0
  245. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql.test.ts +5 -308
  246. package/templates/nextjs-standalone/src/lib/tools/explore-nsjail.ts +17 -12
  247. package/templates/nextjs-standalone/src/lib/tools/explore-sidecar.ts +25 -0
  248. package/templates/nextjs-standalone/src/lib/tools/explore.ts +28 -32
  249. package/templates/nextjs-standalone/src/lib/tools/python-nsjail.ts +396 -0
  250. package/templates/nextjs-standalone/src/lib/tools/python-sandbox.ts +476 -0
  251. package/templates/nextjs-standalone/src/lib/tools/python-sidecar.ts +150 -0
  252. package/templates/nextjs-standalone/src/lib/tools/python.ts +367 -0
  253. package/templates/nextjs-standalone/src/lib/tools/registry.ts +49 -22
  254. package/templates/nextjs-standalone/src/lib/tools/sql.ts +88 -88
  255. package/templates/nextjs-standalone/src/ui/components/admin/admin-layout.tsx +77 -8
  256. package/templates/nextjs-standalone/src/ui/components/admin/admin-sidebar.tsx +25 -17
  257. package/templates/nextjs-standalone/src/ui/components/admin/change-password-dialog.tsx +128 -0
  258. package/templates/nextjs-standalone/src/ui/components/admin/entity-detail.tsx +3 -3
  259. package/templates/nextjs-standalone/src/ui/components/admin/semantic-file-tree.tsx +159 -0
  260. package/templates/nextjs-standalone/src/ui/components/atlas-chat.tsx +64 -12
  261. package/templates/nextjs-standalone/src/ui/components/chart/result-chart.tsx +25 -15
  262. package/templates/nextjs-standalone/src/ui/components/chat/markdown.tsx +88 -42
  263. package/templates/nextjs-standalone/src/ui/components/chat/python-result-card.tsx +244 -0
  264. package/templates/nextjs-standalone/src/ui/components/chat/sql-block.tsx +39 -15
  265. package/templates/nextjs-standalone/src/ui/components/chat/sql-result-card.tsx +6 -1
  266. package/templates/nextjs-standalone/src/ui/components/chat/tool-part.tsx +12 -3
  267. package/templates/nextjs-standalone/src/ui/components/chat/typing-indicator.tsx +5 -2
  268. package/templates/nextjs-standalone/src/ui/components/conversations/conversation-item.tsx +25 -20
  269. package/templates/nextjs-standalone/src/ui/context.tsx +1 -1
  270. package/templates/nextjs-standalone/src/ui/hooks/use-conversations.ts +3 -3
  271. package/templates/nextjs-standalone/src/ui/hooks/use-dark-mode.ts +17 -10
  272. package/templates/nextjs-standalone/tsconfig.json +0 -1
  273. package/templates/nextjs-standalone/vercel.json +4 -1
  274. package/templates/docker/render.yaml +0 -34
  275. package/templates/docker/semantic/entities/.gitkeep +0 -0
  276. package/templates/docker/semantic/metrics/.gitkeep +0 -0
  277. package/templates/docker/src/lib/db/__tests__/duckdb.test.ts +0 -141
  278. package/templates/docker/src/lib/db/__tests__/salesforce.test.ts +0 -339
  279. package/templates/docker/src/lib/db/__tests__/snowflake.test.ts +0 -217
  280. package/templates/docker/src/lib/db/duckdb.ts +0 -122
  281. package/templates/docker/src/lib/db/salesforce.ts +0 -342
  282. package/templates/docker/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  283. package/templates/docker/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  284. package/templates/docker/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  285. package/templates/docker/src/lib/tools/salesforce.ts +0 -138
  286. package/templates/docker/src/lib/tools/soql-validation.ts +0 -172
  287. package/templates/nextjs-standalone/semantic/entities/.gitkeep +0 -0
  288. package/templates/nextjs-standalone/semantic/metrics/.gitkeep +0 -0
  289. package/templates/nextjs-standalone/src/lib/db/__tests__/duckdb.test.ts +0 -141
  290. package/templates/nextjs-standalone/src/lib/db/__tests__/salesforce.test.ts +0 -339
  291. package/templates/nextjs-standalone/src/lib/db/__tests__/snowflake.test.ts +0 -217
  292. package/templates/nextjs-standalone/src/lib/db/duckdb.ts +0 -122
  293. package/templates/nextjs-standalone/src/lib/db/salesforce.ts +0 -342
  294. package/templates/nextjs-standalone/src/lib/tools/__tests__/salesforce-tool.test.ts +0 -154
  295. package/templates/nextjs-standalone/src/lib/tools/__tests__/soql-validation.test.ts +0 -303
  296. package/templates/nextjs-standalone/src/lib/tools/__tests__/sql-duckdb.test.ts +0 -233
  297. package/templates/nextjs-standalone/src/lib/tools/salesforce.ts +0 -138
  298. package/templates/nextjs-standalone/src/lib/tools/soql-validation.ts +0 -172
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Python execution tool for data analysis and visualization.
3
+ *
4
+ * Runs Python code in an isolated sandbox — a sidecar container
5
+ * (ATLAS_SANDBOX_URL), Vercel Sandbox (Firecracker microVM), or nsjail
6
+ * (Linux namespace sandbox). Backend selection mirrors the explore tool's
7
+ * priority chain.
8
+ *
9
+ * Security model:
10
+ * - AST-based import guard runs first as defense-in-depth (catches obvious mistakes)
11
+ * - The sandbox backend is the actual security boundary (no secrets, no network)
12
+ * - Requires either a sidecar, Vercel sandbox, or nsjail — refuses to run without isolation
13
+ */
14
+
15
+ import { tool } from "ai";
16
+ import { z } from "zod";
17
+ import { createLogger } from "@atlas/api/lib/logger";
18
+ import { withSpan } from "@atlas/api/lib/tracing";
19
+
20
+ const log = createLogger("python");
21
+
22
+ // --- Import guard (defense-in-depth) ---
23
+
24
+ const BLOCKED_MODULES = new Set([
25
+ "subprocess",
26
+ "os",
27
+ "socket",
28
+ "shutil",
29
+ "sys",
30
+ "ctypes",
31
+ "importlib",
32
+ "code",
33
+ "signal",
34
+ "multiprocessing",
35
+ "threading",
36
+ "pty",
37
+ "fcntl",
38
+ "termios",
39
+ "resource",
40
+ "posixpath",
41
+ // Network modules
42
+ "http",
43
+ "urllib",
44
+ "requests",
45
+ "httpx",
46
+ "aiohttp",
47
+ "webbrowser",
48
+ // Dangerous serialization/filesystem
49
+ "pickle",
50
+ "tempfile",
51
+ "pathlib",
52
+ ]);
53
+
54
+ const BLOCKED_BUILTINS = new Set([
55
+ "compile",
56
+ "exec",
57
+ "eval",
58
+ "__import__",
59
+ "open",
60
+ "breakpoint",
61
+ "getattr",
62
+ "globals",
63
+ "locals",
64
+ "vars",
65
+ "dir",
66
+ "delattr",
67
+ "setattr",
68
+ ]);
69
+
70
+ /**
71
+ * Validate Python code for blocked imports and dangerous builtins.
72
+ *
73
+ * Uses Python's own `ast` module to parse the code, then checks for:
74
+ * - `import X` / `from X import ...` where X is in BLOCKED_MODULES
75
+ * - Calls to blocked builtins (exec, eval, compile, __import__, open, getattr, etc.)
76
+ *
77
+ * This is defense-in-depth — the sidecar container is the security boundary.
78
+ * Returns { safe: true } or { safe: false, reason: string }.
79
+ */
80
+ export async function validatePythonCode(
81
+ code: string,
82
+ ): Promise<{ safe: true } | { safe: false; reason: string }> {
83
+ // Build a Python script that uses ast to extract imports and dangerous calls
84
+ const checkerScript = `
85
+ import ast, json, sys
86
+
87
+ code = sys.stdin.read()
88
+ try:
89
+ tree = ast.parse(code)
90
+ except SyntaxError as e:
91
+ json.dump({"error": f"SyntaxError: {e.msg} (line {e.lineno})"}, sys.stdout)
92
+ sys.exit(0)
93
+
94
+ imports = []
95
+ calls = []
96
+
97
+ for node in ast.walk(tree):
98
+ if isinstance(node, ast.Import):
99
+ for alias in node.names:
100
+ imports.append(alias.name.split('.')[0])
101
+ elif isinstance(node, ast.ImportFrom):
102
+ if node.module:
103
+ imports.append(node.module.split('.')[0])
104
+ elif isinstance(node, ast.Call):
105
+ if isinstance(node.func, ast.Name):
106
+ calls.append(node.func.id)
107
+ elif isinstance(node.func, ast.Attribute):
108
+ calls.append(node.func.attr)
109
+
110
+ json.dump({"imports": imports, "calls": calls}, sys.stdout)
111
+ `;
112
+
113
+ let proc;
114
+ try {
115
+ proc = Bun.spawn(["python3", "-c", checkerScript], {
116
+ stdin: "pipe",
117
+ stdout: "pipe",
118
+ stderr: "pipe",
119
+ });
120
+ } catch (err) {
121
+ const detail = err instanceof Error ? err.message : String(err);
122
+ log.warn({ err: detail }, "python3 not available for AST validation — guard skipped, sandbox backend will enforce");
123
+ // If python3 isn't available locally, skip the guard.
124
+ // The sidecar is the security boundary, not this check.
125
+ return { safe: true };
126
+ }
127
+
128
+ try {
129
+ proc.stdin.write(code);
130
+ proc.stdin.end();
131
+ } catch (err) {
132
+ const detail = err instanceof Error ? err.message : String(err);
133
+ log.warn({ err: detail }, "Failed to write to python3 stdin");
134
+ return { safe: false, reason: `Code analysis failed: ${detail}` };
135
+ }
136
+
137
+ const [stdout, stderr] = await Promise.all([
138
+ new Response(proc.stdout).text(),
139
+ new Response(proc.stderr).text(),
140
+ ]);
141
+ const exitCode = await proc.exited;
142
+
143
+ if (exitCode !== 0) {
144
+ log.warn({ stderr, exitCode }, "Python AST checker failed");
145
+ return { safe: false, reason: `Code analysis failed: ${stderr.trim() || "unknown error"}` };
146
+ }
147
+
148
+ let result: { error?: string; imports?: string[]; calls?: string[] };
149
+ try {
150
+ result = JSON.parse(stdout);
151
+ } catch {
152
+ log.warn({ stdout: stdout.slice(0, 500) }, "Python AST checker produced unparseable output");
153
+ return { safe: false, reason: "Code analysis produced invalid output" };
154
+ }
155
+
156
+ if (result.error) {
157
+ return { safe: false, reason: result.error };
158
+ }
159
+
160
+ // Check imports
161
+ for (const mod of result.imports ?? []) {
162
+ if (BLOCKED_MODULES.has(mod)) {
163
+ return { safe: false, reason: `Blocked import: "${mod}" is not allowed` };
164
+ }
165
+ }
166
+
167
+ // Check dangerous builtins
168
+ for (const call of result.calls ?? []) {
169
+ if (BLOCKED_BUILTINS.has(call)) {
170
+ return { safe: false, reason: `Blocked builtin: "${call}()" is not allowed` };
171
+ }
172
+ }
173
+
174
+ return { safe: true };
175
+ }
176
+
177
+ // --- Output types ---
178
+
179
+ export interface PythonChart {
180
+ base64: string;
181
+ mimeType: "image/png";
182
+ }
183
+
184
+ export interface RechartsChart {
185
+ type: "line" | "bar" | "pie";
186
+ data: Record<string, unknown>[];
187
+ categoryKey: string;
188
+ valueKeys: string[];
189
+ }
190
+
191
+ export type PythonResult =
192
+ | {
193
+ success: true;
194
+ output?: string;
195
+ table?: { columns: string[]; rows: unknown[][] };
196
+ charts?: PythonChart[];
197
+ rechartsCharts?: RechartsChart[];
198
+ }
199
+ | {
200
+ success: false;
201
+ error: string;
202
+ output?: string;
203
+ };
204
+
205
+ // --- Backend interface ---
206
+
207
+ /**
208
+ * Python execution backend. Implementations handle isolation (sidecar, Vercel sandbox, nsjail).
209
+ * Each backend receives validated code + optional data and returns a structured result.
210
+ */
211
+ export interface PythonBackend {
212
+ exec(code: string, data?: { columns: string[]; rows: unknown[][] }): Promise<PythonResult>;
213
+ }
214
+
215
+ // --- Backend selection ---
216
+
217
+ /**
218
+ * Resolve the Python execution backend.
219
+ *
220
+ * Priority:
221
+ * 1. Sidecar (ATLAS_SANDBOX_URL) — HTTP-isolated container
222
+ * 2. Vercel (ATLAS_RUNTIME=vercel) — Python 3.13 in Firecracker microVM
223
+ * 3. nsjail explicit (ATLAS_SANDBOX=nsjail) — hard-fail if unavailable
224
+ * 4. nsjail auto-detect (on PATH or ATLAS_NSJAIL_PATH) — graceful fallback
225
+ * 5. No backend — error
226
+ */
227
+ async function getPythonBackend(): Promise<PythonBackend | { error: string }> {
228
+ // 1. Sidecar
229
+ const sidecarUrl = process.env.ATLAS_SANDBOX_URL;
230
+ if (sidecarUrl) {
231
+ const { executePythonViaSidecar } = await import("./python-sidecar");
232
+ return {
233
+ exec: (code, data) => executePythonViaSidecar(sidecarUrl, code, data),
234
+ };
235
+ }
236
+
237
+ // 2. Vercel sandbox (Python 3.13 runtime)
238
+ if (process.env.ATLAS_RUNTIME === "vercel" || process.env.VERCEL) {
239
+ let createPythonSandboxBackend;
240
+ try {
241
+ ({ createPythonSandboxBackend } = await import("./python-sandbox"));
242
+ } catch (err) {
243
+ const detail = err instanceof Error ? err.message : String(err);
244
+ log.error({ err: detail }, "Vercel Python sandbox module not available");
245
+ return { error: `Vercel Python sandbox unavailable: ${detail}` };
246
+ }
247
+ return createPythonSandboxBackend();
248
+ }
249
+
250
+ // 3. nsjail explicit (ATLAS_SANDBOX=nsjail) — hard-fail
251
+ if (process.env.ATLAS_SANDBOX === "nsjail") {
252
+ try {
253
+ const { findNsjailBinary } = await import("./explore-nsjail");
254
+ const nsjailPath = findNsjailBinary();
255
+ if (nsjailPath) {
256
+ const { createPythonNsjailBackend } = await import("./python-nsjail");
257
+ return createPythonNsjailBackend(nsjailPath);
258
+ }
259
+ } catch (err) {
260
+ const detail = err instanceof Error ? err.message : String(err);
261
+ log.error({ err: detail }, "nsjail explicitly requested but Python nsjail backend failed to load");
262
+ }
263
+ return {
264
+ error: "ATLAS_SANDBOX=nsjail but nsjail binary not found. Python execution unavailable.",
265
+ };
266
+ }
267
+
268
+ // 4. nsjail auto-detect
269
+ try {
270
+ const { findNsjailBinary } = await import("./explore-nsjail");
271
+ const nsjailPath = findNsjailBinary();
272
+ if (nsjailPath) {
273
+ const { createPythonNsjailBackend } = await import("./python-nsjail");
274
+ return createPythonNsjailBackend(nsjailPath);
275
+ }
276
+ } catch (err) {
277
+ if (
278
+ err != null &&
279
+ typeof err === "object" &&
280
+ "code" in err &&
281
+ (err as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND"
282
+ ) {
283
+ log.debug("explore-nsjail module not available, skipping nsjail Python backend");
284
+ } else {
285
+ const detail = err instanceof Error ? err.message : String(err);
286
+ log.error({ err: detail }, "Unexpected error initializing nsjail Python backend");
287
+ }
288
+ }
289
+
290
+ // 5. No backend
291
+ return {
292
+ error: "Python execution requires a sandbox (ATLAS_SANDBOX_URL or nsjail). See deployment docs.",
293
+ };
294
+ }
295
+
296
+ // --- Tool definition ---
297
+
298
+ export const executePython = tool({
299
+ description: `Execute Python code for data analysis and visualization.
300
+
301
+ The code runs in an isolated Python sandbox with access to common data science libraries (pandas, numpy, matplotlib, scipy, scikit-learn, statsmodels).
302
+
303
+ When data is provided (from a previous SQL query), it is available as:
304
+ - \`df\`: a pandas DataFrame (if pandas is installed)
305
+ - \`data\`: the raw dict with "columns" and "rows" keys
306
+
307
+ Output options:
308
+ - Table: set \`_atlas_table = {"columns": [...], "rows": [...]}\`
309
+ - Interactive chart (Recharts): set \`_atlas_chart = {"type": "line", "data": [...], "categoryKey": "month", "valueKeys": ["revenue"]}\` (type can be line, bar, pie)
310
+ - PNG chart (matplotlib): save to \`chart_path(0)\`, \`chart_path(1)\`, etc.
311
+ - Text: use \`print()\` for narrative output
312
+
313
+ Blocked: subprocess, os, socket, shutil, sys, ctypes, importlib, exec(), eval(), open(), compile().`,
314
+
315
+ inputSchema: z.object({
316
+ code: z.string().describe("Python code to execute"),
317
+ explanation: z.string().describe("Brief explanation of what this code does and why"),
318
+ data: z
319
+ .object({
320
+ columns: z.array(z.string()),
321
+ rows: z.array(z.array(z.unknown())),
322
+ })
323
+ .optional()
324
+ .describe("Optional data payload from a previous SQL query (columns + rows)"),
325
+ }),
326
+
327
+ execute: async ({ code, explanation, data }) => {
328
+ // 0. Resolve backend
329
+ const backend = await getPythonBackend();
330
+ if ("error" in backend) {
331
+ log.error(backend.error);
332
+ return { success: false, error: backend.error };
333
+ }
334
+
335
+ // 1. Validate imports (defense-in-depth — sandbox is the real boundary)
336
+ const validation = await validatePythonCode(code);
337
+ if (!validation.safe) {
338
+ log.warn({ reason: validation.reason }, "Python code rejected by import guard");
339
+ return { success: false, error: validation.reason };
340
+ }
341
+
342
+ // 2. Execute via selected backend
343
+ const start = performance.now();
344
+ try {
345
+ const result = await withSpan(
346
+ "atlas.python.execute",
347
+ { "code.length": code.length },
348
+ () => backend.exec(code, data),
349
+ );
350
+ const durationMs = Math.round(performance.now() - start);
351
+
352
+ log.debug(
353
+ { durationMs, success: result.success, hasCharts: result.success && !!result.charts?.length },
354
+ "python execution",
355
+ );
356
+
357
+ return {
358
+ ...result,
359
+ explanation,
360
+ };
361
+ } catch (err) {
362
+ const detail = err instanceof Error ? err.message : String(err);
363
+ log.error({ err: detail }, "Python execution failed");
364
+ return { success: false, error: detail };
365
+ }
366
+ },
367
+ });
@@ -136,14 +136,21 @@ Use the executeSQL tool to query the database:
136
136
  - Include appropriate filters, groupings, and ordering
137
137
  - If a query fails, read the error, fix the SQL, and retry (max 2 retries, never retry the same SQL)`;
138
138
 
139
- const QUERY_SALESFORCE_DESCRIPTION = `### 3b. Query Salesforce (SOQL)
140
- Use the querySalesforce tool to query Salesforce objects:
141
- - SOQL uses SELECT ... FROM ObjectName syntax (no schema.table)
142
- - Use relationship queries for related objects (e.g. SELECT Account.Name FROM Contact)
143
- - SOQL does NOT support JOINs — use parent-to-child or child-to-parent relationship queries
144
- - Date literals: TODAY, YESTERDAY, LAST_WEEK, THIS_MONTH, LAST_N_DAYS:30
145
- - Use exact field API names from the entity schemas never guess
146
- - If a query fails, read the error, fix the SOQL, and retry (max 2 retries)`;
139
+ const EXECUTE_PYTHON_DESCRIPTION = `### 4. Analyze Data with Python
140
+ Use the executePython tool for analysis that SQL alone cannot handle:
141
+ - Statistical analysis (correlations, regressions, hypothesis tests)
142
+ - Data transformations (pivoting, reshaping, time series decomposition)
143
+ - Visualizations and advanced charts
144
+
145
+ **Always run executeSQL first**, then pass results to executePython via the \`data\` parameter.
146
+
147
+ **Output modes:**
148
+ - \`_atlas_table\` — structured table results (columns + rows)
149
+ - \`_atlas_chart\` — interactive Recharts chart (preferred for bar/line/pie)
150
+ - \`chart_path(n)\` — matplotlib PNG (use for heatmaps, scatter matrices, violin plots)
151
+ - \`print()\` — narrative text output
152
+
153
+ Do NOT use executePython for simple aggregations, GROUP BY, or filtering — executeSQL handles those.`;
147
154
 
148
155
  // --- Default registry ---
149
156
 
@@ -164,15 +171,12 @@ defaultRegistry.register({
164
171
  defaultRegistry.freeze();
165
172
 
166
173
  /**
167
- * Build a dynamic ToolRegistry with optional Salesforce and action support.
174
+ * Build a dynamic ToolRegistry with optional action and Python support.
168
175
  *
169
- * When `includeSalesforce` is true, the `querySalesforce` tool is added
170
- * alongside the core tools.
171
- * When `includeActions` is true, the action tools (createJiraTicket,
172
- * sendEmailReport) are added.
176
+ * Python tool is included when `ATLAS_PYTHON_ENABLED=true`.
177
+ * Action tools are included when `includeActions` is true.
173
178
  */
174
179
  export async function buildRegistry(options?: {
175
- includeSalesforce?: boolean;
176
180
  includeActions?: boolean;
177
181
  }): Promise<ToolRegistry> {
178
182
  const registry = new ToolRegistry();
@@ -189,14 +193,37 @@ export async function buildRegistry(options?: {
189
193
  tool: executeSQL,
190
194
  });
191
195
 
192
- if (options?.includeSalesforce) {
193
- // eslint-disable-next-line @typescript-eslint/no-require-imports
194
- const { querySalesforce } = require("./salesforce");
195
- registry.register({
196
- name: "querySalesforce",
197
- description: QUERY_SALESFORCE_DESCRIPTION,
198
- tool: querySalesforce,
199
- });
196
+ if (process.env.ATLAS_PYTHON_ENABLED === "true") {
197
+ if (!process.env.ATLAS_SANDBOX_URL) {
198
+ const { createLogger } = await import("@atlas/api/lib/logger");
199
+ const pyLog = createLogger("registry");
200
+ pyLog.error(
201
+ "ATLAS_PYTHON_ENABLED=true but ATLAS_SANDBOX_URL is not set. " +
202
+ "Python execution requires a sandbox sidecar for isolation.",
203
+ );
204
+ throw new Error(
205
+ "ATLAS_PYTHON_ENABLED=true requires ATLAS_SANDBOX_URL to be set. " +
206
+ "The Python tool runs in the sandbox sidecar for security isolation. " +
207
+ "See deployment docs for sidecar setup.",
208
+ );
209
+ }
210
+
211
+ try {
212
+ const { executePython } = await import("./python");
213
+ registry.register({
214
+ name: "executePython",
215
+ description: EXECUTE_PYTHON_DESCRIPTION,
216
+ tool: executePython,
217
+ });
218
+ } catch (err) {
219
+ const { createLogger } = await import("@atlas/api/lib/logger");
220
+ const pyLog = createLogger("registry");
221
+ pyLog.error(
222
+ { err: err instanceof Error ? err : new Error(String(err)) },
223
+ "Failed to load Python tool — executePython will be unavailable",
224
+ );
225
+ throw err;
226
+ }
200
227
  }
201
228
 
202
229
  if (options?.includeActions) {