opencode-discord-notify 0.7.0 → 0.9.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.
Files changed (3) hide show
  1. package/README.md +27 -21
  2. package/dist/index.js +17 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
- # opencode-discord-notify
1
+ # OPENCODE-DISCORD-NOTIFY
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
- [![npm version](https://img.shields.io/npm/v/opencode-discord-notify?logo=npm&logoColor=fff)](https://www.npmjs.com/package/opencode-discord-notify)
5
- [![npm downloads](https://img.shields.io/npm/dm/opencode-discord-notify?logo=npm&logoColor=fff)](https://www.npmjs.com/package/opencode-discord-notify)
6
3
  [![npm license](https://img.shields.io/npm/l/opencode-discord-notify?logo=npm&logoColor=fff)](https://www.npmjs.com/package/opencode-discord-notify)
4
+ [![npm downloads](https://img.shields.io/npm/dt/opencode-discord-notify?logo=npm&logoColor=fff)](https://www.npmjs.com/package/opencode-discord-notify)
5
+ [![npm version](https://img.shields.io/npm/v/opencode-discord-notify?logo=npm&logoColor=fff)](https://www.npmjs.com/package/opencode-discord-notify)
7
6
  ![OpenCode Plugin](https://img.shields.io/badge/OpenCode-Plugin-4c8bf5)
8
7
  ![Discord Webhook](https://img.shields.io/badge/Discord-Webhook-5865F2?logo=discord&logoColor=fff)
9
8
  ![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=fff)
10
9
 
10
+ > **Requires OpenCode v1.1.1 or later** (due to breaking changes in the permission event system)
11
+
11
12
  <p align="center">
12
13
  <img src="assets/image/sample-forum-ch.png" width="700" alt="Discord Forum channel example" />
13
14
  </p>
@@ -60,18 +61,19 @@ export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."
60
61
 
61
62
  ### Environment Variables
62
63
 
63
- | Variable | Required | Default | Description |
64
- | --------------------------------------- | -------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
65
- | `DISCORD_WEBHOOK_URL` | ✅ Yes | - | Discord webhook URL. Plugin is disabled if not set. |
66
- | `DISCORD_WEBHOOK_USERNAME` | ❌ No | - | Custom username for webhook posts |
67
- | `DISCORD_WEBHOOK_AVATAR_URL` | ❌ No | - | Custom avatar URL for webhook posts |
68
- | `DISCORD_WEBHOOK_COMPLETE_MENTION` | ❌ No | - | Add `@everyone` or `@here` to session completion/error notifications |
69
- | `DISCORD_WEBHOOK_PERMISSION_MENTION` | ❌ No | - | Add `@everyone` or `@here` to permission request notifications |
70
- | `DISCORD_WEBHOOK_EXCLUDE_INPUT_CONTEXT` | ❌ No | `1` | Set to `0` to include file context in notifications |
71
- | `DISCORD_WEBHOOK_SHOW_ERROR_ALERT` | ❌ No | `1` | Set to `0` to disable error toast notifications |
72
- | `DISCORD_SEND_PARAMS` | ❌ No | - | Comma-separated embed fields: `sessionID,permissionID,type,pattern,messageID,callID,partID,role,directory,projectID` |
73
- | `DISCORD_WEBHOOK_FALLBACK_URL` | ❌ No | - | Fallback webhook URL for text channel (sends mentions here too for guaranteed ping) |
74
- | `DISCORD_NOTIFY_QUEUE_DB_PATH` | ❌ No | `~/.config/opencode/discord-notify-queue.db` | Custom path for the persistent queue database (automatically uses `:memory:` in test environment) |
64
+ | Variable | Required | Default | Description |
65
+ | ----------------------------------------------- | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
66
+ | `DISCORD_WEBHOOK_URL` | ✅ Yes | - | Discord webhook URL. Plugin is disabled if not set. |
67
+ | `DISCORD_WEBHOOK_USERNAME` | ❌ No | - | Custom username for webhook posts |
68
+ | `DISCORD_WEBHOOK_AVATAR_URL` | ❌ No | - | Custom avatar URL for webhook posts |
69
+ | `DISCORD_WEBHOOK_COMPLETE_MENTION` | ❌ No | - | Add `@everyone` or `@here` to session completion/error notifications |
70
+ | `DISCORD_WEBHOOK_PERMISSION_MENTION` | ❌ No | - | Add `@everyone` or `@here` to permission request notifications |
71
+ | `DISCORD_WEBHOOK_COMPLETE_INCLUDE_LAST_MESSAGE` | ❌ No | `1` | Set to `0` to exclude the last assistant message from session completion notifications |
72
+ | `DISCORD_WEBHOOK_EXCLUDE_INPUT_CONTEXT` | ❌ No | `1` | Set to `0` to include file context in notifications |
73
+ | `DISCORD_WEBHOOK_SHOW_ERROR_ALERT` | ❌ No | `1` | Set to `0` to disable error toast notifications |
74
+ | `DISCORD_SEND_PARAMS` | ❌ No | - | Comma-separated embed fields: `sessionID,permissionID,permission,patterns,messageID,callID,partID,role,directory,projectID` |
75
+ | `DISCORD_WEBHOOK_FALLBACK_URL` | ❌ No | - | Fallback webhook URL for text channel (sends mentions here too for guaranteed ping) |
76
+ | `DISCORD_NOTIFY_QUEUE_DB_PATH` | ❌ No | `~/.config/opencode/discord-notify-queue.db` | Custom path for the persistent queue database |
75
77
 
76
78
  ### Example Configuration
77
79
 
@@ -106,8 +108,10 @@ export DISCORD_WEBHOOK_AVATAR_URL="https://example.com/avatar.png"
106
108
  ### Supported Events
107
109
 
108
110
  - **`session.created`**: Queues session start notification (sent when thread info is available)
109
- - **`permission.updated`**: Posts permission request immediately
111
+ - **`permission.asked`**: Posts permission request immediately
110
112
  - **`session.idle`**: Posts session completion notification
113
+ - Includes the last assistant message in the embed description by default (customizable via `DISCORD_WEBHOOK_COMPLETE_INCLUDE_LAST_MESSAGE`)
114
+ - Message is truncated to 4096 characters if needed
111
115
  - **`session.error`**: Posts error notification (skipped if `sessionID` missing)
112
116
  - **`todo.updated`**: Posts checklist with `[▶]` (in progress), `[✓]` (completed); excludes cancelled
113
117
  - **`message.updated`**: Tracked internally for role detection (not posted)
@@ -176,6 +180,7 @@ All notifications are stored in a local SQLite database before sending:
176
180
  - **Batch size**: Processes 1 message at a time to ensure thread ID consistency
177
181
 
178
182
  **Benefits**:
183
+
179
184
  - Messages survive OpenCode restarts
180
185
  - Prevents data loss during network issues
181
186
  - Ensures correct thread naming with user's first message
@@ -212,7 +217,7 @@ Controls which metadata fields appear in embeds.
212
217
 
213
218
  **Allowed keys:**
214
219
 
215
- - `sessionID`, `permissionID`, `type`, `pattern`, `messageID`, `callID`, `partID`, `role`, `directory`, `projectID`
220
+ - `sessionID`, `permissionID`, `permission`, `patterns`, `messageID`, `callID`, `partID`, `role`, `directory`, `projectID`
216
221
 
217
222
  **Default behavior (unset/empty):**
218
223
 
@@ -221,7 +226,7 @@ Controls which metadata fields appear in embeds.
221
226
  **To send all fields:**
222
227
 
223
228
  ```bash
224
- export DISCORD_SEND_PARAMS="sessionID,permissionID,type,pattern,messageID,callID,partID,role,directory,projectID"
229
+ export DISCORD_SEND_PARAMS="sessionID,permissionID,permission,patterns,messageID,callID,partID,role,directory,projectID"
225
230
  ```
226
231
 
227
232
  **Note:** `session.created` always includes `sessionID` regardless of this setting.
@@ -249,8 +254,9 @@ Main implementation: `src/index.ts`
249
254
  ## Roadmap
250
255
 
251
256
  - [ ] Support multiple webhooks for routing by event type
252
- - [ ] Customizable notification templates
253
- - [ ] Configuration file support (e.g., `opencode-discord-notify.config.json`)
257
+ - [ ] Message filtering/customization
258
+ - [x] Customizable notification templates
259
+ - [x] Configuration file support (e.g., `opencode-discord-notify.config.json`)
254
260
  - [x] Enhanced rate limit handling (smarter retry logic, message queuing)
255
261
  - [x] CI/CD (automated linting, formatting, testing)
256
262
 
package/dist/index.js CHANGED
@@ -220,8 +220,8 @@ var DEFAULT_RATE_LIMIT_WAIT_MS = 1e4;
220
220
  var SEND_PARAM_KEYS = [
221
221
  "sessionID",
222
222
  "permissionID",
223
- "type",
224
- "pattern",
223
+ "permission",
224
+ "patterns",
225
225
  "messageID",
226
226
  "callID",
227
227
  "partID",
@@ -529,6 +529,8 @@ var plugin = async ({ client }) => {
529
529
  const excludeInputContext = excludeInputContextRaw !== "0";
530
530
  const showErrorAlertRaw = (getEnv("DISCORD_WEBHOOK_SHOW_ERROR_ALERT") ?? "1").trim();
531
531
  const showErrorAlert = showErrorAlertRaw !== "0";
532
+ const includeLastMessageInCompleteRaw = (getEnv("DISCORD_WEBHOOK_COMPLETE_INCLUDE_LAST_MESSAGE") ?? "1").trim();
533
+ const includeLastMessageInComplete = includeLastMessageInCompleteRaw !== "0";
532
534
  const waitOnRateLimitMs = DEFAULT_RATE_LIMIT_WAIT_MS;
533
535
  const sendParams = parseSendParams(getEnv("DISCORD_SEND_PARAMS"));
534
536
  const fallbackWebhookUrl = (getEnv("DISCORD_WEBHOOK_FALLBACK_URL") ?? "").trim() || void 0;
@@ -590,6 +592,7 @@ var plugin = async ({ client }) => {
590
592
  }
591
593
  });
592
594
  const firstUserTextBySession = /* @__PURE__ */ new Map();
595
+ const lastAssistantMessageBySession = /* @__PURE__ */ new Map();
593
596
  const pendingTextPartsByMessageId = /* @__PURE__ */ new Map();
594
597
  const messageRoleById = /* @__PURE__ */ new Map();
595
598
  const lastSessionInfo = /* @__PURE__ */ new Map();
@@ -682,6 +685,9 @@ var plugin = async ({ client }) => {
682
685
  const normalized = normalizeThreadTitle(text);
683
686
  if (normalized) firstUserTextBySession.set(sessionID, normalized);
684
687
  }
688
+ if (role === "assistant" && text.trim()) {
689
+ lastAssistantMessageBySession.set(sessionID, text);
690
+ }
685
691
  if (role === "user" && !sessionToThread.has(sessionID)) {
686
692
  const sessionCreatedBody = buildSessionCreatedEmbed(sessionID);
687
693
  if (sessionCreatedBody) {
@@ -727,11 +733,13 @@ var plugin = async ({ client }) => {
727
733
  });
728
734
  return;
729
735
  }
730
- case "permission.updated": {
736
+ case "permission.asked": {
731
737
  const p = event.properties;
732
738
  const sessionID = p?.sessionID;
733
739
  if (!sessionID) return;
734
740
  const mention = buildPermissionMention();
741
+ const patternsArray = p?.patterns;
742
+ const patternsStr = Array.isArray(patternsArray) ? patternsArray.join(", ") : void 0;
735
743
  const embed = {
736
744
  title: "Permission required",
737
745
  description: p?.title,
@@ -742,10 +750,10 @@ var plugin = async ({ client }) => {
742
750
  [
743
751
  ["sessionID", sessionID],
744
752
  ["permissionID", p?.id],
745
- ["type", p?.type],
746
- ["pattern", p?.pattern],
747
- ["messageID", p?.messageID],
748
- ["callID", p?.callID]
753
+ ["permission", p?.permission],
754
+ ["patterns", patternsStr],
755
+ ["messageID", p?.tool?.messageID],
756
+ ["callID", p?.tool?.callID]
749
757
  ],
750
758
  sendParams
751
759
  )
@@ -775,9 +783,11 @@ var plugin = async ({ client }) => {
775
783
  const sessionID = event.properties?.sessionID;
776
784
  if (!sessionID) return;
777
785
  const mention = buildCompleteMention();
786
+ const lastMessage = includeLastMessageInComplete ? lastAssistantMessageBySession.get(sessionID) : void 0;
778
787
  const embed = {
779
788
  title: "Session completed",
780
789
  color: COLORS.success,
790
+ description: lastMessage ? truncateText(lastMessage, DISCORD_EMBED_DESCRIPTION_MAX_LENGTH) : void 0,
781
791
  fields: buildFields(
782
792
  filterSendFields(
783
793
  [["sessionID", sessionID]],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-discord-notify",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "A plugin that posts OpenCode events to a Discord webhook.",
5
5
  "license": "MIT",
6
6
  "type": "module",