@zhin.js/adapter-github 6.0.0 → 6.0.2

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 (47) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +18 -2
  3. package/adapters/github.js +0 -7
  4. package/adapters/github.ts +0 -7
  5. package/agent/prompt-sections/platform.ts +16 -0
  6. package/agent/tools/bind.ts +4 -3
  7. package/agent/tools/create_pr.ts +3 -2
  8. package/agent/tools/install.ts +4 -3
  9. package/agent/tools/patch_file.ts +3 -2
  10. package/agent/tools/prepare_workspace.ts +3 -2
  11. package/agent/tools/push_branch.ts +3 -2
  12. package/agent/tools/star.ts +3 -2
  13. package/agent/tools/subscribe.ts +3 -3
  14. package/agent/tools/subscriptions.ts +4 -4
  15. package/agent/tools/unbind.ts +4 -3
  16. package/agent/tools/unsubscribe.ts +3 -3
  17. package/agent/tools/whoami.ts +4 -3
  18. package/lib/client.d.ts +36 -0
  19. package/lib/client.js +47 -0
  20. package/lib/endpoint.d.ts +10 -24
  21. package/lib/endpoint.js +35 -65
  22. package/lib/github-bot-handlers.d.ts +5 -4
  23. package/lib/github-bot-handlers.js +12 -13
  24. package/lib/github-endpoint-commands.d.ts +1 -1
  25. package/lib/github-tool-handlers.d.ts +9 -8
  26. package/lib/github-tool-handlers.js +26 -33
  27. package/lib/index.d.ts +1 -1
  28. package/lib/index.js +1 -1
  29. package/lib/protocol.d.ts +1 -1
  30. package/lib/protocol.js +1 -1
  31. package/lib/webhook.d.ts +1 -0
  32. package/lib/webhook.js +1 -0
  33. package/package.json +19 -13
  34. package/plugin.js +0 -17
  35. package/src/client.ts +65 -0
  36. package/src/endpoint.ts +36 -75
  37. package/src/github-bot-handlers.ts +13 -9
  38. package/src/github-tool-handlers.ts +27 -32
  39. package/src/index.ts +1 -9
  40. package/src/protocol.ts +1 -1
  41. package/src/webhook.ts +5 -0
  42. package/lib/agent-prompt.d.ts +0 -2
  43. package/lib/agent-prompt.js +0 -84
  44. package/lib/github-agent-deps.d.ts +0 -47
  45. package/lib/github-agent-deps.js +0 -43
  46. package/src/agent-prompt.ts +0 -101
  47. package/src/github-agent-deps.ts +0 -82
package/lib/endpoint.js CHANGED
@@ -1,96 +1,55 @@
1
- /**
2
- * GithubEndpoint — lifecycle, outbound send, inbound admit.
3
- */
4
- import path from 'node:path';
1
+ import { Endpoint } from 'zhin.js/adapter';
5
2
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
6
3
  import { GhClient } from './gh-client.js';
7
- import { registerGithubAgentEndpoint } from './github-agent-deps.js';
8
- import { lookupGithubOauthAccessToken } from './oauth-users.js';
9
4
  import { enrichInboundContent, formatInboundContent, formatOutboundBody, githubInboundConversation, parseChannelId, } from './protocol.js';
10
5
  import { registerGithubWebhookRoutes } from './webhook.js';
11
- import { WorkspaceManager } from './workspace-manager.js';
6
+ import { GithubClient } from './client.js';
12
7
  /**
13
8
  * GitHub 是代码协作面(issue/PR),无好友/群/频道等 IM 社交概念,
14
9
  * 不适用 EndpointManagement 语义端口;本 endpoint 不暴露该端口。
15
10
  */
