@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,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin Slack Web API client using native fetch.
|
|
3
|
+
*
|
|
4
|
+
* No heavy dependencies — POST to slack.com/api endpoints with JSON body
|
|
5
|
+
* and Bearer token auth. For oauth.v2.access, pass an empty token — Slack
|
|
6
|
+
* uses client_id/client_secret from the body instead.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
10
|
+
import type { SlackBlock } from "@atlas/api/lib/slack/format";
|
|
11
|
+
|
|
12
|
+
const log = createLogger("slack-api");
|
|
13
|
+
|
|
14
|
+
const SLACK_API_BASE = "https://slack.com/api";
|
|
15
|
+
|
|
16
|
+
export type SlackAPIResponse =
|
|
17
|
+
| { ok: true; ts?: string; channel?: string; [key: string]: unknown }
|
|
18
|
+
| { ok: false; error: string };
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Call a Slack Web API method.
|
|
22
|
+
*/
|
|
23
|
+
export async function slackAPI(
|
|
24
|
+
method: string,
|
|
25
|
+
token: string,
|
|
26
|
+
body: Record<string, unknown>,
|
|
27
|
+
): Promise<SlackAPIResponse> {
|
|
28
|
+
try {
|
|
29
|
+
const resp = await fetch(`${SLACK_API_BASE}/${method}`, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
33
|
+
Authorization: `Bearer ${token}`,
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (!resp.ok) {
|
|
39
|
+
log.error({ method, status: resp.status }, "Slack API HTTP error");
|
|
40
|
+
return { ok: false, error: `HTTP ${resp.status}` };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
44
|
+
if (!data.ok) {
|
|
45
|
+
log.warn({ method, error: data.error }, "Slack API returned error");
|
|
46
|
+
return { ok: false, error: String(data.error ?? "unknown_error") };
|
|
47
|
+
}
|
|
48
|
+
return data as SlackAPIResponse;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
log.error(
|
|
51
|
+
{ method, err: err instanceof Error ? err.message : String(err) },
|
|
52
|
+
"Slack API request failed",
|
|
53
|
+
);
|
|
54
|
+
return { ok: false, error: `request_failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Post a message to a Slack channel.
|
|
60
|
+
*/
|
|
61
|
+
export async function postMessage(
|
|
62
|
+
token: string,
|
|
63
|
+
params: {
|
|
64
|
+
channel: string;
|
|
65
|
+
text: string;
|
|
66
|
+
blocks?: SlackBlock[];
|
|
67
|
+
thread_ts?: string;
|
|
68
|
+
},
|
|
69
|
+
): Promise<SlackAPIResponse> {
|
|
70
|
+
return slackAPI("chat.postMessage", token, params as Record<string, unknown>);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Update an existing Slack message.
|
|
75
|
+
*/
|
|
76
|
+
export async function updateMessage(
|
|
77
|
+
token: string,
|
|
78
|
+
params: {
|
|
79
|
+
channel: string;
|
|
80
|
+
ts: string;
|
|
81
|
+
text: string;
|
|
82
|
+
blocks?: SlackBlock[];
|
|
83
|
+
},
|
|
84
|
+
): Promise<SlackAPIResponse> {
|
|
85
|
+
return slackAPI("chat.update", token, params as Record<string, unknown>);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Post an ephemeral message visible only to a specific user.
|
|
90
|
+
*/
|
|
91
|
+
export async function postEphemeral(
|
|
92
|
+
token: string,
|
|
93
|
+
params: {
|
|
94
|
+
channel: string;
|
|
95
|
+
user: string;
|
|
96
|
+
text: string;
|
|
97
|
+
blocks?: SlackBlock[];
|
|
98
|
+
thread_ts?: string;
|
|
99
|
+
},
|
|
100
|
+
): Promise<SlackAPIResponse> {
|
|
101
|
+
return slackAPI("chat.postEphemeral", token, params as Record<string, unknown>);
|
|
102
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Atlas query responses to Slack Block Kit format.
|
|
3
|
+
*
|
|
4
|
+
* Respects Slack limits: 50 blocks max, 3000 chars per text block.
|
|
5
|
+
* Truncates large data tables and adds a "Showing first N rows" note.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AgentQueryResult, PendingAction } from "@atlas/api/lib/agent-query";
|
|
9
|
+
|
|
10
|
+
const MAX_TEXT_LENGTH = 3000;
|
|
11
|
+
const MAX_DATA_ROWS = 20;
|
|
12
|
+
const MAX_DATA_CHARS = 3000;
|
|
13
|
+
const MAX_BLOCKS = 50;
|
|
14
|
+
|
|
15
|
+
/** Alias for the shared agent query result — same shape, Slack-specific name. */
|
|
16
|
+
export type SlackQueryResult = AgentQueryResult;
|
|
17
|
+
|
|
18
|
+
export interface SlackButton {
|
|
19
|
+
type: "button";
|
|
20
|
+
text: { type: "plain_text"; text: string };
|
|
21
|
+
action_id: string;
|
|
22
|
+
value: string;
|
|
23
|
+
style?: "primary" | "danger";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type SlackBlock =
|
|
27
|
+
| { type: "section"; text: { type: "mrkdwn" | "plain_text"; text: string } }
|
|
28
|
+
| { type: "context"; elements: { type: "mrkdwn" | "plain_text"; text: string }[] }
|
|
29
|
+
| { type: "actions"; elements: SlackButton[] };
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Format a query result as Slack Block Kit blocks.
|
|
33
|
+
*/
|
|
34
|
+
export function formatQueryResponse(result: SlackQueryResult): SlackBlock[] {
|
|
35
|
+
const blocks: SlackBlock[] = [];
|
|
36
|
+
|
|
37
|
+
// Answer section
|
|
38
|
+
const answer = truncate(result.answer || "No answer generated.", MAX_TEXT_LENGTH);
|
|
39
|
+
blocks.push({
|
|
40
|
+
type: "section",
|
|
41
|
+
text: { type: "mrkdwn", text: answer },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// SQL section
|
|
45
|
+
if (result.sql.length > 0) {
|
|
46
|
+
const sqlText = result.sql.join("\n\n");
|
|
47
|
+
const formatted = truncate(`*SQL*\n\`\`\`${sqlText}\`\`\``, MAX_TEXT_LENGTH);
|
|
48
|
+
blocks.push({
|
|
49
|
+
type: "section",
|
|
50
|
+
text: { type: "mrkdwn", text: formatted },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Data section — column-aligned plain text
|
|
55
|
+
for (const dataset of result.data) {
|
|
56
|
+
if (!dataset.columns.length || !dataset.rows.length) continue;
|
|
57
|
+
|
|
58
|
+
const table = formatDataTable(dataset.columns, dataset.rows);
|
|
59
|
+
if (table) {
|
|
60
|
+
blocks.push({
|
|
61
|
+
type: "section",
|
|
62
|
+
text: { type: "mrkdwn", text: table },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Stay under the block limit
|
|
67
|
+
if (blocks.length >= MAX_BLOCKS - 1) break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Context block with metadata
|
|
71
|
+
blocks.push({
|
|
72
|
+
type: "context",
|
|
73
|
+
elements: [
|
|
74
|
+
{
|
|
75
|
+
type: "mrkdwn",
|
|
76
|
+
text: `${result.steps} steps | ${result.usage.totalTokens.toLocaleString()} tokens`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return blocks.slice(0, MAX_BLOCKS);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Format column data as a code block table.
|
|
86
|
+
*/
|
|
87
|
+
function formatDataTable(
|
|
88
|
+
columns: string[],
|
|
89
|
+
rows: Record<string, unknown>[],
|
|
90
|
+
): string | null {
|
|
91
|
+
if (columns.length === 0 || rows.length === 0) return null;
|
|
92
|
+
|
|
93
|
+
const totalRows = rows.length;
|
|
94
|
+
const displayRows = rows.slice(0, MAX_DATA_ROWS);
|
|
95
|
+
const truncated = totalRows > MAX_DATA_ROWS;
|
|
96
|
+
|
|
97
|
+
// Build column-aligned output
|
|
98
|
+
const header = columns.join(" | ");
|
|
99
|
+
const separator = columns.map((c) => "-".repeat(c.length)).join("-+-");
|
|
100
|
+
const dataLines = displayRows.map((row) =>
|
|
101
|
+
columns.map((col) => String(row[col] ?? "")).join(" | "),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
let table = [header, separator, ...dataLines].join("\n");
|
|
105
|
+
|
|
106
|
+
// Truncate if too long
|
|
107
|
+
if (table.length > MAX_DATA_CHARS) {
|
|
108
|
+
const lines = table.split("\n");
|
|
109
|
+
let charCount = 0;
|
|
110
|
+
let lineCount = 0;
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
if (charCount + line.length + 1 > MAX_DATA_CHARS - 50) break;
|
|
113
|
+
charCount += line.length + 1;
|
|
114
|
+
lineCount++;
|
|
115
|
+
}
|
|
116
|
+
table = lines.slice(0, Math.max(lineCount, 3)).join("\n");
|
|
117
|
+
return `\`\`\`${table}\`\`\`\n_Showing first ${Math.max(lineCount - 2, 1)} of ${totalRows} rows (truncated)_`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const note = truncated
|
|
121
|
+
? `\n_Showing first ${MAX_DATA_ROWS} of ${totalRows} rows_`
|
|
122
|
+
: "";
|
|
123
|
+
|
|
124
|
+
return `\`\`\`${table}\`\`\`${note}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function truncate(text: string, maxLength: number): string {
|
|
128
|
+
if (text.length <= maxLength) return text;
|
|
129
|
+
return text.slice(0, maxLength - 3) + "...";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Format an error message for Slack.
|
|
134
|
+
*/
|
|
135
|
+
export function formatErrorResponse(error: string): SlackBlock[] {
|
|
136
|
+
return [
|
|
137
|
+
{
|
|
138
|
+
type: "section",
|
|
139
|
+
text: {
|
|
140
|
+
type: "mrkdwn",
|
|
141
|
+
text: `:warning: Something went wrong: ${truncate(error, 200)}`,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Format a pending action as a Slack Block Kit approval prompt.
|
|
149
|
+
* Returns a section with the action summary and an actions block with
|
|
150
|
+
* Approve/Deny buttons.
|
|
151
|
+
*/
|
|
152
|
+
export function formatActionApproval(action: PendingAction): SlackBlock[] {
|
|
153
|
+
return [
|
|
154
|
+
{
|
|
155
|
+
type: "section",
|
|
156
|
+
text: {
|
|
157
|
+
type: "mrkdwn",
|
|
158
|
+
text: `:lock: *Action requires approval*\n${truncate(action.summary || action.type, MAX_TEXT_LENGTH - 40)}`,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: "actions",
|
|
163
|
+
elements: [
|
|
164
|
+
{
|
|
165
|
+
type: "button",
|
|
166
|
+
text: { type: "plain_text", text: "Approve" },
|
|
167
|
+
action_id: "atlas_action_approve",
|
|
168
|
+
value: action.id,
|
|
169
|
+
style: "primary",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
type: "button",
|
|
173
|
+
text: { type: "plain_text", text: "Deny" },
|
|
174
|
+
action_id: "atlas_action_deny",
|
|
175
|
+
value: action.id,
|
|
176
|
+
style: "danger",
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Format a resolved action status (replaces the approval buttons).
|
|
185
|
+
*/
|
|
186
|
+
export function formatActionResult(
|
|
187
|
+
action: PendingAction,
|
|
188
|
+
status: "approved" | "denied" | "executed" | "failed",
|
|
189
|
+
error?: string,
|
|
190
|
+
): SlackBlock[] {
|
|
191
|
+
const emoji =
|
|
192
|
+
status === "executed"
|
|
193
|
+
? ":white_check_mark:"
|
|
194
|
+
: status === "approved"
|
|
195
|
+
? ":white_check_mark:"
|
|
196
|
+
: status === "denied"
|
|
197
|
+
? ":no_entry_sign:"
|
|
198
|
+
: ":x:";
|
|
199
|
+
|
|
200
|
+
let text = `${emoji} *Action ${status}*: ${truncate(action.summary || action.type, 200)}`;
|
|
201
|
+
if (error) text += `\n_${truncate(error, 200)}_`;
|
|
202
|
+
|
|
203
|
+
return [
|
|
204
|
+
{
|
|
205
|
+
type: "section",
|
|
206
|
+
text: { type: "mrkdwn", text },
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack installation storage.
|
|
3
|
+
*
|
|
4
|
+
* Stores OAuth bot tokens in the internal database when available.
|
|
5
|
+
* Falls back to SLACK_BOT_TOKEN env var for single-workspace mode.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { hasInternalDB, internalQuery, getInternalDB } from "@atlas/api/lib/db/internal";
|
|
9
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
10
|
+
|
|
11
|
+
const log = createLogger("slack-store");
|
|
12
|
+
|
|
13
|
+
export interface SlackInstallation {
|
|
14
|
+
team_id: string;
|
|
15
|
+
bot_token: string;
|
|
16
|
+
installed_at: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the bot token for a team. Checks internal DB first, then falls
|
|
21
|
+
* back to SLACK_BOT_TOKEN env var.
|
|
22
|
+
*/
|
|
23
|
+
export async function getInstallation(
|
|
24
|
+
teamId: string,
|
|
25
|
+
): Promise<SlackInstallation | null> {
|
|
26
|
+
if (hasInternalDB()) {
|
|
27
|
+
try {
|
|
28
|
+
const rows = await internalQuery<Record<string, unknown>>(
|
|
29
|
+
"SELECT team_id, bot_token, installed_at::text FROM slack_installations WHERE team_id = $1",
|
|
30
|
+
[teamId],
|
|
31
|
+
);
|
|
32
|
+
if (rows.length > 0) {
|
|
33
|
+
const teamIdVal = rows[0].team_id;
|
|
34
|
+
const botToken = rows[0].bot_token;
|
|
35
|
+
const installedAt = rows[0].installed_at;
|
|
36
|
+
if (typeof teamIdVal !== "string" || typeof botToken !== "string" || !botToken) {
|
|
37
|
+
log.warn({ teamId }, "Invalid installation record in database");
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
team_id: teamIdVal,
|
|
42
|
+
bot_token: botToken,
|
|
43
|
+
installed_at: typeof installedAt === "string" ? installedAt : new Date().toISOString(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
log.error(
|
|
49
|
+
{ err: err instanceof Error ? err.message : String(err), teamId },
|
|
50
|
+
"Failed to query slack_installations",
|
|
51
|
+
);
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Single-workspace mode: no internal DB configured, use env var
|
|
57
|
+
const envToken = process.env.SLACK_BOT_TOKEN;
|
|
58
|
+
if (envToken) {
|
|
59
|
+
return {
|
|
60
|
+
team_id: teamId,
|
|
61
|
+
bot_token: envToken,
|
|
62
|
+
installed_at: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Save or update a Slack installation (OAuth flow).
|
|
71
|
+
* Throws if the database write fails.
|
|
72
|
+
*/
|
|
73
|
+
export async function saveInstallation(teamId: string, botToken: string): Promise<void> {
|
|
74
|
+
if (!hasInternalDB()) {
|
|
75
|
+
throw new Error("Cannot save Slack installation — no internal database configured");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const pool = getInternalDB();
|
|
79
|
+
await pool.query(
|
|
80
|
+
`INSERT INTO slack_installations (team_id, bot_token)
|
|
81
|
+
VALUES ($1, $2)
|
|
82
|
+
ON CONFLICT (team_id) DO UPDATE SET bot_token = $2, installed_at = now()`,
|
|
83
|
+
[teamId, botToken],
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Remove a Slack installation.
|
|
89
|
+
* Throws if the database delete fails.
|
|
90
|
+
*/
|
|
91
|
+
export async function deleteInstallation(teamId: string): Promise<void> {
|
|
92
|
+
if (!hasInternalDB()) {
|
|
93
|
+
log.warn({ teamId }, "Cannot delete Slack installation — no internal database configured");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const pool = getInternalDB();
|
|
98
|
+
await pool.query("DELETE FROM slack_installations WHERE team_id = $1", [teamId]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the bot token for a team — convenience wrapper.
|
|
103
|
+
*/
|
|
104
|
+
export async function getBotToken(teamId: string): Promise<string | null> {
|
|
105
|
+
const installation = await getInstallation(teamId);
|
|
106
|
+
return installation?.bot_token ?? null;
|
|
107
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack thread → Atlas conversation ID mapping.
|
|
3
|
+
*
|
|
4
|
+
* Maps Slack thread_ts values to Atlas conversation IDs so follow-up
|
|
5
|
+
* messages in a thread continue the same conversation context.
|
|
6
|
+
*
|
|
7
|
+
* Thread mapping is stored but conversation context is not yet loaded
|
|
8
|
+
* across messages. Each message is currently standalone.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { hasInternalDB, internalQuery, getInternalDB } from "@atlas/api/lib/db/internal";
|
|
12
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
13
|
+
|
|
14
|
+
const log = createLogger("slack-threads");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the Atlas conversation ID for a Slack thread.
|
|
18
|
+
* Returns null if no mapping exists or conversation persistence isn't available.
|
|
19
|
+
*/
|
|
20
|
+
export async function getConversationId(
|
|
21
|
+
channelId: string,
|
|
22
|
+
threadTs: string,
|
|
23
|
+
): Promise<string | null> {
|
|
24
|
+
if (!hasInternalDB()) {
|
|
25
|
+
log.debug("No internal DB — skipping thread mapping lookup");
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const rows = await internalQuery<{ conversation_id: string }>(
|
|
31
|
+
"SELECT conversation_id FROM slack_threads WHERE channel_id = $1 AND thread_ts = $2",
|
|
32
|
+
[channelId, threadTs],
|
|
33
|
+
);
|
|
34
|
+
return rows[0]?.conversation_id ?? null;
|
|
35
|
+
} catch (err) {
|
|
36
|
+
log.error(
|
|
37
|
+
{ err: err instanceof Error ? err.message : String(err), channelId, threadTs },
|
|
38
|
+
"Failed to look up thread mapping",
|
|
39
|
+
);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Store a mapping from Slack thread to Atlas conversation ID.
|
|
46
|
+
*/
|
|
47
|
+
export async function setConversationId(
|
|
48
|
+
channelId: string,
|
|
49
|
+
threadTs: string,
|
|
50
|
+
conversationId: string,
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
if (!hasInternalDB()) {
|
|
53
|
+
log.debug("No internal DB — skipping thread mapping storage");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const pool = getInternalDB();
|
|
58
|
+
await pool.query(
|
|
59
|
+
`INSERT INTO slack_threads (channel_id, thread_ts, conversation_id)
|
|
60
|
+
VALUES ($1, $2, $3)
|
|
61
|
+
ON CONFLICT (thread_ts, channel_id) DO UPDATE SET conversation_id = $3`,
|
|
62
|
+
[channelId, threadTs, conversationId],
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack request signature verification.
|
|
3
|
+
*
|
|
4
|
+
* Verifies incoming requests are genuinely from Slack using HMAC-SHA256
|
|
5
|
+
* signature validation with timing-safe comparison. Rejects requests
|
|
6
|
+
* with timestamps older than 5 minutes to prevent replay attacks.
|
|
7
|
+
*
|
|
8
|
+
* @see https://api.slack.com/authentication/verifying-requests-from-slack
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import crypto from "crypto";
|
|
12
|
+
|
|
13
|
+
const MAX_TIMESTAMP_AGE_SECONDS = 300; // 5 minutes
|
|
14
|
+
|
|
15
|
+
export type VerifyResult =
|
|
16
|
+
| { valid: true }
|
|
17
|
+
| { valid: false; error: string };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Verify a Slack request signature.
|
|
21
|
+
*
|
|
22
|
+
* @param signingSecret - The SLACK_SIGNING_SECRET from app credentials
|
|
23
|
+
* @param signature - The `x-slack-signature` header value (v0=...)
|
|
24
|
+
* @param timestamp - The `x-slack-request-timestamp` header value (unix seconds)
|
|
25
|
+
* @param body - The raw request body string
|
|
26
|
+
*/
|
|
27
|
+
export function verifySlackSignature(
|
|
28
|
+
signingSecret: string,
|
|
29
|
+
signature: string | null,
|
|
30
|
+
timestamp: string | null,
|
|
31
|
+
body: string,
|
|
32
|
+
): VerifyResult {
|
|
33
|
+
if (!signature || !timestamp) {
|
|
34
|
+
return { valid: false, error: "Missing signature or timestamp headers" };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const ts = parseInt(timestamp, 10);
|
|
38
|
+
if (isNaN(ts)) {
|
|
39
|
+
return { valid: false, error: "Invalid timestamp" };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Reject requests with timestamps more than 5 minutes from current time (past or future)
|
|
43
|
+
const now = Math.floor(Date.now() / 1000);
|
|
44
|
+
if (Math.abs(now - ts) > MAX_TIMESTAMP_AGE_SECONDS) {
|
|
45
|
+
return { valid: false, error: "Request timestamp too old" };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const sigBasestring = `v0:${timestamp}:${body}`;
|
|
49
|
+
const mySignature =
|
|
50
|
+
"v0=" +
|
|
51
|
+
crypto
|
|
52
|
+
.createHmac("sha256", signingSecret)
|
|
53
|
+
.update(sigBasestring)
|
|
54
|
+
.digest("hex");
|
|
55
|
+
|
|
56
|
+
// Timing-safe comparison to prevent timing attacks
|
|
57
|
+
try {
|
|
58
|
+
const sigBuffer = Buffer.from(signature, "utf8");
|
|
59
|
+
const myBuffer = Buffer.from(mySignature, "utf8");
|
|
60
|
+
if (sigBuffer.length !== myBuffer.length) {
|
|
61
|
+
return { valid: false, error: "Invalid signature" };
|
|
62
|
+
}
|
|
63
|
+
if (!crypto.timingSafeEqual(sigBuffer, myBuffer)) {
|
|
64
|
+
return { valid: false, error: "Invalid signature" };
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
return { valid: false, error: "Signature verification error" };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { valid: true };
|
|
71
|
+
}
|