@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
@@ -1,7 +1,8 @@
1
1
  import { describe, test, expect, beforeEach, mock } from "bun:test";
2
2
  import { PluginRegistry } from "../registry";
3
3
  import type { PluginLike, PluginContextLike } from "../registry";
4
- import { wireDatasourcePlugins, wireActionPlugins, wireInteractionPlugins, wireContextPlugins } from "../wiring";
4
+ import { wireDatasourcePlugins, wireActionPlugins, wireInteractionPlugins, wireContextPlugins, wireSandboxPlugins } from "../wiring";
5
+ import type { SandboxExecBackend } from "../wiring";
5
6
 
6
7
  const minimalCtx: PluginContextLike = {
7
8
  db: null,
@@ -15,9 +16,9 @@ const minimalCtx: PluginContextLike = {
15
16
 
16
17
  function makeMockConnectionRegistry() {
17
18
  return {
18
- registered: [] as { id: string; conn: unknown; dbType: string; description?: string; validate?: unknown }[],
19
- async registerDirect(id: string, conn: unknown, dbType: string, description?: string, validate?: unknown) {
20
- this.registered.push({ id, conn, dbType, description, validate });
19
+ registered: [] as { id: string; conn: unknown; dbType: string; description?: string; validate?: unknown; meta?: unknown }[],
20
+ registerDirect(id: string, conn: unknown, dbType: string, description?: string, validate?: unknown, meta?: unknown) {
21
+ this.registered.push({ id, conn, dbType, description, validate, meta });
21
22
  },
22
23
  };
23
24
  }
@@ -49,7 +50,7 @@ function makeDatasourcePlugin(
49
50
  };
50
51
  return {
51
52
  id,
52
- type: "datasource",
53
+ types: ["datasource"],
53
54
  version: "1.0.0",
54
55
  connection: {
55
56
  create: () => conn,
@@ -66,7 +67,7 @@ function makeDatasourcePlugin(
66
67
  function makeActionPlugin(id: string, opts?: { unhealthy?: boolean }): PluginLike {
67
68
  return {
68
69
  id,
69
- type: "action",
70
+ types: ["action"],
70
71
  version: "1.0.0",
71
72
  actions: [
72
73
  {
@@ -88,7 +89,7 @@ function makeActionPlugin(id: string, opts?: { unhealthy?: boolean }): PluginLik
88
89
  function makeInteractionPlugin(id: string, routesFn: (app: unknown) => void, opts?: { unhealthy?: boolean }): PluginLike {
89
90
  return {
90
91
  id,
91
- type: "interaction",
92
+ types: ["interaction"],
92
93
  version: "1.0.0",
93
94
  routes: routesFn,
94
95
  ...(opts?.unhealthy
@@ -127,7 +128,7 @@ describe("wireDatasourcePlugins", () => {
127
128
  const validator = (q: string) => ({ valid: /^SELECT/i.test(q) });
128
129
  const plugin: PluginLike = {
129
130
  id: "validated-ds",
130
- type: "datasource",
131
+ types: ["datasource"],
131
132
  version: "1.0.0",
132
133
  connection: {
133
134
  create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
@@ -147,6 +148,47 @@ describe("wireDatasourcePlugins", () => {
147
148
  expect(connRegistry.registered[0].validate).toBe(validator);
148
149
  });
149
150
 
151
+ test("passes parserDialect and forbiddenPatterns through meta", async () => {
152
+ const patterns = [/^\s*(KILL)\b/i];
153
+ const plugin: PluginLike = {
154
+ id: "meta-ds",
155
+ types: ["datasource"],
156
+ version: "1.0.0",
157
+ connection: {
158
+ create: () => ({ query: async () => ({ columns: [], rows: [] }), close: async () => {} }),
159
+ dbType: "clickhouse",
160
+ parserDialect: "PostgresQL",
161
+ forbiddenPatterns: patterns,
162
+ },
163
+ };
164
+ registry.register(plugin);
165
+ await registry.initializeAll(minimalCtx);
166
+
167
+ await wireDatasourcePlugins(
168
+ registry,
169
+ connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
170
+ );
171
+
172
+ expect(connRegistry.registered).toHaveLength(1);
173
+ expect(connRegistry.registered[0].meta).toEqual({
174
+ parserDialect: "PostgresQL",
175
+ forbiddenPatterns: patterns,
176
+ });
177
+ });
178
+
179
+ test("passes undefined meta when no parserDialect or forbiddenPatterns", async () => {
180
+ registry.register(makeDatasourcePlugin("plain-meta"));
181
+ await registry.initializeAll(minimalCtx);
182
+
183
+ await wireDatasourcePlugins(
184
+ registry,
185
+ connRegistry as unknown as import("@atlas/api/lib/db/connection").ConnectionRegistry,
186
+ );
187
+
188
+ expect(connRegistry.registered).toHaveLength(1);
189
+ expect(connRegistry.registered[0].meta).toBeUndefined();
190
+ });
191
+
150
192
  test("passes undefined validate when not provided", async () => {
151
193
  registry.register(makeDatasourcePlugin("plain-ds"));
152
194
  await registry.initializeAll(minimalCtx);
@@ -179,7 +221,7 @@ describe("wireDatasourcePlugins", () => {
179
221
  test("continues when one create() throws and returns failures", async () => {
180
222
  const failingPlugin: PluginLike = {
181
223
  id: "failing-ds",
182
- type: "datasource",
224
+ types: ["datasource"],
183
225
  version: "1.0.0",
184
226
  connection: {
185
227
  create: () => { throw new Error("conn failed"); },
@@ -389,7 +431,7 @@ describe("wireActionPlugins", () => {
389
431
  test("registers all actions from a multi-action plugin", async () => {
390
432
  const plugin: PluginLike = {
391
433
  id: "multi-action",
392
- type: "action",
434
+ types: ["action"],
393
435
  version: "1.0.0",
394
436
  actions: [
395
437
  { name: "action-a", description: "A", tool: {}, actionType: "t", reversible: false, defaultApproval: "manual", requiredCredentials: [] },
@@ -421,7 +463,7 @@ describe("wireActionPlugins", () => {
421
463
 
422
464
  const plugin: PluginLike = {
423
465
  id: "fail-action",
424
- type: "action",
466
+ types: ["action"],
425
467
  version: "1.0.0",
426
468
  actions: [
427
469
  { name: "fail-action", description: "Fails", tool: {}, actionType: "t", reversible: false, defaultApproval: "manual", requiredCredentials: [] },
@@ -485,7 +527,7 @@ describe("wireInteractionPlugins", () => {
485
527
  const fakeApp = { route: mock(() => {}) };
486
528
  const routelessPlugin: PluginLike = {
487
529
  id: "stdio-interaction",
488
- type: "interaction",
530
+ types: ["interaction"],
489
531
  version: "1.0.0",
490
532
  // No routes property — like MCP stdio transport
491
533
  };
@@ -506,7 +548,7 @@ describe("wireInteractionPlugins", () => {
506
548
  function makeContextPlugin(id: string, loadFn: () => Promise<string>, opts?: { unhealthy?: boolean }): PluginLike {
507
549
  return {
508
550
  id,
509
- type: "context",
551
+ types: ["context"],
510
552
  version: "1.0.0",
511
553
  contextProvider: { load: loadFn },
512
554
  ...(opts?.unhealthy
@@ -571,7 +613,7 @@ describe("wireContextPlugins", () => {
571
613
  test("skips context plugins without contextProvider", async () => {
572
614
  const noProvider: PluginLike = {
573
615
  id: "no-provider",
574
- type: "context",
616
+ types: ["context"],
575
617
  version: "1.0.0",
576
618
  };
577
619
  registry.register(noProvider);
@@ -583,3 +625,175 @@ describe("wireContextPlugins", () => {
583
625
  expect(result.failed).toEqual([]);
584
626
  });
585
627
  });
628
+
629
+ // --- wireSandboxPlugins ---
630
+
631
+ function makeMockBackend(tag: string): SandboxExecBackend {
632
+ return {
633
+ exec: async (command: string) => ({
634
+ stdout: `[${tag}] ${command}`,
635
+ stderr: "",
636
+ exitCode: 0,
637
+ }),
638
+ };
639
+ }
640
+
641
+ function makeSandboxPlugin(
642
+ id: string,
643
+ opts?: { priority?: number; createFn?: (root: string) => Promise<SandboxExecBackend> | SandboxExecBackend; unhealthy?: boolean },
644
+ ): PluginLike {
645
+ return {
646
+ id,
647
+ types: ["sandbox"],
648
+ version: "1.0.0",
649
+ sandbox: {
650
+ create: opts?.createFn ?? (async () => makeMockBackend(id)),
651
+ ...(opts?.priority !== undefined ? { priority: opts.priority } : {}),
652
+ },
653
+ ...(opts?.unhealthy
654
+ ? { initialize: async () => { throw new Error("fail"); } }
655
+ : {}),
656
+ };
657
+ }
658
+
659
+ describe("wireSandboxPlugins", () => {
660
+ let registry: PluginRegistry;
661
+
662
+ beforeEach(() => {
663
+ registry = new PluginRegistry();
664
+ });
665
+
666
+ test("returns backend from a single sandbox plugin", async () => {
667
+ registry.register(makeSandboxPlugin("my-sandbox"));
668
+ await registry.initializeAll(minimalCtx);
669
+
670
+ const result = await wireSandboxPlugins(registry, "/semantic");
671
+
672
+ expect(result.backend).not.toBeNull();
673
+ expect(result.pluginId).toBe("my-sandbox");
674
+ expect(result.failed).toEqual([]);
675
+ });
676
+
677
+ test("selects highest-priority plugin", async () => {
678
+ registry.register(makeSandboxPlugin("low", { priority: 40 }));
679
+ registry.register(makeSandboxPlugin("high", { priority: 90 }));
680
+ await registry.initializeAll(minimalCtx);
681
+
682
+ const result = await wireSandboxPlugins(registry, "/semantic");
683
+
684
+ expect(result.pluginId).toBe("high");
685
+ const output = await result.backend!.exec("ls");
686
+ expect(output.stdout).toContain("[high]");
687
+ });
688
+
689
+ test("uses default priority (60) when omitted", async () => {
690
+ registry.register(makeSandboxPlugin("explicit-low", { priority: 50 }));
691
+ registry.register(makeSandboxPlugin("default-priority")); // no priority → 60
692
+ await registry.initializeAll(minimalCtx);
693
+
694
+ const result = await wireSandboxPlugins(registry, "/semantic");
695
+
696
+ expect(result.pluginId).toBe("default-priority");
697
+ });
698
+
699
+ test("falls through to next plugin when create() throws", async () => {
700
+ registry.register(makeSandboxPlugin("broken", {
701
+ priority: 90,
702
+ createFn: async () => { throw new Error("init failed"); },
703
+ }));
704
+ registry.register(makeSandboxPlugin("working", { priority: 50 }));
705
+ await registry.initializeAll(minimalCtx);
706
+
707
+ const result = await wireSandboxPlugins(registry, "/semantic");
708
+
709
+ expect(result.pluginId).toBe("working");
710
+ expect(result.failed).toHaveLength(1);
711
+ expect(result.failed[0].pluginId).toBe("broken");
712
+ expect(result.failed[0].error).toBe("init failed");
713
+ });
714
+
715
+ test("returns null when all plugins fail", async () => {
716
+ registry.register(makeSandboxPlugin("broken-1", {
717
+ createFn: async () => { throw new Error("fail 1"); },
718
+ }));
719
+ registry.register(makeSandboxPlugin("broken-2", {
720
+ createFn: async () => { throw new Error("fail 2"); },
721
+ }));
722
+ await registry.initializeAll(minimalCtx);
723
+
724
+ const result = await wireSandboxPlugins(registry, "/semantic");
725
+
726
+ expect(result.backend).toBeNull();
727
+ expect(result.pluginId).toBeNull();
728
+ expect(result.failed).toHaveLength(2);
729
+ });
730
+
731
+ test("returns null when no sandbox plugins registered", async () => {
732
+ await registry.initializeAll(minimalCtx);
733
+
734
+ const result = await wireSandboxPlugins(registry, "/semantic");
735
+
736
+ expect(result.backend).toBeNull();
737
+ expect(result.pluginId).toBeNull();
738
+ expect(result.failed).toEqual([]);
739
+ });
740
+
741
+ test("skips unhealthy sandbox plugins", async () => {
742
+ registry.register(makeSandboxPlugin("healthy"));
743
+ registry.register(makeSandboxPlugin("unhealthy", { unhealthy: true }));
744
+ await registry.initializeAll(minimalCtx);
745
+
746
+ const result = await wireSandboxPlugins(registry, "/semantic");
747
+
748
+ expect(result.pluginId).toBe("healthy");
749
+ expect(result.failed).toEqual([]);
750
+ });
751
+
752
+ test("skips sandbox plugins missing sandbox.create()", async () => {
753
+ const noCreate: PluginLike = {
754
+ id: "no-create",
755
+ types: ["sandbox"],
756
+ version: "1.0.0",
757
+ // No sandbox property
758
+ };
759
+ registry.register(noCreate);
760
+ await registry.initializeAll(minimalCtx);
761
+
762
+ const result = await wireSandboxPlugins(registry, "/semantic");
763
+
764
+ expect(result.backend).toBeNull();
765
+ expect(result.pluginId).toBeNull();
766
+ expect(result.failed).toEqual([]);
767
+ });
768
+
769
+ test("passes semanticRoot to sandbox.create()", async () => {
770
+ let receivedRoot: string | undefined;
771
+ registry.register(makeSandboxPlugin("root-check", {
772
+ createFn: async (root: string) => {
773
+ receivedRoot = root;
774
+ return makeMockBackend("root-check");
775
+ },
776
+ }));
777
+ await registry.initializeAll(minimalCtx);
778
+
779
+ await wireSandboxPlugins(registry, "/my/custom/semantic");
780
+
781
+ expect(receivedRoot).toBe("/my/custom/semantic");
782
+ });
783
+
784
+ test("rejects backend missing exec method from create()", async () => {
785
+ registry.register(makeSandboxPlugin("bad-backend", {
786
+ createFn: async () => ({} as SandboxExecBackend),
787
+ }));
788
+ registry.register(makeSandboxPlugin("good-backend", { priority: 40 }));
789
+ await registry.initializeAll(minimalCtx);
790
+
791
+ const result = await wireSandboxPlugins(registry, "/semantic");
792
+
793
+ // bad-backend has default priority (60) > good-backend (40), tried first but rejected
794
+ expect(result.pluginId).toBe("good-backend");
795
+ expect(result.failed).toHaveLength(1);
796
+ expect(result.failed[0].pluginId).toBe("bad-backend");
797
+ expect(result.failed[0].error).toContain("missing exec method");
798
+ });
799
+ });
@@ -4,6 +4,9 @@
4
4
 
5
5
  export { plugins, PluginRegistry } from "./registry";
6
6
  export type { PluginLike, PluginContextLike, PluginHealthResult, PluginType, PluginStatus, PluginDescription } from "./registry";
7
- export { wireDatasourcePlugins, wireActionPlugins, wireInteractionPlugins, wireContextPlugins } from "./wiring";
7
+ export { wireDatasourcePlugins, wireActionPlugins, wireInteractionPlugins, wireContextPlugins, wireSandboxPlugins } from "./wiring";
8
+ export type { SandboxExecBackend } from "./wiring";
9
+ export { generateMigrationSQL, generateColumnMigrations, applyMigrations, runPluginMigrations, ensureMigrationsTable, getAppliedMigrations, diffSchema, prefixTableName } from "./migrate";
10
+ export type { MigrateDB, MigrationStatement, SchemaDiff } from "./migrate";
8
11
  export { dispatchHook } from "./hooks";
9
12
  export { getPluginTools, setPluginTools, getContextFragments, setContextFragments } from "./tools";
@@ -14,7 +14,7 @@ import { createLogger } from "@atlas/api/lib/logger";
14
14
  const log = createLogger("plugins:migrate");
15
15
 
16
16
  // ---------------------------------------------------------------------------
17
- // Types (structural — no import from @atlas/plugin-sdk)
17
+ // Types (structural — no import from @useatlas/plugin-sdk)
18
18
  // ---------------------------------------------------------------------------
19
19
 
20
20
  interface FieldDef {
@@ -273,6 +273,109 @@ export async function applyMigrations(
273
273
  return { applied, skipped };
274
274
  }
275
275
 
276
+ // ---------------------------------------------------------------------------
277
+ // Column migrations (ALTER TABLE ADD COLUMN)
278
+ // ---------------------------------------------------------------------------
279
+
280
+ /**
281
+ * Query the actual columns for a given table from information_schema.
282
+ * Returns a Set of lowercase column names.
283
+ */
284
+ async function getExistingColumns(db: MigrateDB, tableName: string): Promise<Set<string>> {
285
+ const result = await db.query(
286
+ "SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = $1",
287
+ [tableName],
288
+ );
289
+ return new Set(result.rows.map((r) => String(r.column_name).toLowerCase()));
290
+ }
291
+
292
+ /**
293
+ * Generate ALTER TABLE ADD COLUMN IF NOT EXISTS statements for fields
294
+ * that exist in the plugin schema but not in the actual database table.
295
+ *
296
+ * Column detection queries `information_schema.columns` in the `public`
297
+ * schema. Only handles column additions — column removal and type
298
+ * changes are not supported (require manual migration).
299
+ */
300
+ export async function generateColumnMigrations(
301
+ db: MigrateDB,
302
+ plugins: PluginWithSchema[],
303
+ ): Promise<MigrationStatement[]> {
304
+ const statements: MigrationStatement[] = [];
305
+
306
+ for (const plugin of plugins) {
307
+ if (!plugin.schema) continue;
308
+
309
+ for (const [tableName, tableDef] of Object.entries(plugin.schema)) {
310
+ const prefixed = prefixTableName(plugin.id, tableName);
311
+
312
+ // Check if table exists at all — skip if it doesn't (CREATE TABLE will handle it)
313
+ const existing = await getExistingColumns(db, prefixed);
314
+ if (existing.size === 0) {
315
+ log.debug({ table: prefixed, pluginId: plugin.id }, "Table not in information_schema — skipping column migration");
316
+ continue;
317
+ }
318
+
319
+ for (const [fieldName, fieldDef] of Object.entries(tableDef.fields)) {
320
+ if (existing.has(fieldName.toLowerCase())) continue;
321
+
322
+ let colDef: string;
323
+ try {
324
+ colDef = fieldToSQL(fieldName, fieldDef);
325
+ } catch (err) {
326
+ throw new Error(
327
+ `Plugin "${plugin.id}", table "${prefixed}": ${err instanceof Error ? err.message : String(err)}`,
328
+ { cause: err },
329
+ );
330
+ }
331
+ const sql = `ALTER TABLE "${prefixed}" ADD COLUMN IF NOT EXISTS ${colDef};`;
332
+
333
+ statements.push({
334
+ pluginId: plugin.id,
335
+ tableName,
336
+ prefixedName: prefixed,
337
+ sql,
338
+ hash: hashSQL(sql),
339
+ });
340
+ }
341
+ }
342
+ }
343
+
344
+ return statements;
345
+ }
346
+
347
+ // ---------------------------------------------------------------------------
348
+ // High-level orchestrator
349
+ // ---------------------------------------------------------------------------
350
+
351
+ /**
352
+ * Run all plugin schema migrations: CREATE TABLE for new tables, then
353
+ * ALTER TABLE ADD COLUMN for new fields on existing tables.
354
+ *
355
+ * Idempotent — safe to call on every startup.
356
+ */
357
+ export async function runPluginMigrations(
358
+ db: MigrateDB,
359
+ plugins: PluginWithSchema[],
360
+ ): Promise<{ applied: string[]; skipped: string[] }> {
361
+ // Phase 1: CREATE TABLE
362
+ const createStatements = generateMigrationSQL(plugins);
363
+ const createResult = await applyMigrations(db, createStatements);
364
+
365
+ // Phase 2: ALTER TABLE ADD COLUMN (for tables that already existed or were just created)
366
+ const columnStatements = await generateColumnMigrations(db, plugins);
367
+ if (columnStatements.length === 0) {
368
+ return createResult;
369
+ }
370
+
371
+ const columnResult = await applyMigrations(db, columnStatements);
372
+
373
+ return {
374
+ applied: [...createResult.applied, ...columnResult.applied],
375
+ skipped: [...createResult.skipped, ...columnResult.skipped],
376
+ };
377
+ }
378
+
276
379
  // ---------------------------------------------------------------------------
277
380
  // Diff: compare declared schema vs actual tables
278
381
  // ---------------------------------------------------------------------------
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Manages plugin lifecycle: registration → initialization → health checks → teardown.
5
5
  * Uses a structural `PluginLike` interface defined locally so `@atlas/api` does not
6
- * depend on `@atlas/plugin-sdk`.
6
+ * depend on `@useatlas/plugin-sdk`.
7
7
  */
8
8
 
9
9
  import { createLogger } from "@atlas/api/lib/logger";
@@ -11,7 +11,7 @@ import { createLogger } from "@atlas/api/lib/logger";
11
11
  const log = createLogger("plugins");
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
- // Structural interfaces (no import from @atlas/plugin-sdk)
14
+ // Structural interfaces (no import from @useatlas/plugin-sdk)
15
15
  // ---------------------------------------------------------------------------
16
16
 
17
17
  export interface PluginHealthResult {
@@ -41,7 +41,8 @@ export interface PluginContextLike {
41
41
  */
42
42
  export interface PluginLike {
43
43
  readonly id: string;
44
- readonly type: PluginType;
44
+ /** Plugin type(s). A plugin can implement multiple types. */
45
+ readonly types: readonly PluginType[];
45
46
  readonly version: string;
46
47
  readonly name?: string;
47
48
  initialize?(ctx: PluginContextLike): Promise<void>;
@@ -59,7 +60,7 @@ interface PluginEntry {
59
60
 
60
61
  export interface PluginDescription {
61
62
  id: string;
62
- type: PluginType;
63
+ types: readonly PluginType[];
63
64
  version: string;
64
65
  name: string;
65
66
  status: PluginStatus;
@@ -83,7 +84,7 @@ export class PluginRegistry {
83
84
  }
84
85
  this.idSet.add(plugin.id);
85
86
  this.entries.push({ plugin, status: "registered" });
86
- log.info({ pluginId: plugin.id, type: plugin.type }, "Plugin registered");
87
+ log.info({ pluginId: plugin.id, types: plugin.types }, "Plugin registered");
87
88
  }
88
89
 
89
90
  /**
@@ -190,13 +191,18 @@ export class PluginRegistry {
190
191
  return this.entries.find((e) => e.plugin.id === id)?.status;
191
192
  }
192
193
 
193
- /** Return plugins of the given type that are currently healthy. */
194
+ /** Return plugins whose types array includes the given type and are currently healthy. */
194
195
  getByType(type: PluginType): PluginLike[] {
195
196
  return this.entries
196
- .filter((e) => e.plugin.type === type && e.status === "healthy")
197
+ .filter((e) => e.plugin.types.includes(type) && e.status === "healthy")
197
198
  .map((e) => e.plugin);
198
199
  }
199
200
 
201
+ /** Return all registered plugins regardless of status (for schema migrations at boot). */
202
+ getAll(): PluginLike[] {
203
+ return this.entries.map((e) => e.plugin);
204
+ }
205
+
200
206
  /** Return all healthy plugins regardless of type (for cross-cutting hooks). */
201
207
  getAllHealthy(): PluginLike[] {
202
208
  return this.entries
@@ -208,7 +214,7 @@ export class PluginRegistry {
208
214
  describe(): PluginDescription[] {
209
215
  return this.entries.map((e) => ({
210
216
  id: e.plugin.id,
211
- type: e.plugin.type,
217
+ types: e.plugin.types,
212
218
  version: e.plugin.version,
213
219
  name: e.plugin.name ?? e.plugin.id,
214
220
  status: e.status,