diff --git a/.dev.vars.example b/.dev.vars.example index 5fc7dca6f..3a7f03f4a 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -35,7 +35,12 @@ MOLTBOT_GATEWAY_TOKEN=dev-token-change-in-prod # Optional chat channels # TELEGRAM_BOT_TOKEN=optional +# TELEGRAM_DM_POLICY=pairing # DISCORD_BOT_TOKEN=optional +# DISCORD_DM_POLICY=pairing +# SLACK_BOT_TOKEN=optional +# SLACK_APP_TOKEN=optional +# SLACK_DM_POLICY=pairing # CDP (Chrome DevTools Protocol) configuration for browser automation # CDP_SECRET=shared-secret-for-cdp-auth diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a72a683fc..f88f1bbda 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,6 +56,11 @@ jobs: env: DISCORD_BOT_TOKEN: "fake-discord-bot-token-for-e2e" DISCORD_DM_POLICY: "pairing" + - name: slack + env: + SLACK_BOT_TOKEN: "fake-slack-bot-token-for-e2e" + SLACK_APP_TOKEN: "fake-slack-app-token-for-e2e" + SLACK_DM_POLICY: "pairing" - name: workers-ai env: CF_AI_GATEWAY_MODEL: "workers-ai/@cf/openai/gpt-oss-120b" @@ -120,6 +125,9 @@ jobs: TELEGRAM_DM_POLICY: ${{ matrix.config.env.TELEGRAM_DM_POLICY }} DISCORD_BOT_TOKEN: ${{ matrix.config.env.DISCORD_BOT_TOKEN }} DISCORD_DM_POLICY: ${{ matrix.config.env.DISCORD_DM_POLICY }} + SLACK_BOT_TOKEN: ${{ matrix.config.env.SLACK_BOT_TOKEN }} + SLACK_APP_TOKEN: ${{ matrix.config.env.SLACK_APP_TOKEN }} + SLACK_DM_POLICY: ${{ matrix.config.env.SLACK_DM_POLICY }} CF_AI_GATEWAY_MODEL: ${{ matrix.config.env.CF_AI_GATEWAY_MODEL }} run: cctr -vv test/e2e diff --git a/AGENTS.md b/AGENTS.md index ec30d2c18..7bdf1542a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -206,6 +206,7 @@ These are the env vars passed TO the container (internal names): | `DISCORD_BOT_TOKEN` | `channels.discord.token` | | | `SLACK_BOT_TOKEN` | `channels.slack.botToken` | | | `SLACK_APP_TOKEN` | `channels.slack.appToken` | | +| `SLACK_DM_POLICY` | `channels.slack.dm.policy` | `pairing` (default) or `open` | ## OpenClaw Config Schema diff --git a/README.md b/README.md index ea82f03af..0ad7d5da1 100644 --- a/README.md +++ b/README.md @@ -436,6 +436,7 @@ The previous `AI_GATEWAY_API_KEY` + `AI_GATEWAY_BASE_URL` approach is still supp | `DISCORD_DM_POLICY` | No | Discord DM policy: `pairing` (default) or `open` | | `SLACK_BOT_TOKEN` | No | Slack bot token | | `SLACK_APP_TOKEN` | No | Slack app token | +| `SLACK_DM_POLICY` | No | Slack DM policy: `pairing` (default) or `open` | | `CDP_SECRET` | No | Shared secret for CDP endpoint authentication (see [Browser Automation](#optional-browser-automation-cdp)) | | `WORKER_URL` | No | Public URL of the worker (required for CDP) | diff --git a/moltworker b/moltworker new file mode 160000 index 000000000..ee5006aeb --- /dev/null +++ b/moltworker @@ -0,0 +1 @@ +Subproject commit ee5006aeb3d167bb0e4dd26f4376738c8102e12c diff --git a/src/gateway/env.test.ts b/src/gateway/env.test.ts index 89af2efb8..e0276d35c 100644 --- a/src/gateway/env.test.ts +++ b/src/gateway/env.test.ts @@ -110,6 +110,7 @@ describe('buildEnvVars', () => { DISCORD_DM_POLICY: 'open', SLACK_BOT_TOKEN: 'slack-bot', SLACK_APP_TOKEN: 'slack-app', + SLACK_DM_POLICY: 'open', }); const result = buildEnvVars(env); @@ -119,6 +120,7 @@ describe('buildEnvVars', () => { expect(result.DISCORD_DM_POLICY).toBe('open'); expect(result.SLACK_BOT_TOKEN).toBe('slack-bot'); expect(result.SLACK_APP_TOKEN).toBe('slack-app'); + expect(result.SLACK_DM_POLICY).toBe('open'); }); it('maps DEV_MODE to OPENCLAW_DEV_MODE for container', () => { diff --git a/src/gateway/env.ts b/src/gateway/env.ts index d9e01171b..3163e95d1 100644 --- a/src/gateway/env.ts +++ b/src/gateway/env.ts @@ -45,6 +45,7 @@ export function buildEnvVars(env: MoltbotEnv): Record { if (env.DISCORD_DM_POLICY) envVars.DISCORD_DM_POLICY = env.DISCORD_DM_POLICY; if (env.SLACK_BOT_TOKEN) envVars.SLACK_BOT_TOKEN = env.SLACK_BOT_TOKEN; if (env.SLACK_APP_TOKEN) envVars.SLACK_APP_TOKEN = env.SLACK_APP_TOKEN; + if (env.SLACK_DM_POLICY) envVars.SLACK_DM_POLICY = env.SLACK_DM_POLICY; if (env.CF_AI_GATEWAY_MODEL) envVars.CF_AI_GATEWAY_MODEL = env.CF_AI_GATEWAY_MODEL; if (env.CF_ACCOUNT_ID) envVars.CF_ACCOUNT_ID = env.CF_ACCOUNT_ID; if (env.CDP_SECRET) envVars.CDP_SECRET = env.CDP_SECRET; diff --git a/src/types.ts b/src/types.ts index a85d32da3..52579bbdb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -30,6 +30,7 @@ export interface MoltbotEnv { DISCORD_DM_POLICY?: string; SLACK_BOT_TOKEN?: string; SLACK_APP_TOKEN?: string; + SLACK_DM_POLICY?: string; // Cloudflare Access configuration for admin routes CF_ACCESS_TEAM_DOMAIN?: string; // e.g., 'myteam.cloudflareaccess.com' CF_ACCESS_AUD?: string; // Application Audience (AUD) tag diff --git a/start-openclaw.sh b/start-openclaw.sh index c862a80ce..d8c76abe2 100644 --- a/start-openclaw.sh +++ b/start-openclaw.sh @@ -253,10 +253,16 @@ if (process.env.DISCORD_BOT_TOKEN) { // Slack configuration if (process.env.SLACK_BOT_TOKEN && process.env.SLACK_APP_TOKEN) { + const dmPolicy = process.env.SLACK_DM_POLICY || 'pairing'; + const dm = { policy: dmPolicy }; + if (dmPolicy === 'open') { + dm.allowFrom = ['*']; + } config.channels.slack = { botToken: process.env.SLACK_BOT_TOKEN, appToken: process.env.SLACK_APP_TOKEN, enabled: true, + dm: dm, }; } diff --git a/wrangler.jsonc b/wrangler.jsonc index 7b2ce8d0b..526890fca 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -87,7 +87,9 @@ // - CF_ACCESS_AUD: Cloudflare Access application audience // // Chat channels (optional): - // - TELEGRAM_BOT_TOKEN, DISCORD_BOT_TOKEN, SLACK_BOT_TOKEN, SLACK_APP_TOKEN + // - TELEGRAM_BOT_TOKEN, TELEGRAM_DM_POLICY + // - DISCORD_BOT_TOKEN, DISCORD_DM_POLICY + // - SLACK_BOT_TOKEN, SLACK_APP_TOKEN, SLACK_DM_POLICY // // Browser automation (optional): // - CDP_SECRET: Shared secret for /cdp endpoint authentication