From ff6d2b3c4b13b021747f6b4e596113ccbfd25999 Mon Sep 17 00:00:00 2001 From: J Date: Wed, 1 Jul 2026 14:17:02 +0800 Subject: [PATCH] docs(slack): add commands scope to /issue manifest; fix chat-run wording (MUL-3908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review follow-up: the manifest examples registered features.slash_commands but omitted the commands bot scope, so updating + reinstalling could still fail to grant the /issue command. Add - commands to oauth_config.scopes.bot in all four locales and document it in the permissions table. Also correct the misleading "no agent run" wording in the slash-command header and router comment: a todo issue assigned to the agent still triggers it via maybeEnqueueOnAssign (issue-assignment), like the message /issue — the slash command only skips the chat session / chat run. Co-authored-by: multica-agent --- apps/docs/content/docs/slack-bot-integration.ja.mdx | 2 ++ apps/docs/content/docs/slack-bot-integration.ko.mdx | 2 ++ apps/docs/content/docs/slack-bot-integration.mdx | 2 ++ apps/docs/content/docs/slack-bot-integration.zh.mdx | 2 ++ server/cmd/server/router.go | 5 +++-- server/internal/integrations/slack/slash_command.go | 12 +++++++----- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/docs/content/docs/slack-bot-integration.ja.mdx b/apps/docs/content/docs/slack-bot-integration.ja.mdx index da482e127..b05dd5348 100644 --- a/apps/docs/content/docs/slack-bot-integration.ja.mdx +++ b/apps/docs/content/docs/slack-bot-integration.ja.mdx @@ -49,6 +49,7 @@ oauth_config: - chat:write - reactions:write - users:read + - commands settings: event_subscriptions: bot_events: @@ -76,6 +77,7 @@ settings: | `im:history` + `message.im` | Bot への **DM** を受け取ります(すべての DM メッセージが読み取られます)。 | | `channels:history` / `groups:history` / `mpim:history` + 対応する `message.*` イベント | パブリックチャンネル、プライベートチャンネル、グループ DM のメッセージを受け取ります。これらの中では、Bot は自分を **@ メンション**したメッセージにのみ反応します。 | | `users:read` | Multica が(`bots.info` を介して)あなたの 2 つのトークンが同じアプリのものであることを検証するために必要です。 | +| `commands` | `/issue` スラッシュコマンドを有効にする bot スコープです(`features.slash_commands` と対になります)。これがないと、マニフェストを更新して再インストールしてもコマンドが付与されません。 | | `socket_mode_enabled: true` | Bot は Socket Mode 経由で外向きに接続します——**公開 URL/リクエスト URL は不要**です。 | | `interactivity.is_enabled: false` | Multica のプロンプトはボタンではなくプレーンなリンクなので、インタラクティビティは不要です。 | | `slash_commands`(`/issue`) | `/issue` スラッシュコマンドを登録し、誰でもメッセージ入力欄から Multica イシューを起票できるようにします。Socket Mode 経由で配信され、リクエスト URL は不要です。 | diff --git a/apps/docs/content/docs/slack-bot-integration.ko.mdx b/apps/docs/content/docs/slack-bot-integration.ko.mdx index bb719272d..ca8bf194f 100644 --- a/apps/docs/content/docs/slack-bot-integration.ko.mdx +++ b/apps/docs/content/docs/slack-bot-integration.ko.mdx @@ -49,6 +49,7 @@ oauth_config: - chat:write - reactions:write - users:read + - commands settings: event_subscriptions: bot_events: @@ -76,6 +77,7 @@ settings: | `im:history` + `message.im` | 봇에게 보내는 **DM**을 받습니다(모든 DM 메시지를 읽습니다). | | `channels:history` / `groups:history` / `mpim:history` + 대응하는 `message.*` 이벤트 | 공개 채널, 비공개 채널, 그룹 DM의 메시지를 받습니다. 이런 곳에서 봇은 자신을 **@로 멘션한** 메시지에만 반응합니다. | | `users:read` | Multica가 두 토큰이 같은 앱에 속하는지 (`bots.info`를 통해) 확인하는 데 필요합니다. | +| `commands` | `/issue` 슬래시 명령을 활성화하는 bot 스코프입니다(`features.slash_commands`와 짝을 이룹니다). 이것이 없으면 매니페스트를 업데이트하고 재설치해도 명령이 부여되지 않습니다. | | `socket_mode_enabled: true` | 봇이 Socket Mode로 밖으로 연결합니다 — **공개 URL / request URL이 필요 없습니다**. | | `interactivity.is_enabled: false` | Multica의 안내는 버튼이 아니라 일반 링크라서, interactivity가 필요 없습니다. | | `slash_commands`(`/issue`) | `/issue` 슬래시 명령을 등록해, 누구나 메시지 입력창에서 Multica 이슈를 생성할 수 있게 합니다. Socket Mode로 전달되며 요청 URL이 필요 없습니다. | diff --git a/apps/docs/content/docs/slack-bot-integration.mdx b/apps/docs/content/docs/slack-bot-integration.mdx index 28668d753..b1a389820 100644 --- a/apps/docs/content/docs/slack-bot-integration.mdx +++ b/apps/docs/content/docs/slack-bot-integration.mdx @@ -49,6 +49,7 @@ oauth_config: - chat:write - reactions:write - users:read + - commands settings: event_subscriptions: bot_events: @@ -76,6 +77,7 @@ This manifest configures everything Multica needs, so you don't set anything by | `im:history` + `message.im` | Receive **DMs** to the bot (every DM message is read). | | `channels:history` / `groups:history` / `mpim:history` + the matching `message.*` events | Receive messages in public channels, private channels, and group DMs. In these, the bot only acts on messages that **@-mention** it. | | `users:read` | Required so Multica can verify (via `bots.info`) that your two tokens belong to the same app. | +| `commands` | The bot scope that enables the `/issue` slash command (pairs with `features.slash_commands`). Without it, updating the manifest and reinstalling won't grant the command. | | `socket_mode_enabled: true` | The bot connects out over Socket Mode — **no public URL / request URL needed**. | | `interactivity.is_enabled: false` | Multica's prompts are plain links, not buttons, so interactivity isn't needed. | | `slash_commands` (`/issue`) | Registers the `/issue` slash command so anyone can file a Multica issue from the message box. Delivered over Socket Mode — no request URL. | diff --git a/apps/docs/content/docs/slack-bot-integration.zh.mdx b/apps/docs/content/docs/slack-bot-integration.zh.mdx index b429a7e57..20e8606de 100644 --- a/apps/docs/content/docs/slack-bot-integration.zh.mdx +++ b/apps/docs/content/docs/slack-bot-integration.zh.mdx @@ -49,6 +49,7 @@ oauth_config: - chat:write - reactions:write - users:read + - commands settings: event_subscriptions: bot_events: @@ -76,6 +77,7 @@ settings: | `im:history` + `message.im` | 接收发给 Bot 的**私聊**(每一条私聊消息都会被读取)。 | | `channels:history` / `groups:history` / `mpim:history` + 对应的 `message.*` 事件 | 接收公开频道、私有频道和群组私聊里的消息。在这些场景里,Bot 只对 **@ 了**它的消息做出响应。 | | `users:read` | 必需,这样 Multica 才能(通过 `bots.info`)核实你的两个 token 属于同一个 app。 | +| `commands` | 启用 `/issue` 斜杠命令所需的 bot 权限(和 `features.slash_commands` 搭配)。少了它,即使更新 manifest 并重装,也拿不到这个命令。 | | `socket_mode_enabled: true` | Bot 通过 Socket Mode 向外连接——**无需任何公网 URL / request URL**。 | | `interactivity.is_enabled: false` | Multica 的提示是纯链接,不是按钮,所以不需要交互性。 | | `slash_commands`(`/issue`) | 注册 `/issue` 斜杠命令,让任何人都能从消息框直接创建一个 Multica issue。通过 Socket Mode 下发——无需 request URL。 | diff --git a/server/cmd/server/router.go b/server/cmd/server/router.go index 11dfce457..270677d51 100644 --- a/server/cmd/server/router.go +++ b/server/cmd/server/router.go @@ -471,8 +471,9 @@ func NewRouterWithOptions(pool *pgxpool.Pool, hub *realtime.Hub, bus *events.Bus // `/issue` slash command (MUL-3908): a real Slack slash command, // delivered over the same Socket Mode connection. It is a one-shot - // issue creation (no chat session / agent run) with a private ephemeral - // confirmation, reusing the shared IssueService + binding service. + // issue creation (no chat session or chat run; a todo issue assigned to + // the agent still triggers it via normal issue-assignment) with a private + // ephemeral confirmation, reusing the shared IssueService + binding service. slackSlash := slack.NewSlashCommandProcessor(slack.SlashCommandConfig{ Queries: queries, Issues: h.IssueService, diff --git a/server/internal/integrations/slack/slash_command.go b/server/internal/integrations/slack/slash_command.go index 067b7c375..f2fdf3490 100644 --- a/server/internal/integrations/slack/slash_command.go +++ b/server/internal/integrations/slack/slash_command.go @@ -25,13 +25,15 @@ import ( // slash command in the app manifest is what makes it reach us — as an // `EventTypeSlashCommand` over the same Socket Mode connection. // -// Unlike the message path (session + dedup + debounced agent run), a slash -// command creates no channel message and starts no chat session: it is a -// one-shot issue creation with a PRIVATE (ephemeral) confirmation back to the -// invoker via the command's response_url. It reuses the same installation +// Unlike the message path (chat session + dedup + debounced chat run), a slash +// command creates no channel message and starts no chat session / chat run: it +// is a one-shot issue creation with a PRIVATE (ephemeral) confirmation back to +// the invoker via the command's response_url. It reuses the same installation // routing, identity + membership checks, and the shared IssueService, so a // slash-command issue shares the counter, dup guard, project boundary, -// broadcast, analytics and agent-enqueue with every other create path. +// broadcast, analytics and agent-enqueue with every other create path — i.e. a +// `todo` issue assigned to the agent still triggers the agent through the normal +// issue-assignment path (maybeEnqueueOnAssign), exactly like the message /issue. const issueSlashCommand = "/issue"