opencode-discord-notify 0.5.0 → 0.6.0
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-JP.md +7 -1
- package/README.md +7 -1
- package/dist/index.js +94 -16
- package/package.json +1 -1
package/README-JP.md
CHANGED
|
@@ -65,7 +65,8 @@ OpenCode を再起動してください。
|
|
|
65
65
|
- **指定可能キー**: `sessionID`, `permissionID`, `type`, `pattern`, `messageID`, `callID`, `partID`, `role`, `directory`, `projectID`
|
|
66
66
|
- **デフォルト動作**(未設定・空文字): 全て無効化(何も送信しない)
|
|
67
67
|
- **全て送信したい場合**: 全キーを列挙してください
|
|
68
|
-
- **注意**: `session.created` は `DISCORD_SEND_PARAMS` に関わらず `sessionID
|
|
68
|
+
- **注意**: `session.created` は `DISCORD_SEND_PARAMS` に関わらず `sessionID` を必ず含みます
|
|
69
|
+
- `DISCORD_WEBHOOK_FALLBACK_URL`: フォールバック先のテキストチャネル webhook URL(任意。設定すると、`@everyone` または `@here` を含むメッセージが自動的にこの webhook にも送信されます。Forum webhook ではメンションが ping しない Discord の仕様上、有用)
|
|
69
70
|
|
|
70
71
|
## 仕様メモ
|
|
71
72
|
|
|
@@ -91,6 +92,11 @@ OpenCode を再起動してください。
|
|
|
91
92
|
- `tool`: 通知しない
|
|
92
93
|
- `reasoning`: 通知しない(内部思考が含まれる可能性があるため)
|
|
93
94
|
- `DISCORD_SEND_PARAMS` の制御対象は embed の fields のみです(title/description/content/timestamp などは対象外)。また `share` は fields としては送りません(Session started の embed URL には `shareUrl` を使います)。
|
|
95
|
+
- `DISCORD_WEBHOOK_FALLBACK_URL` が設定されている場合:
|
|
96
|
+
- `@everyone` または `@here` を含むメッセージ(`DISCORD_WEBHOOK_COMPLETE_MENTION` または `DISCORD_WEBHOOK_PERMISSION_MENTION` 経由)は、Forum webhook(スレッド投稿)とフォールバック先のテキストチャネル webhook の両方に自動的に送信されます。
|
|
97
|
+
- これにより、Forum webhook ではメンションが ping しない Discord の仕様上、確実に通知を届けることができます。
|
|
98
|
+
- フォールバックメッセージには、`DISCORD_SEND_PARAMS` の設定に関わらず、常に `sessionID` と `thread title` フィールドが含まれます(テキストチャネルでのコンテキスト提供のため)。`thread title` は Forum のスレッド名と同じ値(最初のユーザーテキスト、または存在しない場合はセッションタイトル)です。
|
|
99
|
+
- フォールバック送信は Forum スレッドキューとは独立しており、即座に実行されます。
|
|
94
100
|
|
|
95
101
|
## 動作確認(手動)
|
|
96
102
|
|
package/README.md
CHANGED
|
@@ -67,7 +67,8 @@ Optional:
|
|
|
67
67
|
- **Allowed keys**: `sessionID`, `permissionID`, `type`, `pattern`, `messageID`, `callID`, `partID`, `role`, `directory`, `projectID`
|
|
68
68
|
- **Default behavior** (unset/empty): all fields are disabled (nothing sent)
|
|
69
69
|
- **To send all fields**: list all keys explicitly
|
|
70
|
-
- **Note**: `session.created` always includes `sessionID
|
|
70
|
+
- **Note**: `session.created` always includes `sessionID` regardless
|
|
71
|
+
- `DISCORD_WEBHOOK_FALLBACK_URL`: fallback webhook URL for text channel (optional; when set, messages containing `@everyone` or `@here` are automatically sent to this webhook as well; useful because Forum webhooks may not ping mentions due to Discord behavior)
|
|
71
72
|
|
|
72
73
|
## Notes / behavior
|
|
73
74
|
|
|
@@ -93,6 +94,11 @@ Optional:
|
|
|
93
94
|
- `tool`: not posted
|
|
94
95
|
- `reasoning`: not posted (to avoid exposing internal thoughts)
|
|
95
96
|
- `DISCORD_SEND_PARAMS` controls embed fields only (it does not affect title/description/content/timestamp). `share` is not an embed field (but Session started uses `shareUrl` as the embed URL).
|
|
97
|
+
- When `DISCORD_WEBHOOK_FALLBACK_URL` is set:
|
|
98
|
+
- Messages containing `@everyone` or `@here` (via `DISCORD_WEBHOOK_COMPLETE_MENTION` or `DISCORD_WEBHOOK_PERMISSION_MENTION`) are automatically sent to both the Forum webhook (as a thread post) and the fallback text channel webhook.
|
|
99
|
+
- This ensures reliable notifications while maintaining thread structure in Forums, since Forum webhooks may not ping mentions due to Discord behavior.
|
|
100
|
+
- Fallback messages always include `sessionID` and `thread title` fields, regardless of `DISCORD_SEND_PARAMS` settings, to provide context in the text channel. The `thread title` is the same as the Forum thread name (first user text, or session title if unavailable).
|
|
101
|
+
- Fallback sending is independent of the Forum thread queue and happens immediately.
|
|
96
102
|
|
|
97
103
|
## Manual test
|
|
98
104
|
|
package/dist/index.js
CHANGED
|
@@ -260,6 +260,49 @@ async function postDiscordWebhook(input, deps) {
|
|
|
260
260
|
`Discord webhook failed: ${response.status} ${response.statusText} ${text}`
|
|
261
261
|
);
|
|
262
262
|
}
|
|
263
|
+
async function postFallbackIfNeeded(input, deps) {
|
|
264
|
+
const {
|
|
265
|
+
body,
|
|
266
|
+
mention,
|
|
267
|
+
sessionID,
|
|
268
|
+
fallbackUrl,
|
|
269
|
+
firstUserTextBySession,
|
|
270
|
+
lastSessionInfo
|
|
271
|
+
} = input;
|
|
272
|
+
if (!fallbackUrl || !mention) return;
|
|
273
|
+
const fallbackBody = {
|
|
274
|
+
...body,
|
|
275
|
+
// thread_nameは削除(テキストチャネルでは不要)
|
|
276
|
+
thread_name: void 0
|
|
277
|
+
};
|
|
278
|
+
if (fallbackBody.embeds && fallbackBody.embeds.length > 0) {
|
|
279
|
+
const originalEmbed = fallbackBody.embeds[0];
|
|
280
|
+
const threadTitle = firstUserTextBySession.get(sessionID) || lastSessionInfo.get(sessionID)?.title;
|
|
281
|
+
const additionalFields = buildFields([
|
|
282
|
+
["sessionID", sessionID],
|
|
283
|
+
["thread title", threadTitle]
|
|
284
|
+
]);
|
|
285
|
+
fallbackBody.embeds = [
|
|
286
|
+
{
|
|
287
|
+
...originalEmbed,
|
|
288
|
+
fields: [
|
|
289
|
+
...originalEmbed.fields ?? [],
|
|
290
|
+
...additionalFields ?? []
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
];
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
await postDiscordWebhook(
|
|
297
|
+
{
|
|
298
|
+
webhookUrl: fallbackUrl,
|
|
299
|
+
body: fallbackBody
|
|
300
|
+
},
|
|
301
|
+
deps
|
|
302
|
+
);
|
|
303
|
+
} catch (e) {
|
|
304
|
+
}
|
|
305
|
+
}
|
|
263
306
|
var GLOBAL_GUARD_KEY = "__opencode_discord_notify_registered__";
|
|
264
307
|
var plugin = async ({ client }) => {
|
|
265
308
|
const globalWithGuard = globalThis;
|
|
@@ -281,6 +324,7 @@ var plugin = async ({ client }) => {
|
|
|
281
324
|
const showErrorAlert = showErrorAlertRaw !== "0";
|
|
282
325
|
const waitOnRateLimitMs = DEFAULT_RATE_LIMIT_WAIT_MS;
|
|
283
326
|
const sendParams = parseSendParams(getEnv("DISCORD_SEND_PARAMS"));
|
|
327
|
+
const fallbackWebhookUrl = (getEnv("DISCORD_WEBHOOK_FALLBACK_URL") ?? "").trim() || void 0;
|
|
284
328
|
const lastAlertAtByKey = /* @__PURE__ */ new Map();
|
|
285
329
|
const sentTextPartIds = /* @__PURE__ */ new Set();
|
|
286
330
|
const showToast = async ({ title, message, variant }) => {
|
|
@@ -517,11 +561,7 @@ var plugin = async ({ client }) => {
|
|
|
517
561
|
["directory", info?.directory],
|
|
518
562
|
["share", shareUrl]
|
|
519
563
|
],
|
|
520
|
-
withForcedSendParams(sendParams, [
|
|
521
|
-
"sessionID",
|
|
522
|
-
"projectID",
|
|
523
|
-
"directory"
|
|
524
|
-
])
|
|
564
|
+
withForcedSendParams(sendParams, ["sessionID"])
|
|
525
565
|
)
|
|
526
566
|
)
|
|
527
567
|
};
|
|
@@ -533,6 +573,7 @@ var plugin = async ({ client }) => {
|
|
|
533
573
|
const p = event.properties;
|
|
534
574
|
const sessionID = p?.sessionID;
|
|
535
575
|
if (!sessionID) return;
|
|
576
|
+
const mention = buildPermissionMention();
|
|
536
577
|
const embed = {
|
|
537
578
|
title: "Permission required",
|
|
538
579
|
description: p?.title,
|
|
@@ -552,33 +593,56 @@ var plugin = async ({ client }) => {
|
|
|
552
593
|
)
|
|
553
594
|
)
|
|
554
595
|
};
|
|
555
|
-
const
|
|
556
|
-
enqueueToThread(sessionID, {
|
|
596
|
+
const body = {
|
|
557
597
|
content: mention ? `${mention.content}` : void 0,
|
|
558
598
|
allowed_mentions: mention?.allowed_mentions,
|
|
559
599
|
embeds: [embed]
|
|
560
|
-
}
|
|
600
|
+
};
|
|
601
|
+
enqueueToThread(sessionID, body);
|
|
602
|
+
await postFallbackIfNeeded(
|
|
603
|
+
{
|
|
604
|
+
body,
|
|
605
|
+
mention,
|
|
606
|
+
sessionID,
|
|
607
|
+
fallbackUrl: fallbackWebhookUrl,
|
|
608
|
+
firstUserTextBySession,
|
|
609
|
+
lastSessionInfo
|
|
610
|
+
},
|
|
611
|
+
postDeps
|
|
612
|
+
);
|
|
561
613
|
return;
|
|
562
614
|
}
|
|
563
615
|
case "session.idle": {
|
|
564
616
|
const sessionID = event.properties?.sessionID;
|
|
565
617
|
if (!sessionID) return;
|
|
618
|
+
const mention = buildCompleteMention();
|
|
566
619
|
const embed = {
|
|
567
620
|
title: "Session completed",
|
|
568
621
|
color: COLORS.success,
|
|
569
622
|
fields: buildFields(
|
|
570
623
|
filterSendFields(
|
|
571
624
|
[["sessionID", sessionID]],
|
|
572
|
-
|
|
625
|
+
sendParams
|
|
573
626
|
)
|
|
574
627
|
)
|
|
575
628
|
};
|
|
576
|
-
const
|
|
577
|
-
enqueueToThread(sessionID, {
|
|
629
|
+
const body = {
|
|
578
630
|
content: mention ? `${mention.content}` : void 0,
|
|
579
631
|
allowed_mentions: mention?.allowed_mentions,
|
|
580
632
|
embeds: [embed]
|
|
581
|
-
}
|
|
633
|
+
};
|
|
634
|
+
enqueueToThread(sessionID, body);
|
|
635
|
+
await postFallbackIfNeeded(
|
|
636
|
+
{
|
|
637
|
+
body,
|
|
638
|
+
mention,
|
|
639
|
+
sessionID,
|
|
640
|
+
fallbackUrl: fallbackWebhookUrl,
|
|
641
|
+
firstUserTextBySession,
|
|
642
|
+
lastSessionInfo
|
|
643
|
+
},
|
|
644
|
+
postDeps
|
|
645
|
+
);
|
|
582
646
|
return;
|
|
583
647
|
}
|
|
584
648
|
case "session.error": {
|
|
@@ -605,11 +669,24 @@ var plugin = async ({ client }) => {
|
|
|
605
669
|
};
|
|
606
670
|
if (!sessionID) return;
|
|
607
671
|
const mention = buildCompleteMention();
|
|
608
|
-
|
|
609
|
-
|
|
672
|
+
const body = {
|
|
673
|
+
// 🐛 既存バグ修正: `$Session error` → `${mention.content}`
|
|
674
|
+
content: mention ? `${mention.content}` : void 0,
|
|
610
675
|
allowed_mentions: mention?.allowed_mentions,
|
|
611
676
|
embeds: [embed]
|
|
612
|
-
}
|
|
677
|
+
};
|
|
678
|
+
enqueueToThread(sessionID, body);
|
|
679
|
+
await postFallbackIfNeeded(
|
|
680
|
+
{
|
|
681
|
+
body,
|
|
682
|
+
mention,
|
|
683
|
+
sessionID,
|
|
684
|
+
fallbackUrl: fallbackWebhookUrl,
|
|
685
|
+
firstUserTextBySession,
|
|
686
|
+
lastSessionInfo
|
|
687
|
+
},
|
|
688
|
+
postDeps
|
|
689
|
+
);
|
|
613
690
|
await flushPending(sessionID);
|
|
614
691
|
return;
|
|
615
692
|
}
|
|
@@ -691,7 +768,8 @@ plugin.__test__ = {
|
|
|
691
768
|
toIsoTimestamp,
|
|
692
769
|
postDiscordWebhook,
|
|
693
770
|
parseSendParams,
|
|
694
|
-
getTodoStatusMarker
|
|
771
|
+
getTodoStatusMarker,
|
|
772
|
+
postFallbackIfNeeded
|
|
695
773
|
};
|
|
696
774
|
var index_default = plugin;
|
|
697
775
|
export {
|