16
- export class GithubEndpoint {
11
+ export class GithubEndpoint extends Endpoint {
17
12
  #logger;
18
13
  #options;
19
- gh;
20
- config;
21
- name;
22
- #workspaceManager = null;
14
+ client;
23
15
  #routeReleases = [];
24
16
  #open = false;
25
17
  #started = false;
26
- #unregisterAgent;
27
18
  constructor(options) {
19
+ super();
28
20
  this.#logger = getAdapterLogger('github', options.config.id);
29
21
  this.#options = options;
30
- this.config = options.config;
31
- this.name = options.config.id;
32
- this.gh = options.createClient?.(options.config) ?? defaultCreateClient(options.config);
33
- }
34
- getAPI() {
35
- return this.gh;
36
- }
37
- async getUserOrDefaultAPI(platform, platformUid) {
38
- if (platform && platformUid) {
39
- const token = await lookupGithubOauthAccessToken(this.#options.database, platform, platformUid);
40
- if (token)
41
- return this.gh.withToken(token);
42
- }
43
- return this.gh;
44
- }
45
- getClientId() {
46
- return this.gh.clientId || null;
47
- }
48
- getHost() {
49
- return this.config.host;
50
- }
51
- getAppSlug() {
52
- return this.gh.appSlug || null;
22
+ const api = options.createClient?.(options.config) ?? defaultCreateClient(options.config);
23
+ this.client = new GithubClient(options.config.id, api, options.config, options.database);
53
24
  }
54
- getInstallations() {
55
- return this.gh.installations || [];
56
- }
57
- getWorkspaceManager() {
58
- if (this.#workspaceManager)
59
- return this.#workspaceManager;
60
- const workspaceRoot = this.config.workspaceRoot
61
- ?? path.join(process.cwd(), 'data', 'github-workspaces');
62
- this.#workspaceManager = new WorkspaceManager(this.gh, workspaceRoot);
63
- return this.#workspaceManager;
64
- }
65
- getDatabase() {
66
- return this.#options.database;
25
+ get config() {
26
+ return this.client.config;
67
27
  }
68
28
  async start() {
69
29
  if (this.#started)
70
30
  return;
71
31
  this.#started = true;
72
32
  try {
73
- const result = await this.gh.verifyAuth();
33
+ const result = await this.client.api.verifyAuth();
74
34
  if (!result.ok)
75
35
  throw new Error(`GitHub 认证失败: ${result.message}`);
76
- this.#unregisterAgent = registerGithubAgentEndpoint(this.name, this);
77
- if (this.config.webhookSecret) {
36
+ if (this.client.config.webhookSecret) {
78
37
  if (!this.#options.http) {
79
38
  throw new TypeError('GitHub webhook_secret requires httpHostToken');
80
39
  }
81
40
  this.#routeReleases.push(...registerGithubWebhookRoutes(this.#options.http, this));
82
41
  this.#logger.debug(formatCompact({
83
- endpoint: this.name,
42
+ endpoint: this.client.name,
84
43
  op: 'webhook',
85
- path: this.config.webhookPath,
44
+ path: this.client.config.webhookPath,
86
45
  }));
87
46
  }
88
47
  else {
89
48
  this.#logger.debug(formatCompact({
90
- endpoint: this.name,
49
+ endpoint: this.client.name,
91
50
  op: 'connect',
92
51
  mode: 'api-only',
93
- bot: this.gh.authenticatedUser,
52
+ bot: this.client.api.authenticatedUser,
94
53
  }));
95
54
  }
96
55
  }
@@ -110,8 +69,6 @@ export class GithubEndpoint {
110
69
  this.#open = false;
111
70
  for (const release of this.#routeReleases.splice(0))
112
71
  release();
113
- this.#unregisterAgent?.();
114
- this.#unregisterAgent = undefined;
115
72
  this.#started = false;
116
73
  this.#logger.debug(formatCompact({ op: 'disconnect' }));
117
74
  }
@@ -121,13 +78,13 @@ export class GithubEndpoint {
121
78
  throw new Error(`无效的 GitHub conversation ID: ${conversation.id}`);
122
79
  const text = formatOutboundBody(payload);
123
80
  const r = parsed.type === 'issue'
124
- ? await this.gh.createIssueComment(parsed.repo, parsed.number, text)
125
- : await this.gh.createPRComment(parsed.repo, parsed.number, text);
81
+ ? await this.client.api.createIssueComment(parsed.repo, parsed.number, text)
82
+ : await this.client.api.createPRComment(parsed.repo, parsed.number, text);
126
83
  if (!r.ok)
127
84
  throw new Error(`发送失败: ${JSON.stringify(r.data)}`);
128
85
  this.#logger.debug(formatCompact({
129
86
  op: 'github_send',
130
- endpoint: this.name,
87
+ endpoint: this.client.name,
131
88
  target: `${conversation.kind}:${conversation.id}`,
132
89
  messageId: r.data.id,
133
90
  }));
@@ -137,17 +94,19 @@ export class GithubEndpoint {
137
94
  admit(comment) {
138
95
  if (!this.#open)
139
96
  return;
140
- const botUser = this.config.botLogin || this.gh.getBotLogin() || this.gh.authenticatedUser;
97
+ const botUser = this.client.config.botLogin
98
+ || this.client.api.getBotLogin()
99
+ || this.client.api.authenticatedUser;
141
100
  if (botUser && comment.sender === botUser)
142
101
  return;
143
102
  const conversation = githubInboundConversation(String(this.#options.id), comment);
144
- const content = enrichInboundContent(formatInboundContent(comment.content), this.config, botUser ?? undefined, comment.repo);
145
- void this.#options.gateway.receive({
103
+ const content = enrichInboundContent(formatInboundContent(comment.content), this.client.config, botUser ?? undefined, comment.repo);
104
+ void this.emit('message.receive', {
146
105
  conversation,
147
106
  message: { conversation, id: comment.id },
148
107
  content,
149
108
  sender: { id: comment.sender, name: comment.sender },
150
- endpointId: this.name,
109
+ endpointId: this.client.name,
151
110
  metadata: Object.freeze({
152
111
  repo: comment.repo,
153
112
  kind: comment.kind,
@@ -161,6 +120,17 @@ export class GithubEndpoint {
161
120
  }));
162
121
  });
163
122
  }
123
+ admitPlatform(name, event) {
124
+ if (!this.#open)
125
+ return;
126
+ void this.emitPlatform(name, event).catch((error) => {
127
+ this.#logger.warn(formatCompact({
128
+ op: 'github_platform_event_failed',
129
+ event: name,
130
+ error: error instanceof Error ? error.message : String(error),
131
+ }));
132
+ });
133
+ }
164
134
  }
165
135
  export function defaultCreateClient(config) {
166
136
  const appAuth = config.appId && config.privateKey
@@ -2,25 +2,26 @@
2
2
  * GitHub App Bot workflow handlers (Installation Token identity).
3
3
  */
4
4
  import type { Message } from 'zhin.js';
5
+ import type { GithubClient } from './client.js';
5
6
  export declare function executeGithubPrepareWorkspace(args: {
6
7
  repo?: string;
7
- }, commMessage?: Message): Promise<string>;
8
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
8
9
  export declare function executeGithubPatchFile(args: {
9
10
  repo?: string;
10
11
  path: string;
11
12
  content: string;
12
13
  message: string;
13
14
  branch?: string;
14
- }, commMessage?: Message): Promise<string>;
15
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
15
16
  export declare function executeGithubPushBranch(args: {
16
17
  repo?: string;
17
18
  branch?: string;
18
19
  message: string;
19
- }, commMessage?: Message): Promise<string>;
20
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
20
21
  export declare function executeGithubCreatePr(args: {
21
22
  repo?: string;
22
23
  title: string;
23
24
  body?: string;
24
25
  head?: string;
25
26
  base?: string;
26
- }, commMessage?: Message): Promise<string>;
27
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
@@ -1,8 +1,7 @@
1
1
  import { getCurrentCommMessage } from '@zhin.js/agent/security';
2
- import { getAdapter, getGithubAgentDeps } from './github-agent-deps.js';
3
2
  import { parseMessageChannel, resolveWorkspaceBranch, formatChannelContext, } from './github-channel-context.js';
4
- function requireBotGh() {
5
- const gh = getAdapter().getAPI();
3
+ function requireBotGh(client) {
4
+ const gh = client.api;
6
5
  if (!gh?.isAppAuth) {
7
6
  throw new Error('需要 GitHub App 认证(app_id + private_key),Bot 写操作不可用');
8
7
  }
@@ -23,11 +22,11 @@ function resolveChannel(msg, repo) {
23
22
  }
24
23
  throw new Error('无法解析 GitHub 频道(需要 Issue/PR 评论上下文)');
25
24
  }
26
- export async function executeGithubPrepareWorkspace(args, commMessage) {
25
+ export async function executeGithubPrepareWorkspace(args, client, commMessage) {
27
26
  const msg = resolveCommMessage(commMessage);
28
27
  const ctx = resolveChannel(msg, args.repo);
29
- const gh = requireBotGh();
30
- const wm = getGithubAgentDeps().getWorkspaceManager();
28
+ const gh = requireBotGh(client);
29
+ const wm = client.workspaceManager;
31
30
  const { branch, base } = await resolveWorkspaceBranch(gh, ctx);
32
31
  const repoPath = await wm.checkoutBranch(ctx.repo, branch, base);
33
32
  return [
@@ -37,10 +36,10 @@ export async function executeGithubPrepareWorkspace(args, commMessage) {
37
36
  `📍 ${formatChannelContext(ctx)}`,
38
37
  ].join('\n');
39
38
  }
40
- export async function executeGithubPatchFile(args, commMessage) {
39
+ export async function executeGithubPatchFile(args, client, commMessage) {
41
40
  const msg = resolveCommMessage(commMessage);
42
41
  const ctx = resolveChannel(msg, args.repo);
43
- const gh = requireBotGh();
42
+ const gh = requireBotGh(client);
44
43
  const { branch } = args.branch
45
44
  ? { branch: args.branch }
46
45
  : await resolveWorkspaceBranch(gh, ctx);
@@ -53,19 +52,19 @@ export async function executeGithubPatchFile(args, commMessage) {
53
52
  const url = r.data.content?.html_url ?? r.data.commit?.html_url ?? '';
54
53
  return `✅ 已更新 \`${args.path}\` @ \`${branch}\`${url ? `\n🔗 ${url}` : ''}`;
55
54
  }
56
- export async function executeGithubPushBranch(args, commMessage) {
55
+ export async function executeGithubPushBranch(args, client, commMessage) {
57
56
  const msg = resolveCommMessage(commMessage);
58
57
  const ctx = resolveChannel(msg, args.repo);
59
- const gh = requireBotGh();
60
- const wm = getGithubAgentDeps().getWorkspaceManager();
58
+ const gh = requireBotGh(client);
59
+ const wm = client.workspaceManager;
61
60
  const branch = args.branch ?? (await resolveWorkspaceBranch(gh, ctx)).branch;
62
61
  const result = await wm.commitAndPush(ctx.repo, branch, args.message);
63
62
  return `✅ ${result}\n📍 ${ctx.repo} @ \`${branch}\``;
64
63
  }
65
- export async function executeGithubCreatePr(args, commMessage) {
64
+ export async function executeGithubCreatePr(args, client, commMessage) {
66
65
  const msg = resolveCommMessage(commMessage);
67
66
  const ctx = resolveChannel(msg, args.repo);
68
- const gh = requireBotGh();
67
+ const gh = requireBotGh(client);
69
68
  const resolved = await resolveWorkspaceBranch(gh, ctx);
70
69
  const head = args.head ?? resolved.branch;
71
70
  const base = args.base ?? resolved.base;
@@ -1 +1 @@
1
- export declare const githubEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
1
+ export declare const githubEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
@@ -1,17 +1,18 @@
1
1
  import type { Message } from 'zhin.js';
2
+ import type { GithubClient } from './client.js';
2
3
  export declare function executeGithubStar(args: {
3
4
  action: 'star' | 'unstar' | 'check';
4
5
  repo: string;
5
- }, commMessage?: Message): Promise<string>;
6
- export declare function executeGithubBind(_args: Record<string, never>, commMessage?: Message): Promise<string>;
7
- export declare function executeGithubUnbind(_args: Record<string, never>, commMessage?: Message): Promise<string>;
8
- export declare function executeGithubWhoami(_args: Record<string, never>, commMessage?: Message): Promise<string>;
9
- export declare function executeGithubInstall(): Promise<string>;
6
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
7
+ export declare function executeGithubBind(_args: Record<string, never>, client: GithubClient, commMessage?: Message): Promise<string>;
8
+ export declare function executeGithubUnbind(_args: Record<string, never>, client: GithubClient, commMessage?: Message): Promise<string>;
9
+ export declare function executeGithubWhoami(_args: Record<string, never>, client: GithubClient, commMessage?: Message): Promise<string>;
10
+ export declare function executeGithubInstall(client: GithubClient): Promise<string>;
10
11
  export declare function executeGithubSubscribe(args: {
11
12
  repo: string;
12
13
  events?: string;
13
- }, commMessage?: Message): Promise<string>;
14
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
14
15
  export declare function executeGithubUnsubscribe(args: {
15
16
  repo: string;
16
- }, commMessage?: Message): Promise<string>;
17
- export declare function executeGithubSubscriptions(_args: Record<string, never>, commMessage?: Message): Promise<string>;
17
+ }, client: GithubClient, commMessage?: Message): Promise<string>;
18
+ export declare function executeGithubSubscriptions(_args: Record<string, never>, client: GithubClient, commMessage?: Message): Promise<string>;
@@ -1,28 +1,24 @@
1
1
  import { formatCompact } from '@zhin.js/logger';
2
2
  import { getCurrentCommMessage } from '@zhin.js/agent/security';
3
3
  import { GhClient } from './gh-client.js';
4
- import { getAdapter, getGithubAgentDeps } from './github-agent-deps.js';
5
- function oauthModel() {
6
- const db = getGithubAgentDeps().getDatabase?.();
4
+ function oauthModel(client) {
5
+ const db = client.database;
7
6
  return db?.models?.get('github_oauth_users');
8
7
  }
9
- function subscriptionsModel() {
10
- const db = getGithubAgentDeps().getDatabase?.();
8
+ function subscriptionsModel(client) {
9
+ const db = client.database;
11
10
  return db?.models?.get('github_subscriptions');
12
11
  }
13
12
  function depsLogger() {
14
- return getGithubAgentDeps().logger ?? {
13
+ return {
15
14
  debug: (...args) => console.debug(...args),
16
15
  warn: (...args) => console.warn(...args),
17
16
  error: (...args) => console.error(...args),
18
17
  };
19
18
  }
20
- export async function executeGithubStar(args, commMessage) {
21
- const adapter = getAdapter();
19
+ export async function executeGithubStar(args, client, commMessage) {
22
20
  const msg = commMessage ?? getCurrentCommMessage();
23
- const gh = await adapter.getUserOrDefaultAPI(msg?.$adapter, msg?.$sender.id);
24
- if (!gh)
25
- return '❌ 没有可用的 GitHub bot';
21
+ const gh = await client.getUserOrDefaultApi(msg?.$adapter, msg?.$sender.id);
26
22
  switch (args.action) {
27
23
  case 'star': {
28
24
  const r = await gh.starRepo(args.repo);
@@ -40,16 +36,15 @@ export async function executeGithubStar(args, commMessage) {
40
36
  return `❌ 未知操作: ${args.action}`;
41
37
  }
42
38
  }
43
- export async function executeGithubBind(_args, commMessage) {
44
- const adapter = getAdapter();
39
+ export async function executeGithubBind(_args, client, commMessage) {
45
40
  const log = depsLogger();
46
41
  const msg = commMessage ?? getCurrentCommMessage();
47
42
  if (!msg?.$adapter || !msg?.$sender?.id)
48
43
  return '❌ 无法获取当前用户信息';
49
- const clientId = adapter.getClientId();
44
+ const clientId = client.clientId;
50
45
  if (!clientId)
51
46
  return '❌ Endpoint 未配置 GitHub App 或 App 无 client_id,无法进行账号绑定';
52
- const model = oauthModel();
47
+ const model = oauthModel(client);
53
48
  if (!model)
54
49
  return '❌ 数据库未就绪';
55
50
  const [existing] = await model.select().where({ platform: msg.$adapter, platform_uid: msg.$sender.id });
@@ -57,7 +52,7 @@ export async function executeGithubBind(_args, commMessage) {
57
52
  return `⚠️ 你已绑定 GitHub 账号: ${existing.github_login}\n如需重新绑定,请先执行 github_unbind`;
58
53
  }
59
54
  try {
60
- const host = adapter.getHost();
55
+ const host = client.host;
61
56
  const codeResp = await GhClient.deviceFlowRequestCode(clientId, host);
62
57
  const tokenPromise = GhClient.deviceFlowPollToken(clientId, codeResp.device_code, codeResp.interval, codeResp.expires_in, host);
63
58
  const replyMsg = [
@@ -97,11 +92,11 @@ export async function executeGithubBind(_args, commMessage) {
97
92
  return `❌ Device Flow 启动失败: ${e instanceof Error ? e.message : String(e)}`;
98
93
  }
99
94
  }
100
- export async function executeGithubUnbind(_args, commMessage) {
95
+ export async function executeGithubUnbind(_args, client, commMessage) {
101
96
  const msg = commMessage ?? getCurrentCommMessage();
102
97
  if (!msg?.$adapter || !msg?.$sender?.id)
103
98
  return '❌ 无法获取当前用户信息';
104
- const model = oauthModel();
99
+ const model = oauthModel(client);
105
100
  if (!model)
106
101
  return '❌ 数据库未就绪';
107
102
  const [existing] = await model.select().where({ platform: msg.$adapter, platform_uid: msg.$sender.id });
@@ -110,31 +105,29 @@ export async function executeGithubUnbind(_args, commMessage) {
110
105
  await model.delete().where({ id: existing.id });
111
106
  return `✅ 已解除 GitHub 账号绑定: ${existing.github_login}`;
112
107
  }
113
- export async function executeGithubWhoami(_args, commMessage) {
114
- const adapter = getAdapter();
108
+ export async function executeGithubWhoami(_args, client, commMessage) {
115
109
  const msg = commMessage ?? getCurrentCommMessage();
116
110
  if (!msg?.$adapter || !msg?.$sender?.id)
117
111
  return '❌ 无法获取当前用户信息';
118
- const model = oauthModel();
112
+ const model = oauthModel(client);
119
113
  if (!model)
120
114
  return '❌ 数据库未就绪';
121
115
  const [existing] = await model.select().where({ platform: msg.$adapter, platform_uid: msg.$sender.id });
122
116
  if (!existing)
123
117
  return '📭 你尚未绑定 GitHub 账号\n🔗 使用 github_bind 绑定你的账号';
124
- const userGh = new GhClient({ host: adapter.getHost(), token: existing.access_token });
118
+ const userGh = new GhClient({ host: client.host, token: existing.access_token });
125
119
  const auth = await userGh.verifyAuth();
126
120
  if (auth.ok) {
127
121
  return `👤 已绑定 GitHub 账号: ${auth.user}\n📅 绑定时间: ${new Date(existing.created_at).toLocaleString('zh-CN')}`;
128
122
  }
129
123
  return `⚠️ 已绑定账号 ${existing.github_login},但 Token 已失效\n🔗 请执行 github_unbind 后重新 github_bind`;
130
124
  }
131
- export async function executeGithubInstall() {
132
- const adapter = getAdapter();
133
- const slug = adapter.getAppSlug();
125
+ export async function executeGithubInstall(client) {
126
+ const slug = client.appSlug;
134
127
  if (!slug)
135
128
  return '❌ Endpoint 未配置 GitHub App';
136
- const host = adapter.getHost() || 'github.com';
137
- const installations = adapter.getInstallations();
129
+ const host = client.host || 'github.com';
130
+ const installations = client.installations;
138
131
  let msg = `🔗 请点击以下链接安装 GitHub App 到你的仓库:\n https://${host}/apps/${slug}/installations/new`;
139
132
  if (installations.length) {
140
133
  msg += `\n\n📋 当前已安装 (${installations.length}):`;
@@ -144,12 +137,12 @@ export async function executeGithubInstall() {
144
137
  }
145
138
  return msg;
146
139
  }
147
- export async function executeGithubSubscribe(args, commMessage) {
140
+ export async function executeGithubSubscribe(args, client, commMessage) {
148
141
  const msg = commMessage ?? getCurrentCommMessage();
149
142
  if (!msg?.$adapter || !msg?.$sender.id || !msg?.$channel?.id || !msg?.$endpoint) {
150
143
  return '❌ 无法获取当前聊天通道信息';
151
144
  }
152
- const model = subscriptionsModel();
145
+ const model = subscriptionsModel(client);
153
146
  if (!model)
154
147
  return '❌ 数据库未就绪';
155
148
  const validEvents = ['push', 'issue', 'star', 'fork', 'unstar', 'pull_request'];
@@ -179,12 +172,12 @@ export async function executeGithubSubscribe(args, commMessage) {
179
172
  });
180
173
  return `✅ 已订阅 ${args.repo}\n📡 事件: ${events.join(', ')}\n📌 通知将推送到当前通道`;
181
174
  }
182
- export async function executeGithubUnsubscribe(args, commMessage) {
175
+ export async function executeGithubUnsubscribe(args, client, commMessage) {
183
176
  const msg = commMessage ?? getCurrentCommMessage();
184
177
  if (!msg?.$adapter || !msg?.$channel?.id || !msg?.$endpoint) {
185
178
  return '❌ 无法获取当前聊天通道信息';
186
179
  }
187
- const model = subscriptionsModel();
180
+ const model = subscriptionsModel(client);
188
181
  if (!model)
189
182
  return '❌ 数据库未就绪';
190
183
  const [existing] = await model.select().where({
@@ -198,12 +191,12 @@ export async function executeGithubUnsubscribe(args, commMessage) {
198
191
  await model.delete().where({ id: existing.id });
199
192
  return `✅ 已取消订阅 ${args.repo}`;
200
193
  }
201
- export async function executeGithubSubscriptions(_args, commMessage) {
194
+ export async function executeGithubSubscriptions(_args, client, commMessage) {
202
195
  const msg = commMessage ?? getCurrentCommMessage();
203
196
  if (!msg?.$adapter || !msg?.$channel?.id || !msg?.$endpoint) {
204
197
  return '❌ 无法获取当前聊天通道信息';
205
198
  }
206
- const model = subscriptionsModel();
199
+ const model = subscriptionsModel(client);
207
200
  if (!model)
208
201
  return '❌ 数据库未就绪';
209
202
  const subs = await model.select().where({
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { buildChannelId, enrichInboundContent, formatInboundContent, formatNotification, formatOutboundBody, normalizeWebhookPath, parseChannelId, parseIssueCommentInbound, parsePrReviewCommentInbound, parsePrReviewInbound, resolveGithubConfig, shouldAutoReplyRepo, verifyWebhookSignature, type GithubAdapterConfig, type GithubInboundComment, type GithubWireSegment, type ResolvedGithubConfig, } from './protocol.js';
2
2
  export * from './types.js';
3
- export { getAdapter, getGithubAgentDeps, registerGithubAgentEndpoint, setGithubAgentDeps, type GithubAgentDeps, type GithubAgentEndpoint, } from './github-agent-deps.js';
4
3
  export { GhClient } from './gh-client.js';
4
+ export { GithubClient, githubClient, type GithubClientEventMap } from './client.js';
5
5
  export { WorkspaceManager } from './workspace-manager.js';
6
6
  export { parseMessageChannel, issueBranchName, resolveWorkspaceBranch, formatChannelContext, } from './github-channel-context.js';
7
7
  export { GithubEndpoint, defaultCreateClient, type GithubEndpointOptions, } from './endpoint.js';
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { buildChannelId, enrichInboundContent, formatInboundContent, formatNotification, formatOutboundBody, normalizeWebhookPath, parseChannelId, parseIssueCommentInbound, parsePrReviewCommentInbound, parsePrReviewInbound, resolveGithubConfig, shouldAutoReplyRepo, verifyWebhookSignature, } from './protocol.js';
2
2
  export * from './types.js';
3
- export { getAdapter, getGithubAgentDeps, registerGithubAgentEndpoint, setGithubAgentDeps, } from './github-agent-deps.js';
4
3
  export { GhClient } from './gh-client.js';
4
+ export { GithubClient, githubClient } from './client.js';
5
5
  export { WorkspaceManager } from './workspace-manager.js';
6
6
  export { parseMessageChannel, issueBranchName, resolveWorkspaceBranch, formatChannelContext, } from './github-channel-context.js';
7
7
  export { GithubEndpoint, defaultCreateClient, } from './endpoint.js';
package/lib/protocol.d.ts CHANGED
@@ -77,7 +77,7 @@ export declare function normalizeWebhookPath(path: string): string;
77
77
  export declare function shouldAutoReplyRepo(config: Pick<ResolvedGithubConfig, 'autoReplyRepos'>, repo: string): boolean;
78
78
  /** Prepend synthetic @bot for auto_reply repos (gateway text path). */
79
79
  export declare function enrichInboundContent(content: string, config: Pick<ResolvedGithubConfig, 'autoReplyRepos' | 'botLogin'>, botLogin: string | undefined, repo: string): string;
80
- /** Build inbound text for MessageGateway.receive from markdown/comment body. */
80
+ /** Build inbound text for OutboundMessageService.receive from markdown/comment body. */
81
81
  export declare function formatInboundContent(body: string): string;
82
82
  /** Build markdown body for Issue/PR comment send. */
83
83
  export declare function formatOutboundBody(payload: unknown): string;
package/lib/protocol.js CHANGED
@@ -83,7 +83,7 @@ export function enrichInboundContent(content, config, botLogin, repo) {
83
83
  return content;
84
84
  return `@${login} ${content}`;
85
85
  }
86
- /** Build inbound text for MessageGateway.receive from markdown/comment body. */
86
+ /** Build inbound text for OutboundMessageService.receive from markdown/comment body. */
87
87
  export function formatInboundContent(body) {
88
88
  return body;
89
89
  }
package/lib/webhook.d.ts CHANGED
@@ -6,6 +6,7 @@ import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
6
6
  import { type GithubInboundComment, type ResolvedGithubConfig } from './protocol.js';
7
7
  export interface GithubWebhookHandler {
8
8
  readonly config: ResolvedGithubConfig;
9
+ admitPlatform(name: string, event: unknown): void;
9
10
  admit(comment: GithubInboundComment): void;
10
11
  }
11
12
  export declare function registerGithubWebhookRoutes(http: HttpHost, handler: GithubWebhookHandler): HttpRouteRegistration[];
package/lib/webhook.js CHANGED
@@ -66,6 +66,7 @@ export async function dispatchGithubWebhookPayload(event, payload, handler) {
66
66
  const body = payload;
67
67
  const repo = body.repository?.full_name;
68
68
  logger.debug(`Webhook: ${event}${body.action ? `.${body.action}` : ''} ${repo || ''}`);
69
+ handler.admitPlatform(typeof body.action === 'string' && body.action ? `${event}.${body.action}` : event, payload);
69
70
  if (event === 'issue_comment') {
70
71
  const inbound = parseIssueCommentInbound(payload);
71
72
  if (inbound)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-github",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Zhin.js GitHub adapter for Plugin Runtime (App auth + webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -41,20 +41,22 @@
41
41
  "directory": "plugins/adapters/github"
42
42
  },
43
43
  "dependencies": {
44
- "@zhin.js/adapter": "1.2.0",
45
- "@zhin.js/core": "1.5.13",
46
- "@zhin.js/host-http": "1.0.12",
44
+ "@zhin.js/adapter": "1.2.1",
45
+ "@zhin.js/core": "1.5.14",
46
+ "@zhin.js/feature-kit": "1.0.13",
47
+ "@zhin.js/host-http": "1.0.13",
47
48
  "@zhin.js/im-contract": "1.0.4",
48
- "@zhin.js/logger": "1.0.76"
49
+ "@zhin.js/logger": "1.0.77"
49
50
  },
50
51
  "peerDependencies": {
51
52
  "zod": "^4.0.0",
52
- "@zhin.js/adapter": "1.2.0",
53
- "@zhin.js/agent": "1.1.15",
54
- "@zhin.js/command": "1.0.15",
55
- "@zhin.js/core": "1.5.13",
56
- "@zhin.js/host-http": "1.0.12",
57
- "zhin.js": "6.0.13"
53
+ "@zhin.js/adapter": "1.2.1",
54
+ "@zhin.js/agent": "1.1.17",
55
+ "@zhin.js/command": "1.0.16",
56
+ "@zhin.js/core": "1.5.14",
57
+ "@zhin.js/host-http": "1.0.13",
58
+ "@zhin.js/prompt-section": "0.0.1",
59
+ "zhin.js": "6.0.14"
58
60
  },
59
61
  "peerDependenciesMeta": {
60
62
  "@zhin.js/agent": {
@@ -63,6 +65,9 @@
63
65
  "@zhin.js/command": {
64
66
  "optional": true
65
67
  },
68
+ "@zhin.js/prompt-section": {
69
+ "optional": true
70
+ },
66
71
  "zhin.js": {
67
72
  "optional": true
68
73
  },
@@ -75,8 +80,9 @@
75
80
  "typescript": "^6.0.3",
76
81
  "vitest": "^4.1.10",
77
82
  "zod": "^4.4.3",
78
- "@zhin.js/agent": "1.1.15",
79
- "zhin.js": "6.0.13"
83
+ "@zhin.js/agent": "1.1.17",
84
+ "@zhin.js/prompt-section": "0.0.1",
85
+ "zhin.js": "6.0.14"
80
86
  },
81
87
  "files": [
82
88
  "adapters",
package/plugin.js CHANGED
@@ -34,22 +34,5 @@ export default definePlugin({
34
34
  defineGithubOauthUsersTable(host);
35
35
  host.define('github_subscriptions', { ...GITHUB_SUBSCRIPTIONS_SCHEMA });
36
36
  }
37
- // Agent prompt contributor (orchestrator/deferred-worker GitHub guidance).
38
- // `zhin.js/agent` is an optional peer — skip silently on IM-only installs.
39
- let cancelled = false;
40
- let unregister;
41
- void Promise.all([
42
- import('zhin.js/agent'),
43
- import("./lib/agent-prompt.js"),
44
- ]).then(([agent, prompt]) => {
45
- if (cancelled)
46
- return;
47
- agent.registerAgentPromptContributor(prompt.createGithubAgentPromptContributor());
48
- unregister = () => agent.unregisterAgentPromptContributor('github');
49
- }).catch(() => { });
50
- return () => {
51
- cancelled = true;
52
- unregister?.();
53
- };
54
37
  },
55
38
  });