@zhin.js/adapter-github 0.1.35 → 0.1.36
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/lib/adapter.d.ts +52 -9
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +254 -189
- package/lib/adapter.js.map +1 -1
- package/lib/bot.d.ts +5 -2
- package/lib/bot.d.ts.map +1 -1
- package/lib/bot.js +19 -26
- package/lib/bot.js.map +1 -1
- package/lib/{api.d.ts → gh-client.d.ts} +113 -42
- package/lib/gh-client.d.ts.map +1 -0
- package/lib/gh-client.js +555 -0
- package/lib/gh-client.js.map +1 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +212 -126
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +23 -29
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +2 -2
- package/lib/types.js.map +1 -1
- package/package.json +2 -2
- package/plugin.yml +1 -1
- package/skills/github/SKILL.md +17 -8
- package/src/adapter.ts +265 -188
- package/src/bot.ts +19 -25
- package/src/gh-client.ts +640 -0
- package/src/index.ts +219 -123
- package/src/types.ts +29 -34
- package/lib/api.d.ts.map +0 -1
- package/lib/api.js +0 -300
- package/lib/api.js.map +0 -1
- package/src/api.ts +0 -353
package/lib/index.js
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { usePlugin } from 'zhin.js';
|
|
5
5
|
import { GitHubAdapter } from './adapter.js';
|
|
6
|
+
import { GhClient } from './gh-client.js';
|
|
6
7
|
export * from './types.js';
|
|
7
8
|
export { GitHubBot, parseMarkdown, toMarkdown } from './bot.js';
|
|
8
9
|
export { GitHubAdapter } from './adapter.js';
|
|
10
|
+
export { GhClient } from './gh-client.js';
|
|
9
11
|
const plugin = usePlugin();
|
|
10
12
|
const { provide, defineModel, useContext, logger } = plugin;
|
|
11
13
|
defineModel('github_subscriptions', {
|
|
@@ -28,15 +30,12 @@ defineModel('github_oauth_users', {
|
|
|
28
30
|
platform: { type: 'text', nullable: false },
|
|
29
31
|
platform_uid: { type: 'text', nullable: false },
|
|
30
32
|
github_login: { type: 'text', nullable: false },
|
|
31
|
-
github_id: { type: 'integer', nullable: false },
|
|
32
33
|
access_token: { type: 'text', nullable: false },
|
|
33
|
-
|
|
34
|
-
created_at: { type: 'date', nullable: false },
|
|
35
|
-
updated_at: { type: 'date', nullable: false },
|
|
34
|
+
created_at: { type: 'integer', default: 0 },
|
|
36
35
|
});
|
|
37
36
|
provide({
|
|
38
37
|
name: 'github',
|
|
39
|
-
description: 'GitHub Adapter — Issues/PRs as chat channels, full repo management via
|
|
38
|
+
description: 'GitHub Adapter — Issues/PRs as chat channels, full repo management via gh CLI',
|
|
40
39
|
mounted: async (p) => {
|
|
41
40
|
const adapter = new GitHubAdapter(p);
|
|
42
41
|
await adapter.start();
|
|
@@ -46,9 +45,29 @@ provide({
|
|
|
46
45
|
await adapter.stop();
|
|
47
46
|
},
|
|
48
47
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
adapter.
|
|
48
|
+
// 混合模式:有 router + webhook_secret → Webhook 实时;否则 → 轮询降级
|
|
49
|
+
useContext('github', (adapter) => {
|
|
50
|
+
if (adapter.hasWebhookConfig) {
|
|
51
|
+
// 尝试注册 Webhook(需要 router Context)
|
|
52
|
+
const router = plugin.inject('router');
|
|
53
|
+
if (router) {
|
|
54
|
+
adapter.setupWebhook(router);
|
|
55
|
+
logger.info('GitHub 事件源: Webhook (实时)');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// router 还没就绪,等它挂载后再注册
|
|
59
|
+
plugin.useContext('router', (r) => {
|
|
60
|
+
adapter.setupWebhook(r);
|
|
61
|
+
logger.info('GitHub 事件源: Webhook (实时, 延迟注册)');
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Webhook 未配置或未激活时,总是启动轮询作为兜底
|
|
66
|
+
if (!adapter.webhookActive) {
|
|
67
|
+
adapter.startPolling();
|
|
68
|
+
logger.info('GitHub 事件源: 轮询');
|
|
69
|
+
}
|
|
70
|
+
return () => adapter.stopPolling();
|
|
52
71
|
});
|
|
53
72
|
// ── Tool 工具注册 ─────────────────────────────────────────────────────────
|
|
54
73
|
useContext('tool', 'github', (toolService, adapter) => {
|
|
@@ -75,8 +94,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
75
94
|
},
|
|
76
95
|
platforms: ['github'],
|
|
77
96
|
tags: ['github'],
|
|
78
|
-
execute: async (args) => {
|
|
79
|
-
const api = adapter.
|
|
97
|
+
execute: async (args, context) => {
|
|
98
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
80
99
|
if (!api)
|
|
81
100
|
return '❌ 没有可用的 GitHub bot';
|
|
82
101
|
const { action, repo, number: num, title, body, head, base, state, approve, method } = args;
|
|
@@ -163,8 +182,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
163
182
|
},
|
|
164
183
|
platforms: ['github'],
|
|
165
184
|
tags: ['github'],
|
|
166
|
-
execute: async (args) => {
|
|
167
|
-
const api = adapter.
|
|
185
|
+
execute: async (args, context) => {
|
|
186
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
168
187
|
if (!api)
|
|
169
188
|
return '❌ 没有可用的 GitHub bot';
|
|
170
189
|
const { action, repo, number: num, title, body, labels, state } = args;
|
|
@@ -236,8 +255,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
236
255
|
},
|
|
237
256
|
platforms: ['github'],
|
|
238
257
|
tags: ['github'],
|
|
239
|
-
execute: async (args) => {
|
|
240
|
-
const api = adapter.
|
|
258
|
+
execute: async (args, context) => {
|
|
259
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
241
260
|
if (!api)
|
|
242
261
|
return '❌ 没有可用的 GitHub bot';
|
|
243
262
|
const { action, repo, limit: lim } = args;
|
|
@@ -311,8 +330,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
311
330
|
},
|
|
312
331
|
platforms: ['github'],
|
|
313
332
|
tags: ['github'],
|
|
314
|
-
execute: async (args) => {
|
|
315
|
-
const api = adapter.
|
|
333
|
+
execute: async (args, context) => {
|
|
334
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
316
335
|
if (!api)
|
|
317
336
|
return '❌ 没有可用的 GitHub bot';
|
|
318
337
|
const { action, query: q, limit: lim } = args;
|
|
@@ -365,8 +384,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
365
384
|
},
|
|
366
385
|
platforms: ['github'],
|
|
367
386
|
tags: ['github'],
|
|
368
|
-
execute: async (args) => {
|
|
369
|
-
const api = adapter.
|
|
387
|
+
execute: async (args, context) => {
|
|
388
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
370
389
|
if (!api)
|
|
371
390
|
return '❌ 没有可用的 GitHub bot';
|
|
372
391
|
const { action, repo, number: num, labels } = args;
|
|
@@ -422,8 +441,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
422
441
|
},
|
|
423
442
|
platforms: ['github'],
|
|
424
443
|
tags: ['github'],
|
|
425
|
-
execute: async (args) => {
|
|
426
|
-
const api = adapter.
|
|
444
|
+
execute: async (args, context) => {
|
|
445
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
427
446
|
if (!api)
|
|
428
447
|
return '❌ 没有可用的 GitHub bot';
|
|
429
448
|
const { action, repo, number: num, assignees } = args;
|
|
@@ -453,8 +472,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
453
472
|
},
|
|
454
473
|
platforms: ['github'],
|
|
455
474
|
tags: ['github'],
|
|
456
|
-
execute: async (args) => {
|
|
457
|
-
const api = adapter.
|
|
475
|
+
execute: async (args, context) => {
|
|
476
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
458
477
|
if (!api)
|
|
459
478
|
return '❌ 没有可用的 GitHub bot';
|
|
460
479
|
const r = await api.getFileContent(args.repo, args.path, args.ref);
|
|
@@ -492,8 +511,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
492
511
|
},
|
|
493
512
|
platforms: ['github'],
|
|
494
513
|
tags: ['github'],
|
|
495
|
-
execute: async (args) => {
|
|
496
|
-
const api = adapter.
|
|
514
|
+
execute: async (args, context) => {
|
|
515
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
497
516
|
if (!api)
|
|
498
517
|
return '❌ 没有可用的 GitHub bot';
|
|
499
518
|
const { action, repo, sha, path, base, head, limit: lim } = args;
|
|
@@ -539,8 +558,8 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
539
558
|
},
|
|
540
559
|
platforms: ['github'],
|
|
541
560
|
tags: ['github'],
|
|
542
|
-
execute: async (args) => {
|
|
543
|
-
const api = adapter.
|
|
561
|
+
execute: async (args, context) => {
|
|
562
|
+
const api = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
544
563
|
if (!api)
|
|
545
564
|
return '❌ 没有可用的 GitHub bot';
|
|
546
565
|
const { type: itemType, repo, number: num, title, body, state } = args;
|
|
@@ -564,7 +583,7 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
564
583
|
// --- Star ---
|
|
565
584
|
{
|
|
566
585
|
name: 'github_star',
|
|
567
|
-
description: 'Star 或取消 Star 一个 GitHub
|
|
586
|
+
description: 'Star 或取消 Star 一个 GitHub 仓库(使用你绑定的 GitHub 账号,未绑定则用 Bot 默认账号)',
|
|
568
587
|
parameters: {
|
|
569
588
|
type: 'object',
|
|
570
589
|
properties: {
|
|
@@ -576,24 +595,22 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
576
595
|
platforms: ['github'],
|
|
577
596
|
tags: ['github'],
|
|
578
597
|
execute: async (args, context) => {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (!client)
|
|
583
|
-
return '❌ 你还没有绑定 GitHub 账号,请先使用 github_bind';
|
|
598
|
+
const gh = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
599
|
+
if (!gh)
|
|
600
|
+
return '❌ 没有可用的 GitHub bot';
|
|
584
601
|
const { action, repo } = args;
|
|
585
602
|
switch (action) {
|
|
586
603
|
case 'star': {
|
|
587
|
-
const r = await
|
|
588
|
-
return r.ok
|
|
604
|
+
const r = await gh.starRepo(repo);
|
|
605
|
+
return r.ok ? `⭐ 已 Star ${repo}` : `❌ ${r.data?.message || JSON.stringify(r.data)}`;
|
|
589
606
|
}
|
|
590
607
|
case 'unstar': {
|
|
591
|
-
const r = await
|
|
592
|
-
return r.ok
|
|
608
|
+
const r = await gh.unstarRepo(repo);
|
|
609
|
+
return r.ok ? `💔 已取消 Star ${repo}` : `❌ ${r.data?.message || JSON.stringify(r.data)}`;
|
|
593
610
|
}
|
|
594
611
|
case 'check': {
|
|
595
|
-
const starred = await
|
|
596
|
-
return starred ? `⭐
|
|
612
|
+
const starred = await gh.isStarred(repo);
|
|
613
|
+
return starred ? `⭐ 已 Star ${repo}` : `☆ 尚未 Star ${repo}`;
|
|
597
614
|
}
|
|
598
615
|
default: return `❌ 未知操作: ${action}`;
|
|
599
616
|
}
|
|
@@ -602,7 +619,7 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
602
619
|
// --- Fork ---
|
|
603
620
|
{
|
|
604
621
|
name: 'github_fork',
|
|
605
|
-
description: 'Fork 一个 GitHub
|
|
622
|
+
description: 'Fork 一个 GitHub 仓库(使用你绑定的 GitHub 账号,未绑定则用 Bot 默认账号)',
|
|
606
623
|
parameters: {
|
|
607
624
|
type: 'object',
|
|
608
625
|
properties: {
|
|
@@ -613,17 +630,166 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
613
630
|
platforms: ['github'],
|
|
614
631
|
tags: ['github'],
|
|
615
632
|
execute: async (args, context) => {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
return '❌ 你还没有绑定 GitHub 账号,请先使用 github_bind';
|
|
621
|
-
const r = await client.forkRepo(args.repo);
|
|
633
|
+
const gh = await adapter.getUserOrDefaultAPI(context?.platform, context?.senderId);
|
|
634
|
+
if (!gh)
|
|
635
|
+
return '❌ 没有可用的 GitHub bot';
|
|
636
|
+
const r = await gh.forkRepo(args.repo);
|
|
622
637
|
if (!r.ok)
|
|
623
638
|
return `❌ ${r.data?.message || JSON.stringify(r.data)}`;
|
|
624
639
|
return `🍴 已 Fork ${args.repo} → ${r.data.full_name}\n🔗 ${r.data.html_url}`;
|
|
625
640
|
},
|
|
626
641
|
},
|
|
642
|
+
// --- Bind (Device Flow) ---
|
|
643
|
+
{
|
|
644
|
+
name: 'github_bind',
|
|
645
|
+
description: '绑定你的 GitHub 账号 — 使用 Device Flow 授权,无需输入密码',
|
|
646
|
+
parameters: {
|
|
647
|
+
type: 'object',
|
|
648
|
+
properties: {},
|
|
649
|
+
},
|
|
650
|
+
tags: ['github'],
|
|
651
|
+
execute: async (_args, context) => {
|
|
652
|
+
if (!context?.platform || !context?.senderId) {
|
|
653
|
+
return '❌ 无法获取当前用户信息';
|
|
654
|
+
}
|
|
655
|
+
const clientId = adapter.getClientId();
|
|
656
|
+
if (!clientId)
|
|
657
|
+
return '❌ Bot 未配置 GitHub App 或 App 无 client_id,无法进行账号绑定';
|
|
658
|
+
const db = plugin.root?.inject('database');
|
|
659
|
+
const model = db?.models?.get('github_oauth_users');
|
|
660
|
+
if (!model)
|
|
661
|
+
return '❌ 数据库未就绪';
|
|
662
|
+
// 检查是否已绑定
|
|
663
|
+
const [existing] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
664
|
+
if (existing) {
|
|
665
|
+
return `⚠️ 你已绑定 GitHub 账号: ${existing.github_login}\n如需重新绑定,请先执行 github_unbind`;
|
|
666
|
+
}
|
|
667
|
+
try {
|
|
668
|
+
const host = adapter.getHost();
|
|
669
|
+
const codeResp = await GhClient.deviceFlowRequestCode(clientId, host);
|
|
670
|
+
// 异步轮询 token(最多等 codeResp.expires_in 秒)
|
|
671
|
+
const tokenPromise = GhClient.deviceFlowPollToken(clientId, codeResp.device_code, codeResp.interval, codeResp.expires_in, host);
|
|
672
|
+
// 先回复用户授权链接
|
|
673
|
+
const replyMsg = [
|
|
674
|
+
`🔗 请在浏览器中打开以下链接进行授权:`,
|
|
675
|
+
` ${codeResp.verification_uri}`,
|
|
676
|
+
``,
|
|
677
|
+
`📋 输入验证码: **${codeResp.user_code}**`,
|
|
678
|
+
``,
|
|
679
|
+
`⏳ 等待授权中…(${Math.floor(codeResp.expires_in / 60)} 分钟内有效)`,
|
|
680
|
+
].join('\n');
|
|
681
|
+
// 在后台等待用户授权完成
|
|
682
|
+
tokenPromise.then(async (tokenData) => {
|
|
683
|
+
if (!tokenData) {
|
|
684
|
+
// 授权超时或被拒绝 — 由于 execute 已经返回了,这里只能通过日志记录
|
|
685
|
+
logger.warn(`GitHub Device Flow 超时/拒绝: ${context.platform}:${context.senderId}`);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
// 使用 token 获取 GitHub 用户名
|
|
689
|
+
const userGh = new GhClient({ host, token: tokenData.access_token });
|
|
690
|
+
const authResult = await userGh.verifyAuth();
|
|
691
|
+
const login = authResult.ok ? authResult.user : 'unknown';
|
|
692
|
+
await model.insert({
|
|
693
|
+
id: Date.now(),
|
|
694
|
+
platform: context.platform,
|
|
695
|
+
platform_uid: context.senderId,
|
|
696
|
+
github_login: login,
|
|
697
|
+
access_token: tokenData.access_token,
|
|
698
|
+
created_at: Date.now(),
|
|
699
|
+
});
|
|
700
|
+
logger.info(`GitHub 账号绑定成功: ${context.platform}:${context.senderId} → ${login}`);
|
|
701
|
+
// 尝试回复绑定成功消息
|
|
702
|
+
if (context.message?.$reply) {
|
|
703
|
+
await context.message.$reply(`✅ GitHub 账号绑定成功!\n👤 ${login}`);
|
|
704
|
+
}
|
|
705
|
+
}).catch(err => {
|
|
706
|
+
logger.error('GitHub Device Flow 错误:', err);
|
|
707
|
+
});
|
|
708
|
+
return replyMsg;
|
|
709
|
+
}
|
|
710
|
+
catch (e) {
|
|
711
|
+
return `❌ Device Flow 启动失败: ${e.message}`;
|
|
712
|
+
}
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
// --- Unbind ---
|
|
716
|
+
{
|
|
717
|
+
name: 'github_unbind',
|
|
718
|
+
description: '解除你绑定的 GitHub 账号',
|
|
719
|
+
parameters: {
|
|
720
|
+
type: 'object',
|
|
721
|
+
properties: {},
|
|
722
|
+
},
|
|
723
|
+
tags: ['github'],
|
|
724
|
+
execute: async (_args, context) => {
|
|
725
|
+
if (!context?.platform || !context?.senderId) {
|
|
726
|
+
return '❌ 无法获取当前用户信息';
|
|
727
|
+
}
|
|
728
|
+
const db = plugin.root?.inject('database');
|
|
729
|
+
const model = db?.models?.get('github_oauth_users');
|
|
730
|
+
if (!model)
|
|
731
|
+
return '❌ 数据库未就绪';
|
|
732
|
+
const [existing] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
733
|
+
if (!existing)
|
|
734
|
+
return '📭 你尚未绑定 GitHub 账号';
|
|
735
|
+
await model.delete().where({ id: existing.id });
|
|
736
|
+
return `✅ 已解除 GitHub 账号绑定: ${existing.github_login}`;
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
// --- Whoami ---
|
|
740
|
+
{
|
|
741
|
+
name: 'github_whoami',
|
|
742
|
+
description: '查看你绑定的 GitHub 账号信息',
|
|
743
|
+
parameters: {
|
|
744
|
+
type: 'object',
|
|
745
|
+
properties: {},
|
|
746
|
+
},
|
|
747
|
+
tags: ['github'],
|
|
748
|
+
execute: async (_args, context) => {
|
|
749
|
+
if (!context?.platform || !context?.senderId) {
|
|
750
|
+
return '❌ 无法获取当前用户信息';
|
|
751
|
+
}
|
|
752
|
+
const db = plugin.root?.inject('database');
|
|
753
|
+
const model = db?.models?.get('github_oauth_users');
|
|
754
|
+
if (!model)
|
|
755
|
+
return '❌ 数据库未就绪';
|
|
756
|
+
const [existing] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
757
|
+
if (!existing)
|
|
758
|
+
return '📭 你尚未绑定 GitHub 账号\n🔗 使用 github_bind 绑定你的账号';
|
|
759
|
+
// 验证 token 是否仍然有效
|
|
760
|
+
const userGh = new GhClient({ host: adapter.getHost(), token: existing.access_token });
|
|
761
|
+
const auth = await userGh.verifyAuth();
|
|
762
|
+
if (auth.ok) {
|
|
763
|
+
return `👤 已绑定 GitHub 账号: ${auth.user}\n📅 绑定时间: ${new Date(existing.created_at).toLocaleString('zh-CN')}`;
|
|
764
|
+
}
|
|
765
|
+
return `⚠️ 已绑定账号 ${existing.github_login},但 Token 已失效\n🔗 请执行 github_unbind 后重新 github_bind`;
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
// --- Install App ---
|
|
769
|
+
{
|
|
770
|
+
name: 'github_install',
|
|
771
|
+
description: '获取安装 GitHub App 的链接 — 安装后 Bot 可以访问你的仓库,你也可以使用更多功能',
|
|
772
|
+
parameters: {
|
|
773
|
+
type: 'object',
|
|
774
|
+
properties: {},
|
|
775
|
+
},
|
|
776
|
+
tags: ['github'],
|
|
777
|
+
execute: async () => {
|
|
778
|
+
const slug = adapter.getAppSlug();
|
|
779
|
+
if (!slug)
|
|
780
|
+
return '❌ Bot 未配置 GitHub App';
|
|
781
|
+
const host = adapter.getHost() || 'github.com';
|
|
782
|
+
const installations = adapter.getInstallations();
|
|
783
|
+
let msg = `🔗 请点击以下链接安装 GitHub App 到你的仓库:\n https://${host}/apps/${slug}/installations/new`;
|
|
784
|
+
if (installations.length) {
|
|
785
|
+
msg += `\n\n📋 当前已安装 (${installations.length}):`;
|
|
786
|
+
for (const inst of installations) {
|
|
787
|
+
msg += `\n • ${inst.account.login} (${inst.account.type})`;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return msg;
|
|
791
|
+
},
|
|
792
|
+
},
|
|
627
793
|
// --- Subscribe ---
|
|
628
794
|
{
|
|
629
795
|
name: 'github_subscribe',
|
|
@@ -739,90 +905,10 @@ useContext('tool', 'github', (toolService, adapter) => {
|
|
|
739
905
|
}).join('\n\n');
|
|
740
906
|
},
|
|
741
907
|
},
|
|
742
|
-
// --- Bind ---
|
|
743
|
-
{
|
|
744
|
-
name: 'github_bind',
|
|
745
|
-
description: '绑定 GitHub 账号,生成 OAuth 授权链接',
|
|
746
|
-
parameters: {
|
|
747
|
-
type: 'object',
|
|
748
|
-
properties: {},
|
|
749
|
-
},
|
|
750
|
-
platforms: ['github'],
|
|
751
|
-
tags: ['github'],
|
|
752
|
-
execute: async (_args, context) => {
|
|
753
|
-
if (!context?.platform || !context?.senderId)
|
|
754
|
-
return '❌ 无法获取用户信息';
|
|
755
|
-
// 检查是否已绑定
|
|
756
|
-
const db = plugin.root?.inject('database');
|
|
757
|
-
const model = db?.models?.get('github_oauth_users');
|
|
758
|
-
if (model) {
|
|
759
|
-
const [existing] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
760
|
-
if (existing)
|
|
761
|
-
return `✅ 你已绑定 GitHub 账号: ${existing.github_login}\n如需重新绑定,请先使用 github_unbind 解绑`;
|
|
762
|
-
}
|
|
763
|
-
const url = adapter.createOAuthState(context.platform, context.senderId);
|
|
764
|
-
if (!url)
|
|
765
|
-
return '❌ GitHub App 未配置 OAuth (缺少 client_id)';
|
|
766
|
-
return `🔗 请点击以下链接绑定你的 GitHub 账号:\n${url}\n\n链接有效期 5 分钟`;
|
|
767
|
-
},
|
|
768
|
-
},
|
|
769
|
-
// --- Unbind ---
|
|
770
|
-
{
|
|
771
|
-
name: 'github_unbind',
|
|
772
|
-
description: '解绑 GitHub 账号',
|
|
773
|
-
parameters: {
|
|
774
|
-
type: 'object',
|
|
775
|
-
properties: {},
|
|
776
|
-
},
|
|
777
|
-
platforms: ['github'],
|
|
778
|
-
tags: ['github'],
|
|
779
|
-
execute: async (_args, context) => {
|
|
780
|
-
if (!context?.platform || !context?.senderId)
|
|
781
|
-
return '❌ 无法获取用户信息';
|
|
782
|
-
const db = plugin.root?.inject('database');
|
|
783
|
-
const model = db?.models?.get('github_oauth_users');
|
|
784
|
-
if (!model)
|
|
785
|
-
return '❌ 数据库未就绪';
|
|
786
|
-
const [existing] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
787
|
-
if (!existing)
|
|
788
|
-
return '📭 你还没有绑定 GitHub 账号';
|
|
789
|
-
await model.delete().where({ id: existing.id });
|
|
790
|
-
return `✅ 已解绑 GitHub 账号: ${existing.github_login}`;
|
|
791
|
-
},
|
|
792
|
-
},
|
|
793
|
-
// --- Whoami ---
|
|
794
|
-
{
|
|
795
|
-
name: 'github_whoami',
|
|
796
|
-
description: '查看当前绑定的 GitHub 账号信息',
|
|
797
|
-
parameters: {
|
|
798
|
-
type: 'object',
|
|
799
|
-
properties: {},
|
|
800
|
-
},
|
|
801
|
-
platforms: ['github'],
|
|
802
|
-
tags: ['github'],
|
|
803
|
-
execute: async (_args, context) => {
|
|
804
|
-
if (!context?.platform || !context?.senderId)
|
|
805
|
-
return '❌ 无法获取用户信息';
|
|
806
|
-
const db = plugin.root?.inject('database');
|
|
807
|
-
const model = db?.models?.get('github_oauth_users');
|
|
808
|
-
if (!model)
|
|
809
|
-
return '❌ 数据库未就绪';
|
|
810
|
-
const [row] = await model.select().where({ platform: context.platform, platform_uid: context.senderId });
|
|
811
|
-
if (!row)
|
|
812
|
-
return '📭 你还没有绑定 GitHub 账号,使用 github_bind 进行绑定';
|
|
813
|
-
return [
|
|
814
|
-
`🐙 GitHub 账号信息`,
|
|
815
|
-
`👤 用户名: ${row.github_login}`,
|
|
816
|
-
`🆔 GitHub ID: ${row.github_id}`,
|
|
817
|
-
`📅 绑定时间: ${row.created_at instanceof Date ? row.created_at.toLocaleDateString() : String(row.created_at).split('T')[0]}`,
|
|
818
|
-
`🔑 权限: ${row.scope || '(默认)'}`,
|
|
819
|
-
].join('\n');
|
|
820
|
-
},
|
|
821
|
-
},
|
|
822
908
|
];
|
|
823
909
|
const disposers = tools.map(t => toolService.addTool(t, plugin.name));
|
|
824
910
|
logger.debug(`GitHub 工具已注册: ${tools.map(t => t.name).join(', ')}`);
|
|
825
911
|
return () => disposers.forEach(d => d());
|
|
826
912
|
});
|
|
827
|
-
logger.debug('GitHub 适配器已加载 (
|
|
913
|
+
logger.debug('GitHub 适配器已加载 (gh CLI 认证)');
|
|
828
914
|
//# sourceMappingURL=index.js.map
|