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