@made-by-moonlight/athene-plugin-notifier-discord 0.9.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/LICENSE +22 -0
- package/README.md +39 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +353 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +270 -0
- package/dist/index.test.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Composio, Inc.
|
|
4
|
+
Copyright (c) 2026 slievr (Athene fork)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# notifier-discord
|
|
2
|
+
|
|
3
|
+
Discord webhook notifier plugin for AO. Sends rich embed notifications for session events, PR creation, CI status, and escalations.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. In your Discord server: **Server Settings > Integrations > Webhooks > New Webhook**
|
|
8
|
+
2. Copy the webhook URL
|
|
9
|
+
3. Add to `agent-orchestrator.yaml`:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
defaults:
|
|
13
|
+
notifiers:
|
|
14
|
+
- desktop
|
|
15
|
+
- discord
|
|
16
|
+
|
|
17
|
+
notifiers:
|
|
18
|
+
discord:
|
|
19
|
+
plugin: discord
|
|
20
|
+
webhookUrl: https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Config options
|
|
24
|
+
|
|
25
|
+
| Option | Default | Description |
|
|
26
|
+
|--------|---------|-------------|
|
|
27
|
+
| `webhookUrl` | (required) | Discord webhook URL |
|
|
28
|
+
| `username` | "Athene" | Bot display name |
|
|
29
|
+
| `avatarUrl` | (none) | Bot avatar image URL |
|
|
30
|
+
| `threadId` | (none) | Post to a specific thread |
|
|
31
|
+
| `retries` | 2 | Retry attempts on 5xx |
|
|
32
|
+
| `retryDelayMs` | 1000 | Base retry delay (exponential backoff) |
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- Rich embeds with color-coded priority (red=urgent, blue=action, yellow=warning, green=info)
|
|
37
|
+
- PR links, CI status, and action buttons in embed fields
|
|
38
|
+
- Thread support for organizing notifications by project
|
|
39
|
+
- Retry with exponential backoff on 5xx responses
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Notifier } from "@made-by-moonlight/athene-core";
|
|
2
|
+
export declare const manifest: {
|
|
3
|
+
name: string;
|
|
4
|
+
slot: "notifier";
|
|
5
|
+
description: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function create(config?: Record<string, unknown>): Notifier;
|
|
9
|
+
declare const _default: {
|
|
10
|
+
manifest: {
|
|
11
|
+
name: string;
|
|
12
|
+
slot: "notifier";
|
|
13
|
+
description: string;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
create: typeof create;
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EAQd,MAAM,gCAAgC,CAAC;AAGxC,eAAO,MAAM,QAAQ;;;;;CAKpB,CAAC;AAmYF,wBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAgEjE;;;;;;;;;;AAED,wBAAqE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { getNotificationDataV3, recordActivityEvent, validateUrl, CI_STATUS, } from "@made-by-moonlight/athene-core";
|
|
2
|
+
import { isRetryableHttpStatus, normalizeRetryConfig } from "@made-by-moonlight/athene-core/utils";
|
|
3
|
+
export const manifest = {
|
|
4
|
+
name: "discord",
|
|
5
|
+
slot: "notifier",
|
|
6
|
+
description: "Notifier plugin: Discord webhook notifications with rich embeds",
|
|
7
|
+
version: "0.1.0",
|
|
8
|
+
};
|
|
9
|
+
const DISCORD_WEBHOOK_URL_RE = /^https:\/\/(?:discord\.com|discordapp\.com)\/api\/webhooks\//;
|
|
10
|
+
const DISCORD_EMBED_TITLE_MAX = 256;
|
|
11
|
+
const EMBED_DESCRIPTION_MAX = 4096;
|
|
12
|
+
const DISCORD_FIELD_NAME_MAX = 256;
|
|
13
|
+
const DISCORD_FIELD_VALUE_MAX = 1024;
|
|
14
|
+
const DISCORD_MAX_FIELDS = 25;
|
|
15
|
+
const SUCCESS_TONE = {
|
|
16
|
+
emoji: "\u{2705}",
|
|
17
|
+
label: "Complete",
|
|
18
|
+
color: 0x57f287,
|
|
19
|
+
};
|
|
20
|
+
const PRIORITY_TONE = {
|
|
21
|
+
urgent: {
|
|
22
|
+
emoji: "\u{1F6A8}",
|
|
23
|
+
label: "Urgent",
|
|
24
|
+
color: 0xed4245,
|
|
25
|
+
},
|
|
26
|
+
action: {
|
|
27
|
+
emoji: "\u{1F449}",
|
|
28
|
+
label: "Action required",
|
|
29
|
+
color: 0x5865f2,
|
|
30
|
+
},
|
|
31
|
+
warning: {
|
|
32
|
+
emoji: "\u{26A0}\u{FE0F}",
|
|
33
|
+
label: "Warning",
|
|
34
|
+
color: 0xfee75c,
|
|
35
|
+
},
|
|
36
|
+
info: {
|
|
37
|
+
emoji: "\u{2139}\u{FE0F}",
|
|
38
|
+
label: "Information",
|
|
39
|
+
color: 0x3498db,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
function truncate(value, maxLength) {
|
|
43
|
+
return value.length > maxLength ? `${value.slice(0, maxLength - 1)}\u2026` : value;
|
|
44
|
+
}
|
|
45
|
+
function titleCaseStatus(value) {
|
|
46
|
+
return value
|
|
47
|
+
.split(/[_\s.-]+/)
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
|
|
50
|
+
.join(" ");
|
|
51
|
+
}
|
|
52
|
+
function toneForEvent(event) {
|
|
53
|
+
if (event.type === "merge.ready")
|
|
54
|
+
return { ...SUCCESS_TONE, label: "Ready to merge" };
|
|
55
|
+
if (event.type === "summary.all_complete")
|
|
56
|
+
return { ...SUCCESS_TONE, label: "All complete" };
|
|
57
|
+
if (event.type === "ci.failing" || event.type === "session.stuck")
|
|
58
|
+
return PRIORITY_TONE.urgent;
|
|
59
|
+
if (event.type === "review.changes_requested")
|
|
60
|
+
return PRIORITY_TONE.warning;
|
|
61
|
+
return PRIORITY_TONE[event.priority] ?? PRIORITY_TONE.info;
|
|
62
|
+
}
|
|
63
|
+
function eventTitle(event, data) {
|
|
64
|
+
const pr = data?.subject.pr;
|
|
65
|
+
switch (event.type) {
|
|
66
|
+
case "ci.failing":
|
|
67
|
+
return pr ? `CI failing on PR #${pr.number}` : "CI failing";
|
|
68
|
+
case "merge.ready":
|
|
69
|
+
return pr ? `PR #${pr.number} ready to merge` : "Pull request ready to merge";
|
|
70
|
+
case "review.changes_requested":
|
|
71
|
+
return pr ? `Changes requested on PR #${pr.number}` : "Review changes requested";
|
|
72
|
+
case "session.needs_input":
|
|
73
|
+
return "Agent needs input";
|
|
74
|
+
case "session.stuck":
|
|
75
|
+
return "Agent may be stuck";
|
|
76
|
+
case "session.killed":
|
|
77
|
+
case "session.exited":
|
|
78
|
+
return "Agent exited";
|
|
79
|
+
case "pr.closed":
|
|
80
|
+
return pr ? `PR #${pr.number} closed` : "Pull request closed";
|
|
81
|
+
case "summary.all_complete":
|
|
82
|
+
return "All sessions complete";
|
|
83
|
+
default:
|
|
84
|
+
return titleCaseStatus(event.type);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function fieldValue(value) {
|
|
88
|
+
if (value === undefined || value === null || value === "")
|
|
89
|
+
return "Not available";
|
|
90
|
+
return truncate(String(value), DISCORD_FIELD_VALUE_MAX);
|
|
91
|
+
}
|
|
92
|
+
function appendField(fields, name, value, inline = true) {
|
|
93
|
+
if (value === undefined || value === null || value === "")
|
|
94
|
+
return;
|
|
95
|
+
if (fields.length >= DISCORD_MAX_FIELDS)
|
|
96
|
+
return;
|
|
97
|
+
fields.push({
|
|
98
|
+
name: truncate(name, DISCORD_FIELD_NAME_MAX),
|
|
99
|
+
value: fieldValue(value),
|
|
100
|
+
inline,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function formatMarkdownLink(label, url) {
|
|
104
|
+
return `[${label.replace(/[\][()]/g, "")}](${url.replace(/\)/g, "%29")})`;
|
|
105
|
+
}
|
|
106
|
+
function formatBranch(data) {
|
|
107
|
+
const pr = data?.subject.pr;
|
|
108
|
+
if (pr?.branch && pr.baseBranch)
|
|
109
|
+
return `${pr.branch} -> ${pr.baseBranch}`;
|
|
110
|
+
return pr?.branch ?? pr?.baseBranch ?? data?.subject.branch;
|
|
111
|
+
}
|
|
112
|
+
function formatCheck(check) {
|
|
113
|
+
const status = check.conclusion ? `${check.status}/${check.conclusion}` : check.status;
|
|
114
|
+
const label = `${check.name}: ${status}`;
|
|
115
|
+
return check.url ? formatMarkdownLink(label, check.url) : label;
|
|
116
|
+
}
|
|
117
|
+
function isAbsoluteHttpUrl(value) {
|
|
118
|
+
if (!value)
|
|
119
|
+
return false;
|
|
120
|
+
try {
|
|
121
|
+
const parsed = new URL(value);
|
|
122
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function appendDataFields(fields, data) {
|
|
129
|
+
if (!data)
|
|
130
|
+
return;
|
|
131
|
+
const pr = data.subject.pr;
|
|
132
|
+
const issue = data.subject.issue;
|
|
133
|
+
const branch = formatBranch(data);
|
|
134
|
+
appendField(fields, "Pull Request", pr
|
|
135
|
+
? `${formatMarkdownLink(`#${pr.number}`, pr.url)}${pr.title ? ` - ${pr.title}` : ""}`
|
|
136
|
+
: undefined, false);
|
|
137
|
+
appendField(fields, "Branch", branch);
|
|
138
|
+
appendField(fields, "Issue", issue ? `${issue.id}${issue.title ? ` - ${issue.title}` : ""}` : undefined);
|
|
139
|
+
appendField(fields, "CI", data.ci?.status ? formatCiStatus(data) : undefined);
|
|
140
|
+
appendField(fields, "Review", data.review?.decision ? titleCaseStatus(data.review.decision) : undefined);
|
|
141
|
+
appendField(fields, "Review Threads", data.review?.unresolvedThreads);
|
|
142
|
+
appendField(fields, "Merge", typeof data.merge?.ready === "boolean" ? (data.merge.ready ? "Ready" : "Not ready") : undefined);
|
|
143
|
+
appendField(fields, "Conflicts", typeof data.merge?.conflicts === "boolean"
|
|
144
|
+
? data.merge.conflicts
|
|
145
|
+
? "Found"
|
|
146
|
+
: "None"
|
|
147
|
+
: undefined);
|
|
148
|
+
appendField(fields, "Sync", typeof data.merge?.isBehind === "boolean"
|
|
149
|
+
? data.merge.isBehind
|
|
150
|
+
? "Behind base"
|
|
151
|
+
: "Up to date"
|
|
152
|
+
: undefined);
|
|
153
|
+
appendField(fields, "Transition", data.transition ? `${data.transition.from} -> ${data.transition.to}` : undefined);
|
|
154
|
+
appendField(fields, "Reaction", data.reaction ? `${data.reaction.key} -> ${data.reaction.action}` : undefined);
|
|
155
|
+
appendField(fields, "Escalation", data.escalation ? `${data.escalation.attempts} attempts (${data.escalation.cause})` : undefined);
|
|
156
|
+
const checks = (data.ci?.failedChecks ?? []).slice(0, 8).map(formatCheck);
|
|
157
|
+
appendField(fields, "Checks", checks.length > 0 ? checks.join("\n") : undefined, false);
|
|
158
|
+
appendField(fields, "Blockers", data.merge?.blockers?.length ? data.merge.blockers.slice(0, 8).join("\n") : undefined, false);
|
|
159
|
+
const links = [
|
|
160
|
+
...(pr?.url ? [formatMarkdownLink("Pull request", pr.url)] : []),
|
|
161
|
+
...(data.review?.url ? [formatMarkdownLink("Review", data.review.url)] : []),
|
|
162
|
+
];
|
|
163
|
+
appendField(fields, "Links", links.length > 0 ? links.join(" | ") : undefined, false);
|
|
164
|
+
}
|
|
165
|
+
function formatCiStatus(data) {
|
|
166
|
+
if (!data.ci?.status)
|
|
167
|
+
return "";
|
|
168
|
+
const ciEmoji = data.ci.status === CI_STATUS.PASSING ? "\u{2705}" : "\u{274C}";
|
|
169
|
+
const failedChecks = data.ci.failedChecks?.map((check) => check.name) ?? [];
|
|
170
|
+
const failedCheckText = failedChecks.length > 0 ? `\nFailed: ${failedChecks.join(", ")}` : "";
|
|
171
|
+
return `${ciEmoji} ${titleCaseStatus(data.ci.status)}${failedCheckText}`;
|
|
172
|
+
}
|
|
173
|
+
function appendActionField(fields, data, actions) {
|
|
174
|
+
const seen = new Set();
|
|
175
|
+
const links = [];
|
|
176
|
+
const prUrl = data?.subject.pr?.url;
|
|
177
|
+
if (prUrl) {
|
|
178
|
+
links.push(formatMarkdownLink("View PR", prUrl));
|
|
179
|
+
seen.add(prUrl);
|
|
180
|
+
}
|
|
181
|
+
const reviewUrl = data?.review?.url;
|
|
182
|
+
if (reviewUrl && !seen.has(reviewUrl)) {
|
|
183
|
+
links.push(formatMarkdownLink("View Review", reviewUrl));
|
|
184
|
+
seen.add(reviewUrl);
|
|
185
|
+
}
|
|
186
|
+
for (const action of actions ?? []) {
|
|
187
|
+
if (action.url) {
|
|
188
|
+
if (seen.has(action.url))
|
|
189
|
+
continue;
|
|
190
|
+
links.push(formatMarkdownLink(action.label, action.url));
|
|
191
|
+
seen.add(action.url);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (isAbsoluteHttpUrl(action.callbackEndpoint)) {
|
|
195
|
+
links.push(formatMarkdownLink(action.label, action.callbackEndpoint));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
links.push(`\`${action.label}\``);
|
|
199
|
+
}
|
|
200
|
+
appendField(fields, "Actions", links.slice(0, 8).join(" | "), false);
|
|
201
|
+
}
|
|
202
|
+
function formatDescription(event, data) {
|
|
203
|
+
const subtitle = data?.subject.pr?.title ?? data?.subject.summary;
|
|
204
|
+
const description = subtitle ? `**${subtitle}**\n${event.message}` : event.message;
|
|
205
|
+
return truncate(description, EMBED_DESCRIPTION_MAX);
|
|
206
|
+
}
|
|
207
|
+
function buildEmbed(event, actions) {
|
|
208
|
+
const data = getNotificationDataV3(event.data);
|
|
209
|
+
const tone = toneForEvent(event);
|
|
210
|
+
const fields = [];
|
|
211
|
+
appendField(fields, "Project", event.projectId);
|
|
212
|
+
appendField(fields, "Session", event.sessionId);
|
|
213
|
+
appendField(fields, "Priority", tone.label);
|
|
214
|
+
appendDataFields(fields, data);
|
|
215
|
+
appendActionField(fields, data, actions);
|
|
216
|
+
const embed = {
|
|
217
|
+
title: truncate(`${tone.emoji} ${eventTitle(event, data)}`, DISCORD_EMBED_TITLE_MAX),
|
|
218
|
+
description: formatDescription(event, data),
|
|
219
|
+
color: tone.color,
|
|
220
|
+
...(data?.subject.pr?.url ? { url: data.subject.pr.url } : {}),
|
|
221
|
+
fields,
|
|
222
|
+
timestamp: event.timestamp.toISOString(),
|
|
223
|
+
footer: { text: "Athene" },
|
|
224
|
+
};
|
|
225
|
+
return embed;
|
|
226
|
+
}
|
|
227
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
228
|
+
async function postWithRetry(webhookUrl, payload, retries, retryDelayMs) {
|
|
229
|
+
let lastError;
|
|
230
|
+
// Separate counter for 429 Retry-After waits so they don't consume the error
|
|
231
|
+
// retry budget — a server-mandated wait shouldn't cost a retry slot.
|
|
232
|
+
let rateLimitRetries = 0;
|
|
233
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
234
|
+
const controller = new AbortController();
|
|
235
|
+
const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
|
236
|
+
try {
|
|
237
|
+
const response = await fetch(webhookUrl, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: JSON.stringify(payload),
|
|
241
|
+
signal: controller.signal,
|
|
242
|
+
});
|
|
243
|
+
if (response.ok || response.status === 204)
|
|
244
|
+
return;
|
|
245
|
+
// Handle rate limiting: wait then retry without burning an error retry slot.
|
|
246
|
+
// Use Retry-After if present, otherwise fall back to retryDelayMs.
|
|
247
|
+
if (response.status === 429) {
|
|
248
|
+
if (rateLimitRetries < retries) {
|
|
249
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
250
|
+
const waitMs = retryAfter ? (parseFloat(retryAfter) || 1) * 1000 : retryDelayMs;
|
|
251
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
252
|
+
rateLimitRetries++;
|
|
253
|
+
attempt--; // undo the for-loop increment so error budget is preserved
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
// Rate-limit budget exhausted — fail immediately rather than falling through
|
|
257
|
+
// to the error retry path (which would compound the two counters).
|
|
258
|
+
const body = await response.text().catch(() => "");
|
|
259
|
+
recordActivityEvent({
|
|
260
|
+
source: "notifier",
|
|
261
|
+
kind: "notifier.rate_limited",
|
|
262
|
+
level: "warn",
|
|
263
|
+
summary: `Discord webhook rate-limit retry budget exhausted`,
|
|
264
|
+
data: {
|
|
265
|
+
plugin: "notifier-discord",
|
|
266
|
+
status: 429,
|
|
267
|
+
rateLimitRetries,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
lastError = new Error(`Discord webhook rate-limited (HTTP 429)${body ? `: ${body.trim()}` : ""}`);
|
|
271
|
+
throw lastError;
|
|
272
|
+
}
|
|
273
|
+
const body = await response.text();
|
|
274
|
+
lastError = new Error(`Discord webhook failed (${response.status}): ${body}`);
|
|
275
|
+
if (!isRetryableHttpStatus(response.status)) {
|
|
276
|
+
throw lastError;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
if (err === lastError)
|
|
281
|
+
throw err;
|
|
282
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
clearTimeout(timer);
|
|
286
|
+
}
|
|
287
|
+
if (attempt < retries) {
|
|
288
|
+
const delay = retryDelayMs * 2 ** attempt;
|
|
289
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
throw lastError;
|
|
293
|
+
}
|
|
294
|
+
export function create(config) {
|
|
295
|
+
const webhookUrl = config?.webhookUrl;
|
|
296
|
+
const username = config?.username ?? "Athene";
|
|
297
|
+
const avatarUrl = config?.avatarUrl;
|
|
298
|
+
const threadId = config?.threadId;
|
|
299
|
+
const { retries, retryDelayMs } = normalizeRetryConfig(config);
|
|
300
|
+
if (!webhookUrl) {
|
|
301
|
+
console.warn("[notifier-discord] No webhookUrl configured.\n" +
|
|
302
|
+
" Set it in agent-orchestrator.yaml under notifiers.discord.webhookUrl\n" +
|
|
303
|
+
" Create a webhook: Discord Server Settings > Integrations > Webhooks > New Webhook");
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
validateUrl(webhookUrl, "notifier-discord");
|
|
307
|
+
if (!DISCORD_WEBHOOK_URL_RE.test(webhookUrl)) {
|
|
308
|
+
console.warn("[notifier-discord] webhookUrl does not match expected Discord webhook format.\n" +
|
|
309
|
+
" Expected: https://discord.com/api/webhooks/... or https://discordapp.com/api/webhooks/...");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Discord requires thread_id as a URL query param, not in the JSON body
|
|
313
|
+
const effectiveUrl = webhookUrl && threadId
|
|
314
|
+
? `${webhookUrl}${webhookUrl.includes("?") ? "&" : "?"}thread_id=${encodeURIComponent(threadId)}`
|
|
315
|
+
: webhookUrl;
|
|
316
|
+
function buildPayload(embeds) {
|
|
317
|
+
const payload = { username, embeds, allowed_mentions: { parse: [] } };
|
|
318
|
+
if (avatarUrl)
|
|
319
|
+
payload.avatar_url = avatarUrl;
|
|
320
|
+
return payload;
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
name: "discord",
|
|
324
|
+
async notify(event) {
|
|
325
|
+
if (!effectiveUrl)
|
|
326
|
+
return;
|
|
327
|
+
const payload = buildPayload([buildEmbed(event)]);
|
|
328
|
+
await postWithRetry(effectiveUrl, payload, retries, retryDelayMs);
|
|
329
|
+
},
|
|
330
|
+
async notifyWithActions(event, actions) {
|
|
331
|
+
if (!effectiveUrl)
|
|
332
|
+
return;
|
|
333
|
+
const payload = buildPayload([buildEmbed(event, actions)]);
|
|
334
|
+
await postWithRetry(effectiveUrl, payload, retries, retryDelayMs);
|
|
335
|
+
},
|
|
336
|
+
async post(message, _context) {
|
|
337
|
+
if (!effectiveUrl)
|
|
338
|
+
return null;
|
|
339
|
+
const payload = {
|
|
340
|
+
username,
|
|
341
|
+
content: message,
|
|
342
|
+
allowed_mentions: { parse: [] },
|
|
343
|
+
};
|
|
344
|
+
if (avatarUrl)
|
|
345
|
+
payload.avatar_url = avatarUrl;
|
|
346
|
+
// thread_id is already passed as a URL query param via effectiveUrl
|
|
347
|
+
await postWithRetry(effectiveUrl, payload, retries, retryDelayMs);
|
|
348
|
+
return null;
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
export default { manifest, create };
|
|
353
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { create, manifest } from "./index.js";
|
|
3
|
+
function makeEvent(overrides = {}) {
|
|
4
|
+
return {
|
|
5
|
+
id: "evt-1",
|
|
6
|
+
type: "reaction.escalated",
|
|
7
|
+
priority: "urgent",
|
|
8
|
+
sessionId: "ao-5",
|
|
9
|
+
projectId: "ao",
|
|
10
|
+
timestamp: new Date("2026-03-20T12:00:00Z"),
|
|
11
|
+
message: "CI failed after 5 retries",
|
|
12
|
+
data: { attempts: 5, reason: "ci_failed" },
|
|
13
|
+
...overrides,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function makeV3Data(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
schemaVersion: 3,
|
|
19
|
+
subject: { session: { id: "ao-5", projectId: "ao" } },
|
|
20
|
+
...overrides,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
describe("notifier-discord", () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.restoreAllMocks();
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.unstubAllGlobals();
|
|
29
|
+
});
|
|
30
|
+
it("has correct manifest", () => {
|
|
31
|
+
expect(manifest.name).toBe("discord");
|
|
32
|
+
expect(manifest.slot).toBe("notifier");
|
|
33
|
+
});
|
|
34
|
+
it("posts to Discord webhook URL", async () => {
|
|
35
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
36
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
37
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
38
|
+
await notifier.notify(makeEvent());
|
|
39
|
+
expect(fetchMock).toHaveBeenCalledOnce();
|
|
40
|
+
expect(fetchMock.mock.calls[0][0]).toBe("https://discord.com/api/webhooks/123/abc");
|
|
41
|
+
});
|
|
42
|
+
it("sends Discord embed with correct structure", async () => {
|
|
43
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
44
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
45
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
46
|
+
await notifier.notify(makeEvent());
|
|
47
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
48
|
+
expect(body.username).toBe("Athene");
|
|
49
|
+
expect(body.allowed_mentions).toEqual({ parse: [] });
|
|
50
|
+
expect(body.embeds).toHaveLength(1);
|
|
51
|
+
const embed = body.embeds[0];
|
|
52
|
+
expect(embed.title).toContain("Reaction Escalated");
|
|
53
|
+
expect(embed.description).toBe("CI failed after 5 retries");
|
|
54
|
+
expect(embed.color).toBe(0xed4245); // red for urgent
|
|
55
|
+
expect(embed.timestamp).toBe("2026-03-20T12:00:00.000Z");
|
|
56
|
+
expect(embed.footer.text).toBe("Athene");
|
|
57
|
+
});
|
|
58
|
+
it("includes project and priority fields", async () => {
|
|
59
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
60
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
61
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
62
|
+
await notifier.notify(makeEvent());
|
|
63
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
64
|
+
const fields = body.embeds[0].fields;
|
|
65
|
+
expect(fields).toContainEqual(expect.objectContaining({ name: "Project", value: "ao" }));
|
|
66
|
+
expect(fields).toContainEqual(expect.objectContaining({ name: "Session", value: "ao-5" }));
|
|
67
|
+
expect(fields).toContainEqual(expect.objectContaining({ name: "Priority", value: "Urgent" }));
|
|
68
|
+
});
|
|
69
|
+
it("includes PR link when available", async () => {
|
|
70
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
71
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
72
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
73
|
+
await notifier.notify(makeEvent({
|
|
74
|
+
data: makeV3Data({
|
|
75
|
+
subject: {
|
|
76
|
+
session: { id: "ao-5", projectId: "ao" },
|
|
77
|
+
pr: { number: 42, url: "https://github.com/org/repo/pull/42" },
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
}));
|
|
81
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
82
|
+
const prField = body.embeds[0].fields.find((f) => f.name === "Pull Request");
|
|
83
|
+
expect(prField.value).toContain("https://github.com/org/repo/pull/42");
|
|
84
|
+
});
|
|
85
|
+
it("includes CI status when available", async () => {
|
|
86
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
87
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
88
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
89
|
+
await notifier.notify(makeEvent({ data: makeV3Data({ ci: { status: "passing" } }) }));
|
|
90
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
91
|
+
const ciField = body.embeds[0].fields.find((f) => f.name === "CI");
|
|
92
|
+
expect(ciField.value).toContain("Passing");
|
|
93
|
+
});
|
|
94
|
+
it("encodes closing parentheses in markdown link URLs", async () => {
|
|
95
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
96
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
97
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
98
|
+
await notifier.notify(makeEvent({
|
|
99
|
+
data: makeV3Data({
|
|
100
|
+
ci: {
|
|
101
|
+
status: "failing",
|
|
102
|
+
failedChecks: [
|
|
103
|
+
{
|
|
104
|
+
name: "build(test)",
|
|
105
|
+
status: "completed",
|
|
106
|
+
conclusion: "failure",
|
|
107
|
+
url: "https://github.com/org/repo/actions/runs/1?q=(abc)",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
}));
|
|
113
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
114
|
+
const checksField = body.embeds[0].fields.find((f) => f.name === "Checks");
|
|
115
|
+
expect(checksField.value).toContain("[buildtest: completed/failure](https://github.com/org/repo/actions/runs/1?q=(abc%29)");
|
|
116
|
+
});
|
|
117
|
+
it("notifyWithActions includes action links", async () => {
|
|
118
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
119
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
120
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
121
|
+
const actions = [
|
|
122
|
+
{ label: "View PR", url: "https://github.com/org/repo/pull/42" },
|
|
123
|
+
{ label: "retry" },
|
|
124
|
+
];
|
|
125
|
+
await notifier.notifyWithActions(makeEvent(), actions);
|
|
126
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
127
|
+
const actionsField = body.embeds[0].fields.find((f) => f.name === "Actions");
|
|
128
|
+
expect(actionsField.value).toContain("View PR");
|
|
129
|
+
expect(actionsField.value).toContain("retry");
|
|
130
|
+
});
|
|
131
|
+
it("post sends plain content message", async () => {
|
|
132
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
133
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
134
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
135
|
+
await notifier.post("Session ao-5 completed successfully");
|
|
136
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
137
|
+
expect(body.content).toBe("Session ao-5 completed successfully");
|
|
138
|
+
expect(body.allowed_mentions).toEqual({ parse: [] });
|
|
139
|
+
expect(body.embeds).toBeUndefined();
|
|
140
|
+
});
|
|
141
|
+
it("uses custom username when configured", async () => {
|
|
142
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
143
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
144
|
+
const notifier = create({
|
|
145
|
+
webhookUrl: "https://discord.com/api/webhooks/123/abc",
|
|
146
|
+
username: "AO Bot",
|
|
147
|
+
});
|
|
148
|
+
await notifier.notify(makeEvent());
|
|
149
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
150
|
+
expect(body.username).toBe("AO Bot");
|
|
151
|
+
});
|
|
152
|
+
it("includes avatar_url when configured", async () => {
|
|
153
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
154
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
155
|
+
const notifier = create({
|
|
156
|
+
webhookUrl: "https://discord.com/api/webhooks/123/abc",
|
|
157
|
+
avatarUrl: "https://example.com/avatar.png",
|
|
158
|
+
});
|
|
159
|
+
await notifier.notify(makeEvent());
|
|
160
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
161
|
+
expect(body.avatar_url).toBe("https://example.com/avatar.png");
|
|
162
|
+
});
|
|
163
|
+
it("includes thread_id when configured", async () => {
|
|
164
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
165
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
166
|
+
const notifier = create({
|
|
167
|
+
webhookUrl: "https://discord.com/api/webhooks/123/abc",
|
|
168
|
+
threadId: "1234567890",
|
|
169
|
+
});
|
|
170
|
+
await notifier.notify(makeEvent());
|
|
171
|
+
// Discord requires thread_id as a URL query param, not in the JSON body
|
|
172
|
+
const calledUrl = fetchMock.mock.calls[0][0];
|
|
173
|
+
expect(calledUrl).toBe("https://discord.com/api/webhooks/123/abc?thread_id=1234567890");
|
|
174
|
+
});
|
|
175
|
+
it("is a no-op when webhookUrl not configured", async () => {
|
|
176
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
177
|
+
const fetchMock = vi.fn();
|
|
178
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
179
|
+
const notifier = create();
|
|
180
|
+
await notifier.notify(makeEvent());
|
|
181
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
182
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("No webhookUrl configured"));
|
|
183
|
+
});
|
|
184
|
+
it("uses correct color for each priority", async () => {
|
|
185
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
186
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
187
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
188
|
+
await notifier.notify(makeEvent({ priority: "info" }));
|
|
189
|
+
let body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
190
|
+
expect(body.embeds[0].color).toBe(0x3498db); // blue
|
|
191
|
+
await notifier.notify(makeEvent({ priority: "warning" }));
|
|
192
|
+
body = JSON.parse(fetchMock.mock.calls[1][1].body);
|
|
193
|
+
expect(body.embeds[0].color).toBe(0xfee75c); // yellow
|
|
194
|
+
});
|
|
195
|
+
it("uses success color and professional fields for merge-ready events", async () => {
|
|
196
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 200 });
|
|
197
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
198
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
199
|
+
await notifier.notify(makeEvent({
|
|
200
|
+
type: "merge.ready",
|
|
201
|
+
priority: "action",
|
|
202
|
+
message: "PR #1579 is ready to merge",
|
|
203
|
+
data: makeV3Data({
|
|
204
|
+
subject: {
|
|
205
|
+
session: { id: "ao-5", projectId: "ao" },
|
|
206
|
+
pr: {
|
|
207
|
+
number: 1579,
|
|
208
|
+
title: "Normalize AO notifier payloads",
|
|
209
|
+
url: "https://github.com/org/repo/pull/1579",
|
|
210
|
+
branch: "feat/notifiers",
|
|
211
|
+
baseBranch: "main",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
ci: { status: "passing" },
|
|
215
|
+
review: { decision: "approved" },
|
|
216
|
+
merge: { ready: true, conflicts: false, isBehind: false },
|
|
217
|
+
}),
|
|
218
|
+
}));
|
|
219
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
220
|
+
const embed = body.embeds[0];
|
|
221
|
+
expect(embed.title).toContain("PR #1579 ready to merge");
|
|
222
|
+
expect(embed.color).toBe(0x57f287);
|
|
223
|
+
expect(embed.url).toBe("https://github.com/org/repo/pull/1579");
|
|
224
|
+
expect(embed.description).toContain("Normalize AO notifier payloads");
|
|
225
|
+
expect(embed.fields).toContainEqual(expect.objectContaining({ name: "CI" }));
|
|
226
|
+
expect(embed.fields).toContainEqual(expect.objectContaining({ name: "Review", value: "Approved" }));
|
|
227
|
+
expect(embed.fields).toContainEqual(expect.objectContaining({ name: "Merge", value: "Ready" }));
|
|
228
|
+
expect(embed.fields).toContainEqual(expect.objectContaining({ name: "Sync", value: "Up to date" }));
|
|
229
|
+
});
|
|
230
|
+
it("handles 204 No Content as success", async () => {
|
|
231
|
+
const fetchMock = vi.fn().mockResolvedValue({ ok: true, status: 204 });
|
|
232
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
233
|
+
const notifier = create({ webhookUrl: "https://discord.com/api/webhooks/123/abc" });
|
|
234
|
+
await expect(notifier.notify(makeEvent())).resolves.toBeUndefined();
|
|
235
|
+
});
|
|
236
|
+
it("retries on 5xx response", async () => {
|
|
237
|
+
vi.useFakeTimers();
|
|
238
|
+
const fetchMock = vi
|
|
239
|
+
.fn()
|
|
240
|
+
.mockResolvedValueOnce({ ok: false, status: 503, text: () => Promise.resolve("down") })
|
|
241
|
+
.mockResolvedValueOnce({ ok: true, status: 200 });
|
|
242
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
243
|
+
const notifier = create({
|
|
244
|
+
webhookUrl: "https://discord.com/api/webhooks/123/abc",
|
|
245
|
+
retries: 1,
|
|
246
|
+
retryDelayMs: 50,
|
|
247
|
+
});
|
|
248
|
+
const promise = notifier.notify(makeEvent());
|
|
249
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
250
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
251
|
+
await vi.advanceTimersByTimeAsync(50);
|
|
252
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
253
|
+
await promise;
|
|
254
|
+
vi.useRealTimers();
|
|
255
|
+
});
|
|
256
|
+
it("does not retry on 4xx response", async () => {
|
|
257
|
+
const fetchMock = vi
|
|
258
|
+
.fn()
|
|
259
|
+
.mockResolvedValue({ ok: false, status: 401, text: () => Promise.resolve("unauthorized") });
|
|
260
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
261
|
+
const notifier = create({
|
|
262
|
+
webhookUrl: "https://discord.com/api/webhooks/123/abc",
|
|
263
|
+
retries: 2,
|
|
264
|
+
retryDelayMs: 1,
|
|
265
|
+
});
|
|
266
|
+
await expect(notifier.notify(makeEvent())).rejects.toThrow("Discord webhook failed (401)");
|
|
267
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@made-by-moonlight/athene-plugin-notifier-discord",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "Notifier plugin: Discord webhook notifications",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/slievr/Athene.git",
|
|
21
|
+
"directory": "packages/plugins/notifier-discord"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/slievr/Athene",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/slievr/Athene/issues"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@made-by-moonlight/athene-core": "0.9.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^25.2.3",
|
|
35
|
+
"rimraf": "^6.0.0",
|
|
36
|
+
"typescript": "^5.7.0",
|
|
37
|
+
"vitest": "^3.0.0"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"clean": "rimraf dist"
|
|
47
|
+
}
|
|
48
|
+
}
|