discord-bridge 0.1.5 → 0.2.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 CHANGED
@@ -100,7 +100,6 @@ npm update -g discord-bridge
100
100
 
101
101
  ```bash
102
102
  export DISCORD_BRIDGE_TOKEN="your_bot_token_here"
103
- export DISCORD_BRIDGE_USER_ID="your_user_id_here"
104
103
  ```
105
104
 
106
105
  設定後、`source ~/.zshrc` で反映してください(新しいターミナルを開く場合は不要です)。
@@ -111,11 +110,14 @@ Claude Code / Codex CLI を使うプロジェクトのルートに `.discord-bri
111
110
 
112
111
  ```json
113
112
  {
114
- "channelId": "your_channel_id_here"
113
+ "channelId": "your_channel_id_here",
114
+ "allowedUserIds": ["your_user_id_here"]
115
115
  }
116
116
  ```
117
117
 
118
- > **Note**: チャンネル ID は秘密情報ではありませんが、プロジェクト固有の設定です。チームで共有する場合はそのままコミットし、個人用の場合は `.gitignore` に追加してください。
118
+ `allowedUserIds` に複数のユーザー ID を指定すると、全員の発言に応答します。1人目のユーザーが質問通知(`/ask`)のメンション対象になります。
119
+
120
+ > **Note**: `channelId` と `allowedUserIds` は秘密情報ではありませんが、プロジェクト固有の設定です。チームで共有する場合はそのままコミットし、個人用の場合は `.gitignore` に追加してください。
119
121
 
120
122
  ### 4. スキルのインストール
121
123
 
@@ -190,7 +192,7 @@ Discord で「戻ったよ」と伝えます。
190
192
  | Bot がオフライン | `DISCORD_BRIDGE_TOKEN` が正しいか |
191
193
  | メッセージが届かない | MESSAGE CONTENT INTENT が有効か |
192
194
  | チャンネルが見つからない | `.discord-bridge.json` の `channelId` が正しいか |
193
- | 返答が受信されない | `DISCORD_BRIDGE_USER_ID` が正しいか |
195
+ | 返答が受信されない | `.discord-bridge.json``allowedUserIds` が正しいか |
194
196
 
195
197
  ## ライセンス
196
198
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-bridge",
3
- "version": "0.1.5",
3
+ "version": "0.2.1",
4
4
  "description": "Claude Code <-> Discord bidirectional communication bridge",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,11 +1,20 @@
1
1
  #!/bin/bash
2
- # Discord Bridge ヘルスチェック
2
+ # Discord Bridge ヘルスチェック(チャンネル登録込み)
3
3
  # Usage: discord-status.sh
4
4
  PORT="${DISCORD_BRIDGE_PORT:-13456}"
5
5
  PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
6
6
  CHANNEL_ID=""
7
+ ALLOWED_USER_IDS=""
7
8
  if [ -n "$PROJECT_ROOT" ] && [ -f "$PROJECT_ROOT/.discord-bridge.json" ]; then
8
- CHANNEL_ID=$(python3 -c "import json; print(json.load(open('$PROJECT_ROOT/.discord-bridge.json'))['channelId'])" 2>/dev/null)
9
+ CHANNEL_ID=$(python3 -c "import json; print(json.load(open('$PROJECT_ROOT/.discord-bridge.json')).get('channelId', ''))" 2>/dev/null)
10
+ ALLOWED_USER_IDS=$(python3 -c "import json; print(json.dumps(json.load(open('$PROJECT_ROOT/.discord-bridge.json')).get('allowedUserIds', [])))" 2>/dev/null)
11
+ fi
12
+
13
+ # チャンネル設定をサーバーに登録
14
+ if [ -n "$CHANNEL_ID" ] && [ -n "$ALLOWED_USER_IDS" ]; then
15
+ curl -s -X POST "http://localhost:${PORT}/register-channel" \
16
+ -H "Content-Type: application/json" \
17
+ -d "{\"channelId\": \"${CHANNEL_ID}\", \"allowedUserIds\": ${ALLOWED_USER_IDS}}" > /dev/null
9
18
  fi
10
19
 
11
20
  if [ -n "$CHANNEL_ID" ]; then
package/server/index.js CHANGED
@@ -14,7 +14,6 @@ import path from "path";
14
14
 
15
15
  const CONFIG = {
16
16
  token: process.env.DISCORD_BRIDGE_TOKEN,
17
- userId: process.env.DISCORD_BRIDGE_USER_ID,
18
17
  host: "127.0.0.1",
19
18
  port: parseInt(process.env.DISCORD_BRIDGE_PORT || "13456", 10),
20
19
  defaultTimeout: 5 * 60 * 1000,
@@ -24,14 +23,18 @@ const CONFIG = {
24
23
  sseKeepAliveInterval: 30 * 1000,
25
24
  };
26
25
 
26
+ // Per-channel allowed user IDs (registered via POST /register-channel)
27
+ const channelAllowedUsers = new Map();
28
+
29
+ function isAllowedUser(authorId, channelId) {
30
+ const allowed = channelAllowedUsers.get(channelId);
31
+ if (!allowed || allowed.length === 0) return true; // 未登録チャンネルは全員許可
32
+ return allowed.includes(authorId);
33
+ }
34
+
27
35
  function validateConfig() {
28
- const missing = [];
29
- if (!CONFIG.token) missing.push("DISCORD_BRIDGE_TOKEN");
30
- if (!CONFIG.userId) missing.push("DISCORD_BRIDGE_USER_ID");
31
- if (missing.length > 0) {
32
- throw new Error(
33
- `Missing required environment variables: ${missing.join(", ")}`
34
- );
36
+ if (!CONFIG.token) {
37
+ throw new Error("Missing required environment variable: DISCORD_BRIDGE_TOKEN");
35
38
  }
36
39
  }
37
40
 
@@ -95,8 +98,8 @@ async function initDiscord() {
95
98
  });
96
99
 
97
100
  discordClient.on("messageCreate", (message) => {
98
- if (message.author.id !== CONFIG.userId) return;
99
101
  if (message.author.bot) return;
102
+ if (!isAllowedUser(message.author.id, message.channel.id)) return;
100
103
 
101
104
  const chId = message.channel.id;
102
105
 
@@ -210,10 +213,25 @@ app.get("/health", (_req, res) => {
210
213
  response.channel = channelId;
211
214
  response.queuedMessages = getMessageQueue(channelId).length;
212
215
  response.sseSubscribers = getSseSubscribers(channelId).size;
216
+ response.allowedUserIds = channelAllowedUsers.get(channelId) ?? [];
213
217
  }
214
218
  res.json(response);
215
219
  });
216
220
 
221
+ // ---- POST /register-channel ----
222
+ app.post("/register-channel", (req, res) => {
223
+ const { channelId, allowedUserIds } = req.body;
224
+ if (!channelId) {
225
+ return res.status(400).json({ status: "error", error: "channelId is required" });
226
+ }
227
+ if (!Array.isArray(allowedUserIds)) {
228
+ return res.status(400).json({ status: "error", error: "allowedUserIds must be an array" });
229
+ }
230
+ const ids = allowedUserIds.filter((id) => typeof id === "string");
231
+ channelAllowedUsers.set(channelId, ids);
232
+ res.json({ status: "ok", channelId, allowedUserIds: ids });
233
+ });
234
+
217
235
  // ---- GET /events (SSE) ----
218
236
  app.get("/events", (req, res) => {
219
237
  const channelId = req.query.channelId;
@@ -295,7 +313,8 @@ app.post("/ask", async (req, res) => {
295
313
  fields,
296
314
  });
297
315
 
298
- await sendMessage(channelId, `<@${CONFIG.userId}>`, [embed]);
316
+ const mentionUser = channelAllowedUsers.get(channelId)?.[0];
317
+ await sendMessage(channelId, mentionUser ? `<@${mentionUser}>` : null, [embed]);
299
318
 
300
319
  try {
301
320
  const reply = await waitForReply(channelId, timeoutMs);
@@ -428,7 +447,7 @@ app.get("/messages", async (req, res) => {
428
447
  const ch = await fetchChannel(channelId);
429
448
  const fetched = await ch.messages.fetch({ limit: remaining });
430
449
  const history = fetched
431
- .filter((m) => m.author.id === CONFIG.userId && !m.author.bot)
450
+ .filter((m) => isAllowedUser(m.author.id) && !m.author.bot)
432
451
  .map((m) => ({
433
452
  content: m.content,
434
453
  attachments: m.attachments.map((a) => ({