slackhive 0.1.37 → 0.1.39
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/.dockerignore +14 -0
- package/.env.example +44 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +65 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +27 -0
- package/.github/dependabot.yml +20 -0
- package/.github/workflows/audit.yml +149 -0
- package/.github/workflows/ci.yml +135 -0
- package/CHANGELOG.md +52 -0
- package/CODE_OF_CONDUCT.md +37 -0
- package/CONTRIBUTING.md +204 -0
- package/LICENSE +21 -0
- package/README.md +19 -0
- package/SECURITY.md +47 -0
- package/apps/runner/Dockerfile +33 -0
- package/apps/runner/dist/__tests__/channel-restrictions.test.d.ts +8 -0
- package/apps/runner/dist/__tests__/channel-restrictions.test.js +63 -0
- package/apps/runner/dist/__tests__/channel-restrictions.test.js.map +1 -0
- package/apps/runner/dist/__tests__/claude-handler-resolve.test.d.ts +20 -0
- package/apps/runner/dist/__tests__/claude-handler-resolve.test.js +178 -0
- package/apps/runner/dist/__tests__/claude-handler-resolve.test.js.map +1 -0
- package/apps/runner/dist/__tests__/compile-claude-md.test.d.ts +13 -0
- package/apps/runner/dist/__tests__/compile-claude-md.test.js +144 -0
- package/apps/runner/dist/__tests__/compile-claude-md.test.js.map +1 -0
- package/apps/runner/dist/__tests__/memory-sync.test.d.ts +11 -0
- package/apps/runner/dist/__tests__/memory-sync.test.js +56 -0
- package/apps/runner/dist/__tests__/memory-sync.test.js.map +1 -0
- package/apps/runner/dist/__tests__/slack-file-support.test.d.ts +9 -0
- package/apps/runner/dist/__tests__/slack-file-support.test.js +271 -0
- package/apps/runner/dist/__tests__/slack-file-support.test.js.map +1 -0
- package/apps/runner/dist/__tests__/slack-formatting.test.d.ts +12 -0
- package/apps/runner/dist/__tests__/slack-formatting.test.js +400 -0
- package/apps/runner/dist/__tests__/slack-formatting.test.js.map +1 -0
- package/apps/runner/dist/__tests__/thread-context.test.d.ts +12 -0
- package/apps/runner/dist/__tests__/thread-context.test.js +182 -0
- package/apps/runner/dist/__tests__/thread-context.test.js.map +1 -0
- package/apps/runner/dist/agent-runner.d.ts +118 -0
- package/apps/runner/dist/agent-runner.js +352 -0
- package/apps/runner/dist/agent-runner.js.map +1 -0
- package/apps/runner/dist/claude-handler.d.ts +122 -0
- package/apps/runner/dist/claude-handler.js +402 -0
- package/apps/runner/dist/claude-handler.js.map +1 -0
- package/apps/runner/dist/compile-claude-md.d.ts +59 -0
- package/apps/runner/dist/compile-claude-md.js +291 -0
- package/apps/runner/dist/compile-claude-md.js.map +1 -0
- package/apps/runner/dist/correction-handler.d.ts +46 -0
- package/apps/runner/dist/correction-handler.js +162 -0
- package/apps/runner/dist/correction-handler.js.map +1 -0
- package/apps/runner/dist/correction-manager.d.ts +53 -0
- package/apps/runner/dist/correction-manager.js +241 -0
- package/apps/runner/dist/correction-manager.js.map +1 -0
- package/apps/runner/dist/db.d.ts +193 -0
- package/apps/runner/dist/db.js +492 -0
- package/apps/runner/dist/db.js.map +1 -0
- package/apps/runner/dist/index.d.ts +9 -0
- package/apps/runner/dist/index.js +43 -0
- package/apps/runner/dist/index.js.map +1 -0
- package/apps/runner/dist/job-scheduler.d.ts +57 -0
- package/apps/runner/dist/job-scheduler.js +150 -0
- package/apps/runner/dist/job-scheduler.js.map +1 -0
- package/apps/runner/dist/logger.d.ts +32 -0
- package/apps/runner/dist/logger.js +52 -0
- package/apps/runner/dist/logger.js.map +1 -0
- package/apps/runner/dist/mcp-process-manager.d.ts +38 -0
- package/apps/runner/dist/mcp-process-manager.js +189 -0
- package/apps/runner/dist/mcp-process-manager.js.map +1 -0
- package/apps/runner/dist/memory-mcp.d.ts +14 -0
- package/apps/runner/dist/memory-mcp.js +88 -0
- package/apps/runner/dist/memory-mcp.js.map +1 -0
- package/apps/runner/dist/memory-watcher.d.ts +78 -0
- package/apps/runner/dist/memory-watcher.js +220 -0
- package/apps/runner/dist/memory-watcher.js.map +1 -0
- package/apps/runner/dist/slack-handler.d.ts +120 -0
- package/apps/runner/dist/slack-handler.js +843 -0
- package/apps/runner/dist/slack-handler.js.map +1 -0
- package/apps/runner/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/apps/runner/package.json +42 -0
- package/apps/runner/src/__tests__/channel-restrictions.test.ts +75 -0
- package/apps/runner/src/__tests__/claude-handler-resolve.test.ts +160 -0
- package/apps/runner/src/__tests__/compile-claude-md.test.ts +139 -0
- package/apps/runner/src/__tests__/memory-sync.test.ts +59 -0
- package/apps/runner/src/__tests__/slack-file-support.test.ts +376 -0
- package/apps/runner/src/__tests__/slack-formatting.test.ts +495 -0
- package/apps/runner/src/__tests__/thread-context.test.ts +215 -0
- package/apps/runner/src/agent-runner.ts +397 -0
- package/apps/runner/src/claude-handler.ts +475 -0
- package/apps/runner/src/compile-claude-md.ts +283 -0
- package/apps/runner/src/correction-handler.ts +191 -0
- package/apps/runner/src/correction-manager.ts +285 -0
- package/apps/runner/src/db.ts +604 -0
- package/apps/runner/src/index.ts +46 -0
- package/apps/runner/src/job-scheduler.ts +165 -0
- package/apps/runner/src/logger.ts +49 -0
- package/apps/runner/src/mcp-process-manager.ts +195 -0
- package/apps/runner/src/memory-mcp.ts +85 -0
- package/apps/runner/src/memory-watcher.ts +215 -0
- package/apps/runner/src/slack-handler.ts +929 -0
- package/apps/runner/tsconfig.json +17 -0
- package/apps/runner/vitest.config.mts +17 -0
- package/apps/web/.eslintrc.json +3 -0
- package/apps/web/.next/app-build-manifest.json +323 -0
- package/apps/web/.next/app-path-routes-manifest.json +46 -0
- package/apps/web/.next/build-manifest.json +33 -0
- package/apps/web/.next/cache/.previewinfo +1 -0
- package/apps/web/.next/cache/.rscinfo +1 -0
- package/apps/web/.next/cache/webpack/client-production/0.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/1.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/2.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/3.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/4.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/index.pack +0 -0
- package/apps/web/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/apps/web/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/apps/web/.next/cache/webpack/edge-server-production/1.pack +0 -0
- package/apps/web/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/apps/web/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
- package/apps/web/.next/cache/webpack/server-production/0.pack +0 -0
- package/apps/web/.next/cache/webpack/server-production/1.pack +0 -0
- package/apps/web/.next/cache/webpack/server-production/2.pack +0 -0
- package/apps/web/.next/cache/webpack/server-production/index.pack +0 -0
- package/apps/web/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/apps/web/.next/diagnostics/build-diagnostics.json +6 -0
- package/apps/web/.next/diagnostics/framework.json +1 -0
- package/apps/web/.next/package.json +1 -0
- package/apps/web/.next/react-loadable-manifest.json +1 -0
- package/apps/web/.next/server/app/_not-found/page.js +2 -0
- package/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/agents/[slug]/page.js +4 -0
- package/apps/web/.next/server/app/agents/[slug]/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/agents/[slug]/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/agents/new/page.js +2 -0
- package/apps/web/.next/server/app/agents/new/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/agents/new/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/access/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/access/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/access/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/claude-md/route.js +6 -0
- package/apps/web/.next/server/app/api/agents/[id]/claude-md/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/claude-md/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/logs/route.js +3 -0
- package/apps/web/.next/server/app/api/agents/[id]/logs/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/logs/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/manifest/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/manifest/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/manifest/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/mcps/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/mcps/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/mcps/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/[memId]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/memories/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/permissions/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/permissions/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/permissions/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/reload/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/reload/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/reload/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/restrictions/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/restrictions/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/restrictions/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/route.js +33 -0
- package/apps/web/.next/server/app/api/agents/[id]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/[skillId]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/skills/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/slack-info/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/slack-info/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/slack-info/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/restore/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/[sid]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/snapshots/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/start/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/start/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/start/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/stop/route.js +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/stop/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/[id]/stop/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/agents/route.js +91 -0
- package/apps/web/.next/server/app/api/agents/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/agents/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/auth/login/route.js +1 -0
- package/apps/web/.next/server/app/api/auth/login/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/auth/logout/route.js +1 -0
- package/apps/web/.next/server/app/api/auth/logout/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/auth/me/route.js +1 -0
- package/apps/web/.next/server/app/api/auth/me/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/auth/users/[id]/route.js +1 -0
- package/apps/web/.next/server/app/api/auth/users/[id]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/auth/users/[id]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/auth/users/route.js +1 -0
- package/apps/web/.next/server/app/api/auth/users/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/auth/users/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/env-vars/[key]/route.js +1 -0
- package/apps/web/.next/server/app/api/env-vars/[key]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/env-vars/[key]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/env-vars/route.js +1 -0
- package/apps/web/.next/server/app/api/env-vars/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/env-vars/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/route.js +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/runs/route.js +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/runs/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/jobs/[id]/runs/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/jobs/route.js +1 -0
- package/apps/web/.next/server/app/api/jobs/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/jobs/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/route.js +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/test/route.js +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/test/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/mcps/[id]/test/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/mcps/route.js +1 -0
- package/apps/web/.next/server/app/api/mcps/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/mcps/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/api/settings/route.js +1 -0
- package/apps/web/.next/server/app/api/settings/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/icon.svg/route.js +1 -0
- package/apps/web/.next/server/app/icon.svg/route.js.nft.json +1 -0
- package/apps/web/.next/server/app/jobs/page.js +2 -0
- package/apps/web/.next/server/app/jobs/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/jobs/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/login/page.js +2 -0
- package/apps/web/.next/server/app/login/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/login/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/page.js +2 -0
- package/apps/web/.next/server/app/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/settings/env-vars/page.js +2 -0
- package/apps/web/.next/server/app/settings/env-vars/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/settings/env-vars/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/settings/mcps/page.js +2 -0
- package/apps/web/.next/server/app/settings/mcps/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/settings/mcps/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app/settings/page.js +2 -0
- package/apps/web/.next/server/app/settings/page.js.nft.json +1 -0
- package/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -0
- package/apps/web/.next/server/app-paths-manifest.json +46 -0
- package/apps/web/.next/server/chunks/1157.js +9 -0
- package/apps/web/.next/server/chunks/2287.js +1 -0
- package/apps/web/.next/server/chunks/3444.js +1 -0
- package/apps/web/.next/server/chunks/383.js +6 -0
- package/apps/web/.next/server/chunks/4012.js +58 -0
- package/apps/web/.next/server/chunks/6791.js +1 -0
- package/apps/web/.next/server/chunks/7171.js +1 -0
- package/apps/web/.next/server/chunks/8819.js +22 -0
- package/apps/web/.next/server/edge-runtime-webpack.js +2 -0
- package/apps/web/.next/server/edge-runtime-webpack.js.map +1 -0
- package/apps/web/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/apps/web/.next/server/middleware-build-manifest.js +1 -0
- package/apps/web/.next/server/middleware-manifest.json +32 -0
- package/apps/web/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/apps/web/.next/server/next-font-manifest.js +1 -0
- package/apps/web/.next/server/next-font-manifest.json +1 -0
- package/apps/web/.next/server/pages/_app.js +1 -0
- package/apps/web/.next/server/pages/_app.js.nft.json +1 -0
- package/apps/web/.next/server/pages/_document.js +1 -0
- package/apps/web/.next/server/pages/_document.js.nft.json +1 -0
- package/apps/web/.next/server/pages/_error.js +19 -0
- package/apps/web/.next/server/pages/_error.js.nft.json +1 -0
- package/apps/web/.next/server/pages-manifest.json +5 -0
- package/apps/web/.next/server/server-reference-manifest.js +1 -0
- package/apps/web/.next/server/server-reference-manifest.json +1 -0
- package/apps/web/.next/server/src/middleware.js +14 -0
- package/apps/web/.next/server/src/middleware.js.map +1 -0
- package/apps/web/.next/server/webpack-runtime.js +1 -0
- package/apps/web/.next/static/chunks/18-90b700ea37b686a2.js +1 -0
- package/apps/web/.next/static/chunks/87c73c54-24122e7b92478d00.js +1 -0
- package/apps/web/.next/static/chunks/9664-af80478aa73ba424.js +1 -0
- package/apps/web/.next/static/chunks/app/_not-found/page-b9cee17ed89ca24a.js +1 -0
- package/apps/web/.next/static/chunks/app/agents/[slug]/page-18369fc3fe1a9a7b.js +1 -0
- package/apps/web/.next/static/chunks/app/agents/new/page-bf11cf8901c7e2cd.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/access/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/claude-md/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/logs/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/manifest/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/mcps/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/memories/[memId]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/memories/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/permissions/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/reload/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/restrictions/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/skills/[skillId]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/skills/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/slack-info/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/[sid]/restore/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/[sid]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/snapshots/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/start/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/[id]/stop/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/agents/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/auth/login/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/auth/logout/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/auth/me/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/auth/users/[id]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/auth/users/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/env-vars/[key]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/env-vars/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/jobs/[id]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/jobs/[id]/runs/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/jobs/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/mcps/[id]/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/mcps/[id]/test/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/mcps/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/api/settings/route-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/jobs/page-f5aa89a47c50efd8.js +1 -0
- package/apps/web/.next/static/chunks/app/layout-2079f4964aa7314e.js +1 -0
- package/apps/web/.next/static/chunks/app/login/layout-07f0f73ac9839899.js +1 -0
- package/apps/web/.next/static/chunks/app/login/page-aa259283dc38e8f9.js +1 -0
- package/apps/web/.next/static/chunks/app/page-e83437b608104dff.js +1 -0
- package/apps/web/.next/static/chunks/app/settings/env-vars/page-06479dbdfb78b76b.js +1 -0
- package/apps/web/.next/static/chunks/app/settings/mcps/page-75650686ed6490c7.js +1 -0
- package/apps/web/.next/static/chunks/app/settings/page-e1e62fc41ff6cddd.js +1 -0
- package/apps/web/.next/static/chunks/framework-811407f832a33072.js +1 -0
- package/apps/web/.next/static/chunks/main-3f1cddbdd67b1546.js +1 -0
- package/apps/web/.next/static/chunks/main-app-cebd8a6a5ccbf72d.js +1 -0
- package/apps/web/.next/static/chunks/pages/_app-50fa07b56b2d29ac.js +1 -0
- package/apps/web/.next/static/chunks/pages/_error-fed8688bdd23f211.js +1 -0
- package/apps/web/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/apps/web/.next/static/chunks/webpack-6c05566dba553c97.js +1 -0
- package/apps/web/.next/static/css/15371687405525e2.css +5 -0
- package/apps/web/.next/static/ikfNbLhuw7jntn35bz0lk/_buildManifest.js +1 -0
- package/apps/web/.next/static/ikfNbLhuw7jntn35bz0lk/_ssgManifest.js +1 -0
- package/apps/web/.next/trace +5 -0
- package/apps/web/.next/types/app/agents/[slug]/page.ts +84 -0
- package/apps/web/.next/types/app/agents/new/page.ts +84 -0
- package/apps/web/.next/types/app/api/agents/[id]/access/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/claude-md/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/logs/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/manifest/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/mcps/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/memories/[memId]/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/memories/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/permissions/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/reload/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/restrictions/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/skills/[skillId]/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/skills/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/slack-info/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/snapshots/[sid]/restore/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/snapshots/[sid]/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/snapshots/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/start/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/[id]/stop/route.ts +347 -0
- package/apps/web/.next/types/app/api/agents/route.ts +347 -0
- package/apps/web/.next/types/app/api/auth/login/route.ts +347 -0
- package/apps/web/.next/types/app/api/auth/logout/route.ts +347 -0
- package/apps/web/.next/types/app/api/auth/me/route.ts +347 -0
- package/apps/web/.next/types/app/api/auth/users/[id]/route.ts +347 -0
- package/apps/web/.next/types/app/api/auth/users/route.ts +347 -0
- package/apps/web/.next/types/app/api/env-vars/[key]/route.ts +347 -0
- package/apps/web/.next/types/app/api/env-vars/route.ts +347 -0
- package/apps/web/.next/types/app/api/jobs/[id]/route.ts +347 -0
- package/apps/web/.next/types/app/api/jobs/[id]/runs/route.ts +347 -0
- package/apps/web/.next/types/app/api/jobs/route.ts +347 -0
- package/apps/web/.next/types/app/api/mcps/[id]/route.ts +347 -0
- package/apps/web/.next/types/app/api/mcps/[id]/test/route.ts +347 -0
- package/apps/web/.next/types/app/api/mcps/route.ts +347 -0
- package/apps/web/.next/types/app/api/settings/route.ts +347 -0
- package/apps/web/.next/types/app/jobs/page.ts +84 -0
- package/apps/web/.next/types/app/login/layout.ts +84 -0
- package/apps/web/.next/types/app/login/page.ts +84 -0
- package/apps/web/.next/types/app/page.ts +84 -0
- package/apps/web/.next/types/app/settings/env-vars/page.ts +84 -0
- package/apps/web/.next/types/app/settings/mcps/page.ts +84 -0
- package/apps/web/.next/types/app/settings/page.ts +84 -0
- package/apps/web/.next/types/cache-life.d.ts +141 -0
- package/apps/web/.next/types/package.json +1 -0
- package/apps/web/.next/types/routes.d.ts +114 -0
- package/apps/web/.next/types/validator.ts +448 -0
- package/apps/web/Dockerfile +37 -0
- package/apps/web/next-env.d.ts +6 -0
- package/apps/web/next.config.js +6 -0
- package/apps/web/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/apps/web/package.json +48 -0
- package/apps/web/postcss.config.js +3 -0
- package/apps/web/public/logo.svg +17 -0
- package/apps/web/src/app/agents/[slug]/page.tsx +2235 -0
- package/apps/web/src/app/agents/new/page.tsx +1161 -0
- package/apps/web/src/app/api/agents/[id]/access/route.ts +76 -0
- package/apps/web/src/app/api/agents/[id]/claude-md/route.ts +111 -0
- package/apps/web/src/app/api/agents/[id]/logs/route.ts +84 -0
- package/apps/web/src/app/api/agents/[id]/manifest/route.ts +32 -0
- package/apps/web/src/app/api/agents/[id]/mcps/route.ts +73 -0
- package/apps/web/src/app/api/agents/[id]/memories/[memId]/route.ts +31 -0
- package/apps/web/src/app/api/agents/[id]/memories/route.ts +56 -0
- package/apps/web/src/app/api/agents/[id]/permissions/route.ts +74 -0
- package/apps/web/src/app/api/agents/[id]/reload/route.ts +33 -0
- package/apps/web/src/app/api/agents/[id]/restrictions/route.ts +85 -0
- package/apps/web/src/app/api/agents/[id]/route.ts +81 -0
- package/apps/web/src/app/api/agents/[id]/skills/[skillId]/route.ts +52 -0
- package/apps/web/src/app/api/agents/[id]/skills/route.ts +80 -0
- package/apps/web/src/app/api/agents/[id]/slack-info/route.ts +38 -0
- package/apps/web/src/app/api/agents/[id]/snapshots/[sid]/restore/route.ts +61 -0
- package/apps/web/src/app/api/agents/[id]/snapshots/[sid]/route.ts +53 -0
- package/apps/web/src/app/api/agents/[id]/snapshots/route.ts +84 -0
- package/apps/web/src/app/api/agents/[id]/start/route.ts +35 -0
- package/apps/web/src/app/api/agents/[id]/stop/route.ts +35 -0
- package/apps/web/src/app/api/agents/route.ts +99 -0
- package/apps/web/src/app/api/auth/login/route.ts +39 -0
- package/apps/web/src/app/api/auth/logout/route.ts +21 -0
- package/apps/web/src/app/api/auth/me/route.ts +24 -0
- package/apps/web/src/app/api/auth/users/[id]/route.ts +48 -0
- package/apps/web/src/app/api/auth/users/route.ts +63 -0
- package/apps/web/src/app/api/env-vars/[key]/route.ts +66 -0
- package/apps/web/src/app/api/env-vars/route.ts +59 -0
- package/apps/web/src/app/api/jobs/[id]/route.ts +51 -0
- package/apps/web/src/app/api/jobs/[id]/runs/route.ts +24 -0
- package/apps/web/src/app/api/jobs/route.ts +42 -0
- package/apps/web/src/app/api/mcps/[id]/route.ts +60 -0
- package/apps/web/src/app/api/mcps/[id]/test/route.ts +195 -0
- package/apps/web/src/app/api/mcps/route.ts +72 -0
- package/apps/web/src/app/api/settings/route.ts +42 -0
- package/apps/web/src/app/globals.css +124 -0
- package/apps/web/src/app/icon.svg +17 -0
- package/apps/web/src/app/jobs/page.tsx +543 -0
- package/apps/web/src/app/layout-shell.tsx +89 -0
- package/apps/web/src/app/layout.tsx +18 -0
- package/apps/web/src/app/login/layout.tsx +9 -0
- package/apps/web/src/app/login/page.tsx +150 -0
- package/apps/web/src/app/page.tsx +573 -0
- package/apps/web/src/app/settings/env-vars/page.tsx +216 -0
- package/apps/web/src/app/settings/mcps/page.tsx +763 -0
- package/apps/web/src/app/settings/page.tsx +528 -0
- package/apps/web/src/app/sidebar.tsx +345 -0
- package/apps/web/src/lib/__tests__/api-guard.test.ts +189 -0
- package/apps/web/src/lib/__tests__/auth.test.ts +262 -0
- package/apps/web/src/lib/__tests__/boss-registry.test.ts +323 -0
- package/apps/web/src/lib/__tests__/compile.test.ts +161 -0
- package/apps/web/src/lib/__tests__/db-agent-hierarchy.test.ts +136 -0
- package/apps/web/src/lib/__tests__/db-env-vars.test.ts +216 -0
- package/apps/web/src/lib/__tests__/db-restrictions.test.ts +117 -0
- package/apps/web/src/lib/__tests__/db.integration.test.ts +271 -0
- package/apps/web/src/lib/__tests__/diff.test.ts +102 -0
- package/apps/web/src/lib/__tests__/mcp-mask.test.ts +274 -0
- package/apps/web/src/lib/__tests__/skill-templates.test.ts +237 -0
- package/apps/web/src/lib/__tests__/slack-manifest.test.ts +105 -0
- package/apps/web/src/lib/api-guard.ts +68 -0
- package/apps/web/src/lib/auth-context.tsx +71 -0
- package/apps/web/src/lib/auth.ts +128 -0
- package/apps/web/src/lib/boss-registry.ts +90 -0
- package/apps/web/src/lib/compile.ts +51 -0
- package/apps/web/src/lib/db.ts +1196 -0
- package/apps/web/src/lib/diff.ts +43 -0
- package/apps/web/src/lib/mcp-mask.ts +91 -0
- package/apps/web/src/lib/portal.tsx +23 -0
- package/apps/web/src/lib/skill-templates.ts +148 -0
- package/apps/web/src/lib/slack-manifest.ts +85 -0
- package/apps/web/src/middleware.ts +68 -0
- package/apps/web/tailwind.config.js +6 -0
- package/apps/web/tsconfig.json +23 -0
- package/apps/web/vitest.config.mts +21 -0
- package/cli/.claude/settings.local.json +6 -0
- package/cli/README.md +281 -0
- package/cli/node_modules/.package-lock.json +427 -0
- package/cli/node_modules/commander/LICENSE +22 -0
- package/cli/node_modules/commander/Readme.md +1157 -0
- package/cli/node_modules/commander/esm.mjs +16 -0
- package/cli/node_modules/commander/index.js +24 -0
- package/cli/node_modules/commander/lib/argument.js +149 -0
- package/cli/node_modules/commander/lib/command.js +2509 -0
- package/cli/node_modules/commander/lib/error.js +39 -0
- package/cli/node_modules/commander/lib/help.js +520 -0
- package/cli/node_modules/commander/lib/option.js +330 -0
- package/cli/node_modules/commander/lib/suggestSimilar.js +101 -0
- package/cli/node_modules/commander/package-support.json +16 -0
- package/cli/node_modules/commander/package.json +84 -0
- package/cli/node_modules/commander/typings/esm.d.mts +3 -0
- package/cli/node_modules/commander/typings/index.d.ts +969 -0
- package/cli/package-lock.json +449 -0
- package/cli/package.json +44 -0
- package/cli/src/commands/init.ts +514 -0
- package/cli/src/commands/manage.ts +115 -0
- package/cli/src/index.ts +63 -0
- package/cli/tsconfig.json +14 -0
- package/docker-compose.yml +122 -0
- package/docs/agents/boss-agents.mdx +108 -0
- package/docs/agents/creating-agents.mdx +132 -0
- package/docs/agents/memory.mdx +113 -0
- package/docs/agents/tools.mdx +103 -0
- package/docs/configuration/env-vars.mdx +166 -0
- package/docs/configuration/mcp-servers.mdx +203 -0
- package/docs/configuration/slack-app.mdx +175 -0
- package/docs/docs.json +79 -0
- package/docs/favicon.svg +17 -0
- package/docs/features/history.mdx +60 -0
- package/docs/features/import-export.mdx +77 -0
- package/docs/features/logs.mdx +131 -0
- package/docs/features/multi-workspace.mdx +90 -0
- package/docs/features/scheduled-jobs.mdx +231 -0
- package/docs/features/users.mdx +92 -0
- package/docs/introduction.mdx +160 -0
- package/docs/logo/dark.svg +17 -0
- package/docs/logo/light.svg +17 -0
- package/docs/logo/wide-dark.svg +12 -0
- package/docs/logo/wide-light.svg +12 -0
- package/docs/quickstart.mdx +270 -0
- package/docs/self-hosting/docker.mdx +151 -0
- package/docs/self-hosting/production.mdx +176 -0
- package/package.json +20 -36
- package/packages/shared/dist/index.d.ts +8 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +24 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/types.d.ts +584 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/types.js +39 -0
- package/packages/shared/dist/types.js.map +1 -0
- package/packages/shared/package.json +15 -0
- package/packages/shared/src/db/schema.sql +354 -0
- package/packages/shared/src/index.ts +8 -0
- package/packages/shared/src/types.ts +683 -0
- package/packages/shared/tsconfig.json +17 -0
- package/scripts/dev.sh +45 -0
- /package/{dist → cli/dist}/commands/init.d.ts +0 -0
- /package/{dist → cli/dist}/commands/init.js +0 -0
- /package/{dist → cli/dist}/commands/manage.d.ts +0 -0
- /package/{dist → cli/dist}/commands/manage.js +0 -0
- /package/{dist → cli/dist}/index.d.ts +0 -0
- /package/{dist → cli/dist}/index.js +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Current user API — returns session info from cookie.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/auth/me
|
|
5
|
+
*
|
|
6
|
+
* @module web/api/auth/me
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { NextResponse } from 'next/server';
|
|
10
|
+
import { getSessionFromRequest } from '@/lib/auth';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Returns the current user's username and role from the session cookie.
|
|
14
|
+
*
|
|
15
|
+
* @param {Request} req - Incoming request.
|
|
16
|
+
* @returns {Promise<NextResponse>} JSON with user info or 401.
|
|
17
|
+
*/
|
|
18
|
+
export async function GET(req: Request): Promise<NextResponse> {
|
|
19
|
+
const session = getSessionFromRequest(req);
|
|
20
|
+
if (!session) {
|
|
21
|
+
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
|
22
|
+
}
|
|
23
|
+
return NextResponse.json({ username: session.username, role: session.role });
|
|
24
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview User management API — delete and update role.
|
|
3
|
+
*
|
|
4
|
+
* DELETE /api/auth/users/[id] — Delete a user (admin only)
|
|
5
|
+
* PATCH /api/auth/users/[id] — Update a user's role (admin only)
|
|
6
|
+
*
|
|
7
|
+
* @module web/api/auth/users/[id]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { NextResponse } from 'next/server';
|
|
11
|
+
import { requireRole } from '@/lib/auth';
|
|
12
|
+
import { deleteUser, updateUserRole } from '@/lib/db';
|
|
13
|
+
|
|
14
|
+
const VALID_ROLES = ['admin', 'editor', 'viewer'];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Deletes a user by ID (admin only).
|
|
18
|
+
*/
|
|
19
|
+
export async function DELETE(req: Request, { params }: { params: Promise<{ id: string }> }): Promise<NextResponse> {
|
|
20
|
+
try {
|
|
21
|
+
requireRole(req, 'admin');
|
|
22
|
+
} catch {
|
|
23
|
+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
|
24
|
+
}
|
|
25
|
+
const { id } = await params;
|
|
26
|
+
await deleteUser(id);
|
|
27
|
+
return new NextResponse(null, { status: 204 });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Updates a user's role (admin only).
|
|
32
|
+
* Body: { role: 'admin' | 'editor' | 'viewer' }
|
|
33
|
+
*/
|
|
34
|
+
export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }): Promise<NextResponse> {
|
|
35
|
+
try {
|
|
36
|
+
requireRole(req, 'admin');
|
|
37
|
+
} catch {
|
|
38
|
+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
|
39
|
+
}
|
|
40
|
+
const { id } = await params;
|
|
41
|
+
const body = await req.json().catch(() => ({}));
|
|
42
|
+
const { role } = body;
|
|
43
|
+
if (!role || !VALID_ROLES.includes(role)) {
|
|
44
|
+
return NextResponse.json({ error: `Invalid role. Must be one of: ${VALID_ROLES.join(', ')}` }, { status: 400 });
|
|
45
|
+
}
|
|
46
|
+
await updateUserRole(id, role);
|
|
47
|
+
return NextResponse.json({ id, role });
|
|
48
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview User management API — list and create users.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/auth/users — list all users (admin only).
|
|
5
|
+
* POST /api/auth/users — create a user `{ username, password, role }` (admin only).
|
|
6
|
+
*
|
|
7
|
+
* @module web/api/auth/users
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { NextResponse } from 'next/server';
|
|
11
|
+
import { requireRole, hashPassword } from '@/lib/auth';
|
|
12
|
+
import { getAllUsers, createUser } from '@/lib/db';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lists all platform users (excluding password hashes).
|
|
16
|
+
*
|
|
17
|
+
* @param {Request} req - Incoming request.
|
|
18
|
+
* @returns {Promise<NextResponse>} JSON array of users.
|
|
19
|
+
*/
|
|
20
|
+
export async function GET(req: Request): Promise<NextResponse> {
|
|
21
|
+
try {
|
|
22
|
+
requireRole(req, 'admin');
|
|
23
|
+
} catch {
|
|
24
|
+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
|
25
|
+
}
|
|
26
|
+
const users = await getAllUsers();
|
|
27
|
+
return NextResponse.json(users);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new platform user.
|
|
32
|
+
*
|
|
33
|
+
* @param {Request} req - JSON body with `username`, `password`, `role`.
|
|
34
|
+
* @returns {Promise<NextResponse>} Created user JSON.
|
|
35
|
+
*/
|
|
36
|
+
export async function POST(req: Request): Promise<NextResponse> {
|
|
37
|
+
try {
|
|
38
|
+
requireRole(req, 'admin');
|
|
39
|
+
} catch {
|
|
40
|
+
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { username, password, role } = await req.json();
|
|
44
|
+
|
|
45
|
+
if (!username || !password) {
|
|
46
|
+
return NextResponse.json({ error: 'username and password required' }, { status: 400 });
|
|
47
|
+
}
|
|
48
|
+
if (role && !['admin', 'editor', 'viewer'].includes(role)) {
|
|
49
|
+
return NextResponse.json({ error: 'role must be admin, editor, or viewer' }, { status: 400 });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const hash = await hashPassword(password);
|
|
54
|
+
const user = await createUser(username, hash, role || 'viewer');
|
|
55
|
+
return NextResponse.json(user, { status: 201 });
|
|
56
|
+
} catch (e: unknown) {
|
|
57
|
+
const msg = e instanceof Error ? e.message : 'Unknown error';
|
|
58
|
+
if (msg.includes('unique') || msg.includes('duplicate')) {
|
|
59
|
+
return NextResponse.json({ error: 'Username already exists' }, { status: 409 });
|
|
60
|
+
}
|
|
61
|
+
return NextResponse.json({ error: msg }, { status: 500 });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview REST API for a single env var entry.
|
|
3
|
+
*
|
|
4
|
+
* PUT /api/env-vars/[key] — Update value and/or description
|
|
5
|
+
* DELETE /api/env-vars/[key] — Remove the env var
|
|
6
|
+
*
|
|
7
|
+
* @module web/api/env-vars/[key]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
11
|
+
import { setEnvVar, updateEnvVarDescription, deleteEnvVar } from '@/lib/db';
|
|
12
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* PUT /api/env-vars/[key]
|
|
16
|
+
* Updates an env var. Supply value to replace it, description to update label.
|
|
17
|
+
* At least one of value or description must be provided.
|
|
18
|
+
*
|
|
19
|
+
* @param {NextRequest} request - Body: { value?: string, description?: string }
|
|
20
|
+
* @param {{ params: { key: string } }} context - Route params.
|
|
21
|
+
* @returns {Promise<NextResponse>}
|
|
22
|
+
*/
|
|
23
|
+
export async function PUT(
|
|
24
|
+
request: NextRequest,
|
|
25
|
+
{ params }: { params: Promise<{ key: string }> }
|
|
26
|
+
): Promise<NextResponse> {
|
|
27
|
+
const denied = guardAdmin(request);
|
|
28
|
+
if (denied) return denied;
|
|
29
|
+
try {
|
|
30
|
+
const { key } = await params;
|
|
31
|
+
const body = (await request.json()) as { value?: string; description?: string };
|
|
32
|
+
if (body.value !== undefined) {
|
|
33
|
+
await setEnvVar(key, body.value, body.description);
|
|
34
|
+
} else if (body.description !== undefined) {
|
|
35
|
+
await updateEnvVarDescription(key, body.description);
|
|
36
|
+
} else {
|
|
37
|
+
return NextResponse.json({ error: 'value or description required' }, { status: 400 });
|
|
38
|
+
}
|
|
39
|
+
return NextResponse.json({ key });
|
|
40
|
+
} catch (err) {
|
|
41
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* DELETE /api/env-vars/[key]
|
|
47
|
+
* Removes an env var from the store.
|
|
48
|
+
*
|
|
49
|
+
* @param {NextRequest} request - Incoming request.
|
|
50
|
+
* @param {{ params: { key: string } }} context - Route params.
|
|
51
|
+
* @returns {Promise<NextResponse>}
|
|
52
|
+
*/
|
|
53
|
+
export async function DELETE(
|
|
54
|
+
request: NextRequest,
|
|
55
|
+
{ params }: { params: Promise<{ key: string }> }
|
|
56
|
+
): Promise<NextResponse> {
|
|
57
|
+
const denied = guardAdmin(request);
|
|
58
|
+
if (denied) return denied;
|
|
59
|
+
try {
|
|
60
|
+
const { key } = await params;
|
|
61
|
+
await deleteEnvVar(key);
|
|
62
|
+
return NextResponse.json({ ok: true });
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview REST API for the platform env vars store.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/env-vars — List all env var keys + metadata (values never returned)
|
|
5
|
+
* POST /api/env-vars — Create or update an env var
|
|
6
|
+
*
|
|
7
|
+
* @module web/api/env-vars
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
11
|
+
import { getAllEnvVars, setEnvVar } from '@/lib/db';
|
|
12
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/env-vars
|
|
16
|
+
* Returns all env var keys and descriptions. Values are never included.
|
|
17
|
+
*
|
|
18
|
+
* @returns {Promise<NextResponse>} JSON array of { key, description, updatedAt }.
|
|
19
|
+
*/
|
|
20
|
+
export async function GET(): Promise<NextResponse> {
|
|
21
|
+
try {
|
|
22
|
+
const vars = await getAllEnvVars();
|
|
23
|
+
return NextResponse.json(vars);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* POST /api/env-vars
|
|
31
|
+
* Creates or updates an env var. Requires editor role or above.
|
|
32
|
+
*
|
|
33
|
+
* @param {NextRequest} request - Body: { key: string, value: string, description?: string }
|
|
34
|
+
* @returns {Promise<NextResponse>} 201 on success.
|
|
35
|
+
*/
|
|
36
|
+
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
37
|
+
const denied = guardAdmin(request);
|
|
38
|
+
if (denied) return denied;
|
|
39
|
+
try {
|
|
40
|
+
const { key, value, description } = (await request.json()) as {
|
|
41
|
+
key: string;
|
|
42
|
+
value: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
};
|
|
45
|
+
if (!key || !value) {
|
|
46
|
+
return NextResponse.json({ error: 'key and value are required' }, { status: 400 });
|
|
47
|
+
}
|
|
48
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(key)) {
|
|
49
|
+
return NextResponse.json(
|
|
50
|
+
{ error: 'key must be uppercase letters, digits, and underscores (e.g. DATABASE_URL)' },
|
|
51
|
+
{ status: 400 }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
await setEnvVar(key, value, description);
|
|
55
|
+
return NextResponse.json({ key }, { status: 201 });
|
|
56
|
+
} catch (err) {
|
|
57
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Single job API — get, update, delete.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/jobs/[id] — get a job.
|
|
5
|
+
* PATCH /api/jobs/[id] — update a job.
|
|
6
|
+
* DELETE /api/jobs/[id] — delete a job.
|
|
7
|
+
*
|
|
8
|
+
* @module web/api/jobs/[id]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { NextResponse } from 'next/server';
|
|
12
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
13
|
+
import { getJobById, updateJob, deleteJob, publishAgentEvent } from '@/lib/db';
|
|
14
|
+
|
|
15
|
+
type Ctx = { params: Promise<{ id: string }> };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns a single job by ID.
|
|
19
|
+
*/
|
|
20
|
+
export async function GET(_req: Request, { params }: Ctx): Promise<NextResponse> {
|
|
21
|
+
const { id } = await params;
|
|
22
|
+
const job = await getJobById(id);
|
|
23
|
+
if (!job) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
24
|
+
return NextResponse.json(job);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Updates a scheduled job.
|
|
29
|
+
*/
|
|
30
|
+
export async function PATCH(req: Request, { params }: Ctx): Promise<NextResponse> {
|
|
31
|
+
const denied = guardAdmin(req);
|
|
32
|
+
if (denied) return denied;
|
|
33
|
+
const { id } = await params;
|
|
34
|
+
const body = await req.json();
|
|
35
|
+
const job = await updateJob(id, body);
|
|
36
|
+
if (!job) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
37
|
+
await publishAgentEvent({ type: 'reload-jobs' });
|
|
38
|
+
return NextResponse.json(job);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Deletes a scheduled job.
|
|
43
|
+
*/
|
|
44
|
+
export async function DELETE(req: Request, { params }: Ctx): Promise<NextResponse> {
|
|
45
|
+
const denied = guardAdmin(req);
|
|
46
|
+
if (denied) return denied;
|
|
47
|
+
const { id } = await params;
|
|
48
|
+
await deleteJob(id);
|
|
49
|
+
await publishAgentEvent({ type: 'reload-jobs' });
|
|
50
|
+
return new NextResponse(null, { status: 204 });
|
|
51
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Job runs API — execution history for a scheduled job.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/jobs/[id]/runs — paginated run history.
|
|
5
|
+
*
|
|
6
|
+
* @module web/api/jobs/[id]/runs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { NextResponse } from 'next/server';
|
|
10
|
+
import { getJobRuns } from '@/lib/db';
|
|
11
|
+
|
|
12
|
+
type Ctx = { params: Promise<{ id: string }> };
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns paginated run history for a job.
|
|
16
|
+
*/
|
|
17
|
+
export async function GET(req: Request, { params }: Ctx): Promise<NextResponse> {
|
|
18
|
+
const { id } = await params;
|
|
19
|
+
const url = new URL(req.url);
|
|
20
|
+
const limit = parseInt(url.searchParams.get('limit') || '20', 10);
|
|
21
|
+
const offset = parseInt(url.searchParams.get('offset') || '0', 10);
|
|
22
|
+
const runs = await getJobRuns(id, limit, offset);
|
|
23
|
+
return NextResponse.json(runs);
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Scheduled jobs API — list and create jobs.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/jobs — list all jobs with last run info.
|
|
5
|
+
* POST /api/jobs — create a new scheduled job.
|
|
6
|
+
*
|
|
7
|
+
* @module web/api/jobs
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { NextResponse } from 'next/server';
|
|
11
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
12
|
+
import { getAllJobs, createJob, publishAgentEvent } from '@/lib/db';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lists all scheduled jobs with their most recent run.
|
|
16
|
+
*
|
|
17
|
+
* @returns {Promise<NextResponse>} JSON array of jobs.
|
|
18
|
+
*/
|
|
19
|
+
export async function GET(): Promise<NextResponse> {
|
|
20
|
+
const jobs = await getAllJobs();
|
|
21
|
+
return NextResponse.json(jobs);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new scheduled job.
|
|
26
|
+
*
|
|
27
|
+
* @param {Request} req - JSON body with job fields.
|
|
28
|
+
* @returns {Promise<NextResponse>} Created job.
|
|
29
|
+
*/
|
|
30
|
+
export async function POST(req: Request): Promise<NextResponse> {
|
|
31
|
+
const denied = guardAdmin(req);
|
|
32
|
+
if (denied) return denied;
|
|
33
|
+
|
|
34
|
+
const body = await req.json();
|
|
35
|
+
if (!body.name || !body.prompt || !body.cronSchedule || !body.targetId || !body.agentId) {
|
|
36
|
+
return NextResponse.json({ error: 'agentId, name, prompt, cronSchedule, and targetId are required' }, { status: 400 });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const job = await createJob(body);
|
|
40
|
+
await publishAgentEvent({ type: 'reload-jobs' });
|
|
41
|
+
return NextResponse.json(job, { status: 201 });
|
|
42
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview REST API route for a single MCP server resource.
|
|
3
|
+
*
|
|
4
|
+
* GET /api/mcps/[id] — Get a specific MCP server
|
|
5
|
+
* PATCH /api/mcps/[id] — Update an MCP server
|
|
6
|
+
* DELETE /api/mcps/[id] — Remove an MCP server from the catalog
|
|
7
|
+
*
|
|
8
|
+
* @module web/api/mcps/[id]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
12
|
+
import { getMcpServerById, updateMcpServer, deleteMcpServer } from '@/lib/db';
|
|
13
|
+
import type { UpsertMcpServerRequest } from '@slackhive/shared';
|
|
14
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
15
|
+
import { maskMcpServer, mergeMcpConfig } from '@/lib/mcp-mask';
|
|
16
|
+
|
|
17
|
+
type RouteParams = { params: Promise<{ id: string }> };
|
|
18
|
+
|
|
19
|
+
export async function GET(_req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
|
|
20
|
+
try {
|
|
21
|
+
const { id } = await params;
|
|
22
|
+
const server = await getMcpServerById(id);
|
|
23
|
+
if (!server) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
24
|
+
return NextResponse.json(maskMcpServer(server));
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function PATCH(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
|
|
31
|
+
const denied = guardAdmin(req);
|
|
32
|
+
if (denied) return denied;
|
|
33
|
+
try {
|
|
34
|
+
const { id } = await params;
|
|
35
|
+
const body = (await req.json()) as Partial<UpsertMcpServerRequest>;
|
|
36
|
+
// If config is being updated, merge masked values with existing secrets
|
|
37
|
+
if (body.config) {
|
|
38
|
+
const existing = await getMcpServerById(id);
|
|
39
|
+
if (!existing) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
40
|
+
body.config = mergeMcpConfig(existing.config, body.config);
|
|
41
|
+
}
|
|
42
|
+
const updated = await updateMcpServer(id, body);
|
|
43
|
+
if (!updated) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
44
|
+
return NextResponse.json(maskMcpServer(updated));
|
|
45
|
+
} catch (err) {
|
|
46
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function DELETE(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
|
|
51
|
+
const denied = guardAdmin(req);
|
|
52
|
+
if (denied) return denied;
|
|
53
|
+
try {
|
|
54
|
+
const { id } = await params;
|
|
55
|
+
await deleteMcpServer(id);
|
|
56
|
+
return new NextResponse(null, { status: 204 });
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return NextResponse.json({ error: (err as Error).message }, { status: 500 });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MCP server connectivity test endpoint.
|
|
3
|
+
*
|
|
4
|
+
* POST /api/mcps/[id]/test
|
|
5
|
+
*
|
|
6
|
+
* For stdio MCPs: spawns the process, sends an MCP initialize request over
|
|
7
|
+
* stdin/stdout, and verifies the server responds with a valid JSON-RPC result.
|
|
8
|
+
* Times out after 10 seconds.
|
|
9
|
+
*
|
|
10
|
+
* For SSE/HTTP MCPs: sends a GET request to the configured URL and checks
|
|
11
|
+
* for a 2xx response.
|
|
12
|
+
*
|
|
13
|
+
* @module web/api/mcps/[id]/test
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
17
|
+
import { getMcpServerById, getEnvVarValues } from '@/lib/db';
|
|
18
|
+
import { guardAdmin } from '@/lib/api-guard';
|
|
19
|
+
import { spawn } from 'child_process';
|
|
20
|
+
import { writeFile, unlink, mkdir } from 'fs/promises';
|
|
21
|
+
import { tmpdir } from 'os';
|
|
22
|
+
import { join } from 'path';
|
|
23
|
+
import type { McpStdioConfig, McpSseConfig } from '@slackhive/shared';
|
|
24
|
+
|
|
25
|
+
type RouteParams = { params: Promise<{ id: string }> };
|
|
26
|
+
|
|
27
|
+
const TIMEOUT_MS = 30_000;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* POST /api/mcps/[id]/test
|
|
31
|
+
* Runs a quick connectivity check against the MCP server.
|
|
32
|
+
*
|
|
33
|
+
* @returns {Promise<NextResponse>} { ok: true, message } or { ok: false, error }
|
|
34
|
+
*/
|
|
35
|
+
export async function POST(req: NextRequest, { params }: RouteParams): Promise<NextResponse> {
|
|
36
|
+
const denied = guardAdmin(req);
|
|
37
|
+
if (denied) return denied;
|
|
38
|
+
|
|
39
|
+
const { id } = await params;
|
|
40
|
+
const server = await getMcpServerById(id);
|
|
41
|
+
if (!server) {
|
|
42
|
+
return NextResponse.json({ error: 'MCP server not found' }, { status: 404 });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (server.type === 'stdio') {
|
|
47
|
+
const result = await testStdioMcp(server.config as McpStdioConfig, server.name);
|
|
48
|
+
return NextResponse.json(result);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// SSE / HTTP — just check the URL is reachable
|
|
52
|
+
const cfg = server.config as McpSseConfig & { envRefs?: Record<string, string> };
|
|
53
|
+
const headers: Record<string, string> = { ...(cfg.headers ?? {}) };
|
|
54
|
+
if (cfg.envRefs && Object.keys(cfg.envRefs).length > 0) {
|
|
55
|
+
try {
|
|
56
|
+
const envVarValues = await getEnvVarValues();
|
|
57
|
+
for (const [headerKey, storeKey] of Object.entries(cfg.envRefs)) {
|
|
58
|
+
const val = envVarValues[storeKey];
|
|
59
|
+
if (val) headers[headerKey] = headers[headerKey] ? `${headers[headerKey]}${val}` : val;
|
|
60
|
+
}
|
|
61
|
+
} catch { /* skip if env vars unavailable */ }
|
|
62
|
+
}
|
|
63
|
+
const res = await fetch(cfg.url, {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers,
|
|
66
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
67
|
+
});
|
|
68
|
+
if (res.ok || res.status === 405) {
|
|
69
|
+
// 405 Method Not Allowed is fine — the endpoint exists
|
|
70
|
+
return NextResponse.json({ ok: true, message: `Reachable (HTTP ${res.status})` });
|
|
71
|
+
}
|
|
72
|
+
return NextResponse.json({ ok: false, error: `HTTP ${res.status}: ${res.statusText}` });
|
|
73
|
+
} catch (err) {
|
|
74
|
+
return NextResponse.json({ ok: false, error: (err as Error).message });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Spawns a stdio MCP process, sends an MCP initialize request, and verifies
|
|
80
|
+
* the response. Resolves envRefs from the env_vars store before spawning.
|
|
81
|
+
*/
|
|
82
|
+
async function testStdioMcp(
|
|
83
|
+
cfg: McpStdioConfig,
|
|
84
|
+
name: string
|
|
85
|
+
): Promise<{ ok: boolean; message?: string; error?: string; tools?: string[] }> {
|
|
86
|
+
const resolvedEnv: Record<string, string> = { ...(cfg.env ?? {}) };
|
|
87
|
+
if (cfg.envRefs && Object.keys(cfg.envRefs).length > 0) {
|
|
88
|
+
try {
|
|
89
|
+
const envVarValues = await getEnvVarValues();
|
|
90
|
+
for (const [subKey, storeKey] of Object.entries(cfg.envRefs)) {
|
|
91
|
+
if (envVarValues[storeKey] !== undefined) resolvedEnv[subKey] = envVarValues[storeKey];
|
|
92
|
+
}
|
|
93
|
+
} catch { /* ENV_SECRET_KEY not set — skip */ }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let command: string;
|
|
97
|
+
let args: string[];
|
|
98
|
+
let tmpScript: string | null = null;
|
|
99
|
+
|
|
100
|
+
if (cfg.tsSource) {
|
|
101
|
+
const dir = join(tmpdir(), 'slackhive-mcp-test');
|
|
102
|
+
await mkdir(dir, { recursive: true });
|
|
103
|
+
tmpScript = join(dir, `test-${Date.now()}.ts`);
|
|
104
|
+
await writeFile(tmpScript, cfg.tsSource, 'utf8');
|
|
105
|
+
command = 'tsx';
|
|
106
|
+
args = [tmpScript];
|
|
107
|
+
} else {
|
|
108
|
+
command = cfg.command;
|
|
109
|
+
args = cfg.args ?? [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const cleanup = () => { if (tmpScript) unlink(tmpScript).catch(() => {}); };
|
|
113
|
+
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
let stdout = '';
|
|
116
|
+
let stderr = '';
|
|
117
|
+
let settled = false;
|
|
118
|
+
|
|
119
|
+
const timer = setTimeout(() => {
|
|
120
|
+
if (!settled) {
|
|
121
|
+
settled = true;
|
|
122
|
+
proc.kill();
|
|
123
|
+
cleanup();
|
|
124
|
+
resolve({ ok: false, error: `Timed out after ${TIMEOUT_MS / 1000}s — process did not respond` });
|
|
125
|
+
}
|
|
126
|
+
}, TIMEOUT_MS);
|
|
127
|
+
|
|
128
|
+
const proc = spawn(command, args, {
|
|
129
|
+
env: { ...process.env, NODE_PATH: '/app/node_modules', ...resolvedEnv },
|
|
130
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
proc.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
|
134
|
+
|
|
135
|
+
const initRequest = JSON.stringify({
|
|
136
|
+
jsonrpc: '2.0',
|
|
137
|
+
id: 1,
|
|
138
|
+
method: 'initialize',
|
|
139
|
+
params: {
|
|
140
|
+
protocolVersion: '2024-11-05',
|
|
141
|
+
capabilities: {},
|
|
142
|
+
clientInfo: { name: 'slackhive-test', version: '1.0.0' },
|
|
143
|
+
},
|
|
144
|
+
}) + '\n';
|
|
145
|
+
|
|
146
|
+
proc.stdin.write(initRequest);
|
|
147
|
+
|
|
148
|
+
proc.stdout.on('data', (d: Buffer) => {
|
|
149
|
+
stdout += d.toString();
|
|
150
|
+
const lines = stdout.split('\n').filter(l => l.trim());
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
try {
|
|
153
|
+
const msg = JSON.parse(line) as { id?: number; result?: { serverInfo?: { name?: string }; capabilities?: { tools?: unknown } }; error?: { message?: string } };
|
|
154
|
+
if (msg.id === 1) {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
if (!settled) {
|
|
157
|
+
settled = true;
|
|
158
|
+
proc.kill();
|
|
159
|
+
cleanup();
|
|
160
|
+
if (msg.error) {
|
|
161
|
+
resolve({ ok: false, error: msg.error.message ?? 'MCP error' });
|
|
162
|
+
} else {
|
|
163
|
+
const serverName = msg.result?.serverInfo?.name ?? name;
|
|
164
|
+
resolve({ ok: true, message: `Connected to "${serverName}" successfully` });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
// incomplete line, keep buffering
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
proc.on('error', (err) => {
|
|
175
|
+
clearTimeout(timer);
|
|
176
|
+
if (!settled) {
|
|
177
|
+
settled = true;
|
|
178
|
+
cleanup();
|
|
179
|
+
resolve({ ok: false, error: `Failed to start: ${err.message}${stderr ? ` — ${stderr.trim()}` : ''}` });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
proc.on('exit', (code) => {
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
if (!settled) {
|
|
186
|
+
settled = true;
|
|
187
|
+
cleanup();
|
|
188
|
+
resolve({
|
|
189
|
+
ok: false,
|
|
190
|
+
error: `Process exited with code ${code}${stderr ? ` — ${stderr.trim()}` : ''}`,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|