@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,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel Sandbox backend for the explore tool.
|
|
3
|
+
*
|
|
4
|
+
* Uses @vercel/sandbox to run commands in an ephemeral microVM.
|
|
5
|
+
* Only loaded when ATLAS_RUNTIME=vercel or running on the Vercel platform.
|
|
6
|
+
*
|
|
7
|
+
* Security: the sandbox runs with networkPolicy "deny-all" (no egress)
|
|
8
|
+
* and its filesystem is ephemeral — writes do not affect the host.
|
|
9
|
+
* Files from semantic/ are copied in at creation time.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ExploreBackend, ExecResult } from "./explore";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
16
|
+
import { SENSITIVE_PATTERNS } from "@atlas/api/lib/security";
|
|
17
|
+
|
|
18
|
+
const log = createLogger("explore-sandbox");
|
|
19
|
+
|
|
20
|
+
function collectSemanticFiles(
|
|
21
|
+
localDir: string,
|
|
22
|
+
sandboxDir: string
|
|
23
|
+
): { path: string; content: Buffer }[] {
|
|
24
|
+
const results: { path: string; content: Buffer }[] = [];
|
|
25
|
+
|
|
26
|
+
function walk(dir: string, relative: string) {
|
|
27
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
28
|
+
const localPath = path.join(dir, entry.name);
|
|
29
|
+
const remotePath = `${relative}/${entry.name}`;
|
|
30
|
+
|
|
31
|
+
if (entry.isSymbolicLink()) {
|
|
32
|
+
// Resolve symlinks — they may point to directories or files
|
|
33
|
+
try {
|
|
34
|
+
const realPath = fs.realpathSync(localPath);
|
|
35
|
+
if (!realPath.startsWith(localDir)) {
|
|
36
|
+
log.warn(
|
|
37
|
+
{ localPath, realPath },
|
|
38
|
+
"Skipping symlink escaping semantic root",
|
|
39
|
+
);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const stat = fs.statSync(localPath);
|
|
43
|
+
if (stat.isDirectory()) {
|
|
44
|
+
walk(localPath, remotePath);
|
|
45
|
+
} else if (stat.isFile()) {
|
|
46
|
+
results.push({
|
|
47
|
+
path: remotePath,
|
|
48
|
+
content: fs.readFileSync(localPath),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
log.warn(
|
|
53
|
+
{ localPath, err: err instanceof Error ? err.message : String(err) },
|
|
54
|
+
"Skipping unreadable symlink",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
} else if (entry.isDirectory()) {
|
|
58
|
+
walk(localPath, remotePath);
|
|
59
|
+
} else if (entry.isFile()) {
|
|
60
|
+
try {
|
|
61
|
+
results.push({
|
|
62
|
+
path: remotePath,
|
|
63
|
+
content: fs.readFileSync(localPath),
|
|
64
|
+
});
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.error(
|
|
67
|
+
{ localPath, err: err instanceof Error ? err.message : String(err) },
|
|
68
|
+
"Failed to read file",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
walk(localDir, sandboxDir);
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Format an error for logging, with extra detail from @vercel/sandbox APIError json/text fields when present. */
|
|
80
|
+
function sandboxErrorDetail(err: unknown): string {
|
|
81
|
+
if (!(err instanceof Error)) return String(err);
|
|
82
|
+
const detail = err.message;
|
|
83
|
+
// APIError from @vercel/sandbox carries json/text with the server response.
|
|
84
|
+
// These properties are not in our type stubs — discovered from runtime errors.
|
|
85
|
+
const json = (err as unknown as Record<string, unknown>).json;
|
|
86
|
+
const text = (err as unknown as Record<string, unknown>).text;
|
|
87
|
+
if (json) {
|
|
88
|
+
try {
|
|
89
|
+
return `${detail} — response: ${JSON.stringify(json)}`;
|
|
90
|
+
} catch {
|
|
91
|
+
return `${detail} — response: [unserializable object]`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (typeof text === "string" && text) return `${detail} — body: ${text.slice(0, 500)}`;
|
|
95
|
+
return detail;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Prefix for sandbox file paths: the SDK resolves relative paths under /vercel/sandbox/.
|
|
99
|
+
const SANDBOX_SEMANTIC_REL = "semantic";
|
|
100
|
+
// Must match the absolute resolution of SANDBOX_SEMANTIC_REL (used as runCommand cwd).
|
|
101
|
+
const SANDBOX_SEMANTIC_CWD = "/vercel/sandbox/semantic";
|
|
102
|
+
|
|
103
|
+
export async function createSandboxBackend(
|
|
104
|
+
semanticRoot: string
|
|
105
|
+
): Promise<ExploreBackend> {
|
|
106
|
+
// 1. Import the optional dependency
|
|
107
|
+
let Sandbox: (typeof import("@vercel/sandbox"))["Sandbox"];
|
|
108
|
+
try {
|
|
109
|
+
({ Sandbox } = await import("@vercel/sandbox"));
|
|
110
|
+
} catch (err) {
|
|
111
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
112
|
+
log.error({ err: detail }, "Failed to import @vercel/sandbox");
|
|
113
|
+
throw new Error(
|
|
114
|
+
"Vercel Sandbox runtime selected but @vercel/sandbox is not installed. " +
|
|
115
|
+
"Run 'bun add @vercel/sandbox' or set ATLAS_RUNTIME to a different backend.",
|
|
116
|
+
{ cause: err }
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 2. Create the sandbox
|
|
121
|
+
let sandbox: InstanceType<typeof Sandbox>;
|
|
122
|
+
try {
|
|
123
|
+
sandbox = await Sandbox.create({
|
|
124
|
+
runtime: "node24",
|
|
125
|
+
networkPolicy: "deny-all",
|
|
126
|
+
});
|
|
127
|
+
} catch (err) {
|
|
128
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
129
|
+
log.error({ err: detail }, "Sandbox.create() failed");
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Failed to create Vercel Sandbox: ${detail}. ` +
|
|
132
|
+
"Check your Vercel deployment configuration and sandbox quotas.",
|
|
133
|
+
{ cause: err }
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// 3. Collect semantic layer files
|
|
139
|
+
// Use relative paths so the SDK writes under /vercel/sandbox/ (the writable
|
|
140
|
+
// base directory). Absolute root paths like /semantic cause the Sandbox API
|
|
141
|
+
// to return HTTP 400 — the SDK resolves relative paths to /vercel/sandbox/.
|
|
142
|
+
let files: { path: string; content: Buffer }[];
|
|
143
|
+
try {
|
|
144
|
+
files = collectSemanticFiles(semanticRoot, SANDBOX_SEMANTIC_REL);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
147
|
+
log.error({ err: detail }, "Failed to collect semantic layer files");
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Cannot read semantic layer at ${semanticRoot}: ${detail}. ` +
|
|
150
|
+
"Ensure the semantic/ directory exists and is readable.",
|
|
151
|
+
{ cause: err }
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (files.length === 0) {
|
|
156
|
+
log.error(
|
|
157
|
+
{ semanticRoot },
|
|
158
|
+
"No semantic layer files found — sandbox will have empty semantic directory",
|
|
159
|
+
);
|
|
160
|
+
throw new Error(
|
|
161
|
+
"No semantic layer files found. " +
|
|
162
|
+
"Run 'bun run atlas -- init' to generate a semantic layer, then redeploy."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 4. Copy semantic files into the sandbox filesystem
|
|
167
|
+
// Create directories first (mkDir is not recursive), then upload files.
|
|
168
|
+
const dirs = new Set<string>();
|
|
169
|
+
for (const f of files) {
|
|
170
|
+
let dir = path.posix.dirname(f.path);
|
|
171
|
+
while (dir !== "/" && dir !== ".") {
|
|
172
|
+
dirs.add(dir);
|
|
173
|
+
dir = path.posix.dirname(dir);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const dir of [...dirs].sort()) {
|
|
178
|
+
try {
|
|
179
|
+
await sandbox.mkDir(dir);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
const detail = sandboxErrorDetail(err);
|
|
182
|
+
log.error({ err: detail, dir }, "Failed to create directory in sandbox");
|
|
183
|
+
const safeDetail = SENSITIVE_PATTERNS.test(detail)
|
|
184
|
+
? "sandbox API error (details in server logs)"
|
|
185
|
+
: detail;
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Failed to create directory "${dir}" in sandbox: ${safeDetail}.`,
|
|
188
|
+
{ cause: err },
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
await sandbox.writeFiles(files);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
const detail = sandboxErrorDetail(err);
|
|
197
|
+
log.error({ err: detail, fileCount: files.length }, "Failed to write files into sandbox");
|
|
198
|
+
const safeDetail = SENSITIVE_PATTERNS.test(detail)
|
|
199
|
+
? "sandbox API error (details in server logs)"
|
|
200
|
+
: detail;
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Failed to upload ${files.length} semantic files to sandbox: ${safeDetail}.`,
|
|
203
|
+
{ cause: err }
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// Clean up the sandbox before re-throwing
|
|
208
|
+
try {
|
|
209
|
+
await sandbox.stop();
|
|
210
|
+
} catch (stopErr) {
|
|
211
|
+
log.warn(
|
|
212
|
+
{ err: stopErr instanceof Error ? stopErr.message : String(stopErr) },
|
|
213
|
+
"Failed to stop sandbox during error cleanup",
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
exec: async (command: string): Promise<ExecResult> => {
|
|
221
|
+
try {
|
|
222
|
+
const result = await sandbox.runCommand({
|
|
223
|
+
cmd: "sh",
|
|
224
|
+
args: ["-c", command],
|
|
225
|
+
cwd: SANDBOX_SEMANTIC_CWD,
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
stdout: await result.stdout(),
|
|
229
|
+
stderr: await result.stderr(),
|
|
230
|
+
exitCode: result.exitCode,
|
|
231
|
+
};
|
|
232
|
+
} catch (err) {
|
|
233
|
+
const detail = sandboxErrorDetail(err);
|
|
234
|
+
log.error({ err: detail }, "Sandbox command failed");
|
|
235
|
+
// Stop the broken sandbox before invalidating the cache
|
|
236
|
+
try {
|
|
237
|
+
await sandbox.stop();
|
|
238
|
+
} catch (stopErr) {
|
|
239
|
+
log.warn(
|
|
240
|
+
{ err: stopErr instanceof Error ? stopErr.message : String(stopErr) },
|
|
241
|
+
"Failed to stop sandbox during error cleanup",
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
// Invalidate cached backend so next call creates a fresh sandbox
|
|
245
|
+
const { invalidateExploreBackend } = await import("./explore");
|
|
246
|
+
invalidateExploreBackend();
|
|
247
|
+
throw new Error(
|
|
248
|
+
`Sandbox infrastructure error: ${detail}. Will retry with a fresh sandbox.`,
|
|
249
|
+
{ cause: err }
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
close: async () => {
|
|
254
|
+
try {
|
|
255
|
+
await sandbox.stop();
|
|
256
|
+
} catch (err) {
|
|
257
|
+
log.warn(
|
|
258
|
+
{ err: err instanceof Error ? err.message : String(err) },
|
|
259
|
+
"Failed to stop sandbox during close",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidecar backend for the explore tool.
|
|
3
|
+
*
|
|
4
|
+
* Calls a separate HTTP service (the sandbox sidecar) to execute shell
|
|
5
|
+
* commands against the semantic layer. Isolation is provided by the
|
|
6
|
+
* container boundary — the sidecar has no secrets, no database drivers,
|
|
7
|
+
* and a minimal filesystem (bash, coreutils, semantic/ files).
|
|
8
|
+
* Communication occurs only via HTTP.
|
|
9
|
+
*
|
|
10
|
+
* Configured via ATLAS_SANDBOX_URL (e.g. http://sandbox-sidecar:8080).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ExploreBackend, ExecResult } from "./explore";
|
|
14
|
+
import type { SidecarExecResponse } from "@atlas/api/lib/sidecar-types";
|
|
15
|
+
import { createLogger } from "@atlas/api/lib/logger";
|
|
16
|
+
|
|
17
|
+
const log = createLogger("explore-sidecar");
|
|
18
|
+
|
|
19
|
+
/** Default timeout for sidecar requests (ms). */
|
|
20
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
21
|
+
|
|
22
|
+
/** HTTP-level timeout — slightly longer than the command timeout to allow for overhead. */
|
|
23
|
+
const HTTP_OVERHEAD_MS = 5_000;
|
|
24
|
+
|
|
25
|
+
export async function createSidecarBackend(
|
|
26
|
+
sidecarUrl: string,
|
|
27
|
+
): Promise<ExploreBackend> {
|
|
28
|
+
const authToken = process.env.SIDECAR_AUTH_TOKEN;
|
|
29
|
+
|
|
30
|
+
let baseUrl: URL;
|
|
31
|
+
try {
|
|
32
|
+
baseUrl = new URL(sidecarUrl);
|
|
33
|
+
} catch {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Invalid ATLAS_SANDBOX_URL: "${sidecarUrl}". Expected a valid URL (e.g. http://sandbox-sidecar:8080).`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const execUrl = new URL("/exec", baseUrl).toString();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
exec: async (command: string): Promise<ExecResult> => {
|
|
43
|
+
const timeout = DEFAULT_TIMEOUT_MS;
|
|
44
|
+
|
|
45
|
+
let response: Response;
|
|
46
|
+
try {
|
|
47
|
+
response = await fetch(execUrl, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({ command, timeout }),
|
|
54
|
+
signal: AbortSignal.timeout(timeout + HTTP_OVERHEAD_MS),
|
|
55
|
+
});
|
|
56
|
+
} catch (err) {
|
|
57
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
58
|
+
|
|
59
|
+
// Connection refused or timeout — sidecar may be down
|
|
60
|
+
if (
|
|
61
|
+
detail.includes("ECONNREFUSED") ||
|
|
62
|
+
detail.includes("fetch failed") ||
|
|
63
|
+
detail.includes("Failed to connect")
|
|
64
|
+
) {
|
|
65
|
+
log.error({ err: detail, url: execUrl }, "Sidecar connection failed");
|
|
66
|
+
// Invalidate backend cache so the next call re-evaluates the backend priority chain.
|
|
67
|
+
// If the sidecar stays down, the system falls back to just-bash.
|
|
68
|
+
const { invalidateExploreBackend } = await import("./explore");
|
|
69
|
+
invalidateExploreBackend();
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Sidecar unreachable at ${baseUrl.origin}: ${detail}. ` +
|
|
72
|
+
"Check that the sandbox-sidecar service is running.",
|
|
73
|
+
{ cause: err },
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (detail.includes("TimeoutError") || detail.includes("timed out") || detail.includes("aborted")) {
|
|
78
|
+
log.warn({ command, timeout }, "Sidecar request timed out");
|
|
79
|
+
return {
|
|
80
|
+
stdout: "",
|
|
81
|
+
stderr: `Command timed out after ${timeout}ms`,
|
|
82
|
+
exitCode: 124, // Conventional timeout exit code (matches GNU timeout(1))
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
log.error({ err: detail, command }, "Sidecar request failed");
|
|
87
|
+
throw new Error(`Sidecar request failed: ${detail}`, { cause: err });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Handle HTTP-level errors from the sidecar
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
let errorBody: string;
|
|
93
|
+
try {
|
|
94
|
+
errorBody = await response.text();
|
|
95
|
+
} catch {
|
|
96
|
+
errorBody = `HTTP ${response.status}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
log.error(
|
|
100
|
+
{ status: response.status, body: errorBody.slice(0, 500) },
|
|
101
|
+
"Sidecar returned HTTP error",
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// 500 with exec response shape — the sidecar wraps execution errors
|
|
105
|
+
if (response.status === 500) {
|
|
106
|
+
try {
|
|
107
|
+
const parsed = JSON.parse(errorBody);
|
|
108
|
+
if (typeof parsed.exitCode === "number") {
|
|
109
|
+
return {
|
|
110
|
+
stdout: parsed.stdout ?? "",
|
|
111
|
+
stderr: parsed.stderr ?? errorBody,
|
|
112
|
+
exitCode: parsed.exitCode,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
} catch (parseErr) {
|
|
116
|
+
// Sidecar returned non-JSON 500 body — fall through to generic error
|
|
117
|
+
log.debug(
|
|
118
|
+
{ status: response.status, parseError: parseErr instanceof Error ? parseErr.message : String(parseErr) },
|
|
119
|
+
"HTTP 500 body is not valid exec JSON — using generic error",
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
stdout: "",
|
|
126
|
+
stderr: `Sidecar error (HTTP ${response.status}): ${errorBody.slice(0, 500)}`,
|
|
127
|
+
exitCode: 1,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Parse the exec response
|
|
132
|
+
let parsed: unknown;
|
|
133
|
+
try {
|
|
134
|
+
parsed = await response.json();
|
|
135
|
+
} catch (err) {
|
|
136
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
137
|
+
log.error({ err: detail }, "Failed to parse sidecar response");
|
|
138
|
+
return {
|
|
139
|
+
stdout: "",
|
|
140
|
+
stderr: `Failed to parse sidecar response: ${detail}`,
|
|
141
|
+
exitCode: 1,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (typeof parsed !== "object" || parsed === null || typeof (parsed as Record<string, unknown>).exitCode !== "number") {
|
|
146
|
+
log.error({ body: JSON.stringify(parsed).slice(0, 500) }, "Sidecar returned unexpected response shape");
|
|
147
|
+
return {
|
|
148
|
+
stdout: "",
|
|
149
|
+
stderr: "Sidecar returned an unexpected response format. Check ATLAS_SANDBOX_URL configuration.",
|
|
150
|
+
exitCode: 1,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const result = parsed as SidecarExecResponse;
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
stdout: result.stdout ?? "",
|
|
158
|
+
stderr: result.stderr ?? "",
|
|
159
|
+
exitCode: result.exitCode,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|