@burdenoff/vibe-plugin-notify 1.0.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 +188 -0
- package/dist/cli/commands.d.ts +15 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +194 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +237 -0
- package/dist/index.js.map +1 -0
- package/dist/services/webhook-delivery.d.ts +73 -0
- package/dist/services/webhook-delivery.d.ts.map +1 -0
- package/dist/services/webhook-delivery.js +281 -0
- package/dist/services/webhook-delivery.js.map +1 -0
- package/dist/services/webhook-manager.d.ts +67 -0
- package/dist/services/webhook-manager.d.ts.map +1 -0
- package/dist/services/webhook-manager.js +159 -0
- package/dist/services/webhook-manager.js.map +1 -0
- package/dist/types.d.ts +125 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @burdenoff/vibe-plugin-notify
|
|
2
|
+
|
|
3
|
+
Generic webhook notification plugin for AI coding tools - a VibeControls Agent plugin.
|
|
4
|
+
|
|
5
|
+
Receives events from AI coding tools (OpenCode, Claude Code, Gemini CLI, etc.) and delivers to configured webhooks (Slack, Discord, custom).
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────┐ ┌─────────────────────────────────────────────┐
|
|
11
|
+
│ AI Coding Tool │ │ VibeControls Agent │
|
|
12
|
+
│ │ │ │
|
|
13
|
+
│ Tool-specific │────>│ vibe-plugin-notify │
|
|
14
|
+
│ plugin (e.g. │POST │ │ │
|
|
15
|
+
│ opencode-vibe- │ │ ├──> Slack webhook │
|
|
16
|
+
│ webhook) │ │ ├──> Discord webhook │
|
|
17
|
+
└─────────────────────┘ │ └──> Custom webhook │
|
|
18
|
+
└─────────────────────────────────────────────┘
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Why this architecture?**
|
|
22
|
+
|
|
23
|
+
| Component | Purpose |
|
|
24
|
+
| -------------------- | -------------------------------------------------------------- |
|
|
25
|
+
| Tool-specific plugin | Runs **inside AI tool** - 100% reliable native event detection |
|
|
26
|
+
| `vibe-plugin-notify` | Runs in **VibeControls** - webhook management, CLI, delivery |
|
|
27
|
+
|
|
28
|
+
## Supported AI Tools
|
|
29
|
+
|
|
30
|
+
| Tool | Plugin | Status |
|
|
31
|
+
| ----------- | ----------------------- | ------- |
|
|
32
|
+
| OpenCode | `opencode-vibe-webhook` | Ready |
|
|
33
|
+
| Claude Code | Coming soon | Planned |
|
|
34
|
+
| Gemini CLI | Coming soon | Planned |
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Install this plugin in VibeControls
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
vibe plugin install @burdenoff/vibe-plugin-notify
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Install tool-specific plugin
|
|
45
|
+
|
|
46
|
+
For OpenCode:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Add to opencode.json
|
|
50
|
+
{
|
|
51
|
+
"plugins": ["opencode-vibe-webhook"]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Add a webhook
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
vibe notify add https://hooks.slack.com/services/xxx/yyy/zzz
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That's it! When your AI tool completes a task, you'll get a notification.
|
|
62
|
+
|
|
63
|
+
## CLI Commands
|
|
64
|
+
|
|
65
|
+
| Command | Description |
|
|
66
|
+
| -------------------------- | ------------------------ |
|
|
67
|
+
| `vibe notify add <url>` | Add a webhook URL |
|
|
68
|
+
| `vibe notify list` | List all webhooks |
|
|
69
|
+
| `vibe notify remove <id>` | Remove a webhook |
|
|
70
|
+
| `vibe notify test <id>` | Send a test notification |
|
|
71
|
+
| `vibe notify enable <id>` | Enable a webhook |
|
|
72
|
+
| `vibe notify disable <id>` | Disable a webhook |
|
|
73
|
+
|
|
74
|
+
## Usage Examples
|
|
75
|
+
|
|
76
|
+
### Add a Slack Webhook
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
vibe notify add https://hooks.slack.com/services/T00/B00/XXX --name "Slack Alerts"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Add a Discord Webhook
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
vibe notify add https://discord.com/api/webhooks/123/abc --name "Discord"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Add with specific events
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
vibe notify add https://example.com/webhook --events "session.idle,session.error"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## REST API
|
|
95
|
+
|
|
96
|
+
| Method | Endpoint | Description |
|
|
97
|
+
| -------- | ---------------------------------- | ------------------------------- |
|
|
98
|
+
| `GET` | `/api/notify/health` | Health check |
|
|
99
|
+
| `POST` | `/api/notify/hook` | Receive events from tool plugin |
|
|
100
|
+
| `GET` | `/api/notify/webhooks` | List webhooks |
|
|
101
|
+
| `POST` | `/api/notify/webhooks` | Create webhook |
|
|
102
|
+
| `DELETE` | `/api/notify/webhooks/:id` | Delete webhook |
|
|
103
|
+
| `POST` | `/api/notify/webhooks/:id/test` | Test webhook |
|
|
104
|
+
| `POST` | `/api/notify/webhooks/:id/enable` | Enable webhook |
|
|
105
|
+
| `POST` | `/api/notify/webhooks/:id/disable` | Disable webhook |
|
|
106
|
+
| `GET` | `/api/notify/deliveries` | Delivery history |
|
|
107
|
+
|
|
108
|
+
## Webhook Payload
|
|
109
|
+
|
|
110
|
+
When an AI tool completes a task, webhooks receive:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"id": "dlv_abc123",
|
|
115
|
+
"timestamp": "2026-02-27T10:30:00.000Z",
|
|
116
|
+
"event": {
|
|
117
|
+
"type": "session.idle",
|
|
118
|
+
"sessionId": "sess_xyz",
|
|
119
|
+
"sessionTitle": "Add user authentication",
|
|
120
|
+
"projectName": "my-app",
|
|
121
|
+
"properties": {}
|
|
122
|
+
},
|
|
123
|
+
"source": {
|
|
124
|
+
"agent": "vibecontrols-agent",
|
|
125
|
+
"plugin": "notify",
|
|
126
|
+
"version": "1.0.0",
|
|
127
|
+
"tool": "opencode"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Slack Format
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
:white_check_mark: *Task Completed* (opencode)
|
|
136
|
+
> Add user authentication
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Discord Format
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
**Task Completed** (opencode)
|
|
143
|
+
> Add user authentication
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Supported Events
|
|
147
|
+
|
|
148
|
+
| Event | Description |
|
|
149
|
+
| ------------------ | ------------------------ |
|
|
150
|
+
| `session.idle` | Task completed (default) |
|
|
151
|
+
| `session.error` | Task failed |
|
|
152
|
+
| `permission.asked` | AI needs user permission |
|
|
153
|
+
| `*` | All events |
|
|
154
|
+
|
|
155
|
+
## Creating a Tool Plugin
|
|
156
|
+
|
|
157
|
+
To add support for a new AI coding tool, create a plugin that posts events to `/api/notify/hook`:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Example event payload
|
|
161
|
+
const event = {
|
|
162
|
+
type: "session.idle",
|
|
163
|
+
source: "your-tool-name",
|
|
164
|
+
properties: {
|
|
165
|
+
sessionID: "sess_123",
|
|
166
|
+
sessionTitle: "Task description",
|
|
167
|
+
},
|
|
168
|
+
timestamp: new Date().toISOString(),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
await fetch("http://localhost:4321/api/notify/hook", {
|
|
172
|
+
method: "POST",
|
|
173
|
+
headers: { "Content-Type": "application/json" },
|
|
174
|
+
body: JSON.stringify(event),
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [opencode-vibe-webhook](../opencode-vibe-webhook/) for a reference implementation.
|
|
179
|
+
|
|
180
|
+
## Requirements
|
|
181
|
+
|
|
182
|
+
- VibeControls Agent 2.0+
|
|
183
|
+
- Tool-specific plugin (e.g., `opencode-vibe-webhook` for OpenCode)
|
|
184
|
+
- Bun 1.3+
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
Proprietary - Burdenoff Consultancy Services Pvt. Ltd.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Commands for vibe-plugin-notify
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* vibe notify add <url> - Add a webhook
|
|
6
|
+
* vibe notify list - List all webhooks
|
|
7
|
+
* vibe notify remove <id> - Remove a webhook
|
|
8
|
+
* vibe notify test <id> - Test a webhook
|
|
9
|
+
* vibe notify enable <id> - Enable a webhook
|
|
10
|
+
* vibe notify disable <id> - Disable a webhook
|
|
11
|
+
*/
|
|
12
|
+
import type { Command } from "commander";
|
|
13
|
+
import type { HostServices } from "../types.js";
|
|
14
|
+
export declare function registerCommands(program: Command, hostServices: HostServices): void;
|
|
15
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAqBjE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,GACzB,IAAI,CA+PN"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Commands for vibe-plugin-notify
|
|
3
|
+
*
|
|
4
|
+
* Commands:
|
|
5
|
+
* vibe notify add <url> - Add a webhook
|
|
6
|
+
* vibe notify list - List all webhooks
|
|
7
|
+
* vibe notify remove <id> - Remove a webhook
|
|
8
|
+
* vibe notify test <id> - Test a webhook
|
|
9
|
+
* vibe notify enable <id> - Enable a webhook
|
|
10
|
+
* vibe notify disable <id> - Disable a webhook
|
|
11
|
+
*/
|
|
12
|
+
export function registerCommands(program, hostServices) {
|
|
13
|
+
const cmd = program
|
|
14
|
+
.command("notify")
|
|
15
|
+
.description("Webhook management for AI coding tool notifications");
|
|
16
|
+
// Add webhook
|
|
17
|
+
cmd
|
|
18
|
+
.command("add <url>")
|
|
19
|
+
.description("Add a webhook URL")
|
|
20
|
+
.option("-n, --name <name>", "Friendly name for the webhook")
|
|
21
|
+
.option("-e, --events <events>", "Comma-separated event types (default: session.idle)")
|
|
22
|
+
.action(async (url, options) => {
|
|
23
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
24
|
+
const eventTypes = options.events?.split(",").map((e) => e.trim());
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Content-Type": "application/json" },
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
url,
|
|
31
|
+
name: options.name,
|
|
32
|
+
eventTypes,
|
|
33
|
+
test: true,
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
const data = (await response.json());
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
const errorData = data;
|
|
39
|
+
console.error(`Error: ${errorData.error || "Failed to add webhook"}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const successData = data;
|
|
43
|
+
console.log("\nWebhook added successfully!\n");
|
|
44
|
+
console.log(` ID: ${successData.webhook.id}`);
|
|
45
|
+
console.log(` Name: ${successData.webhook.name}`);
|
|
46
|
+
console.log(` URL: ${successData.webhook.url}`);
|
|
47
|
+
console.log(` Events: ${successData.webhook.eventTypes.join(", ")}`);
|
|
48
|
+
if (successData.test) {
|
|
49
|
+
if (successData.test.success) {
|
|
50
|
+
console.log(` Test: Passed (${successData.test.statusCode})`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.log(` Test: Failed - ${successData.test.error}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
console.log();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
// List webhooks
|
|
64
|
+
cmd
|
|
65
|
+
.command("list")
|
|
66
|
+
.description("List all webhooks")
|
|
67
|
+
.action(async () => {
|
|
68
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks`);
|
|
71
|
+
const data = (await response.json());
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
const errorData = data;
|
|
74
|
+
console.error(`Error: ${errorData.error || "Failed to list webhooks"}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const listData = data;
|
|
78
|
+
if (listData.webhooks.length === 0) {
|
|
79
|
+
console.log("\nNo webhooks configured.\n");
|
|
80
|
+
console.log("Add one with: vibe notify add <url>\n");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.log(`\nWebhooks (${listData.count}):\n`);
|
|
84
|
+
for (const webhook of listData.webhooks) {
|
|
85
|
+
const status = webhook.enabled ? "enabled" : "disabled";
|
|
86
|
+
console.log(` ${webhook.id}`);
|
|
87
|
+
console.log(` Name: ${webhook.name}`);
|
|
88
|
+
console.log(` URL: ${webhook.url}`);
|
|
89
|
+
console.log(` Status: ${status}`);
|
|
90
|
+
console.log(` Events: ${webhook.eventTypes.join(", ")}`);
|
|
91
|
+
console.log();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// Remove webhook
|
|
100
|
+
cmd
|
|
101
|
+
.command("remove <id>")
|
|
102
|
+
.description("Remove a webhook")
|
|
103
|
+
.action(async (id) => {
|
|
104
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
105
|
+
try {
|
|
106
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks/${id}`, {
|
|
107
|
+
method: "DELETE",
|
|
108
|
+
});
|
|
109
|
+
const data = (await response.json());
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
const errorData = data;
|
|
112
|
+
console.error(`Error: ${errorData.error || "Failed to remove webhook"}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
console.log(`\nWebhook ${id} removed.\n`);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
// Test webhook
|
|
123
|
+
cmd
|
|
124
|
+
.command("test <id>")
|
|
125
|
+
.description("Send a test notification to a webhook")
|
|
126
|
+
.action(async (id) => {
|
|
127
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
128
|
+
try {
|
|
129
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks/${id}/test`, { method: "POST" });
|
|
130
|
+
const data = (await response.json());
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
const errorData = data;
|
|
133
|
+
console.error(`Error: ${errorData.error || "Failed to test webhook"}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
const testData = data;
|
|
137
|
+
console.log(`\nTest notification sent to: ${testData.webhook.name}\n`);
|
|
138
|
+
if (testData.test?.success) {
|
|
139
|
+
console.log(` Result: Passed (HTTP ${testData.test.statusCode})\n`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
console.log(` Result: Failed\n`);
|
|
143
|
+
console.log(` Error: ${testData.test?.error}\n`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// Enable webhook
|
|
152
|
+
cmd
|
|
153
|
+
.command("enable <id>")
|
|
154
|
+
.description("Enable a webhook")
|
|
155
|
+
.action(async (id) => {
|
|
156
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
157
|
+
try {
|
|
158
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks/${id}/enable`, { method: "POST" });
|
|
159
|
+
const data = (await response.json());
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
const errorData = data;
|
|
162
|
+
console.error(`Error: ${errorData.error || "Failed to enable webhook"}`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
console.log(`\nWebhook ${id} enabled.\n`);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
// Disable webhook
|
|
173
|
+
cmd
|
|
174
|
+
.command("disable <id>")
|
|
175
|
+
.description("Disable a webhook")
|
|
176
|
+
.action(async (id) => {
|
|
177
|
+
const baseUrl = hostServices.getAgentBaseUrl();
|
|
178
|
+
try {
|
|
179
|
+
const response = await fetch(`${baseUrl}/api/notify/webhooks/${id}/disable`, { method: "POST" });
|
|
180
|
+
const data = (await response.json());
|
|
181
|
+
if (!response.ok) {
|
|
182
|
+
const errorData = data;
|
|
183
|
+
console.error(`Error: ${errorData.error || "Failed to disable webhook"}`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
console.log(`\nWebhook ${id} disabled.\n`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @burdenoff/vibe-plugin-notify v1.0.0
|
|
3
|
+
*
|
|
4
|
+
* Generic webhook notifications for AI coding tools.
|
|
5
|
+
* Receives events from native plugins and delivers to configured webhooks.
|
|
6
|
+
*
|
|
7
|
+
* Supported AI Tools:
|
|
8
|
+
* - OpenCode (via opencode-vibe-webhook plugin)
|
|
9
|
+
* - Claude Code (via claudecode-vibe-webhook plugin) [future]
|
|
10
|
+
* - Gemini CLI (via gemini-vibe-webhook plugin) [future]
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Webhook CRUD management via CLI and REST API
|
|
14
|
+
* - Supports Slack, Discord, and custom webhooks
|
|
15
|
+
* - Delivery with retries and tracking
|
|
16
|
+
* - Simple CLI: vibe notify add <url>
|
|
17
|
+
*
|
|
18
|
+
* Install: vibe plugin install @burdenoff/vibe-plugin-notify
|
|
19
|
+
*/
|
|
20
|
+
import type { VibePlugin } from "./types.js";
|
|
21
|
+
export type { VibePlugin, HostServices, WebhookEndpoint, WebhookDelivery, NotifyEvent, } from "./types.js";
|
|
22
|
+
export declare const vibePlugin: VibePlugin;
|
|
23
|
+
export default vibePlugin;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AAMpB,YAAY,EACV,UAAU,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AAcpB,eAAO,MAAM,UAAU,EAAE,UA2PxB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @burdenoff/vibe-plugin-notify v1.0.0
|
|
3
|
+
*
|
|
4
|
+
* Generic webhook notifications for AI coding tools.
|
|
5
|
+
* Receives events from native plugins and delivers to configured webhooks.
|
|
6
|
+
*
|
|
7
|
+
* Supported AI Tools:
|
|
8
|
+
* - OpenCode (via opencode-vibe-webhook plugin)
|
|
9
|
+
* - Claude Code (via claudecode-vibe-webhook plugin) [future]
|
|
10
|
+
* - Gemini CLI (via gemini-vibe-webhook plugin) [future]
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Webhook CRUD management via CLI and REST API
|
|
14
|
+
* - Supports Slack, Discord, and custom webhooks
|
|
15
|
+
* - Delivery with retries and tracking
|
|
16
|
+
* - Simple CLI: vibe notify add <url>
|
|
17
|
+
*
|
|
18
|
+
* Install: vibe plugin install @burdenoff/vibe-plugin-notify
|
|
19
|
+
*/
|
|
20
|
+
import { Elysia } from "elysia";
|
|
21
|
+
import { DEFAULT_CONFIG } from "./types.js";
|
|
22
|
+
import { WebhookDeliveryService } from "./services/webhook-delivery.js";
|
|
23
|
+
import { registerCommands } from "./cli/commands.js";
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Module-level references for lifecycle management
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
let deliveryService = null;
|
|
28
|
+
let hostServicesRef = null;
|
|
29
|
+
const config = { ...DEFAULT_CONFIG };
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Plugin definition
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
export const vibePlugin = {
|
|
34
|
+
name: "notify",
|
|
35
|
+
version: "1.0.0",
|
|
36
|
+
description: "Webhook notifications for AI coding tools",
|
|
37
|
+
tags: ["backend", "cli", "integration"],
|
|
38
|
+
cliCommand: "notify",
|
|
39
|
+
apiPrefix: "/api/notify",
|
|
40
|
+
publicPaths: ["/health", "/hook"],
|
|
41
|
+
/**
|
|
42
|
+
* Create routes for the plugin
|
|
43
|
+
*/
|
|
44
|
+
createRoutes(_deps) {
|
|
45
|
+
return (new Elysia()
|
|
46
|
+
// Health check (public)
|
|
47
|
+
.get("/health", () => {
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
plugin: "notify",
|
|
51
|
+
version: "1.0.0",
|
|
52
|
+
mode: "webhook-receiver",
|
|
53
|
+
};
|
|
54
|
+
})
|
|
55
|
+
// Hook endpoint - receives events from AI tool plugins (public)
|
|
56
|
+
.post("/hook", async ({ body, set }) => {
|
|
57
|
+
if (!deliveryService) {
|
|
58
|
+
set.status = 503;
|
|
59
|
+
return { error: "Plugin not initialized" };
|
|
60
|
+
}
|
|
61
|
+
const hookData = body;
|
|
62
|
+
// Extract event from payload (standard format from native plugins)
|
|
63
|
+
const eventData = hookData?.event;
|
|
64
|
+
// Determine source (opencode, claudecode, gemini, etc.)
|
|
65
|
+
const source = hookData?.source?.plugin || "unknown";
|
|
66
|
+
hostServicesRef?.logger.info("notify", `[HOOK] Event received from ${source}`, { type: eventData?.type || "unknown" });
|
|
67
|
+
const event = {
|
|
68
|
+
type: eventData?.type || "task.completed",
|
|
69
|
+
properties: {
|
|
70
|
+
sessionId: eventData?.sessionId,
|
|
71
|
+
sessionTitle: eventData?.sessionTitle,
|
|
72
|
+
projectName: eventData?.projectName,
|
|
73
|
+
projectPath: eventData?.projectPath,
|
|
74
|
+
source: source,
|
|
75
|
+
...(eventData?.properties || {}),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
// Deliver webhooks
|
|
79
|
+
await deliveryService.processEvent(event);
|
|
80
|
+
return { success: true, message: "Event processed" };
|
|
81
|
+
})
|
|
82
|
+
// List all webhooks
|
|
83
|
+
.get("/webhooks", async ({ set }) => {
|
|
84
|
+
if (!deliveryService) {
|
|
85
|
+
set.status = 503;
|
|
86
|
+
return { error: "Plugin not initialized" };
|
|
87
|
+
}
|
|
88
|
+
const manager = deliveryService.getWebhookManager();
|
|
89
|
+
const webhooks = await manager.listWebhooks();
|
|
90
|
+
return { webhooks, count: webhooks.length };
|
|
91
|
+
})
|
|
92
|
+
// Create a new webhook
|
|
93
|
+
.post("/webhooks", async ({ body, set }) => {
|
|
94
|
+
if (!deliveryService) {
|
|
95
|
+
set.status = 503;
|
|
96
|
+
return { error: "Plugin not initialized" };
|
|
97
|
+
}
|
|
98
|
+
const input = body;
|
|
99
|
+
try {
|
|
100
|
+
const manager = deliveryService.getWebhookManager();
|
|
101
|
+
const webhook = await manager.createWebhook({
|
|
102
|
+
url: input.url,
|
|
103
|
+
name: input.name,
|
|
104
|
+
eventTypes: input.eventTypes,
|
|
105
|
+
});
|
|
106
|
+
// Optionally send test webhook
|
|
107
|
+
let testResult = null;
|
|
108
|
+
if (input.test !== false) {
|
|
109
|
+
testResult = await deliveryService.sendTestWebhook(webhook.id);
|
|
110
|
+
}
|
|
111
|
+
return { webhook, test: testResult };
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
set.status = 400;
|
|
115
|
+
return {
|
|
116
|
+
error: error instanceof Error ? error.message : String(error),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
// Get a specific webhook
|
|
121
|
+
.get("/webhooks/:id", async ({ params, set }) => {
|
|
122
|
+
if (!deliveryService) {
|
|
123
|
+
set.status = 503;
|
|
124
|
+
return { error: "Plugin not initialized" };
|
|
125
|
+
}
|
|
126
|
+
const manager = deliveryService.getWebhookManager();
|
|
127
|
+
const webhook = await manager.getWebhook(params.id);
|
|
128
|
+
if (!webhook) {
|
|
129
|
+
set.status = 404;
|
|
130
|
+
return { error: "Webhook not found" };
|
|
131
|
+
}
|
|
132
|
+
return { webhook };
|
|
133
|
+
})
|
|
134
|
+
// Delete a webhook
|
|
135
|
+
.delete("/webhooks/:id", async ({ params, set }) => {
|
|
136
|
+
if (!deliveryService) {
|
|
137
|
+
set.status = 503;
|
|
138
|
+
return { error: "Plugin not initialized" };
|
|
139
|
+
}
|
|
140
|
+
const manager = deliveryService.getWebhookManager();
|
|
141
|
+
const deleted = await manager.deleteWebhook(params.id);
|
|
142
|
+
if (!deleted) {
|
|
143
|
+
set.status = 404;
|
|
144
|
+
return { error: "Webhook not found" };
|
|
145
|
+
}
|
|
146
|
+
return { success: true, message: "Webhook deleted" };
|
|
147
|
+
})
|
|
148
|
+
// Enable a webhook
|
|
149
|
+
.post("/webhooks/:id/enable", async ({ params, set }) => {
|
|
150
|
+
if (!deliveryService) {
|
|
151
|
+
set.status = 503;
|
|
152
|
+
return { error: "Plugin not initialized" };
|
|
153
|
+
}
|
|
154
|
+
const manager = deliveryService.getWebhookManager();
|
|
155
|
+
const webhook = await manager.enableWebhook(params.id);
|
|
156
|
+
if (!webhook) {
|
|
157
|
+
set.status = 404;
|
|
158
|
+
return { error: "Webhook not found" };
|
|
159
|
+
}
|
|
160
|
+
return { webhook };
|
|
161
|
+
})
|
|
162
|
+
// Disable a webhook
|
|
163
|
+
.post("/webhooks/:id/disable", async ({ params, set }) => {
|
|
164
|
+
if (!deliveryService) {
|
|
165
|
+
set.status = 503;
|
|
166
|
+
return { error: "Plugin not initialized" };
|
|
167
|
+
}
|
|
168
|
+
const manager = deliveryService.getWebhookManager();
|
|
169
|
+
const webhook = await manager.disableWebhook(params.id);
|
|
170
|
+
if (!webhook) {
|
|
171
|
+
set.status = 404;
|
|
172
|
+
return { error: "Webhook not found" };
|
|
173
|
+
}
|
|
174
|
+
return { webhook };
|
|
175
|
+
})
|
|
176
|
+
// Test a webhook
|
|
177
|
+
.post("/webhooks/:id/test", async ({ params, set }) => {
|
|
178
|
+
if (!deliveryService) {
|
|
179
|
+
set.status = 503;
|
|
180
|
+
return { error: "Plugin not initialized" };
|
|
181
|
+
}
|
|
182
|
+
const manager = deliveryService.getWebhookManager();
|
|
183
|
+
const webhook = await manager.getWebhook(params.id);
|
|
184
|
+
if (!webhook) {
|
|
185
|
+
set.status = 404;
|
|
186
|
+
return { error: "Webhook not found" };
|
|
187
|
+
}
|
|
188
|
+
const result = await deliveryService.sendTestWebhook(params.id);
|
|
189
|
+
return {
|
|
190
|
+
webhook: { id: webhook.id, name: webhook.name },
|
|
191
|
+
test: result,
|
|
192
|
+
};
|
|
193
|
+
})
|
|
194
|
+
// List deliveries
|
|
195
|
+
.get("/deliveries", async ({ query, set }) => {
|
|
196
|
+
if (!deliveryService) {
|
|
197
|
+
set.status = 503;
|
|
198
|
+
return { error: "Plugin not initialized" };
|
|
199
|
+
}
|
|
200
|
+
const q = query;
|
|
201
|
+
const deliveries = await deliveryService.getDeliveries({
|
|
202
|
+
webhookId: q.webhookId,
|
|
203
|
+
status: q.status,
|
|
204
|
+
limit: q.limit ? parseInt(q.limit, 10) : 50,
|
|
205
|
+
});
|
|
206
|
+
return { deliveries, count: deliveries.length };
|
|
207
|
+
}));
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* Initialize services when server starts
|
|
211
|
+
*/
|
|
212
|
+
async onServerStart(_app, hostServices) {
|
|
213
|
+
const { storage, logger } = hostServices;
|
|
214
|
+
hostServicesRef = hostServices;
|
|
215
|
+
logger.info("notify", "Initializing plugin...");
|
|
216
|
+
// Initialize delivery service
|
|
217
|
+
deliveryService = new WebhookDeliveryService(storage, logger, config);
|
|
218
|
+
logger.info("notify", "Plugin initialized (webhook receiver mode)");
|
|
219
|
+
logger.info("notify", "Waiting for events from AI tool plugins at /api/notify/hook");
|
|
220
|
+
},
|
|
221
|
+
/**
|
|
222
|
+
* Cleanup when server stops
|
|
223
|
+
*/
|
|
224
|
+
async onServerStop() {
|
|
225
|
+
deliveryService = null;
|
|
226
|
+
hostServicesRef = null;
|
|
227
|
+
console.log(" Plugin 'notify' cleaned up");
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* Register CLI commands
|
|
231
|
+
*/
|
|
232
|
+
onCliSetup(program, hostServices) {
|
|
233
|
+
registerCommands(program, hostServices);
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
export default vibePlugin;
|
|
237
|
+
//# sourceMappingURL=index.js.map
|