@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,379 @@
1
+ /**
2
+ * Semantic layer exploration tool.
3
+ *
4
+ * Abstracts the shell backend behind an ExploreBackend interface so the
5
+ * explore tool works across five isolation levels:
6
+ * - sandbox plugin: pluggable explore backend via the Plugin SDK (priority-sorted)
7
+ * - @vercel/sandbox: ephemeral microVM with networkPolicy "deny-all" (Vercel)
8
+ * - nsjail: Linux namespace sandbox (self-hosted Docker)
9
+ * - sidecar: HTTP-isolated container with no secrets (Railway/Render)
10
+ * - just-bash: OverlayFs ensures read-only access; writes stay in memory (dev, or production fallback)
11
+ *
12
+ * Runtime selection priority: sandbox plugin > Vercel sandbox > nsjail (explicit) > sidecar > nsjail (auto-detect) > just-bash.
13
+ * A production warning is logged when falling back to just-bash.
14
+ */
15
+
16
+ import { tool } from "ai";
17
+ import { z } from "zod";
18
+ import * as path from "path";
19
+ import { createLogger } from "@atlas/api/lib/logger";
20
+ import { withSpan } from "@atlas/api/lib/tracing";
21
+
22
+ /** Must match SANDBOX_DEFAULT_PRIORITY in @atlas/plugin-sdk/types. */
23
+ const SANDBOX_DEFAULT_PRIORITY = 60;
24
+
25
+ const log = createLogger("explore");
26
+
27
+ const SEMANTIC_ROOT = path.resolve(process.cwd(), "semantic");
28
+
29
+ // --- Backend interface ---
30
+
31
+ export interface ExecResult {
32
+ stdout: string;
33
+ stderr: string;
34
+ exitCode: number;
35
+ }
36
+
37
+ /**
38
+ * Shell backend for the explore tool.
39
+ *
40
+ * Implementations MUST provide read-only filesystem access scoped to the
41
+ * semantic layer directory. Commands execute within /semantic as the working
42
+ * directory. Writes should be silently discarded or cause errors, never
43
+ * modify the host filesystem.
44
+ */
45
+ export interface ExploreBackend {
46
+ exec(command: string): Promise<ExecResult>;
47
+ close?(): Promise<void>;
48
+ }
49
+
50
+ // --- Self-hosted backend (just-bash) ---
51
+
52
+ async function createBashBackend(
53
+ semanticRoot: string
54
+ ): Promise<ExploreBackend> {
55
+ let Bash, OverlayFs;
56
+ try {
57
+ ({ Bash, OverlayFs } = await import("just-bash"));
58
+ } catch (err) {
59
+ const detail = err instanceof Error ? err.message : String(err);
60
+ log.error({ err: detail }, "Failed to import just-bash");
61
+ throw new Error(
62
+ "Failed to load the just-bash runtime for the explore tool. " +
63
+ "Ensure 'just-bash' is installed ('bun install'). " +
64
+ "If running on Vercel, set ATLAS_RUNTIME=vercel.",
65
+ { cause: err }
66
+ );
67
+ }
68
+
69
+ const overlay = new OverlayFs({
70
+ root: semanticRoot,
71
+ mountPoint: "/semantic",
72
+ });
73
+ const bash = new Bash({
74
+ fs: overlay,
75
+ cwd: "/semantic",
76
+ executionLimits: {
77
+ maxCommandCount: 5000,
78
+ maxLoopIterations: 1000,
79
+ },
80
+ });
81
+ return {
82
+ exec: async (command: string) => {
83
+ const result = await bash.exec(command);
84
+ return {
85
+ stdout: result.stdout,
86
+ stderr: result.stderr,
87
+ exitCode: result.exitCode,
88
+ };
89
+ },
90
+ };
91
+ }
92
+
93
+ // --- Runtime detection ---
94
+
95
+ function useVercelSandbox(): boolean {
96
+ return process.env.ATLAS_RUNTIME === "vercel" || !!process.env.VERCEL;
97
+ }
98
+
99
+ let _nsjailAvailable: boolean | null = null;
100
+
101
+ function useNsjail(): boolean {
102
+ if (process.env.ATLAS_SANDBOX === "nsjail") return true;
103
+ if (_nsjailAvailable !== null) return _nsjailAvailable;
104
+ // Auto-detect nsjail on PATH (deferred require to avoid loading module at startup)
105
+ try {
106
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
107
+ const { isNsjailAvailable } = require("./explore-nsjail");
108
+ _nsjailAvailable = isNsjailAvailable();
109
+ } catch (err) {
110
+ if (
111
+ err instanceof Error &&
112
+ "code" in err &&
113
+ (err as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND"
114
+ ) {
115
+ _nsjailAvailable = false;
116
+ } else {
117
+ log.error(
118
+ { error: err instanceof Error ? err.message : String(err) },
119
+ "Unexpected error loading explore-nsjail module",
120
+ );
121
+ _nsjailAvailable = false;
122
+ }
123
+ }
124
+ return _nsjailAvailable ?? false;
125
+ }
126
+
127
+ function useSidecar(): boolean {
128
+ return !!process.env.ATLAS_SANDBOX_URL;
129
+ }
130
+
131
+ /** Track nsjail init failures to avoid infinite retry loops. */
132
+ let _nsjailFailed = false;
133
+
134
+ /** Track sidecar init failures so the health endpoint reports accurately. */
135
+ let _sidecarFailed = false;
136
+
137
+ export type ExploreBackendType = "vercel-sandbox" | "nsjail" | "sidecar" | "just-bash" | "plugin";
138
+
139
+ /** Name of the active sandbox plugin (if any). Set during backend init. */
140
+ let _activeSandboxPluginId: string | null = null;
141
+
142
+ /** Returns the active sandbox plugin id (if any, for health/startup reporting). */
143
+ export function getActiveSandboxPluginId(): string | null {
144
+ return _activeSandboxPluginId;
145
+ }
146
+
147
+ /**
148
+ * Returns which explore backend is active (for health endpoint).
149
+ *
150
+ * Plugin detection is lazy — _activeSandboxPluginId is only set after the
151
+ * first explore command triggers getExploreBackend(). Before that, this
152
+ * function falls through to the built-in detection chain.
153
+ */
154
+ export function getExploreBackendType(): ExploreBackendType {
155
+ if (_activeSandboxPluginId) return "plugin";
156
+ if (useVercelSandbox()) return "vercel-sandbox";
157
+ // Explicit nsjail (ATLAS_SANDBOX=nsjail) — hard-fail if unavailable
158
+ if (process.env.ATLAS_SANDBOX === "nsjail" && !_nsjailFailed) return "nsjail";
159
+ // Sidecar takes priority over nsjail auto-detection (Railway/Render set ATLAS_SANDBOX_URL)
160
+ if (useSidecar() && !_sidecarFailed) return "sidecar";
161
+ // nsjail auto-detect (binary on PATH)
162
+ if (!_nsjailFailed && useNsjail()) return "nsjail";
163
+ return "just-bash";
164
+ }
165
+
166
+ let backendPromise: Promise<ExploreBackend> | null = null;
167
+
168
+ /** Clear cached backend so the next call recreates it. */
169
+ export function invalidateExploreBackend(): void {
170
+ backendPromise = null;
171
+ _activeSandboxPluginId = null;
172
+ }
173
+
174
+ /** Permanently mark nsjail as failed and clear the backend cache.
175
+ * Called from explore-nsjail.ts on exit code 109 (sandbox setup failure). */
176
+ export function markNsjailFailed(): void {
177
+ _nsjailFailed = true;
178
+ backendPromise = null;
179
+ }
180
+
181
+ /** Permanently mark the sidecar as failed so health reports "just-bash".
182
+ * Called from startup.ts when the sidecar health check fails. */
183
+ export function markSidecarFailed(): void {
184
+ _sidecarFailed = true;
185
+ }
186
+
187
+ function getExploreBackend(): Promise<ExploreBackend> {
188
+ if (!backendPromise) {
189
+ backendPromise = (async (): Promise<ExploreBackend> => {
190
+ // Priority 0: Sandbox plugins (sorted by priority, highest first)
191
+ // Skipped when ATLAS_SANDBOX=nsjail — operator explicitly wants nsjail only
192
+ if (process.env.ATLAS_SANDBOX !== "nsjail") {
193
+ let sandboxPlugins: Array<{ id: string; [k: string]: unknown }> = [];
194
+ try {
195
+ const { plugins } = await import("@atlas/api/lib/plugins/registry");
196
+ sandboxPlugins = plugins.getByType("sandbox");
197
+ } catch (err) {
198
+ const detail = err instanceof Error ? err.message : String(err);
199
+ log.debug({ err: detail }, "Plugin registry not available for sandbox check");
200
+ }
201
+
202
+ if (sandboxPlugins.length > 0) {
203
+ type SandboxShape = { sandbox: { create(root: string): Promise<ExploreBackend> | ExploreBackend; priority?: number } };
204
+ const sorted = [...sandboxPlugins].sort((a, b) => {
205
+ const pa = (a as unknown as SandboxShape).sandbox.priority ?? SANDBOX_DEFAULT_PRIORITY;
206
+ const pb = (b as unknown as SandboxShape).sandbox.priority ?? SANDBOX_DEFAULT_PRIORITY;
207
+ return pb - pa;
208
+ });
209
+ for (const sp of sorted) {
210
+ const sandbox = (sp as unknown as SandboxShape).sandbox;
211
+ try {
212
+ const backend = await sandbox.create(SEMANTIC_ROOT);
213
+ _activeSandboxPluginId = sp.id;
214
+ log.info({ pluginId: sp.id }, "Using sandbox plugin for explore backend");
215
+ return backend;
216
+ } catch (err) {
217
+ const detail = err instanceof Error ? err.message : String(err);
218
+ log.error({ pluginId: sp.id, err: detail }, "Sandbox plugin create() failed, trying next");
219
+ }
220
+ }
221
+ log.error({ count: sorted.length }, "All sandbox plugins failed to create a backend");
222
+ }
223
+ }
224
+
225
+ // Priority 1: Vercel Sandbox (Firecracker VM)
226
+ if (useVercelSandbox()) {
227
+ const { createSandboxBackend } = await import("./explore-sandbox");
228
+ return createSandboxBackend(SEMANTIC_ROOT);
229
+ }
230
+
231
+ // Priority 2: nsjail explicit (ATLAS_SANDBOX=nsjail) — hard-fail if init fails
232
+ if (process.env.ATLAS_SANDBOX === "nsjail" && !_nsjailFailed) {
233
+ try {
234
+ const { createNsjailBackend } = await import("./explore-nsjail");
235
+ return await createNsjailBackend(SEMANTIC_ROOT, {
236
+ onInfrastructureError: invalidateExploreBackend,
237
+ onNsjailFailed: markNsjailFailed,
238
+ });
239
+ } catch (err) {
240
+ const detail = err instanceof Error ? err.message : String(err);
241
+ throw new Error(
242
+ "nsjail was explicitly requested (ATLAS_SANDBOX=nsjail) but failed to initialize: " +
243
+ detail + ". Fix the nsjail installation or remove ATLAS_SANDBOX to allow fallback.",
244
+ { cause: err },
245
+ );
246
+ }
247
+ }
248
+
249
+ // Priority 3: Sidecar service (HTTP-isolated microservice)
250
+ // When ATLAS_SANDBOX_URL is set, sidecar is the intended backend (Railway/Render).
251
+ // Skips nsjail auto-detection entirely — no noisy namespace warnings.
252
+ if (useSidecar()) {
253
+ const { createSidecarBackend } = await import("./explore-sidecar");
254
+ return createSidecarBackend(process.env.ATLAS_SANDBOX_URL!);
255
+ }
256
+
257
+ // Priority 4: nsjail auto-detect (binary on PATH, graceful fallback)
258
+ if (!_nsjailFailed && useNsjail()) {
259
+ try {
260
+ const { createNsjailBackend } = await import("./explore-nsjail");
261
+ return await createNsjailBackend(SEMANTIC_ROOT, {
262
+ onInfrastructureError: invalidateExploreBackend,
263
+ onNsjailFailed: markNsjailFailed,
264
+ });
265
+ } catch (err) {
266
+ const detail = err instanceof Error ? err.message : String(err);
267
+ _nsjailFailed = true;
268
+ log.error(
269
+ { error: detail, fallback: "just-bash" },
270
+ "nsjail backend failed to initialize, falling back to just-bash",
271
+ );
272
+ }
273
+ }
274
+
275
+ // Priority 5: just-bash (no process isolation)
276
+ if (process.env.NODE_ENV === "production") {
277
+ log.warn(
278
+ "Explore tool running without process isolation. " +
279
+ "Install nsjail, configure a sidecar (ATLAS_SANDBOX_URL), or deploy on Vercel for sandboxed execution. " +
280
+ "See: https://github.com/google/nsjail",
281
+ );
282
+ }
283
+ return createBashBackend(SEMANTIC_ROOT);
284
+ })().catch((err) => {
285
+ backendPromise = null; // allow retry on next call
286
+ throw err;
287
+ });
288
+ }
289
+ return backendPromise;
290
+ }
291
+
292
+ // --- Tool definition ---
293
+
294
+ export const explore = tool({
295
+ description: `Run bash commands to explore the semantic layer (YAML files describing the data model). The working directory is /semantic.
296
+
297
+ Available commands include: ls, cat, head, tail, grep, find, wc, tree, sort, uniq, cut, awk, sed, and more. Use pipes and flags freely.
298
+
299
+ The semantic directory contains:
300
+ - catalog.yml: Index of all entities and their descriptions
301
+ - entities/*.yml: Default connection table schemas with columns, types, sample values, joins
302
+ - metrics/*.yml: Default connection metric definitions with authoritative SQL
303
+ - glossary.yml: Business term definitions and disambiguation
304
+ - {source}/entities/*.yml: Per-source table schemas (e.g. warehouse/entities/)
305
+ - {source}/metrics/*.yml: Per-source metric definitions
306
+ - {source}/glossary.yml: Source-specific glossary (optional)
307
+
308
+ When multiple data sources are configured, each source has its own subdirectory.
309
+ Entity YAMLs may contain \`cross_source_joins\` describing relationships to tables on other sources — these cannot be SQL-JOINed directly; query each source separately.
310
+ Always start by listing the root directory to see what sources are available.`,
311
+
312
+ inputSchema: z.object({
313
+ command: z
314
+ .string()
315
+ .describe(
316
+ 'A bash command to run, e.g. \'cat catalog.yml\', \'grep -r revenue entities/\', \'find . -name "*.yml"\''
317
+ ),
318
+ }),
319
+
320
+ execute: async ({ command }) => {
321
+ let backend: ExploreBackend;
322
+ try {
323
+ backend = await getExploreBackend();
324
+ } catch (err) {
325
+ const detail = err instanceof Error ? err.message : String(err);
326
+ log.error({ err: detail }, "Explore backend initialization failed");
327
+ return `Error: Explore tool is unavailable — ${detail}`;
328
+ }
329
+
330
+ try {
331
+ const { dispatchHook, dispatchMutableHook } = await import("@atlas/api/lib/plugins/hooks");
332
+ let execCommand: string;
333
+ try {
334
+ const hookCtx = { command } as const;
335
+ execCommand = await dispatchMutableHook(
336
+ "beforeExplore",
337
+ hookCtx,
338
+ "command",
339
+ );
340
+ } catch (err) {
341
+ const detail = err instanceof Error ? err.message : String(err);
342
+ log.warn({ err: detail, command }, "Explore command rejected by plugin");
343
+ return `Error: Command rejected by plugin: ${detail}`;
344
+ }
345
+
346
+ // No command re-validation needed — the explore backend (nsjail/sidecar/OverlayFs)
347
+ // enforces read-only scoping regardless of command content
348
+ if (execCommand !== command) {
349
+ log.debug({ original: command, rewritten: execCommand }, "Explore command rewritten by plugin");
350
+ }
351
+
352
+ const start = performance.now();
353
+ const result = await withSpan(
354
+ "atlas.explore",
355
+ { command: execCommand.slice(0, 200) },
356
+ () => backend.exec(execCommand),
357
+ );
358
+ const durationMs = Math.round(performance.now() - start);
359
+
360
+ log.debug(
361
+ { command: execCommand, durationMs, exitCode: result.exitCode },
362
+ "explore command",
363
+ );
364
+
365
+ if (result.exitCode !== 0) {
366
+ return `Error (exit ${result.exitCode}):\n${result.stderr}`;
367
+ }
368
+
369
+ const output = result.stdout || "(no output)";
370
+ await dispatchHook("afterExplore", { command: execCommand, output });
371
+
372
+ return output;
373
+ } catch (err) {
374
+ const detail = err instanceof Error ? err.message : String(err);
375
+ log.error({ err: detail, command }, "Explore command failed");
376
+ return `Error: ${detail}`;
377
+ }
378
+ },
379
+ });
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Tool registry for the Atlas agent.
3
+ *
4
+ * Decouples tool definitions from the agent loop so tool sets can be
5
+ * composed dynamically. Each tool's {@link AtlasTool.description} is
6
+ * injected into the agent's system prompt via {@link ToolRegistry.describe}.
7
+ * The default registry contains the core tools (explore, executeSQL)
8
+ * with their workflow descriptions extracted from the system prompt.
9
+ */
10
+
11
+ import type { ToolSet } from "ai";
12
+ import { type AtlasAction, isAction } from "@atlas/api/lib/action-types";
13
+ import { explore } from "./explore";
14
+ import { executeSQL } from "./sql";
15
+
16
+ export type { AtlasAction };
17
+ export { isAction };
18
+
19
+ export interface AtlasTool {
20
+ readonly name: string;
21
+ /** Workflow guidance injected into the system prompt via describe(). */
22
+ readonly description: string;
23
+ readonly tool: ToolSet[string];
24
+ }
25
+
26
+ export class ToolRegistry {
27
+ private tools = new Map<string, AtlasTool>();
28
+ private frozen = false;
29
+
30
+ register(entry: AtlasTool): void {
31
+ if (this.frozen) {
32
+ throw new Error("Cannot register tools on a frozen registry");
33
+ }
34
+ if (!entry.name.trim()) {
35
+ throw new Error("Tool name must not be empty");
36
+ }
37
+ if (!entry.description.trim()) {
38
+ throw new Error("Tool description must not be empty");
39
+ }
40
+ this.tools.set(entry.name, entry);
41
+ }
42
+
43
+ /** Freeze the registry, preventing further registrations. */
44
+ freeze(): this {
45
+ this.frozen = true;
46
+ return this;
47
+ }
48
+
49
+ get(name: string): AtlasTool | undefined {
50
+ return this.tools.get(name);
51
+ }
52
+
53
+ getAll(): ToolSet {
54
+ const result: ToolSet = {};
55
+ for (const [name, entry] of this.tools) {
56
+ result[name] = entry.tool;
57
+ }
58
+ return result;
59
+ }
60
+
61
+ /** Concatenate all tool descriptions. Output order follows registration order. */
62
+ describe(): string {
63
+ return Array.from(this.tools.values())
64
+ .map((entry) => entry.description)
65
+ .join("\n\n");
66
+ }
67
+
68
+ /** Iterate over all registered tool entries. */
69
+ entries(): IterableIterator<[string, AtlasTool]> {
70
+ return this.tools.entries();
71
+ }
72
+
73
+ get size(): number {
74
+ return this.tools.size;
75
+ }
76
+
77
+ /**
78
+ * Create a new registry by merging one or more registries on top of a base.
79
+ * Entries in later registries take precedence. The returned registry is
80
+ * **unfrozen** — the caller should freeze it when ready.
81
+ */
82
+ static merge(base: ToolRegistry, ...others: ToolRegistry[]): ToolRegistry {
83
+ const merged = new ToolRegistry();
84
+ for (const [, entry] of base.entries()) {
85
+ merged.register(entry);
86
+ }
87
+ for (const other of others) {
88
+ for (const [name, entry] of other.entries()) {
89
+ if (merged.get(name)) continue; // base takes precedence
90
+ merged.register(entry);
91
+ }
92
+ }
93
+ return merged;
94
+ }
95
+
96
+ /** Return all registered tools that are actions (have actionType metadata). */
97
+ getActions(): AtlasAction[] {
98
+ return Array.from(this.tools.values()).filter(isAction) as AtlasAction[];
99
+ }
100
+
101
+ /**
102
+ * Check that all required credentials for registered actions are present
103
+ * in the environment. Returns an array of `{ action, missing }` for each
104
+ * action with missing credentials (empty array means all good).
105
+ */
106
+ validateActionCredentials(): { action: string; missing: string[] }[] {
107
+ const results: { action: string; missing: string[] }[] = [];
108
+ for (const action of this.getActions()) {
109
+ const missing = action.requiredCredentials.filter(
110
+ (key) => !process.env[key],
111
+ );
112
+ if (missing.length > 0) {
113
+ results.push({ action: action.name, missing });
114
+ }
115
+ }
116
+ return results;
117
+ }
118
+ }
119
+
120
+ // --- Workflow descriptions (extracted from the system prompt) ---
121
+
122
+ const EXPLORE_DESCRIPTION = `### 2. Explore the Semantic Layer
123
+ Use the explore tool to run bash commands against the semantic/ directory:
124
+ - Start with \`cat catalog.yml\` to find relevant entities
125
+ - Read entity schemas: \`cat entities/companies.yml\`, \`head -30 entities/deals.yml\`
126
+ - Search across files: \`grep -r "revenue" entities/\`, \`grep -rl "join" entities/\`
127
+ - List and discover files: \`ls entities/\`, \`find . -name "*.yml"\`, \`tree\`
128
+ - Check metrics/*.yml for canonical metric definitions — use these SQL patterns exactly
129
+ - Combine commands with pipes: \`grep -r "column" entities/ | sort\`, \`cat entities/deals.yml | grep -A5 "measures"\`
130
+ - Never guess column names. Always verify against the schema.`;
131
+
132
+ const EXECUTE_SQL_DESCRIPTION = `### 3. Write and Execute SQL
133
+ Use the executeSQL tool to query the database:
134
+ - Use exact column names from the entity schemas
135
+ - If a canonical metric definition exists, use that SQL — do not improvise
136
+ - Include appropriate filters, groupings, and ordering
137
+ - If a query fails, read the error, fix the SQL, and retry (max 2 retries, never retry the same SQL)`;
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)`;
147
+
148
+ // --- Default registry ---
149
+
150
+ const defaultRegistry = new ToolRegistry();
151
+
152
+ defaultRegistry.register({
153
+ name: "explore",
154
+ description: EXPLORE_DESCRIPTION,
155
+ tool: explore,
156
+ });
157
+
158
+ defaultRegistry.register({
159
+ name: "executeSQL",
160
+ description: EXECUTE_SQL_DESCRIPTION,
161
+ tool: executeSQL,
162
+ });
163
+
164
+ defaultRegistry.freeze();
165
+
166
+ /**
167
+ * Build a dynamic ToolRegistry with optional Salesforce and action support.
168
+ *
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.
173
+ */
174
+ export async function buildRegistry(options?: {
175
+ includeSalesforce?: boolean;
176
+ includeActions?: boolean;
177
+ }): Promise<ToolRegistry> {
178
+ const registry = new ToolRegistry();
179
+
180
+ registry.register({
181
+ name: "explore",
182
+ description: EXPLORE_DESCRIPTION,
183
+ tool: explore,
184
+ });
185
+
186
+ registry.register({
187
+ name: "executeSQL",
188
+ description: EXECUTE_SQL_DESCRIPTION,
189
+ tool: executeSQL,
190
+ });
191
+
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
+ });
200
+ }
201
+
202
+ if (options?.includeActions) {
203
+ try {
204
+ const { createJiraTicket, sendEmailReport } = await import("./actions");
205
+ registry.register(createJiraTicket as unknown as AtlasTool);
206
+ registry.register(sendEmailReport as unknown as AtlasTool);
207
+ } catch (err) {
208
+ const { createLogger } = await import("@atlas/api/lib/logger");
209
+ const actionLog = createLogger("registry");
210
+ actionLog.error(
211
+ { err: err instanceof Error ? err : new Error(String(err)) },
212
+ "Failed to load action tools — JIRA and email actions will be unavailable",
213
+ );
214
+ }
215
+ }
216
+
217
+ registry.freeze();
218
+ return registry;
219
+ }
220
+
221
+ export { defaultRegistry };