openclaw-channel-github 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +578 -0
  2. package/config.example.json +33 -0
  3. package/dist/index.d.ts +14 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +44 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/auth/auth.d.ts +22 -0
  8. package/dist/src/auth/auth.d.ts.map +1 -0
  9. package/dist/src/auth/auth.js +112 -0
  10. package/dist/src/auth/auth.js.map +1 -0
  11. package/dist/src/config/config.d.ts +60 -0
  12. package/dist/src/config/config.d.ts.map +1 -0
  13. package/dist/src/config/config.js +184 -0
  14. package/dist/src/config/config.js.map +1 -0
  15. package/dist/src/events/events.d.ts +234 -0
  16. package/dist/src/events/events.d.ts.map +1 -0
  17. package/dist/src/events/events.js +53 -0
  18. package/dist/src/events/events.js.map +1 -0
  19. package/dist/src/main.d.ts +2 -0
  20. package/dist/src/main.d.ts.map +1 -0
  21. package/dist/src/main.js +115 -0
  22. package/dist/src/main.js.map +1 -0
  23. package/dist/src/normalizer/normalizer.d.ts +94 -0
  24. package/dist/src/normalizer/normalizer.d.ts.map +1 -0
  25. package/dist/src/normalizer/normalizer.js +486 -0
  26. package/dist/src/normalizer/normalizer.js.map +1 -0
  27. package/dist/src/outbound/outbound.d.ts +24 -0
  28. package/dist/src/outbound/outbound.d.ts.map +1 -0
  29. package/dist/src/outbound/outbound.js +125 -0
  30. package/dist/src/outbound/outbound.js.map +1 -0
  31. package/dist/src/routing/routing.d.ts +22 -0
  32. package/dist/src/routing/routing.d.ts.map +1 -0
  33. package/dist/src/routing/routing.js +97 -0
  34. package/dist/src/routing/routing.js.map +1 -0
  35. package/dist/src/server/server.d.ts +20 -0
  36. package/dist/src/server/server.d.ts.map +1 -0
  37. package/dist/src/server/server.js +283 -0
  38. package/dist/src/server/server.js.map +1 -0
  39. package/dist/src/state/state.d.ts +17 -0
  40. package/dist/src/state/state.d.ts.map +1 -0
  41. package/dist/src/state/state.js +49 -0
  42. package/dist/src/state/state.js.map +1 -0
  43. package/docs/api.md +450 -0
  44. package/docs/usage.md +393 -0
  45. package/openclaw.plugin.json +104 -0
  46. package/package.json +81 -0
