@qwen-code/channel-github 0.21.0-nightly.20260729.0c0ca5fed
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/dist/GithubAdapter.d.ts +54 -0
- package/dist/GithubAdapter.d.ts.map +1 -0
- package/dist/GithubAdapter.js +474 -0
- package/dist/GithubAdapter.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/mention.d.ts +4 -0
- package/dist/mention.d.ts.map +1 -0
- package/dist/mention.js +14 -0
- package/dist/mention.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ChannelAgentBridge, ChannelBaseOptions, ChannelConfig } from '@qwen-code/channel-base';
|
|
2
|
+
import { PollingChannelBase } from '@qwen-code/channel-base';
|
|
3
|
+
interface GithubConfig extends ChannelConfig {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
interface GithubCursor {
|
|
7
|
+
lastProcessedAt: string;
|
|
8
|
+
metaFloor?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Thread keys (`chatId|threadId`) whose issue/PR body has already been fed as
|
|
11
|
+
* a first-contact trigger. Dedupes body dispatch when a thread is re-fetched
|
|
12
|
+
* with `last_read_at` still null — which happens if `markNotificationsAsRead`
|
|
13
|
+
* failed to mark it read (its `updated_at` was bumped past the cutoff between
|
|
14
|
+
* fetch and mark). Bounded to the most recent entries so the cursor stays small.
|
|
15
|
+
*/
|
|
16
|
+
dispatchedBodies?: string[];
|
|
17
|
+
/** Comment node IDs already accepted by the channel. */
|
|
18
|
+
dispatchedComments?: string[];
|
|
19
|
+
/** Direct-action event node IDs already accepted by the channel. */
|
|
20
|
+
dispatchedEvents?: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare class GithubChannel extends PollingChannelBase<GithubCursor> {
|
|
23
|
+
private octokit;
|
|
24
|
+
private botUsername;
|
|
25
|
+
private webOrigin;
|
|
26
|
+
constructor(name: string, config: GithubConfig & Record<string, unknown>, bridge: ChannelAgentBridge, options?: ChannelBaseOptions);
|
|
27
|
+
protected createInitialCursor(): GithubCursor;
|
|
28
|
+
protected validateCursor(parsed: unknown): GithubCursor | null;
|
|
29
|
+
connect(): Promise<void>;
|
|
30
|
+
disconnect(): void;
|
|
31
|
+
sendMessage(_chatId: string, _text: string): Promise<void>;
|
|
32
|
+
protected sendThreadMessage(chatId: string, threadId: string | undefined, text: string): Promise<void>;
|
|
33
|
+
protected pollOnce(): Promise<void>;
|
|
34
|
+
private processCommentLane;
|
|
35
|
+
private processDirectLane;
|
|
36
|
+
private processAggregateLane;
|
|
37
|
+
private findDirectTrigger;
|
|
38
|
+
private fetchNewComments;
|
|
39
|
+
private fetchIssueMeta;
|
|
40
|
+
private fetchPrMeta;
|
|
41
|
+
private tryFirstContactBody;
|
|
42
|
+
private recordDispatchedBody;
|
|
43
|
+
private recordDispatchedComment;
|
|
44
|
+
private recordDispatched;
|
|
45
|
+
private dispatchEnvelope;
|
|
46
|
+
private extractFromSubjectUrl;
|
|
47
|
+
private buildMetadata;
|
|
48
|
+
private buildRouteMetadata;
|
|
49
|
+
private githubApi;
|
|
50
|
+
private markNotificationsAsRead;
|
|
51
|
+
private postErrorComment;
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=GithubAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GithubAdapter.d.ts","sourceRoot":"","sources":["../src/GithubAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,UAAU,YAAa,SAAQ,aAAa;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wDAAwD;IACxD,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAgDD,qBAAa,aAAc,SAAQ,kBAAkB,CAAC,YAAY,CAAC;IACjE,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,SAAS,CAAwB;gBAGvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9C,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE,kBAAkB;IAK9B,SAAS,CAAC,mBAAmB,IAAI,YAAY;cAI1B,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI;IAuBjE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC9B,UAAU,IAAI,IAAI;IAIZ,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAMvC,iBAAiB,CACxC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC;cAuBA,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAwF3B,kBAAkB;YAiDlB,iBAAiB;YAoCjB,oBAAoB;YA4CpB,iBAAiB;YAoDjB,gBAAgB;YA2BhB,cAAc;YAad,WAAW;YAaX,mBAAmB;IAmDjC,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,gBAAgB;YASV,gBAAgB;IAgB9B,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,kBAAkB;YAIZ,SAAS;YA+CT,uBAAuB;YAWvB,gBAAgB;CAqB/B"}
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { Octokit } from '@octokit/rest';
|
|
3
|
+
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
4
|
+
import { PollingChannelBase } from '@qwen-code/channel-base';
|
|
5
|
+
import { testBotMention, stripBotMention } from './mention.js';
|
|
6
|
+
const MAX_DISPATCHED = 500;
|
|
7
|
+
const MAX_AGGREGATE_COMMENTS = 20;
|
|
8
|
+
const MAX_AGGREGATE_COMMENT_CHARS = 400;
|
|
9
|
+
export class GithubChannel extends PollingChannelBase {
|
|
10
|
+
octokit;
|
|
11
|
+
botUsername = null;
|
|
12
|
+
webOrigin = 'https://github.com';
|
|
13
|
+
constructor(name, config, bridge, options) {
|
|
14
|
+
super(name, config, bridge, options);
|
|
15
|
+
}
|
|
16
|
+
createInitialCursor() {
|
|
17
|
+
return { lastProcessedAt: new Date().toISOString() };
|
|
18
|
+
}
|
|
19
|
+
validateCursor(parsed) {
|
|
20
|
+
const base = super.validateCursor(parsed);
|
|
21
|
+
if (!base || typeof base.lastProcessedAt !== 'string')
|
|
22
|
+
return null;
|
|
23
|
+
if (Number.isNaN(new Date(base.lastProcessedAt).getTime()))
|
|
24
|
+
return null;
|
|
25
|
+
if (base.metaFloor !== undefined &&
|
|
26
|
+
(typeof base.metaFloor !== 'string' ||
|
|
27
|
+
Number.isNaN(new Date(base.metaFloor).getTime()))) {
|
|
28
|
+
delete base.metaFloor;
|
|
29
|
+
}
|
|
30
|
+
for (const field of [
|
|
31
|
+
'dispatchedBodies',
|
|
32
|
+
'dispatchedComments',
|
|
33
|
+
'dispatchedEvents',
|
|
34
|
+
]) {
|
|
35
|
+
if (base[field] !== undefined && !Array.isArray(base[field])) {
|
|
36
|
+
base[field] = [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return base;
|
|
40
|
+
}
|
|
41
|
+
async connect() {
|
|
42
|
+
const cfg = this.config;
|
|
43
|
+
const baseUrl = cfg.baseUrl || 'https://api.github.com';
|
|
44
|
+
this.webOrigin = baseUrl
|
|
45
|
+
.replace(/\/api\/v3\/?$/, '')
|
|
46
|
+
.replace(/^https:\/\/api\.github\.com/, 'https://github.com');
|
|
47
|
+
this.octokit = new Octokit({
|
|
48
|
+
auth: cfg.token,
|
|
49
|
+
baseUrl,
|
|
50
|
+
...(this.proxy
|
|
51
|
+
? { request: { agent: new HttpsProxyAgent(this.proxy) } }
|
|
52
|
+
: {}),
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
const { data } = await this.octokit.rest.users.getAuthenticated();
|
|
56
|
+
this.botUsername = data.login;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
throw new Error(`[Channel:${this.name}] failed to resolve bot identity: ${err}`);
|
|
60
|
+
}
|
|
61
|
+
// GitHub logins are case-insensitive; normalize both sides so the
|
|
62
|
+
// allowlist gate and ChannelBase's shared-session authorization match
|
|
63
|
+
// regardless of how the operator typed the config entry.
|
|
64
|
+
const allowed = (this.config.allowedUsers ?? []).map((u) => u.toLowerCase());
|
|
65
|
+
this.config.allowedUsers = allowed;
|
|
66
|
+
this.gate.replaceAllowedUsers(allowed);
|
|
67
|
+
this.startPollLoop();
|
|
68
|
+
}
|
|
69
|
+
disconnect() {
|
|
70
|
+
this.stopPollLoop();
|
|
71
|
+
}
|
|
72
|
+
async sendMessage(_chatId, _text) {
|
|
73
|
+
throw new Error(`[Channel:${this.name}] sendMessage requires a threadId; use sendThreadMessage`);
|
|
74
|
+
}
|
|
75
|
+
async sendThreadMessage(chatId, threadId, text) {
|
|
76
|
+
if (!threadId) {
|
|
77
|
+
return super.sendThreadMessage(chatId, threadId, text);
|
|
78
|
+
}
|
|
79
|
+
const match = threadId.match(/^(?:issue|pr):(\d+)$/);
|
|
80
|
+
if (!match) {
|
|
81
|
+
throw new Error(`[Channel:${this.name}] invalid threadId format: ${threadId}`);
|
|
82
|
+
}
|
|
83
|
+
const issueNumber = Number(match[1]);
|
|
84
|
+
await this.githubApi(() => this.octokit.rest.issues.createComment({
|
|
85
|
+
owner: chatId.split('/')[0],
|
|
86
|
+
repo: chatId.split('/')[1],
|
|
87
|
+
issue_number: issueNumber,
|
|
88
|
+
body: text,
|
|
89
|
+
}), `createComment(${threadId})`);
|
|
90
|
+
}
|
|
91
|
+
async pollOnce() {
|
|
92
|
+
this.cursor.metaFloor ??= this.cursor.lastProcessedAt;
|
|
93
|
+
const since = new Date(new Date(this.cursor.lastProcessedAt).getTime() - 1000).toISOString();
|
|
94
|
+
const notifications = await this.githubApi(() => this.octokit.paginate(this.octokit.rest.activity.listNotificationsForAuthenticatedUser, { since, per_page: 100 }), 'listNotifications');
|
|
95
|
+
notifications.sort((a, b) => a.updated_at.localeCompare(b.updated_at));
|
|
96
|
+
const maxUpdatedAt = notifications.length > 0
|
|
97
|
+
? notifications[notifications.length - 1].updated_at
|
|
98
|
+
: this.cursor.lastProcessedAt;
|
|
99
|
+
// Comment window lower bound: the cursor BEFORE this poll advances it.
|
|
100
|
+
// Comments with updated_at <= windowSince were already eligible for
|
|
101
|
+
// processing in a previous poll — skip them to prevent duplicates when
|
|
102
|
+
// PUT /notifications' async mark fails to mark the thread read.
|
|
103
|
+
const windowSince = this.cursor.lastProcessedAt;
|
|
104
|
+
await this.markNotificationsAsRead(maxUpdatedAt);
|
|
105
|
+
if (maxUpdatedAt > this.cursor.lastProcessedAt) {
|
|
106
|
+
this.cursor.lastProcessedAt = maxUpdatedAt;
|
|
107
|
+
}
|
|
108
|
+
for (const notification of notifications) {
|
|
109
|
+
if (!notification.subject.url)
|
|
110
|
+
continue;
|
|
111
|
+
const extracted = this.extractFromSubjectUrl(notification.subject.url);
|
|
112
|
+
if (!extracted) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const { chatId, threadId, issueNumber } = extracted;
|
|
116
|
+
const lastReadAt = notification.last_read_at;
|
|
117
|
+
const ctx = {
|
|
118
|
+
chatId,
|
|
119
|
+
threadId,
|
|
120
|
+
issueNumber,
|
|
121
|
+
lastReadAt,
|
|
122
|
+
windowSince,
|
|
123
|
+
metaFloor: this.cursor.metaFloor,
|
|
124
|
+
maxUpdatedAt,
|
|
125
|
+
subjectTitle: notification.subject.title || '',
|
|
126
|
+
reason: notification.reason,
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
switch (notification.reason) {
|
|
130
|
+
case 'mention':
|
|
131
|
+
await this.processCommentLane(ctx, true);
|
|
132
|
+
break;
|
|
133
|
+
case 'review_requested':
|
|
134
|
+
if (threadId.startsWith('pr:')) {
|
|
135
|
+
await this.processDirectLane(ctx, 'review_requested');
|
|
136
|
+
await this.processCommentLane(ctx, true);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
await this.processCommentLane(ctx, false);
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
case 'assign':
|
|
143
|
+
await this.processDirectLane(ctx, 'assign');
|
|
144
|
+
await this.processCommentLane(ctx, true);
|
|
145
|
+
break;
|
|
146
|
+
case 'author':
|
|
147
|
+
case 'comment':
|
|
148
|
+
await this.processAggregateLane(ctx);
|
|
149
|
+
break;
|
|
150
|
+
default:
|
|
151
|
+
await this.processCommentLane(ctx, false);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
process.stderr.write(`[Channel:${this.name}] API error processing ${threadId}, skipping: ${err}\n`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async processCommentLane(ctx, onlyMentioned, directed = false) {
|
|
161
|
+
const comments = await this.fetchNewComments(ctx);
|
|
162
|
+
let dispatched = false;
|
|
163
|
+
for (const comment of comments) {
|
|
164
|
+
const key = comment.node_id || String(comment.id);
|
|
165
|
+
if (this.cursor.dispatchedComments?.includes(key))
|
|
166
|
+
continue;
|
|
167
|
+
const body = comment.body || '';
|
|
168
|
+
const hasMention = this.botUsername
|
|
169
|
+
? testBotMention(body, this.botUsername)
|
|
170
|
+
: false;
|
|
171
|
+
if (onlyMentioned && !hasMention)
|
|
172
|
+
continue;
|
|
173
|
+
const senderId = (comment.user?.login || 'unknown').toLowerCase();
|
|
174
|
+
const allowed = this.gate.isAllowed(senderId);
|
|
175
|
+
const envelope = {
|
|
176
|
+
channelName: this.name,
|
|
177
|
+
senderId,
|
|
178
|
+
senderName: comment.user?.login || 'unknown',
|
|
179
|
+
chatId: ctx.chatId,
|
|
180
|
+
threadId: ctx.threadId,
|
|
181
|
+
messageId: String(comment.id),
|
|
182
|
+
text: this.botUsername ? stripBotMention(body, this.botUsername) : body,
|
|
183
|
+
isGroup: true,
|
|
184
|
+
isMentioned: hasMention || (directed && allowed),
|
|
185
|
+
isReplyToBot: false,
|
|
186
|
+
metadata: this.buildRouteMetadata(ctx),
|
|
187
|
+
};
|
|
188
|
+
if (!(await this.dispatchEnvelope(envelope, ctx.issueNumber))) {
|
|
189
|
+
dispatched = true;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (allowed) {
|
|
193
|
+
this.recordDispatchedComment(key);
|
|
194
|
+
if (hasMention)
|
|
195
|
+
dispatched = true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!dispatched && !ctx.lastReadAt) {
|
|
199
|
+
await this.tryFirstContactBody(ctx, onlyMentioned);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async processDirectLane(ctx, reason) {
|
|
203
|
+
const trigger = await this.findDirectTrigger(ctx, reason);
|
|
204
|
+
if (!trigger)
|
|
205
|
+
return;
|
|
206
|
+
const meta = reason === 'review_requested'
|
|
207
|
+
? await this.fetchPrMeta(ctx)
|
|
208
|
+
: await this.fetchIssueMeta(ctx);
|
|
209
|
+
const title = meta.title || ctx.subjectTitle;
|
|
210
|
+
const details = reason === 'review_requested'
|
|
211
|
+
? `Author: ${meta.user?.login || 'unknown'} | State: ${meta.state || 'unknown'} | Draft: ${meta.draft ? 'true' : 'false'} | Branch: ${meta.head?.ref || 'unknown'} → ${meta.base?.ref || 'unknown'}`
|
|
212
|
+
: `Author: ${meta.user?.login || 'unknown'} | State: ${meta.state || 'unknown'}`;
|
|
213
|
+
const envelope = {
|
|
214
|
+
channelName: this.name,
|
|
215
|
+
senderId: trigger.actor,
|
|
216
|
+
senderName: trigger.actor,
|
|
217
|
+
chatId: ctx.chatId,
|
|
218
|
+
threadId: ctx.threadId,
|
|
219
|
+
messageId: String(trigger.id),
|
|
220
|
+
text: reason === 'review_requested'
|
|
221
|
+
? 'Review this pull request and report any actionable findings.'
|
|
222
|
+
: 'Triage this issue and respond with the next action.',
|
|
223
|
+
isGroup: true,
|
|
224
|
+
isMentioned: true,
|
|
225
|
+
isReplyToBot: false,
|
|
226
|
+
metadata: `${this.buildMetadata(ctx.chatId, ctx.threadId, title)}\nTrigger: ${reason}.\n${details}`,
|
|
227
|
+
};
|
|
228
|
+
await this.dispatchEnvelope(envelope, ctx.issueNumber);
|
|
229
|
+
this.recordDispatched('dispatchedEvents', trigger.key);
|
|
230
|
+
}
|
|
231
|
+
async processAggregateLane(ctx) {
|
|
232
|
+
if (this.config.senderPolicy === 'pairing') {
|
|
233
|
+
await this.processCommentLane(ctx, false, true);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const allComments = (await this.fetchNewComments(ctx)).filter((comment) => {
|
|
237
|
+
const key = comment.node_id || String(comment.id);
|
|
238
|
+
const sender = (comment.user?.login || 'unknown').toLowerCase();
|
|
239
|
+
return (!this.cursor.dispatchedComments?.includes(key) &&
|
|
240
|
+
this.gate.isAllowed(sender));
|
|
241
|
+
});
|
|
242
|
+
const comments = allComments.slice(-MAX_AGGREGATE_COMMENTS);
|
|
243
|
+
if (comments.length === 0)
|
|
244
|
+
return;
|
|
245
|
+
for (const comment of allComments) {
|
|
246
|
+
this.recordDispatchedComment(comment.node_id || String(comment.id));
|
|
247
|
+
}
|
|
248
|
+
const first = comments[0];
|
|
249
|
+
const summary = comments
|
|
250
|
+
.map((comment) => `- @${comment.user?.login || 'unknown'}: ${(comment.body || '').trim().slice(0, MAX_AGGREGATE_COMMENT_CHARS)}`)
|
|
251
|
+
.join('\n');
|
|
252
|
+
const envelope = {
|
|
253
|
+
channelName: this.name,
|
|
254
|
+
senderId: (first.user?.login || 'unknown').toLowerCase(),
|
|
255
|
+
senderName: first.user?.login || 'unknown',
|
|
256
|
+
chatId: ctx.chatId,
|
|
257
|
+
threadId: ctx.threadId,
|
|
258
|
+
messageId: String(first.id),
|
|
259
|
+
text: `Review these new comments and respond if needed:\n${summary}`,
|
|
260
|
+
isGroup: true,
|
|
261
|
+
isMentioned: true,
|
|
262
|
+
isReplyToBot: false,
|
|
263
|
+
metadata: this.buildRouteMetadata(ctx),
|
|
264
|
+
};
|
|
265
|
+
await this.dispatchEnvelope(envelope, ctx.issueNumber);
|
|
266
|
+
}
|
|
267
|
+
async findDirectTrigger(ctx, reason) {
|
|
268
|
+
const [owner, repo] = ctx.chatId.split('/');
|
|
269
|
+
const events = (await this.githubApi(() => this.octokit.paginate(this.octokit.rest.issues.listEvents, {
|
|
270
|
+
owner,
|
|
271
|
+
repo,
|
|
272
|
+
issue_number: ctx.issueNumber,
|
|
273
|
+
per_page: 100,
|
|
274
|
+
}), `listEvents(${ctx.threadId})`));
|
|
275
|
+
events.sort((a, b) => (a.created_at || '').localeCompare(b.created_at || ''));
|
|
276
|
+
const bot = this.botUsername?.toLowerCase();
|
|
277
|
+
const event = events.findLast((candidate) => {
|
|
278
|
+
if (!candidate.created_at ||
|
|
279
|
+
candidate.created_at <= ctx.metaFloor ||
|
|
280
|
+
candidate.created_at > ctx.maxUpdatedAt) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return reason === 'assign'
|
|
284
|
+
? (candidate.event === 'assigned' ||
|
|
285
|
+
candidate.event === 'unassigned') &&
|
|
286
|
+
candidate.assignee?.login?.toLowerCase() === bot
|
|
287
|
+
: (candidate.event === 'review_requested' ||
|
|
288
|
+
candidate.event === 'review_request_removed') &&
|
|
289
|
+
candidate.requested_reviewer?.login?.toLowerCase() === bot;
|
|
290
|
+
});
|
|
291
|
+
if (!event ||
|
|
292
|
+
(reason === 'assign'
|
|
293
|
+
? event.event !== 'assigned'
|
|
294
|
+
: event.event !== 'review_requested')) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
const key = event.node_id || String(event.id);
|
|
298
|
+
if (this.cursor.dispatchedEvents?.includes(key))
|
|
299
|
+
return null;
|
|
300
|
+
const actor = reason === 'assign'
|
|
301
|
+
? event.assigner?.login || event.actor?.login
|
|
302
|
+
: event.review_requester?.login || event.actor?.login;
|
|
303
|
+
return actor ? { actor: actor.toLowerCase(), id: event.id, key } : null;
|
|
304
|
+
}
|
|
305
|
+
async fetchNewComments(ctx) {
|
|
306
|
+
const [owner, repo] = ctx.chatId.split('/');
|
|
307
|
+
const comments = (await this.githubApi(() => this.octokit.paginate(this.octokit.rest.issues.listComments, {
|
|
308
|
+
owner,
|
|
309
|
+
repo,
|
|
310
|
+
issue_number: ctx.issueNumber,
|
|
311
|
+
since: ctx.windowSince,
|
|
312
|
+
per_page: 100,
|
|
313
|
+
}), `listComments(${ctx.threadId})`));
|
|
314
|
+
comments.sort((a, b) => (a.created_at || '').localeCompare(b.created_at || ''));
|
|
315
|
+
return comments.filter((comment) => comment.user?.login !== this.botUsername &&
|
|
316
|
+
(!comment.created_at ||
|
|
317
|
+
(comment.created_at > ctx.windowSince &&
|
|
318
|
+
comment.created_at <= ctx.maxUpdatedAt)));
|
|
319
|
+
}
|
|
320
|
+
async fetchIssueMeta(ctx) {
|
|
321
|
+
const { data } = await this.githubApi(() => this.octokit.rest.issues.get({
|
|
322
|
+
owner: ctx.chatId.split('/')[0],
|
|
323
|
+
repo: ctx.chatId.split('/')[1],
|
|
324
|
+
issue_number: ctx.issueNumber,
|
|
325
|
+
}), `issues.get(${ctx.threadId})`);
|
|
326
|
+
return data;
|
|
327
|
+
}
|
|
328
|
+
async fetchPrMeta(ctx) {
|
|
329
|
+
const { data } = await this.githubApi(() => this.octokit.rest.pulls.get({
|
|
330
|
+
owner: ctx.chatId.split('/')[0],
|
|
331
|
+
repo: ctx.chatId.split('/')[1],
|
|
332
|
+
pull_number: ctx.issueNumber,
|
|
333
|
+
}), `pulls.get(${ctx.threadId})`);
|
|
334
|
+
return data;
|
|
335
|
+
}
|
|
336
|
+
async tryFirstContactBody(ctx, requireMention = false) {
|
|
337
|
+
// First contact is gated by `last_read_at` in the caller, but a thread can
|
|
338
|
+
// be re-fetched with `last_read_at` still null if marking it read failed
|
|
339
|
+
// (its updated_at was bumped past the cutoff). Dedup on an explicit record
|
|
340
|
+
// of which bodies we have already fed, so that re-fetch never feeds the body
|
|
341
|
+
// twice. Unlike a `created_at <= cursor` guard, this also feeds bodies whose
|
|
342
|
+
// notification arrived late — after the cursor had advanced past created_at.
|
|
343
|
+
const { chatId, threadId, issueNumber } = ctx;
|
|
344
|
+
const bodyKey = `${chatId}|${threadId}`;
|
|
345
|
+
if (this.cursor.dispatchedBodies?.includes(bodyKey))
|
|
346
|
+
return;
|
|
347
|
+
try {
|
|
348
|
+
const issue = await this.fetchIssueMeta(ctx);
|
|
349
|
+
const body = issue.body || '';
|
|
350
|
+
if (issue.user?.login === this.botUsername)
|
|
351
|
+
return;
|
|
352
|
+
const isMentioned = this.botUsername
|
|
353
|
+
? testBotMention(body, this.botUsername)
|
|
354
|
+
: false;
|
|
355
|
+
if (requireMention && !isMentioned)
|
|
356
|
+
return;
|
|
357
|
+
const text = this.botUsername
|
|
358
|
+
? stripBotMention(body, this.botUsername)
|
|
359
|
+
: body;
|
|
360
|
+
const envelope = {
|
|
361
|
+
channelName: this.name,
|
|
362
|
+
senderId: (issue.user?.login || 'unknown').toLowerCase(),
|
|
363
|
+
senderName: issue.user?.login || 'unknown',
|
|
364
|
+
chatId,
|
|
365
|
+
threadId,
|
|
366
|
+
messageId: `issue-body-${issueNumber}`,
|
|
367
|
+
text,
|
|
368
|
+
isGroup: true,
|
|
369
|
+
isMentioned,
|
|
370
|
+
isReplyToBot: false,
|
|
371
|
+
metadata: this.buildRouteMetadata(ctx),
|
|
372
|
+
};
|
|
373
|
+
await this.dispatchEnvelope(envelope, issueNumber);
|
|
374
|
+
this.recordDispatchedBody(bodyKey);
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
process.stderr.write(`[Channel:${this.name}] failed to fetch issue for first contact: ${err}\n`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
recordDispatchedBody(key) {
|
|
381
|
+
this.recordDispatched('dispatchedBodies', key);
|
|
382
|
+
}
|
|
383
|
+
recordDispatchedComment(key) {
|
|
384
|
+
this.recordDispatched('dispatchedComments', key);
|
|
385
|
+
}
|
|
386
|
+
recordDispatched(field, key) {
|
|
387
|
+
const list = this.cursor[field] ?? [];
|
|
388
|
+
if (!list.includes(key))
|
|
389
|
+
list.push(key);
|
|
390
|
+
this.cursor[field] = list.slice(-MAX_DISPATCHED);
|
|
391
|
+
}
|
|
392
|
+
async dispatchEnvelope(envelope, issueNumber) {
|
|
393
|
+
try {
|
|
394
|
+
await this.handleInbound(envelope);
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
process.stderr.write(`[Channel:${this.name}] handleInbound failed for ${envelope.messageId}: ${err}\n`);
|
|
399
|
+
await this.postErrorComment(envelope.chatId, issueNumber);
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
extractFromSubjectUrl(url) {
|
|
404
|
+
const match = url.match(/\/repos\/([^/]+\/[^/]+)\/(issues|pulls)\/(\d+)/);
|
|
405
|
+
if (!match)
|
|
406
|
+
return null;
|
|
407
|
+
const chatId = match[1];
|
|
408
|
+
const kind = match[2] === 'pulls' ? 'pr' : 'issue';
|
|
409
|
+
const issueNumber = Number(match[3]);
|
|
410
|
+
const threadId = `${kind}:${issueNumber}`;
|
|
411
|
+
return { chatId, threadId, issueNumber };
|
|
412
|
+
}
|
|
413
|
+
buildMetadata(chatId, threadId, title) {
|
|
414
|
+
const type = threadId.startsWith('pr:') ? 'Pull Request' : 'Issue';
|
|
415
|
+
const url = `${this.webOrigin}/${chatId}/${threadId.startsWith('pr:') ? 'pull' : 'issues'}/${threadId.split(':')[1]}`;
|
|
416
|
+
return `Type: ${type} | Title: ${title} | URL: ${url}`;
|
|
417
|
+
}
|
|
418
|
+
buildRouteMetadata(ctx) {
|
|
419
|
+
return `${this.buildMetadata(ctx.chatId, ctx.threadId, ctx.subjectTitle)}\nTrigger: ${ctx.reason}.`;
|
|
420
|
+
}
|
|
421
|
+
async githubApi(fn, label, retries = 3) {
|
|
422
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
423
|
+
try {
|
|
424
|
+
return await fn();
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
if (attempt === retries)
|
|
428
|
+
throw err;
|
|
429
|
+
// Octokit RequestError: { status, response?: { headers } }
|
|
430
|
+
const e = err;
|
|
431
|
+
const headers = e.response?.headers ?? {};
|
|
432
|
+
let cooldown;
|
|
433
|
+
if (headers['retry-after']) {
|
|
434
|
+
const retryAfter = Number(headers['retry-after']);
|
|
435
|
+
cooldown = Number.isFinite(retryAfter)
|
|
436
|
+
? retryAfter * 1000
|
|
437
|
+
: 1000 * 2 ** (attempt - 1);
|
|
438
|
+
}
|
|
439
|
+
else if ((e.status === 403 || e.status === 429) &&
|
|
440
|
+
Number(headers['x-ratelimit-remaining']) === 0 &&
|
|
441
|
+
Number(headers['x-ratelimit-reset']) > 0) {
|
|
442
|
+
cooldown =
|
|
443
|
+
Math.max(0, Number(headers['x-ratelimit-reset']) * 1000 - Date.now()) + 1000;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
cooldown = 1000 * 2 ** (attempt - 1);
|
|
447
|
+
}
|
|
448
|
+
process.stderr.write(`[Channel:${this.name}] ${label} failed (attempt ${attempt}/${retries}, status=${e.status}), retrying in ${cooldown}ms: ${e.message}\n`);
|
|
449
|
+
await this.abortableSleep(cooldown);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
throw new Error('unreachable');
|
|
453
|
+
}
|
|
454
|
+
async markNotificationsAsRead(lastReadAt) {
|
|
455
|
+
await this.githubApi(() => this.octokit.rest.activity.markNotificationsAsRead({
|
|
456
|
+
last_read_at: lastReadAt,
|
|
457
|
+
read: true,
|
|
458
|
+
}), 'markNotificationsAsRead');
|
|
459
|
+
}
|
|
460
|
+
async postErrorComment(chatId, issueNumber) {
|
|
461
|
+
try {
|
|
462
|
+
await this.githubApi(() => this.octokit.rest.issues.createComment({
|
|
463
|
+
owner: chatId.split('/')[0],
|
|
464
|
+
repo: chatId.split('/')[1],
|
|
465
|
+
issue_number: issueNumber,
|
|
466
|
+
body: '⚠️ Failed to process this request. Please re-mention the bot to retry.',
|
|
467
|
+
}), `postErrorComment(${chatId}#${issueNumber})`);
|
|
468
|
+
}
|
|
469
|
+
catch (err) {
|
|
470
|
+
process.stderr.write(`[Channel:${this.name}] postErrorComment also failed for ${chatId}#${issueNumber}, user must re-mention manually: ${err}\n`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
//# sourceMappingURL=GithubAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GithubAdapter.js","sourceRoot":"","sources":["../src/GithubAdapter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,eAAO,MAAM,MAAM,EAAE,aAQpB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GithubChannel } from './GithubAdapter.js';
|
|
2
|
+
export { GithubChannel };
|
|
3
|
+
export const plugin = {
|
|
4
|
+
channelType: 'github',
|
|
5
|
+
displayName: 'GitHub',
|
|
6
|
+
requiredConfigFields: ['token'],
|
|
7
|
+
envResolvableConfigFields: ['baseUrl'],
|
|
8
|
+
defaultSessionScope: 'chat_thread',
|
|
9
|
+
createChannel: (name, config, bridge, options) => new GithubChannel(name, config, bridge, options),
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,CAAC,MAAM,MAAM,GAAkB;IACnC,WAAW,EAAE,QAAQ;IACrB,WAAW,EAAE,QAAQ;IACrB,oBAAoB,EAAE,CAAC,OAAO,CAAC;IAC/B,yBAAyB,EAAE,CAAC,SAAS,CAAC;IACtC,mBAAmB,EAAE,aAAa;IAClC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAC/C,IAAI,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;CACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention.d.ts","sourceRoot":"","sources":["../src/mention.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAKD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMtE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE"}
|
package/dist/mention.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function escapeRegex(str) {
|
|
2
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3
|
+
}
|
|
4
|
+
const MENTION_LOOKBEHIND = '(?<=\\s|^|[([{<:;"\'])';
|
|
5
|
+
const MENTION_LOOKAHEAD = '(?=[^a-zA-Z0-9_/-]|$)';
|
|
6
|
+
export function testBotMention(text, username) {
|
|
7
|
+
const re = new RegExp(`${MENTION_LOOKBEHIND}@${escapeRegex(username)}${MENTION_LOOKAHEAD}`, 'i');
|
|
8
|
+
return re.test(text);
|
|
9
|
+
}
|
|
10
|
+
export function stripBotMention(text, username) {
|
|
11
|
+
const re = new RegExp(`${MENTION_LOOKBEHIND}@${escapeRegex(username)}${MENTION_LOOKAHEAD}`, 'gi');
|
|
12
|
+
return text.replace(re, '');
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=mention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention.js","sourceRoot":"","sources":["../src/mention.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AACpD,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAElD,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,QAAgB;IAC3D,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,GAAG,kBAAkB,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,iBAAiB,EAAE,EACpE,GAAG,CACJ,CAAC;IACF,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC5D,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,GAAG,kBAAkB,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,iBAAiB,EAAE,EACpE,IAAI,CACL,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qwen-code/channel-github",
|
|
3
|
+
"version": "0.21.0-nightly.20260729.0c0ca5fed",
|
|
4
|
+
"description": "GitHub polling channel adapter for Qwen Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc --build",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:ci": "vitest run"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@qwen-code/channel-base": "0.21.0-nightly.20260729.0c0ca5fed",
|
|
24
|
+
"@octokit/rest": "^21.1.1",
|
|
25
|
+
"https-proxy-agent": "^7.0.6"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^5.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|