@made-by-moonlight/athene-plugin-notifier-slack 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 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.
@@ -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,EAIL,KAAK,QAAQ,EAOd,MAAM,gCAAgC,CAAC;AAExC,eAAO,MAAM,QAAQ;;;;;CAKpB,CAAC;AAgVF,wBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAyDjE;;;;;;;;;;AAED,wBAAqE"}
package/dist/index.js ADDED
@@ -0,0 +1,333 @@
1
+ import { getNotificationDataV3, validateUrl, CI_STATUS, } from "@made-by-moonlight/athene-core";
2
+ export const manifest = {
3
+ name: "slack",
4
+ slot: "notifier",
5
+ description: "Notifier plugin: Slack webhook notifications",
6
+ version: "0.1.0",
7
+ };
8
+ const SUCCESS_TONE = {
9
+ emoji: ":white_check_mark:",
10
+ label: "Complete",
11
+ color: "#2EB67D",
12
+ };
13
+ const PRIORITY_TONE = {
14
+ urgent: {
15
+ emoji: ":rotating_light:",
16
+ label: "Urgent",
17
+ color: "#E01E5A",
18
+ },
19
+ action: {
20
+ emoji: ":point_right:",
21
+ label: "Action required",
22
+ color: "#6157D8",
23
+ },
24
+ warning: {
25
+ emoji: ":warning:",
26
+ label: "Warning",
27
+ color: "#ECB22E",
28
+ },
29
+ info: {
30
+ emoji: ":information_source:",
31
+ label: "Information",
32
+ color: "#36C5F0",
33
+ },
34
+ };
35
+ function escapeSlackText(value) {
36
+ return value
37
+ .replace(/&/g, "&amp;")
38
+ .replace(/</g, "&lt;")
39
+ .replace(/>/g, "&gt;")
40
+ .replace(/\*/g, "&#42;")
41
+ .replace(/_/g, "&#95;")
42
+ .replace(/~/g, "&#126;")
43
+ .replace(/`/g, "&#96;");
44
+ }
45
+ function truncate(value, maxLength) {
46
+ return value.length > maxLength ? `${value.slice(0, maxLength - 3)}...` : value;
47
+ }
48
+ function titleCaseStatus(value) {
49
+ return value
50
+ .split(/[_\s.-]+/)
51
+ .filter(Boolean)
52
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
53
+ .join(" ");
54
+ }
55
+ function formatSlackDate(date) {
56
+ const timestamp = Math.floor(date.getTime() / 1000);
57
+ return `<!date^${timestamp}^{date_short_pretty} {time}|${date.toISOString()}>`;
58
+ }
59
+ function toneForEvent(event) {
60
+ if (event.type === "merge.ready") {
61
+ return { ...SUCCESS_TONE, label: "Ready to merge" };
62
+ }
63
+ if (event.type === "summary.all_complete") {
64
+ return { ...SUCCESS_TONE, label: "All complete" };
65
+ }
66
+ if (event.type === "ci.failing" || event.type === "session.stuck") {
67
+ return PRIORITY_TONE.urgent;
68
+ }
69
+ if (event.type === "review.changes_requested") {
70
+ return PRIORITY_TONE.warning;
71
+ }
72
+ return PRIORITY_TONE[event.priority] ?? PRIORITY_TONE.info;
73
+ }
74
+ function eventTitle(event, data) {
75
+ const pr = data?.subject.pr;
76
+ switch (event.type) {
77
+ case "ci.failing":
78
+ return pr ? `CI failing on PR #${pr.number}` : "CI failing";
79
+ case "merge.ready":
80
+ return pr ? `PR #${pr.number} ready to merge` : "Pull request ready to merge";
81
+ case "review.changes_requested":
82
+ return pr ? `Changes requested on PR #${pr.number}` : "Review changes requested";
83
+ case "session.needs_input":
84
+ return "Agent needs input";
85
+ case "session.stuck":
86
+ return "Agent may be stuck";
87
+ case "session.killed":
88
+ case "session.exited":
89
+ return "Agent exited";
90
+ case "pr.closed":
91
+ return pr ? `PR #${pr.number} closed` : "Pull request closed";
92
+ case "summary.all_complete":
93
+ return "All sessions complete";
94
+ default:
95
+ return titleCaseStatus(event.type);
96
+ }
97
+ }
98
+ function formatField(label, value) {
99
+ return {
100
+ type: "mrkdwn",
101
+ text: `*${escapeSlackText(label)}*\n${escapeSlackText(value === undefined || value === null || value === "" ? "Not available" : String(value))}`,
102
+ };
103
+ }
104
+ function buildFieldBlocks(event, data) {
105
+ const pr = data?.subject.pr;
106
+ const issue = data?.subject.issue;
107
+ const branch = pr?.branch && pr.baseBranch
108
+ ? `${pr.branch} -> ${pr.baseBranch}`
109
+ : (pr?.branch ?? pr?.baseBranch ?? data?.subject.branch);
110
+ const fields = [
111
+ formatField("Project", event.projectId),
112
+ formatField("Session", event.sessionId),
113
+ formatField("Priority", toneForEvent(event).label),
114
+ ...(pr
115
+ ? [formatField("Pull Request", `#${pr.number}${pr.title ? ` - ${pr.title}` : ""}`)]
116
+ : []),
117
+ ...(branch ? [formatField("Branch", branch)] : []),
118
+ ...(issue
119
+ ? [formatField("Issue", `${issue.id}${issue.title ? ` - ${issue.title}` : ""}`)]
120
+ : []),
121
+ ...(data?.ci?.status ? [formatField("CI", titleCaseStatus(data.ci.status))] : []),
122
+ ...(data?.review?.decision
123
+ ? [formatField("Review", titleCaseStatus(data.review.decision))]
124
+ : []),
125
+ ...(typeof data?.merge?.ready === "boolean"
126
+ ? [formatField("Merge", data.merge.ready ? "Ready" : "Not ready")]
127
+ : []),
128
+ ...(typeof data?.merge?.isBehind === "boolean"
129
+ ? [formatField("Sync", data.merge.isBehind ? "Behind base" : "Up to date")]
130
+ : []),
131
+ ].slice(0, 10);
132
+ if (fields.length === 0)
133
+ return [];
134
+ return [{ type: "section", fields }];
135
+ }
136
+ function buildStatusContext(data) {
137
+ if (!data)
138
+ return [];
139
+ const context = [];
140
+ if (data.ci?.status) {
141
+ const ciEmoji = data.ci.status === CI_STATUS.PASSING ? ":white_check_mark:" : ":x:";
142
+ const failedChecks = data.ci.failedChecks?.map((check) => escapeSlackText(check.name)) ?? [];
143
+ const failedText = failedChecks.length > 0 ? ` | Failed: ${failedChecks.join(", ")}` : "";
144
+ context.push(`${ciEmoji} CI: ${escapeSlackText(data.ci.status)}${failedText}`);
145
+ }
146
+ if (typeof data.merge?.conflicts === "boolean") {
147
+ context.push(data.merge.conflicts
148
+ ? ":x: Merge conflicts detected"
149
+ : ":white_check_mark: No merge conflicts");
150
+ }
151
+ if (typeof data.review?.unresolvedThreads === "number") {
152
+ context.push(`:speech_balloon: Review threads: ${data.review.unresolvedThreads}`);
153
+ }
154
+ if (data.merge?.blockers?.length) {
155
+ context.push(`:no_entry: Blockers: ${data.merge.blockers.slice(0, 5).map(escapeSlackText).join(", ")}`);
156
+ }
157
+ if (context.length === 0)
158
+ return [];
159
+ return [
160
+ {
161
+ type: "context",
162
+ elements: [{ type: "mrkdwn", text: context.join(" • ") }],
163
+ },
164
+ ];
165
+ }
166
+ function sanitizeActionId(label, index) {
167
+ const sanitized = label
168
+ .toLowerCase()
169
+ .replace(/[^a-z0-9]+/g, "_")
170
+ .replace(/^_|_$/g, "");
171
+ return `ao_${sanitized ? `${sanitized}_${index}` : `action_${index}`}`;
172
+ }
173
+ function buildButton(label, url, style) {
174
+ return {
175
+ type: "button",
176
+ text: { type: "plain_text", text: truncate(label, 75), emoji: true },
177
+ url,
178
+ ...(style ? { style } : {}),
179
+ };
180
+ }
181
+ function buildActionElements(data, actions) {
182
+ const elements = [];
183
+ const seenUrls = new Set();
184
+ const prUrl = data?.subject.pr?.url;
185
+ const reviewUrl = data?.review?.url;
186
+ if (prUrl) {
187
+ elements.push(buildButton("View PR", prUrl, "primary"));
188
+ seenUrls.add(prUrl);
189
+ }
190
+ if (reviewUrl && !seenUrls.has(reviewUrl)) {
191
+ elements.push(buildButton("View Review", reviewUrl));
192
+ seenUrls.add(reviewUrl);
193
+ }
194
+ for (const [index, action] of (actions ?? []).entries()) {
195
+ if (action.url) {
196
+ if (seenUrls.has(action.url))
197
+ continue;
198
+ elements.push(buildButton(action.label, action.url, elements.length === 0 ? "primary" : undefined));
199
+ seenUrls.add(action.url);
200
+ continue;
201
+ }
202
+ if (!action.callbackEndpoint)
203
+ continue;
204
+ const label = truncate(action.label, 75);
205
+ const lower = label.toLowerCase();
206
+ elements.push({
207
+ type: "button",
208
+ text: { type: "plain_text", text: label, emoji: true },
209
+ action_id: sanitizeActionId(label, index),
210
+ value: action.callbackEndpoint,
211
+ ...(lower.includes("kill") || lower.includes("cancel") ? { style: "danger" } : {}),
212
+ });
213
+ }
214
+ return elements.slice(0, 5);
215
+ }
216
+ function buildFallbackText(event, data) {
217
+ const tone = toneForEvent(event);
218
+ return `${tone.label}: ${eventTitle(event, data)} — ${event.message}`;
219
+ }
220
+ function buildAttachment(event, actions) {
221
+ const data = getNotificationDataV3(event.data);
222
+ const tone = toneForEvent(event);
223
+ const title = eventTitle(event, data);
224
+ const subtitle = data?.subject.pr?.title ?? data?.subject.summary;
225
+ const blocks = [
226
+ {
227
+ type: "header",
228
+ text: {
229
+ type: "plain_text",
230
+ text: truncate(`${tone.emoji} ${title}`, 150),
231
+ emoji: true,
232
+ },
233
+ },
234
+ {
235
+ type: "section",
236
+ text: {
237
+ type: "mrkdwn",
238
+ text: `${subtitle ? `*${escapeSlackText(subtitle)}*\n` : ""}${escapeSlackText(event.message)}`,
239
+ },
240
+ },
241
+ ...buildFieldBlocks(event, data),
242
+ ...buildStatusContext(data),
243
+ {
244
+ type: "context",
245
+ elements: [
246
+ {
247
+ type: "mrkdwn",
248
+ text: `Sent by Athene • ${formatSlackDate(event.timestamp)}`,
249
+ },
250
+ ],
251
+ },
252
+ ];
253
+ const actionElements = buildActionElements(data, actions);
254
+ if (actionElements.length > 0) {
255
+ blocks.push({
256
+ type: "actions",
257
+ elements: actionElements,
258
+ });
259
+ }
260
+ blocks.push({ type: "divider" });
261
+ return {
262
+ color: tone.color,
263
+ fallback: buildFallbackText(event, data),
264
+ blocks,
265
+ };
266
+ }
267
+ async function postToWebhook(webhookUrl, payload) {
268
+ const response = await fetch(webhookUrl, {
269
+ method: "POST",
270
+ headers: { "Content-Type": "application/json" },
271
+ body: JSON.stringify(payload),
272
+ });
273
+ if (!response.ok) {
274
+ const body = await response.text();
275
+ throw new Error(`Slack webhook failed (${response.status}): ${body}`);
276
+ }
277
+ }
278
+ export function create(config) {
279
+ const webhookUrl = config?.webhookUrl;
280
+ const defaultChannel = config?.channel;
281
+ const username = config?.username ?? "Athene";
282
+ if (!webhookUrl) {
283
+ console.warn("[notifier-slack] No webhookUrl configured — notifications will be no-ops");
284
+ }
285
+ else {
286
+ validateUrl(webhookUrl, "notifier-slack");
287
+ }
288
+ return {
289
+ name: "slack",
290
+ async notify(event) {
291
+ if (!webhookUrl)
292
+ return;
293
+ const attachment = buildAttachment(event);
294
+ const payload = {
295
+ username,
296
+ text: attachment.fallback,
297
+ attachments: [attachment],
298
+ };
299
+ if (defaultChannel)
300
+ payload.channel = defaultChannel;
301
+ await postToWebhook(webhookUrl, payload);
302
+ },
303
+ async notifyWithActions(event, actions) {
304
+ if (!webhookUrl)
305
+ return;
306
+ const attachment = buildAttachment(event, actions);
307
+ const payload = {
308
+ username,
309
+ text: attachment.fallback,
310
+ attachments: [attachment],
311
+ };
312
+ if (defaultChannel)
313
+ payload.channel = defaultChannel;
314
+ await postToWebhook(webhookUrl, payload);
315
+ },
316
+ async post(message, context) {
317
+ if (!webhookUrl)
318
+ return null;
319
+ const channel = context?.channel ?? defaultChannel;
320
+ const payload = {
321
+ username,
322
+ text: message,
323
+ };
324
+ if (channel)
325
+ payload.channel = channel;
326
+ await postToWebhook(webhookUrl, payload);
327
+ // Incoming webhooks don't return a message ID
328
+ return null;
329
+ },
330
+ };
331
+ }
332
+ export default { manifest, create };
333
+ //# 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,341 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { manifest, create } from "./index.js";
3
+ function makeEvent(overrides = {}) {
4
+ return {
5
+ id: "evt-1",
6
+ type: "session.spawned",
7
+ priority: "info",
8
+ sessionId: "app-1",
9
+ projectId: "my-project",
10
+ timestamp: new Date("2025-06-15T12:00:00Z"),
11
+ message: "Session app-1 spawned successfully",
12
+ data: {},
13
+ ...overrides,
14
+ };
15
+ }
16
+ function makeV3Data(overrides = {}) {
17
+ return {
18
+ schemaVersion: 3,
19
+ subject: { session: { id: "app-1", projectId: "my-project" } },
20
+ ...overrides,
21
+ };
22
+ }
23
+ function mockFetchOk() {
24
+ return vi.fn().mockResolvedValue({
25
+ ok: true,
26
+ text: () => Promise.resolve("ok"),
27
+ });
28
+ }
29
+ function getSlackAttachment(body) {
30
+ return body.attachments[0];
31
+ }
32
+ function getSlackBlocks(body) {
33
+ return getSlackAttachment(body).blocks;
34
+ }
35
+ describe("notifier-slack", () => {
36
+ beforeEach(() => {
37
+ vi.restoreAllMocks();
38
+ vi.unstubAllGlobals();
39
+ });
40
+ describe("manifest", () => {
41
+ it("has correct metadata", () => {
42
+ expect(manifest.name).toBe("slack");
43
+ expect(manifest.slot).toBe("notifier");
44
+ expect(manifest.version).toBe("0.1.0");
45
+ });
46
+ });
47
+ describe("create", () => {
48
+ it("returns a notifier with name 'slack'", () => {
49
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
50
+ expect(notifier.name).toBe("slack");
51
+ });
52
+ it("warns when no webhookUrl configured", () => {
53
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => { });
54
+ create();
55
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("No webhookUrl configured"));
56
+ });
57
+ it("throws on invalid URL scheme", () => {
58
+ expect(() => create({ webhookUrl: "file:///etc/passwd" })).toThrow("must be http(s)");
59
+ });
60
+ });
61
+ describe("notify", () => {
62
+ it("does nothing when no webhookUrl", async () => {
63
+ const fetchMock = mockFetchOk();
64
+ vi.stubGlobal("fetch", fetchMock);
65
+ const notifier = create();
66
+ await notifier.notify(makeEvent());
67
+ expect(fetchMock).not.toHaveBeenCalled();
68
+ });
69
+ it("POSTs to the webhook URL", async () => {
70
+ const fetchMock = mockFetchOk();
71
+ vi.stubGlobal("fetch", fetchMock);
72
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
73
+ await notifier.notify(makeEvent());
74
+ expect(fetchMock).toHaveBeenCalledOnce();
75
+ expect(fetchMock.mock.calls[0][0]).toBe("https://hooks.slack.com/test");
76
+ expect(fetchMock.mock.calls[0][1].method).toBe("POST");
77
+ });
78
+ it("sends JSON with Content-Type header", async () => {
79
+ const fetchMock = mockFetchOk();
80
+ vi.stubGlobal("fetch", fetchMock);
81
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
82
+ await notifier.notify(makeEvent());
83
+ const opts = fetchMock.mock.calls[0][1];
84
+ expect(opts.headers["Content-Type"]).toBe("application/json");
85
+ });
86
+ it("includes username in payload", async () => {
87
+ const fetchMock = mockFetchOk();
88
+ vi.stubGlobal("fetch", fetchMock);
89
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
90
+ await notifier.notify(makeEvent());
91
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
92
+ expect(body.username).toBe("Athene");
93
+ });
94
+ it("uses custom username when configured", async () => {
95
+ const fetchMock = mockFetchOk();
96
+ vi.stubGlobal("fetch", fetchMock);
97
+ const notifier = create({
98
+ webhookUrl: "https://hooks.slack.com/test",
99
+ username: "MyBot",
100
+ });
101
+ await notifier.notify(makeEvent());
102
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
103
+ expect(body.username).toBe("MyBot");
104
+ });
105
+ it("includes channel when configured", async () => {
106
+ const fetchMock = mockFetchOk();
107
+ vi.stubGlobal("fetch", fetchMock);
108
+ const notifier = create({
109
+ webhookUrl: "https://hooks.slack.com/test",
110
+ channel: "#deploys",
111
+ });
112
+ await notifier.notify(makeEvent());
113
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
114
+ expect(body.channel).toBe("#deploys");
115
+ });
116
+ it("throws on non-ok response", async () => {
117
+ const fetchMock = vi.fn().mockResolvedValue({
118
+ ok: false,
119
+ status: 500,
120
+ text: () => Promise.resolve("server error"),
121
+ });
122
+ vi.stubGlobal("fetch", fetchMock);
123
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
124
+ await expect(notifier.notify(makeEvent())).rejects.toThrow("Slack webhook failed (500): server error");
125
+ });
126
+ });
127
+ describe("Block Kit formatting", () => {
128
+ it("includes header block with priority emoji and session ID", async () => {
129
+ const fetchMock = mockFetchOk();
130
+ vi.stubGlobal("fetch", fetchMock);
131
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
132
+ await notifier.notify(makeEvent({ priority: "urgent", sessionId: "backend-3" }));
133
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
134
+ const blocks = getSlackBlocks(body);
135
+ const header = blocks[0];
136
+ expect(header.type).toBe("header");
137
+ expect(header.text.type).toBe("plain_text");
138
+ expect(header.text.text).toContain(":rotating_light:");
139
+ expect(body.text).toContain("Session Spawned");
140
+ expect(getSlackAttachment(body).color).toBe("#E01E5A");
141
+ });
142
+ it("uses correct emoji for each priority level", async () => {
143
+ const fetchMock = mockFetchOk();
144
+ vi.stubGlobal("fetch", fetchMock);
145
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
146
+ const priorities = [
147
+ ["urgent", ":rotating_light:"],
148
+ ["action", ":point_right:"],
149
+ ["warning", ":warning:"],
150
+ ["info", ":information_source:"],
151
+ ];
152
+ for (const [priority, emoji] of priorities) {
153
+ fetchMock.mockClear();
154
+ await notifier.notify(makeEvent({ priority }));
155
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
156
+ expect(getSlackBlocks(body)[0].text.text).toContain(emoji);
157
+ }
158
+ });
159
+ it("includes section block with event message", async () => {
160
+ const fetchMock = mockFetchOk();
161
+ vi.stubGlobal("fetch", fetchMock);
162
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
163
+ await notifier.notify(makeEvent({ message: "CI is green" }));
164
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
165
+ const section = getSlackBlocks(body)[1];
166
+ expect(section.type).toBe("section");
167
+ expect(section.text.text).toBe("CI is green");
168
+ });
169
+ it("escapes user-controlled Slack mrkdwn characters", async () => {
170
+ const fetchMock = mockFetchOk();
171
+ vi.stubGlobal("fetch", fetchMock);
172
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
173
+ await notifier.notify(makeEvent({ message: "Fix *bold* _italic_ ~strike~ `code` & <tag> > done" }));
174
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
175
+ const section = getSlackBlocks(body)[1];
176
+ expect(section.text.text).toBe("Fix &#42;bold&#42; &#95;italic&#95; &#126;strike&#126; &#96;code&#96; &amp; &lt;tag&gt; &gt; done");
177
+ });
178
+ it("includes context block with project and priority", async () => {
179
+ const fetchMock = mockFetchOk();
180
+ vi.stubGlobal("fetch", fetchMock);
181
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
182
+ await notifier.notify(makeEvent({ projectId: "frontend", priority: "action" }));
183
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
184
+ const fieldsBlock = getSlackBlocks(body).find((b) => b.type === "section" && b.fields);
185
+ expect(fieldsBlock).toBeDefined();
186
+ expect(fieldsBlock.fields[0].text).toContain("*Project*");
187
+ expect(fieldsBlock.fields[0].text).toContain("frontend");
188
+ expect(fieldsBlock.fields[2].text).toContain("*Priority*");
189
+ expect(fieldsBlock.fields[2].text).toContain("Action required");
190
+ });
191
+ it("includes PR link when subject.pr.url is present in v3 data", async () => {
192
+ const fetchMock = mockFetchOk();
193
+ vi.stubGlobal("fetch", fetchMock);
194
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
195
+ await notifier.notify(makeEvent({
196
+ data: makeV3Data({
197
+ subject: {
198
+ session: { id: "app-1", projectId: "my-project" },
199
+ pr: { number: 42, url: "https://github.com/org/repo/pull/42" },
200
+ },
201
+ }),
202
+ }));
203
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
204
+ const actionsBlock = getSlackBlocks(body).find((b) => b.type === "actions" && b.elements?.[0]?.text?.text?.includes("View PR"));
205
+ expect(actionsBlock).toBeDefined();
206
+ expect(actionsBlock.elements[0].url).toBe("https://github.com/org/repo/pull/42");
207
+ });
208
+ it("ignores legacy flat prUrl", async () => {
209
+ const fetchMock = mockFetchOk();
210
+ vi.stubGlobal("fetch", fetchMock);
211
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
212
+ await notifier.notify(makeEvent({ data: { prUrl: "https://github.com/org/repo/pull/42" } }));
213
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
214
+ const prBlock = getSlackBlocks(body).find((b) => b.type === "actions" && b.elements?.[0]?.text?.text?.includes("View PR"));
215
+ expect(prBlock).toBeUndefined();
216
+ });
217
+ it("ignores legacy flat ciStatus", async () => {
218
+ const fetchMock = mockFetchOk();
219
+ vi.stubGlobal("fetch", fetchMock);
220
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
221
+ await notifier.notify(makeEvent({ data: { ciStatus: "passing" } }));
222
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
223
+ const ciBlock = getSlackBlocks(body).find((b) => b.type === "context" && b.elements?.[0]?.text?.includes("CI:"));
224
+ expect(ciBlock).toBeUndefined();
225
+ });
226
+ it("includes CI status when ci.status is present in v3 data", async () => {
227
+ const fetchMock = mockFetchOk();
228
+ vi.stubGlobal("fetch", fetchMock);
229
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
230
+ await notifier.notify(makeEvent({ data: makeV3Data({ ci: { status: "passing" } }) }));
231
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
232
+ const ciBlock = getSlackBlocks(body).find((b) => b.type === "context" && b.elements?.[0]?.text?.includes("CI:"));
233
+ expect(ciBlock).toBeDefined();
234
+ expect(ciBlock.elements[0].text).toContain(":white_check_mark:");
235
+ });
236
+ it("uses :x: emoji for failing CI", async () => {
237
+ const fetchMock = mockFetchOk();
238
+ vi.stubGlobal("fetch", fetchMock);
239
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
240
+ await notifier.notify(makeEvent({
241
+ data: makeV3Data({
242
+ ci: {
243
+ status: "failing",
244
+ failedChecks: [{ name: "typecheck", status: "failed" }],
245
+ },
246
+ }),
247
+ }));
248
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
249
+ const ciBlock = getSlackBlocks(body).find((b) => b.type === "context" && b.elements?.[0]?.text?.includes("CI:"));
250
+ expect(ciBlock.elements[0].text).toContain(":x:");
251
+ expect(ciBlock.elements[0].text).toContain("typecheck");
252
+ });
253
+ it("ends with a divider block", async () => {
254
+ const fetchMock = mockFetchOk();
255
+ vi.stubGlobal("fetch", fetchMock);
256
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
257
+ await notifier.notify(makeEvent());
258
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
259
+ const blocks = getSlackBlocks(body);
260
+ const lastBlock = blocks[blocks.length - 1];
261
+ expect(lastBlock.type).toBe("divider");
262
+ });
263
+ });
264
+ describe("notifyWithActions", () => {
265
+ it("includes action buttons with URLs", async () => {
266
+ const fetchMock = mockFetchOk();
267
+ vi.stubGlobal("fetch", fetchMock);
268
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
269
+ const actions = [
270
+ { label: "Merge", url: "https://github.com/org/repo/pull/42/merge" },
271
+ { label: "Open", url: "https://github.com/org/repo/pull/42" },
272
+ ];
273
+ await notifier.notifyWithActions(makeEvent(), actions);
274
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
275
+ const actionsBlock = getSlackBlocks(body).find((b) => b.type === "actions");
276
+ expect(actionsBlock).toBeDefined();
277
+ expect(actionsBlock.elements).toHaveLength(2);
278
+ expect(actionsBlock.elements[0].type).toBe("button");
279
+ expect(actionsBlock.elements[0].text.text).toBe("Merge");
280
+ });
281
+ it("includes callback-based action buttons", async () => {
282
+ const fetchMock = mockFetchOk();
283
+ vi.stubGlobal("fetch", fetchMock);
284
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
285
+ const actions = [
286
+ { label: "Kill Session", callbackEndpoint: "/api/sessions/app-1/kill" },
287
+ ];
288
+ await notifier.notifyWithActions(makeEvent(), actions);
289
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
290
+ const actionsBlock = getSlackBlocks(body).find((b) => b.type === "actions");
291
+ expect(actionsBlock.elements[0].action_id).toBe("ao_kill_session_0");
292
+ expect(actionsBlock.elements[0].value).toBe("/api/sessions/app-1/kill");
293
+ expect(actionsBlock.elements[0].style).toBe("danger");
294
+ });
295
+ it("filters out actions with no url or callback", async () => {
296
+ const fetchMock = mockFetchOk();
297
+ vi.stubGlobal("fetch", fetchMock);
298
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
299
+ const actions = [
300
+ { label: "No-op" },
301
+ { label: "Merge", url: "https://example.com" },
302
+ ];
303
+ await notifier.notifyWithActions(makeEvent(), actions);
304
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
305
+ const actionsBlock = getSlackBlocks(body).find((b) => b.type === "actions");
306
+ expect(actionsBlock.elements).toHaveLength(1);
307
+ expect(actionsBlock.elements[0].text.text).toBe("Merge");
308
+ });
309
+ });
310
+ describe("post", () => {
311
+ it("sends a text message", async () => {
312
+ const fetchMock = mockFetchOk();
313
+ vi.stubGlobal("fetch", fetchMock);
314
+ const notifier = create({ webhookUrl: "https://hooks.slack.com/test" });
315
+ const result = await notifier.post("Hello from AO");
316
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
317
+ expect(body.text).toBe("Hello from AO");
318
+ expect(result).toBeNull();
319
+ });
320
+ it("uses context channel over default", async () => {
321
+ const fetchMock = mockFetchOk();
322
+ vi.stubGlobal("fetch", fetchMock);
323
+ const notifier = create({
324
+ webhookUrl: "https://hooks.slack.com/test",
325
+ channel: "#default",
326
+ });
327
+ await notifier.post("test", { channel: "#override" });
328
+ const body = JSON.parse(fetchMock.mock.calls[0][1].body);
329
+ expect(body.channel).toBe("#override");
330
+ });
331
+ it("returns null when no webhookUrl", async () => {
332
+ const fetchMock = mockFetchOk();
333
+ vi.stubGlobal("fetch", fetchMock);
334
+ const notifier = create();
335
+ const result = await notifier.post("test");
336
+ expect(result).toBeNull();
337
+ expect(fetchMock).not.toHaveBeenCalled();
338
+ });
339
+ });
340
+ });
341
+ //# 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,47 @@
1
+ {
2
+ "name": "@made-by-moonlight/athene-plugin-notifier-slack",
3
+ "version": "0.9.1",
4
+ "description": "Notifier plugin: Slack",
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-slack"
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
+ "typescript": "^5.7.0",
36
+ "vitest": "^3.0.0"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc",
43
+ "typecheck": "tsc --noEmit",
44
+ "test": "vitest run",
45
+ "clean": "rm -rf dist"
46
+ }
47
+ }