opencode-discord-notify 0.9.0 → 0.10.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.md +12 -12
- package/dist/index.js +55 -56
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,19 +61,19 @@ export DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."
|
|
|
61
61
|
|
|
62
62
|
### Environment Variables
|
|
63
63
|
|
|
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
|
|
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
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
|
+
| `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 |
|
|
77
77
|
|
|
78
78
|
### Example Configuration
|
|
79
79
|
|
package/dist/index.js
CHANGED
|
@@ -1,42 +1,3 @@
|
|
|
1
|
-
// src/utils/db.ts
|
|
2
|
-
import { Database } from "bun:sqlite";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import os from "os";
|
|
5
|
-
import path from "path";
|
|
6
|
-
function getDbPath() {
|
|
7
|
-
if (process.env.NODE_ENV === "test" || process.env.VITEST === "true") {
|
|
8
|
-
return ":memory:";
|
|
9
|
-
}
|
|
10
|
-
return process.env.DISCORD_NOTIFY_QUEUE_DB_PATH || path.join(os.homedir(), ".config", "opencode", "discord-notify-queue.db");
|
|
11
|
-
}
|
|
12
|
-
function initDatabase() {
|
|
13
|
-
const dbPath = getDbPath();
|
|
14
|
-
if (dbPath !== ":memory:") {
|
|
15
|
-
const dbDir = path.dirname(dbPath);
|
|
16
|
-
if (!fs.existsSync(dbDir)) {
|
|
17
|
-
fs.mkdirSync(dbDir, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const db = new Database(dbPath);
|
|
21
|
-
db.run("PRAGMA journal_mode = WAL;");
|
|
22
|
-
db.run(`
|
|
23
|
-
CREATE TABLE IF NOT EXISTS discord_queue (
|
|
24
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
-
session_id TEXT NOT NULL,
|
|
26
|
-
thread_id TEXT,
|
|
27
|
-
webhook_body TEXT NOT NULL,
|
|
28
|
-
created_at INTEGER NOT NULL,
|
|
29
|
-
retry_count INTEGER DEFAULT 0,
|
|
30
|
-
last_error TEXT
|
|
31
|
-
);
|
|
32
|
-
`);
|
|
33
|
-
db.run(`
|
|
34
|
-
CREATE INDEX IF NOT EXISTS idx_session_created
|
|
35
|
-
ON discord_queue(session_id, created_at);
|
|
36
|
-
`);
|
|
37
|
-
return db;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
1
|
// src/queue/persistent-queue.ts
|
|
41
2
|
var PersistentQueue = class {
|
|
42
3
|
db;
|
|
@@ -205,6 +166,45 @@ var QueueWorker = class {
|
|
|
205
166
|
}
|
|
206
167
|
};
|
|
207
168
|
|
|
169
|
+
// src/utils/db.ts
|
|
170
|
+
import { Database } from "bun:sqlite";
|
|
171
|
+
import fs from "fs";
|
|
172
|
+
import os from "os";
|
|
173
|
+
import path from "path";
|
|
174
|
+
function getDbPath() {
|
|
175
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST === "true") {
|
|
176
|
+
return ":memory:";
|
|
177
|
+
}
|
|
178
|
+
return process.env.DISCORD_NOTIFY_QUEUE_DB_PATH || path.join(os.homedir(), ".config", "opencode", "discord-notify-queue.db");
|
|
179
|
+
}
|
|
180
|
+
function initDatabase() {
|
|
181
|
+
const dbPath = getDbPath();
|
|
182
|
+
if (dbPath !== ":memory:") {
|
|
183
|
+
const dbDir = path.dirname(dbPath);
|
|
184
|
+
if (!fs.existsSync(dbDir)) {
|
|
185
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const db = new Database(dbPath);
|
|
189
|
+
db.run("PRAGMA journal_mode = WAL;");
|
|
190
|
+
db.run(`
|
|
191
|
+
CREATE TABLE IF NOT EXISTS discord_queue (
|
|
192
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
193
|
+
session_id TEXT NOT NULL,
|
|
194
|
+
thread_id TEXT,
|
|
195
|
+
webhook_body TEXT NOT NULL,
|
|
196
|
+
created_at INTEGER NOT NULL,
|
|
197
|
+
retry_count INTEGER DEFAULT 0,
|
|
198
|
+
last_error TEXT
|
|
199
|
+
);
|
|
200
|
+
`);
|
|
201
|
+
db.run(`
|
|
202
|
+
CREATE INDEX IF NOT EXISTS idx_session_created
|
|
203
|
+
ON discord_queue(session_id, created_at);
|
|
204
|
+
`);
|
|
205
|
+
return db;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
208
|
// src/index.ts
|
|
209
209
|
var DISCORD_FIELD_VALUE_MAX_LENGTH = 1024;
|
|
210
210
|
var DISCORD_EMBED_DESCRIPTION_MAX_LENGTH = 4096;
|
|
@@ -255,10 +255,7 @@ function buildFields(fields, inline = false) {
|
|
|
255
255
|
for (const [name, rawValue] of fields) {
|
|
256
256
|
const value = safeString(rawValue);
|
|
257
257
|
if (!value) continue;
|
|
258
|
-
const truncatedValue = value.length > DISCORD_FIELD_VALUE_MAX_LENGTH ? value.slice(
|
|
259
|
-
0,
|
|
260
|
-
DISCORD_FIELD_VALUE_MAX_LENGTH - ELLIPSIS_LENGTH
|
|
261
|
-
) + ELLIPSIS : value;
|
|
258
|
+
const truncatedValue = value.length > DISCORD_FIELD_VALUE_MAX_LENGTH ? value.slice(0, DISCORD_FIELD_VALUE_MAX_LENGTH - ELLIPSIS_LENGTH) + ELLIPSIS : value;
|
|
262
259
|
result.push({
|
|
263
260
|
name,
|
|
264
261
|
value: truncatedValue,
|
|
@@ -492,10 +489,7 @@ async function postFallbackIfNeeded(input, deps) {
|
|
|
492
489
|
fallbackBody.embeds = [
|
|
493
490
|
{
|
|
494
491
|
...originalEmbed,
|
|
495
|
-
fields: [
|
|
496
|
-
...originalEmbed.fields ?? [],
|
|
497
|
-
...additionalFields ?? []
|
|
498
|
-
]
|
|
492
|
+
fields: [...originalEmbed.fields ?? [], ...additionalFields ?? []]
|
|
499
493
|
}
|
|
500
494
|
];
|
|
501
495
|
}
|
|
@@ -759,8 +753,14 @@ var plugin = async ({ client }) => {
|
|
|
759
753
|
)
|
|
760
754
|
)
|
|
761
755
|
};
|
|
756
|
+
const permissionType = p?.permission || "";
|
|
757
|
+
const permissionDetail = patternsStr || "";
|
|
758
|
+
const permissionSummary = truncateText(
|
|
759
|
+
p?.title || (permissionType && permissionDetail ? `${permissionType}(${permissionDetail})` : permissionType || "Permission requested"),
|
|
760
|
+
100
|
|
761
|
+
);
|
|
762
762
|
const body = {
|
|
763
|
-
content: mention ? `${mention.content}` : void 0,
|
|
763
|
+
content: mention ? `${mention.content} Permission: ${permissionSummary}` : void 0,
|
|
764
764
|
allowed_mentions: mention?.allowed_mentions,
|
|
765
765
|
embeds: [embed]
|
|
766
766
|
};
|
|
@@ -787,16 +787,16 @@ var plugin = async ({ client }) => {
|
|
|
787
787
|
const embed = {
|
|
788
788
|
title: "Session completed",
|
|
789
789
|
color: COLORS.success,
|
|
790
|
-
description: lastMessage ? truncateText(
|
|
790
|
+
description: lastMessage ? truncateText(
|
|
791
|
+
lastMessage,
|
|
792
|
+
DISCORD_EMBED_DESCRIPTION_MAX_LENGTH
|
|
793
|
+
) : void 0,
|
|
791
794
|
fields: buildFields(
|
|
792
|
-
filterSendFields(
|
|
793
|
-
[["sessionID", sessionID]],
|
|
794
|
-
sendParams
|
|
795
|
-
)
|
|
795
|
+
filterSendFields([["sessionID", sessionID]], sendParams)
|
|
796
796
|
)
|
|
797
797
|
};
|
|
798
798
|
const body = {
|
|
799
|
-
content: mention ? `${mention.content}` : void 0,
|
|
799
|
+
content: mention ? `${mention.content} Session completed` : void 0,
|
|
800
800
|
allowed_mentions: mention?.allowed_mentions,
|
|
801
801
|
embeds: [embed]
|
|
802
802
|
};
|
|
@@ -840,8 +840,7 @@ var plugin = async ({ client }) => {
|
|
|
840
840
|
if (!sessionID) return;
|
|
841
841
|
const mention = buildCompleteMention();
|
|
842
842
|
const body = {
|
|
843
|
-
|
|
844
|
-
content: mention ? `${mention.content}` : void 0,
|
|
843
|
+
content: mention ? `${mention.content} Session error` : void 0,
|
|
845
844
|
allowed_mentions: mention?.allowed_mentions,
|
|
846
845
|
embeds: [embed]
|
|
847
846
|
};
|