package/docs/usage.md ADDED
@@ -0,0 +1,393 @@
1
+ # OpenClaw GitHub Channel - Usage Guide
2
+
3
+ ## Overview
4
+
5
+ The OpenClaw GitHub Channel is a webhook-based integration that connects GitHub repositories to the OpenClaw AI agent framework. It enables AI-powered assistance directly within GitHub Issues, Pull Requests, Discussions, and CI/CD workflows.
6
+
7
+ **Key capabilities:**
8
+ - Listen to GitHub webhook events (issues, PRs, reviews, discussions, CI)
9
+ - Normalize events into a unified format for the OpenClaw Gateway
10
+ - Trigger agent responses based on @mentions, slash commands, labels, or auto-trigger rules
11
+ - Send responses back as GitHub comments or PR reviews
12
+ - Prevent bot loops via sender filtering and outbound markers
13
+ - Support multi-account / multi-installation setups
14
+
15
+ ## Quick Start
16
+
17
+ ### Prerequisites
18
+
19
+ 1. A GitHub App with the following permissions:
20
+ - **Issues**: Read & Write
21
+ - **Pull Requests**: Read & Write
22
+ - **Discussions**: Read & Write (optional)
23
+ - **Metadata**: Read
24
+ - **Contents**: Read (optional, for file context)
25
+
26
+ 2. Webhook events configured on the GitHub App:
27
+ - `issues`
28
+ - `issue_comment`
29
+ - `pull_request`
30
+ - `pull_request_review`
31
+ - `pull_request_review_comment`
32
+ - `discussion` (optional)
33
+ - `discussion_comment` (optional)
34
+ - `check_run` (optional)
35
+ - `workflow_run` (optional)
36
+
37
+ 3. Go 1.21+ installed
38
+
39
+ ### Installation
40
+
41
+ #### Option 1: OpenClaw Plugin Install (Recommended)
42
+
43
+ ```bash
44
+ # Install directly via the OpenClaw CLI plugin system
45
+ openclaw plugins install github.com/Iceber/openclaw-channel-github
46
+
47
+ # Verify the installation
48
+ openclaw plugins list
49
+
50
+ # View channel status
51
+ openclaw channels list
52
+ openclaw channels status --channel github
53
+ openclaw channels capabilities --channel github
54
+ ```
55
+
56
+ #### Option 2: Build from Source
57
+
58
+ ```bash
59
+ # Clone the repository
60
+ git clone https://github.com/Iceber/openclaw-channel-github.git
61
+ cd openclaw-channel-github
62
+
63
+ # Build the binary
64
+ make build
65
+
66
+ # Or build manually with Go
67
+ go build -o openclaw-github-channel ./cmd/openclaw-github-channel/
68
+
69
+ # Install system-wide (optional)
70
+ make install
71
+
72
+ # Run with a config file
73
+ ./openclaw-github-channel -config config.json
74
+ ```
75
+
76
+ #### Option 3: Go Install
77
+
78
+ ```bash
79
+ go install github.com/Iceber/openclaw-channel-github/cmd/openclaw-github-channel@latest
80
+ ```
81
+
82
+ ### Minimal Configuration
83
+
84
+ Create a `config.json` file:
85
+
86
+ ```json
87
+ {
88
+ "server": {
89
+ "addr": ":8080"
90
+ },
91
+ "channel": {
92
+ "enabled": true,
93
+ "mode": "app",
94
+ "appId": 123456,
95
+ "installationId": 78901234,
96
+ "privateKeyPath": "/path/to/github-app-private-key.pem",
97
+ "webhookSecret": "your-webhook-secret",
98
+ "repositories": ["your-org/your-repo"],
99
+ "trigger": {
100
+ "requireMention": true,
101
+ "botUsername": "your-bot-name",
102
+ "commands": ["/openclaw"],
103
+ "labels": ["ai-review", "ai-help"]
104
+ },
105
+ "ignoreBots": true
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## Configuration Reference
111
+
112
+ ### Server Configuration
113
+
114
+ | Field | Type | Default | Description |
115
+ |-------|------|---------|-------------|
116
+ | `server.addr` | string | `:8080` | HTTP server listen address |
117
+
118
+ ### Channel Configuration
119
+
120
+ | Field | Type | Required | Description |
121
+ |-------|------|----------|-------------|
122
+ | `channel.enabled` | bool | Yes | Enable/disable the channel |
123
+ | `channel.mode` | string | Yes | Authentication mode: `"app"` or `"token"` |
124
+ | `channel.appId` | int | Yes (app mode) | GitHub App ID |
125
+ | `channel.installationId` | int | Yes (app mode) | GitHub App Installation ID |
126
+ | `channel.privateKeyPath` | string | Yes (app mode) | Path to GitHub App private key PEM file |
127
+ | `channel.webhookSecret` | string | Yes | Webhook signing secret |
128
+ | `channel.repositories` | []string | Yes | Allowlisted repositories (`"owner/repo"` format) |
129
+ | `channel.ignoreBots` | bool | No | Ignore events from bot accounts |
130
+
131
+ ### Trigger Configuration
132
+
133
+ | Field | Type | Default | Description |
134
+ |-------|------|---------|-------------|
135
+ | `channel.trigger.requireMention` | bool | `false` | Require `@bot` mention to trigger |
136
+ | `channel.trigger.botUsername` | string | - | Bot username for mention detection |
137
+ | `channel.trigger.commands` | []string | - | Slash command prefixes (e.g., `["/openclaw"]`) |
138
+ | `channel.trigger.labels` | []string | - | Labels that trigger the bot when applied |
139
+
140
+ ### Auto-Trigger Configuration
141
+
142
+ | Field | Type | Default | Description |
143
+ |-------|------|---------|-------------|
144
+ | `channel.autoTrigger.onPROpened` | bool | `false` | Auto-trigger when a PR is opened |
145
+ | `channel.autoTrigger.onIssueOpened` | bool | `false` | Auto-trigger when an issue is opened |
146
+
147
+ ### Outbound Configuration
148
+
149
+ | Field | Type | Default | Description |
150
+ |-------|------|---------|-------------|
151
+ | `channel.outbound.mode` | string | `"comment"` | Response mode: `"comment"`, `"review"`, or `"auto"` |
152
+ | `channel.outbound.outboundMarker` | string | `<!-- openclaw-outbound -->` | Hidden HTML comment for bot loop prevention |
153
+
154
+ ### Rate Limiting
155
+
156
+ | Field | Type | Default | Description |
157
+ |-------|------|---------|-------------|
158
+ | `channel.rateLimit.maxEventsPerMinute` | int | 0 (unlimited) | Maximum events to process per minute |
159
+
160
+ ### Multi-Account Configuration
161
+
162
+ For managing multiple GitHub App installations:
163
+
164
+ ```json
165
+ {
166
+ "channel": {
167
+ "enabled": true,
168
+ "accounts": {
169
+ "default": {
170
+ "mode": "app",
171
+ "appId": 123456,
172
+ "installationId": 111,
173
+ "privateKeyPath": "/keys/default.pem",
174
+ "webhookSecret": "secret-1",
175
+ "repositories": ["org-a/repo-1", "org-a/repo-2"]
176
+ },
177
+ "enterprise": {
178
+ "mode": "app",
179
+ "appId": 654321,
180
+ "installationId": 222,
181
+ "privateKeyPath": "/keys/enterprise.pem",
182
+ "webhookSecret": "secret-2",
183
+ "repositories": ["org-b/repo-x"]
184
+ }
185
+ },
186
+ "trigger": {
187
+ "requireMention": true,
188
+ "botUsername": "openclaw-bot"
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ ## Trigger Model
195
+
196
+ The channel supports four trigger modes:
197
+
198
+ ### 1. @Mention Trigger
199
+ The bot responds when mentioned in a comment:
200
+ ```
201
+ @openclaw-bot Please summarize this issue.
202
+ ```
203
+
204
+ ### 2. Command Trigger
205
+ The bot responds to slash commands:
206
+ ```
207
+ /openclaw review
208
+ /openclaw summarize
209
+ ```
210
+
211
+ ### 3. Label Trigger
212
+ The bot responds when a configured label is applied to an issue or PR:
213
+ - Apply label `ai-review` → triggers analysis
214
+ - Apply label `ai-help` → triggers assistance
215
+
216
+ ### 4. Auto Trigger
217
+ The bot automatically responds to certain events:
218
+ - PR opened → auto-analyze (when `autoTrigger.onPROpened` is true)
219
+ - Issue opened → auto-respond (when `autoTrigger.onIssueOpened` is true)
220
+
221
+ ### Trigger Priority
222
+ 1. @Mention (highest priority)
223
+ 2. Slash command
224
+ 3. Label match
225
+ 4. Auto-trigger (lowest priority)
226
+
227
+ ## Supported Events
228
+
229
+ ### Core Events (Phase 1)
230
+ | GitHub Event | Action | Normalized Type |
231
+ |-------------|--------|-----------------|
232
+ | `issue_comment` | `created` | `comment` |
233
+ | `issues` | `opened` | `issue_body` |
234
+ | `pull_request` | `opened` | `pr_body` |
235
+ | `pull_request_review` | `submitted` | `review` |
236
+ | `pull_request_review_comment` | `created` | `review_comment` |
237
+
238
+ ### Context Events (Phase 3)
239
+ | GitHub Event | Action | Normalized Type |
240
+ |-------------|--------|-----------------|
241
+ | `issues` | `edited` | `context_update` |
242
+ | `issues` | `closed` | `context_update` |
243
+ | `issues` | `reopened` | `context_update` |
244
+ | `issues` | `labeled` | `context_update` |
245
+ | `issue_comment` | `edited` | `context_update` |
246
+ | `pull_request` | `edited` | `context_update` |
247
+ | `pull_request` | `closed` | `context_update` |
248
+ | `pull_request` | `synchronize` | `context_update` |
249
+ | `pull_request` | `labeled` | `context_update` |
250
+
251
+ ### Discussion Events (Phase 4)
252
+ | GitHub Event | Action | Normalized Type |
253
+ |-------------|--------|-----------------|
254
+ | `discussion` | `created` | `discussion_body` |
255
+ | `discussion_comment` | `created` | `comment` |
256
+
257
+ ### CI Events (Phase 4)
258
+ | GitHub Event | Action | Normalized Type |
259
+ |-------------|--------|-----------------|
260
+ | `check_run` | `completed` | `ci_status` |
261
+ | `workflow_run` | `completed` | `ci_status` |
262
+
263
+ ## Session Model
264
+
265
+ Each GitHub thread (Issue, PR, Discussion) maps to a stable session:
266
+
267
+ ```
268
+ github:<owner>/<repo>:issue:<number>
269
+ github:<owner>/<repo>:pull_request:<number>
270
+ github:<owner>/<repo>:discussion:<number>
271
+ ```
272
+
273
+ For PR review threads (fine-grained):
274
+ ```
275
+ github:<owner>/<repo>:pull_request:<number>:review-thread:<threadId>
276
+ ```
277
+
278
+ Multiple comments within the same thread always map to the same session, enabling continuous conversation context.
279
+
280
+ ## Bot Loop Prevention
281
+
282
+ Three layers of protection:
283
+
284
+ 1. **Sender type filtering**: Events from `Bot` type accounts are ignored (when `ignoreBots` is true)
285
+ 2. **Username matching**: Events from the bot's own username are always ignored
286
+ 3. **Outbound marker**: Responses include a hidden HTML marker (`<!-- openclaw-outbound -->`) that is detected in incoming events to prevent self-triggering
287
+
288
+ ## Security
289
+
290
+ ### Webhook Signature Verification
291
+ All webhook payloads are verified using HMAC-SHA256 (`X-Hub-Signature-256` header).
292
+
293
+ ### Repository Allowlist
294
+ Only events from explicitly allowlisted repositories are processed.
295
+
296
+ ### Delivery Deduplication
297
+ GitHub may retry webhook deliveries. The channel uses delivery ID tracking to prevent duplicate processing.
298
+
299
+ ### Minimal Permissions
300
+ Only request the minimum GitHub App permissions needed:
301
+ - Issues: Read/Write
302
+ - Pull Requests: Read/Write
303
+ - Metadata: Read
304
+
305
+ ## Running Tests
306
+
307
+ ```bash
308
+ # Run all unit tests
309
+ go test ./...
310
+
311
+ # Run with race detector
312
+ go test -race ./...
313
+
314
+ # Run e2e tests only
315
+ go test ./e2e/...
316
+
317
+ # Run with verbose output
318
+ go test -v ./...
319
+ ```
320
+
321
+ ## Architecture
322
+
323
+ ```
324
+ GitHub Webhook POST /webhook
325
+ → HMAC-SHA256 signature verification
326
+ → Delivery ID deduplication
327
+ → Event type parsing
328
+ → Normalization to NormalizedEvent (with context metadata)
329
+ → Repository allowlist check
330
+ → Bot loop prevention (sender type + username + outbound marker)
331
+ → Trigger evaluation (@mention / /command / label / auto)
332
+ → MessageHandler callback
333
+ → Outbound response (comment or PR review)
334
+ ```
335
+
336
+ ### Package Structure
337
+
338
+ ```
339
+ cmd/openclaw-github-channel/ # Entry point
340
+ pkg/
341
+ config/ # Configuration loading and validation
342
+ auth/ # GitHub App authentication, webhook verification
343
+ events/ # Webhook event types and parsing
344
+ normalizer/ # Event normalization to unified format
345
+ routing/ # Session keys, trigger matching
346
+ outbound/ # GitHub API client (comments, reviews, reactions)
347
+ state/ # Idempotency and deduplication
348
+ server/ # HTTP webhook handler
349
+ e2e/ # End-to-end tests
350
+ docs/ # Documentation
351
+ ```
352
+
353
+ ## OpenClaw Plugin Integration
354
+
355
+ This channel is packaged as an OpenClaw plugin and can be managed via the `openclaw` CLI.
356
+
357
+ ### Plugin Manifest
358
+
359
+ The `plugin.yaml` in the repository root defines the plugin metadata, capabilities, and configuration schema. It is used by the `openclaw plugins install` command to register and configure the channel.
360
+
361
+ ### CLI Commands
362
+
363
+ ```bash
364
+ # Install the plugin
365
+ openclaw plugins install github.com/Iceber/openclaw-channel-github
366
+
367
+ # List installed plugins
368
+ openclaw plugins list
369
+
370
+ # Remove the plugin
371
+ openclaw plugins remove github
372
+
373
+ # Channel management
374
+ openclaw channels add --channel github
375
+ openclaw channels list
376
+ openclaw channels status --channel github
377
+ openclaw channels capabilities --channel github
378
+ openclaw channels logs --channel github
379
+ ```
380
+
381
+ ### Capabilities
382
+
383
+ | Capability | Supported |
384
+ |-----------|-----------|
385
+ | Text inbound | ✅ |
386
+ | Text outbound | ✅ |
387
+ | Reaction | ✅ |
388
+ | Edit awareness | ✅ |
389
+ | Delete awareness | ❌ |
390
+ | Attachment send | ❌ |
391
+ | Thread reply | ✅ |
392
+ | Rich review output | ✅ |
393
+ | Realtime typing / presence | ❌ |
@@ -0,0 +1,104 @@
1
+ {
2
+ "$schema": "https://docs.openclaw.ai/schemas/plugin.json",
3
+ "name": "openclaw-channel-github",
4
+ "version": "0.1.0",
5
+ "description": "GitHub Channel for OpenClaw — connects GitHub Issues, Pull Requests, Discussions, and CI/CD workflows to the OpenClaw AI agent framework via webhooks.",
6
+ "author": "Iceber",
7
+ "license": "Apache-2.0",
8
+ "homepage": "https://github.com/Iceber/openclaw-channel-github",
9
+ "repository": "https://github.com/Iceber/openclaw-channel-github",
10
+ "keywords": ["github", "channel", "webhook", "issues", "pull-requests", "code-review"],
11
+ "main": "dist/index.js",
12
+ "channels": [
13
+ {
14
+ "id": "github",
15
+ "name": "GitHub",
16
+ "description": "GitHub Issues, Pull Requests, Discussions, and CI/CD webhook integration",
17
+ "capabilities": {
18
+ "textInbound": true,
19
+ "textOutbound": true,
20
+ "reaction": true,
21
+ "editAwareness": true,
22
+ "deleteAwareness": false,
23
+ "attachmentSend": false,
24
+ "threadReply": true,
25
+ "richReviewOutput": true,
26
+ "realtimeTyping": false,
27
+ "realtimePresence": false
28
+ },
29
+ "events": [
30
+ "issues",
31
+ "issue_comment",
32
+ "pull_request",
33
+ "pull_request_review",
34
+ "pull_request_review_comment",
35
+ "discussion",
36
+ "discussion_comment",
37
+ "check_run",
38
+ "workflow_run"
39
+ ],
40
+ "webhook": {
41
+ "path": "/webhook",
42
+ "method": "POST"
43
+ },
44
+ "healthCheck": {
45
+ "path": "/health",
46
+ "interval": "30s"
47
+ }
48
+ }
49
+ ],
50
+ "permissions": {
51
+ "issues": "write",
52
+ "pull_requests": "write",
53
+ "metadata": "read",
54
+ "discussions": "write",
55
+ "contents": "read"
56
+ },
57
+ "configSchema": {
58
+ "type": "object",
59
+ "properties": {
60
+ "server": {
61
+ "type": "object",
62
+ "properties": {
63
+ "addr": { "type": "string", "default": ":8080" }
64
+ }
65
+ },
66
+ "channel": {
67
+ "type": "object",
68
+ "properties": {
69
+ "enabled": { "type": "boolean", "default": true },
70
+ "mode": { "type": "string", "enum": ["app", "token"], "default": "app" },
71
+ "appId": { "type": "number" },
72
+ "installationId": { "type": "number" },
73
+ "privateKeyPath": { "type": "string" },
74
+ "webhookSecret": { "type": "string" },
75
+ "repositories": { "type": "array", "items": { "type": "string" } },
76
+ "ignoreBots": { "type": "boolean", "default": true },
77
+ "trigger": {
78
+ "type": "object",
79
+ "properties": {
80
+ "requireMention": { "type": "boolean", "default": true },
81
+ "botUsername": { "type": "string" },
82
+ "commands": { "type": "array", "items": { "type": "string" } },
83
+ "labels": { "type": "array", "items": { "type": "string" } }
84
+ }
85
+ },
86
+ "outbound": {
87
+ "type": "object",
88
+ "properties": {
89
+ "mode": { "type": "string", "enum": ["comment", "review", "auto"], "default": "comment" },
90
+ "outboundMarker": { "type": "string", "default": "<!-- openclaw-outbound -->" }
91
+ }
92
+ },
93
+ "autoTrigger": {
94
+ "type": "object",
95
+ "properties": {
96
+ "onPROpened": { "type": "boolean", "default": false },
97
+ "onIssueOpened": { "type": "boolean", "default": false }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "openclaw-channel-github",
3
+ "version": "0.1.0",
4
+ "description": "GitHub Channel for OpenClaw — connects GitHub Issues, Pull Requests, Discussions, and CI/CD workflows to the OpenClaw AI agent framework via webhooks.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "config.example.json",
17
+ "docs",
18
+ "openclaw.plugin.json"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "start": "node dist/main.js",
23
+ "dev": "ts-node src/main.ts",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:e2e": "vitest run e2e/",
27
+ "lint": "eslint src/ e2e/",
28
+ "clean": "rm -rf dist",
29
+ "prepack": "npm run build"
30
+ },
31
+ "keywords": [
32
+ "openclaw",
33
+ "github",
34
+ "channel",
35
+ "webhook",
36
+ "issues",
37
+ "pull-requests",
38
+ "code-review"
39
+ ],
40
+ "author": "Iceber",
41
+ "license": "Apache-2.0",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/Iceber/openclaw-channel-github.git"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/"
49
+ },
50
+ "openclaw": {
51
+ "extensions": [
52
+ "./dist/index.js"
53
+ ],
54
+ "channel": {
55
+ "id": "github",
56
+ "label": "GitHub",
57
+ "selectionLabel": "GitHub (Issues and PRs)",
58
+ "docsPath": "/channels/github",
59
+ "docsLabel": "github",
60
+ "blurb": "GitHub Issues, Pull Requests, Discussions, and CI/CD webhook integration.",
61
+ "aliases": [
62
+ "gh"
63
+ ]
64
+ },
65
+ "install": {
66
+ "npmSpec": "openclaw-channel-github",
67
+ "localPath": ".",
68
+ "defaultChoice": "local"
69
+ }
70
+ },
71
+ "dependencies": {
72
+ "jsonwebtoken": "^9.0.0"
73
+ },
74
+ "devDependencies": {
75
+ "@types/jsonwebtoken": "^9.0.0",
76
+ "@types/node": "^20.0.0",
77
+ "typescript": "^5.5.0",
78
+ "vitest": "^3.0.0",
79
+ "ts-node": "^10.9.0"
80
+ }
81
+ }