@zhin.js/adapter-github 5.0.2 → 5.0.3
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/CHANGELOG.md +16 -0
- package/README.md +2 -2
- package/lib/endpoint.d.ts +2 -5
- package/lib/endpoint.js +9 -9
- package/lib/protocol.d.ts +7 -0
- package/lib/protocol.js +13 -0
- package/package.json +15 -14
- package/src/endpoint.ts +10 -9
- package/src/protocol.ts +18 -0
- /package/commands/endpoint/add/{[name:string].js → [name].js} +0 -0
- /package/commands/endpoint/add/{[name:string].ts → [name].ts} +0 -0
- /package/commands/endpoint/remove/{[name:string].js → [name].js} +0 -0
- /package/commands/endpoint/remove/{[name:string].ts → [name].ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @zhin.js/adapter-github
|
|
2
2
|
|
|
3
|
+
## 5.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [afc0e66]
|
|
8
|
+
- Updated dependencies [2e41ad5]
|
|
9
|
+
- Updated dependencies [9f57124]
|
|
10
|
+
- @zhin.js/core@1.5.2
|
|
11
|
+
- @zhin.js/adapter@1.1.5
|
|
12
|
+
- @zhin.js/im-contract@1.0.1
|
|
13
|
+
- @zhin.js/plugin-runtime@1.1.3
|
|
14
|
+
- @zhin.js/command@1.0.7
|
|
15
|
+
- @zhin.js/host-http@1.0.6
|
|
16
|
+
- @zhin.js/agent@1.1.3
|
|
17
|
+
- zhin.js@6.0.2
|
|
18
|
+
|
|
3
19
|
## 5.0.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ GitHub Plugin Runtime 适配器 — Issue/PR 评论区即聊天通道,GitHub A
|
|
|
6
6
|
|
|
7
7
|
- **聊天通道**:Issue/PR 评论区映射为群聊,支持收发消息
|
|
8
8
|
- **Webhook 入站**:HMAC-SHA256 验签 → `messageGatewayToken`
|
|
9
|
-
- **出站**:`send({
|
|
9
|
+
- **出站**:`send({ conversation, payload })` → Issue/PR comment(`conversation.id` 为 channel ID)
|
|
10
10
|
- **GitHub App 认证**:JWT → Installation Token
|
|
11
11
|
- **Agent 工具**:`agent/` 下 star/bind/subscribe/workspace 等保留
|
|
12
12
|
|
|
@@ -85,7 +85,7 @@ plugins:
|
|
|
85
85
|
| `src/gh-client.ts` | GitHub API 客户端 |
|
|
86
86
|
|
|
87
87
|
- 入站:`httpHostToken` POST → `messageGatewayToken.receive`
|
|
88
|
-
- 出站:`send({
|
|
88
|
+
- 出站:`send({ conversation, payload })`
|
|
89
89
|
|
|
90
90
|
## License
|
|
91
91
|
|
package/lib/endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId, DatabaseHost } from '@zhin.js/plugin-runtime';
|
|
@@ -42,10 +42,7 @@ export declare class GithubEndpoint implements EndpointInstance {
|
|
|
42
42
|
open(): void;
|
|
43
43
|
close(): void;
|
|
44
44
|
stop(): Promise<void>;
|
|
45
|
-
send({
|
|
46
|
-
readonly target: string;
|
|
47
|
-
readonly payload: unknown;
|
|
48
|
-
}): Promise<string>;
|
|
45
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
49
46
|
/** Test / internal: admit a parsed comment when open. */
|
|
50
47
|
admit(comment: GithubInboundComment): void;
|
|
51
48
|
}
|
package/lib/endpoint.js
CHANGED
|
@@ -6,7 +6,7 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
6
6
|
import { GhClient } from './gh-client.js';
|
|
7
7
|
import { registerGithubAgentEndpoint } from './github-agent-deps.js';
|
|
8
8
|
import { lookupGithubOauthAccessToken } from './oauth-users.js';
|
|
9
|
-
import { enrichInboundContent, formatInboundContent, formatOutboundBody, parseChannelId, } from './protocol.js';
|
|
9
|
+
import { enrichInboundContent, formatInboundContent, formatOutboundBody, githubInboundConversation, parseChannelId, } from './protocol.js';
|
|
10
10
|
import { registerGithubWebhookRoutes } from './webhook.js';
|
|
11
11
|
import { WorkspaceManager } from './workspace-manager.js';
|
|
12
12
|
const logger = getLogger('github');
|
|
@@ -114,10 +114,10 @@ export class GithubEndpoint {
|
|
|
114
114
|
this.#started = false;
|
|
115
115
|
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.name }));
|
|
116
116
|
}
|
|
117
|
-
async send({
|
|
118
|
-
const parsed = parseChannelId(
|
|
117
|
+
async send({ conversation, payload }) {
|
|
118
|
+
const parsed = parseChannelId(conversation.id);
|
|
119
119
|
if (!parsed)
|
|
120
|
-
throw new Error(`无效的 GitHub
|
|
120
|
+
throw new Error(`无效的 GitHub conversation ID: ${conversation.id}`);
|
|
121
121
|
const text = formatOutboundBody(payload);
|
|
122
122
|
const r = parsed.type === 'issue'
|
|
123
123
|
? await this.gh.createIssueComment(parsed.repo, parsed.number, text)
|
|
@@ -127,7 +127,7 @@ export class GithubEndpoint {
|
|
|
127
127
|
logger.debug(formatCompact({
|
|
128
128
|
op: 'github_send',
|
|
129
129
|
endpoint: this.name,
|
|
130
|
-
target
|
|
130
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
131
131
|
messageId: r.data.id,
|
|
132
132
|
}));
|
|
133
133
|
return String(r.data.id);
|
|
@@ -139,13 +139,13 @@ export class GithubEndpoint {
|
|
|
139
139
|
const botUser = this.config.botLogin || this.gh.getBotLogin() || this.gh.authenticatedUser;
|
|
140
140
|
if (botUser && comment.sender === botUser)
|
|
141
141
|
return;
|
|
142
|
+
const conversation = githubInboundConversation(String(this.#options.id), comment);
|
|
142
143
|
const content = enrichInboundContent(formatInboundContent(comment.content), this.config, botUser ?? undefined, comment.repo);
|
|
143
144
|
void this.#options.gateway.receive({
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
conversation,
|
|
146
|
+
message: { conversation, id: comment.id },
|
|
146
147
|
content,
|
|
147
148
|
sender: comment.sender,
|
|
148
|
-
id: comment.id,
|
|
149
149
|
metadata: Object.freeze({
|
|
150
150
|
endpoint: this.name,
|
|
151
151
|
repo: comment.repo,
|
|
@@ -155,7 +155,7 @@ export class GithubEndpoint {
|
|
|
155
155
|
}).catch((err) => {
|
|
156
156
|
logger.warn(formatCompact({
|
|
157
157
|
op: 'github_gateway_receive_failed',
|
|
158
|
-
target:
|
|
158
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
159
159
|
error: err instanceof Error ? err.message : String(err),
|
|
160
160
|
}));
|
|
161
161
|
});
|
package/lib/protocol.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
4
4
|
*/
|
|
5
5
|
import type { IncomingMessage } from 'node:http';
|
|
6
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
6
7
|
import { type GenericWebhookPayload, type IssueCommentPayload, type PRReviewCommentPayload, type PRReviewPayload } from './types.js';
|
|
7
8
|
export type { EventType, GenericWebhookPayload, GitHubComment, GitHubEndpointConfig, GitHubIssue, GitHubOAuthUser, GitHubPR, GitHubRepo, GitHubUser, IssueCommentPayload, ParsedChannel, PRReviewCommentPayload, PRReviewPayload, Subscription, } from './types.js';
|
|
8
9
|
export { buildChannelId, parseChannelId } from './types.js';
|
|
@@ -65,6 +66,12 @@ export interface GithubInboundComment {
|
|
|
65
66
|
readonly kind: 'issue_comment' | 'pr_review_comment' | 'pr_review';
|
|
66
67
|
readonly createdAt: number;
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* 入站归一化 → ConversationRef:Issue/PR 评论区即仓库容器内的 channel 会话,
|
|
71
|
+
* 仓库(owner/repo)进 `parent`。出站侧用 `parseChannelId(conversation.id)`
|
|
72
|
+
* 在平台边界还原 repo/type/number。
|
|
73
|
+
*/
|
|
74
|
+
export declare function githubInboundConversation(endpointId: string, comment: GithubInboundComment): ConversationRef;
|
|
68
75
|
export declare function resolveGithubConfig(config?: GithubAdapterConfig): ResolvedGithubConfig;
|
|
69
76
|
export declare function normalizeWebhookPath(path: string): string;
|
|
70
77
|
export declare function shouldAutoReplyRepo(config: Pick<ResolvedGithubConfig, 'autoReplyRepos'>, repo: string): boolean;
|
package/lib/protocol.js
CHANGED
|
@@ -9,6 +9,19 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
9
9
|
const logger = getLogger('github');
|
|
10
10
|
import { buildChannelId, } from './types.js';
|
|
11
11
|
export { buildChannelId, parseChannelId } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* 入站归一化 → ConversationRef:Issue/PR 评论区即仓库容器内的 channel 会话,
|
|
14
|
+
* 仓库(owner/repo)进 `parent`。出站侧用 `parseChannelId(conversation.id)`
|
|
15
|
+
* 在平台边界还原 repo/type/number。
|
|
16
|
+
*/
|
|
17
|
+
export function githubInboundConversation(endpointId, comment) {
|
|
18
|
+
return {
|
|
19
|
+
endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
|
|
20
|
+
kind: 'channel',
|
|
21
|
+
id: comment.channelId,
|
|
22
|
+
parent: { kind: 'channel', id: comment.repo },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
12
25
|
export function resolveGithubConfig(config = {}) {
|
|
13
26
|
const entry = config.endpoints?.find((item) => item.context === 'github');
|
|
14
27
|
const appIdRaw = pickCredential(config.appId != null ? String(config.appId) : undefined, config.app_id != null ? String(config.app_id) : undefined, entry?.appId != null ? String(entry.appId) : undefined, entry?.app_id != null ? String(entry.app_id) : undefined, process.env.GITHUB_APP_ID);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-github",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
4
4
|
"description": "Zhin.js GitHub adapter for Plugin Runtime (App auth + webhook)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -41,21 +41,22 @@
|
|
|
41
41
|
"directory": "plugins/adapters/github"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@zhin.js/adapter": "1.1.
|
|
45
|
-
"@zhin.js/command": "1.0.
|
|
46
|
-
"@zhin.js/core": "1.5.
|
|
47
|
-
"@zhin.js/host-http": "1.0.
|
|
44
|
+
"@zhin.js/adapter": "1.1.5",
|
|
45
|
+
"@zhin.js/command": "1.0.7",
|
|
46
|
+
"@zhin.js/core": "1.5.2",
|
|
47
|
+
"@zhin.js/host-http": "1.0.6",
|
|
48
|
+
"@zhin.js/im-contract": "1.0.1",
|
|
48
49
|
"@zhin.js/logger": "1.0.75",
|
|
49
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
50
|
+
"@zhin.js/plugin-runtime": "1.1.3"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
53
|
"zod": "^4.0.0",
|
|
53
|
-
"@zhin.js/adapter": "1.1.
|
|
54
|
-
"@zhin.js/agent": "1.1.
|
|
55
|
-
"@zhin.js/core": "1.5.
|
|
56
|
-
"@zhin.js/host-http": "1.0.
|
|
57
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
58
|
-
"zhin.js": "6.0.
|
|
54
|
+
"@zhin.js/adapter": "1.1.5",
|
|
55
|
+
"@zhin.js/agent": "1.1.3",
|
|
56
|
+
"@zhin.js/core": "1.5.2",
|
|
57
|
+
"@zhin.js/host-http": "1.0.6",
|
|
58
|
+
"@zhin.js/plugin-runtime": "1.1.3",
|
|
59
|
+
"zhin.js": "6.0.2"
|
|
59
60
|
},
|
|
60
61
|
"peerDependenciesMeta": {
|
|
61
62
|
"zhin.js": {
|
|
@@ -73,8 +74,8 @@
|
|
|
73
74
|
"typescript": "^6.0.3",
|
|
74
75
|
"vitest": "^4.1.10",
|
|
75
76
|
"zod": "^4.4.3",
|
|
76
|
-
"@zhin.js/agent": "1.1.
|
|
77
|
-
"zhin.js": "6.0.
|
|
77
|
+
"@zhin.js/agent": "1.1.3",
|
|
78
|
+
"zhin.js": "6.0.2"
|
|
78
79
|
},
|
|
79
80
|
"files": [
|
|
80
81
|
"adapters",
|
package/src/endpoint.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* GithubEndpoint — lifecycle, outbound send, inbound admit.
|
|
3
3
|
*/
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import type { EndpointInstance } from '@zhin.js/adapter';
|
|
5
|
+
import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
|
|
6
6
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
7
7
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
8
8
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
enrichInboundContent,
|
|
15
15
|
formatInboundContent,
|
|
16
16
|
formatOutboundBody,
|
|
17
|
+
githubInboundConversation,
|
|
17
18
|
parseChannelId,
|
|
18
19
|
type GithubInboundComment,
|
|
19
20
|
type ResolvedGithubConfig,
|
|
@@ -147,9 +148,9 @@ export class GithubEndpoint implements EndpointInstance {
|
|
|
147
148
|
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.name }));
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
async send({
|
|
151
|
-
const parsed = parseChannelId(
|
|
152
|
-
if (!parsed) throw new Error(`无效的 GitHub
|
|
151
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
152
|
+
const parsed = parseChannelId(conversation.id);
|
|
153
|
+
if (!parsed) throw new Error(`无效的 GitHub conversation ID: ${conversation.id}`);
|
|
153
154
|
const text = formatOutboundBody(payload);
|
|
154
155
|
const r = parsed.type === 'issue'
|
|
155
156
|
? await this.gh.createIssueComment(parsed.repo, parsed.number, text)
|
|
@@ -158,7 +159,7 @@ export class GithubEndpoint implements EndpointInstance {
|
|
|
158
159
|
logger.debug(formatCompact({
|
|
159
160
|
op: 'github_send',
|
|
160
161
|
endpoint: this.name,
|
|
161
|
-
target
|
|
162
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
162
163
|
messageId: r.data.id,
|
|
163
164
|
}));
|
|
164
165
|
return String(r.data.id);
|
|
@@ -169,6 +170,7 @@ export class GithubEndpoint implements EndpointInstance {
|
|
|
169
170
|
if (!this.#open) return;
|
|
170
171
|
const botUser = this.config.botLogin || this.gh.getBotLogin() || this.gh.authenticatedUser;
|
|
171
172
|
if (botUser && comment.sender === botUser) return;
|
|
173
|
+
const conversation = githubInboundConversation(String(this.#options.id), comment);
|
|
172
174
|
const content = enrichInboundContent(
|
|
173
175
|
formatInboundContent(comment.content),
|
|
174
176
|
this.config,
|
|
@@ -176,11 +178,10 @@ export class GithubEndpoint implements EndpointInstance {
|
|
|
176
178
|
comment.repo,
|
|
177
179
|
);
|
|
178
180
|
void this.#options.gateway.receive({
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
conversation,
|
|
182
|
+
message: { conversation, id: comment.id },
|
|
181
183
|
content,
|
|
182
184
|
sender: comment.sender,
|
|
183
|
-
id: comment.id,
|
|
184
185
|
metadata: Object.freeze({
|
|
185
186
|
endpoint: this.name,
|
|
186
187
|
repo: comment.repo,
|
|
@@ -190,7 +191,7 @@ export class GithubEndpoint implements EndpointInstance {
|
|
|
190
191
|
}).catch((err) => {
|
|
191
192
|
logger.warn(formatCompact({
|
|
192
193
|
op: 'github_gateway_receive_failed',
|
|
193
|
-
target:
|
|
194
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
194
195
|
error: err instanceof Error ? err.message : String(err),
|
|
195
196
|
}));
|
|
196
197
|
});
|
package/src/protocol.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
|
7
7
|
import type { IncomingMessage } from 'node:http';
|
|
8
8
|
import { pickCredential } from '@zhin.js/adapter';
|
|
9
9
|
import { isMediaRef } from '@zhin.js/core';
|
|
10
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
10
11
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
11
12
|
|
|
12
13
|
const logger = getLogger('github');
|
|
@@ -100,6 +101,23 @@ export interface GithubInboundComment {
|
|
|
100
101
|
readonly createdAt: number;
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
/**
|
|
105
|
+
* 入站归一化 → ConversationRef:Issue/PR 评论区即仓库容器内的 channel 会话,
|
|
106
|
+
* 仓库(owner/repo)进 `parent`。出站侧用 `parseChannelId(conversation.id)`
|
|
107
|
+
* 在平台边界还原 repo/type/number。
|
|
108
|
+
*/
|
|
109
|
+
export function githubInboundConversation(
|
|
110
|
+
endpointId: string,
|
|
111
|
+
comment: GithubInboundComment,
|
|
112
|
+
): ConversationRef {
|
|
113
|
+
return {
|
|
114
|
+
endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
|
|
115
|
+
kind: 'channel',
|
|
116
|
+
id: comment.channelId,
|
|
117
|
+
parent: { kind: 'channel', id: comment.repo },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
103
121
|
export function resolveGithubConfig(config: GithubAdapterConfig = {}): ResolvedGithubConfig {
|
|
104
122
|
const entry = config.endpoints?.find((item) => item.context === 'github');
|
|
105
123
|
const appIdRaw = pickCredential(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|