koishi-plugin-githubsth 1.0.5-alpha.3 → 1.0.5

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.
@@ -3,26 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.apply = apply;
4
4
  function apply(ctx) {
5
5
  const logger = ctx.logger('githubsth');
6
- // Allow . in repo name (e.g. koishi.js) but disallow / inside parts.
7
- // owner: [\w-]+ (alphanumeric, underscore, dash)
8
- // repo: [\w-\.]+ (alphanumeric, underscore, dash, dot)
9
- const repoRegex = /^[\w-]+\/[\w-\.]+$/;
10
- ctx.command('githubsth.trust', '管理信任仓库', { authority: 3 })
11
- .alias('gh.trust');
6
+ const repoRegex = /^[\w-]+\/[\w-.]+$/;
7
+ ctx.command('githubsth.trust', '管理信任仓库', { authority: 3 }).alias('gh.trust');
12
8
  ctx.command('githubsth.trust.add <repo>', '添加信任仓库')
13
9
  .action(async ({ session }, repo) => {
14
10
  if (!repo)
15
- return '请指定仓库名称 (owner/repo)。';
16
- if (!repoRegex.test(repo)) {
17
- return '仓库名称格式不正确 (应为 owner/repo)。';
18
- }
11
+ return '请指定仓库名称(owner/repo)。';
12
+ if (!repoRegex.test(repo))
13
+ return '仓库名称格式不正确(应为 owner/repo)。';
19
14
  try {
20
15
  logger.debug(`Adding trusted repo: ${repo}`);
21
- // Check existence first to avoid UNIQUE constraint error log from driver
22
16
  const existing = await ctx.database.get('github_trusted_repo', { repo });
23
- if (existing.length > 0) {
17
+ if (existing.length > 0)
24
18
  return '该仓库已在信任列表中。';
25
- }
26
19
  await ctx.database.create('github_trusted_repo', {
27
20
  repo,
28
21
  enabled: true,
@@ -33,16 +26,15 @@ function apply(ctx) {
33
26
  }
34
27
  catch (e) {
35
28
  logger.warn('Failed to add trusted repo:', e);
36
- if (e.code === 'SQLITE_CONSTRAINT') {
29
+ if (e.code === 'SQLITE_CONSTRAINT')
37
30
  return '该仓库已在信任列表中。';
38
- }
39
31
  return `添加失败: ${e.message}`;
40
32
  }
41
33
  });
42
34
  ctx.command('githubsth.trust.remove <repo>', '移除信任仓库')
43
- .action(async ({ session }, repo) => {
35
+ .action(async (_, repo) => {
44
36
  if (!repo)
45
- return '请指定仓库名称 (owner/repo)。';
37
+ return '请指定仓库名称(owner/repo)。';
46
38
  const result = await ctx.database.remove('github_trusted_repo', { repo });
47
39
  if (result.matched === 0)
48
40
  return '未找到该信任仓库。';
@@ -53,17 +45,17 @@ function apply(ctx) {
53
45
  const repos = await ctx.database.get('github_trusted_repo', {});
54
46
  if (repos.length === 0)
55
47
  return '暂无信任仓库。';
56
- return repos.map(r => `${r.repo} [${r.enabled ? '启用' : '禁用'}]`).join('\n');
48
+ return repos.map((r) => `${r.repo} [${r.enabled ? '启用' : '禁用'}]`).join('\n');
57
49
  });
58
50
  ctx.command('githubsth.trust.enable <repo>', '启用信任仓库')
59
- .action(async ({ session }, repo) => {
51
+ .action(async (_, repo) => {
60
52
  const result = await ctx.database.set('github_trusted_repo', { repo }, { enabled: true });
61
53
  if (result.matched === 0)
62
54
  return '未找到该信任仓库。';
63
55
  return `已启用信任仓库: ${repo}`;
64
56
  });
65
57
  ctx.command('githubsth.trust.disable <repo>', '禁用信任仓库')
66
- .action(async ({ session }, repo) => {
58
+ .action(async (_, repo) => {
67
59
  const result = await ctx.database.set('github_trusted_repo', { repo }, { enabled: false });
68
60
  if (result.matched === 0)
69
61
  return '未找到该信任仓库。';
@@ -4,89 +4,93 @@ exports.apply = apply;
4
4
  const modes = ['text', 'image', 'auto'];
5
5
  const events = ['push', 'issues', 'issue_comment', 'pull_request', 'pull_request_review', 'star', 'fork', 'release', 'discussion', 'workflow_run', 'digest'];
6
6
  function apply(ctx, config) {
7
- ctx.command('githubsth.render', 'Render settings', { authority: 3 }).alias('gh.render');
8
- ctx.command('githubsth.render.status', 'Show render status', { authority: 3 })
9
- .action(async () => {
7
+ ctx.command('githubsth.render', '渲染设置', { authority: 3 }).alias('gh.render');
8
+ ctx.command('githubsth.render.status', '查看渲染状态', { authority: 3 })
9
+ .action(async ({ session }) => {
10
10
  const status = ctx.githubsthNotifier.getRenderStatus();
11
- return [
12
- `mode: ${status.mode} (configured: ${status.configuredMode})`,
13
- `fallback: ${status.fallback}`,
14
- `theme(default): ${status.theme}`,
15
- `style(default): ${status.style}`,
16
- `width: ${status.width}`,
17
- `timeout: ${status.timeoutMs}ms`,
18
- `digest: ${status.digestEnabled ? 'on' : 'off'} (${status.digestWindowSec}s, max ${status.digestMaxItems})`,
19
- `puppeteer: ${status.hasPuppeteer ? 'ready' : 'missing'}`,
20
- ].join('\n');
11
+ return session?.text('commands.githubsth.render.messages.status_text', [
12
+ status.mode,
13
+ status.configuredMode,
14
+ status.fallback,
15
+ status.theme,
16
+ status.style,
17
+ status.width,
18
+ status.timeoutMs,
19
+ status.digestEnabled ? 'on' : 'off',
20
+ status.digestWindowSec,
21
+ status.digestMaxItems,
22
+ status.hasPuppeteer ? 'ready' : 'missing',
23
+ ]);
21
24
  });
22
- ctx.command('githubsth.render.mode <mode:string>', 'Set render mode', { authority: 3 })
23
- .action(async (_, mode) => {
24
- if (!mode || !modes.includes(mode))
25
- return `Invalid mode. Allowed: ${modes.join(', ')}`;
25
+ ctx.command('githubsth.render.mode <mode:string>', '设置渲染模式', { authority: 3 })
26
+ .action(async ({ session }, mode) => {
27
+ if (!mode || !modes.includes(mode)) {
28
+ return session?.text('commands.githubsth.render.messages.invalid_mode', [modes.join(', ')]);
29
+ }
26
30
  ctx.githubsthNotifier.setRenderMode(mode);
27
- return `Runtime render mode set to ${mode} (config default is ${config.renderMode}).`;
31
+ return session?.text('commands.githubsth.render.messages.mode_set', [mode, config.renderMode]);
28
32
  });
29
- ctx.command('githubsth.render.theme <theme:string>', 'Set default theme', { authority: 3 })
30
- .action(async (_, theme) => {
33
+ ctx.command('githubsth.render.theme <theme:string>', '设置默认主题', { authority: 3 })
34
+ .action(async ({ session }, theme) => {
31
35
  const normalized = ctx.githubsthNotifier.normalizeTheme(theme);
32
36
  if (!normalized)
33
- return 'Invalid theme. Run githubsth.render.themes first.';
37
+ return session?.text('commands.githubsth.render.messages.invalid_theme');
34
38
  config.renderTheme = normalized;
35
- return `Default theme set: ${normalized}`;
39
+ return session?.text('commands.githubsth.render.messages.theme_set', [normalized]);
36
40
  });
37
- ctx.command('githubsth.render.style <style:string>', 'Set default style', { authority: 3 })
38
- .action(async (_, style) => {
41
+ ctx.command('githubsth.render.style <style:string>', '设置默认样式', { authority: 3 })
42
+ .action(async ({ session }, style) => {
39
43
  const normalized = ctx.githubsthNotifier.normalizeStyle(style);
40
44
  if (!normalized)
41
- return 'Invalid style. Run githubsth.render.styles first.';
45
+ return session?.text('commands.githubsth.render.messages.invalid_style');
42
46
  config.renderStyle = normalized;
43
- return `Default style set: ${normalized}`;
47
+ return session?.text('commands.githubsth.render.messages.style_set', [normalized]);
44
48
  });
45
- ctx.command('githubsth.render.width <width:number>', 'Set image width', { authority: 3 })
46
- .action(async (_, width) => {
49
+ ctx.command('githubsth.render.width <width:number>', '设置图片宽度', { authority: 3 })
50
+ .action(async ({ session }, width) => {
47
51
  if (!width || Number.isNaN(width))
48
- return 'Please provide a valid width number.';
52
+ return session?.text('commands.githubsth.render.messages.invalid_width');
49
53
  const normalized = Math.max(480, Math.min(1600, Math.floor(width)));
50
54
  config.renderWidth = normalized;
51
- return `Image width set: ${normalized}px`;
55
+ return session?.text('commands.githubsth.render.messages.width_set', [normalized]);
52
56
  });
53
- ctx.command('githubsth.render.digest <enabled:string>', 'Toggle digest mode (on/off)', { authority: 3 })
54
- .action(async (_, enabled) => {
57
+ ctx.command('githubsth.render.digest <enabled:string>', '切换 digest 模式(on/off', { authority: 3 })
58
+ .action(async ({ session }, enabled) => {
55
59
  const key = String(enabled || '').toLowerCase();
56
60
  if (!['on', 'off', 'true', 'false', '1', '0'].includes(key))
57
- return 'Usage: githubsth.render.digest on|off';
61
+ return session?.text('commands.githubsth.render.messages.digest_usage');
58
62
  config.digestEnabled = ['on', 'true', '1'].includes(key);
59
- return `Digest mode: ${config.digestEnabled ? 'on' : 'off'}`;
63
+ return session?.text('commands.githubsth.render.messages.digest_set', [config.digestEnabled ? 'on' : 'off']);
60
64
  });
61
- ctx.command('githubsth.render.digest.window <seconds:number>', 'Set digest window seconds', { authority: 3 })
62
- .action(async (_, seconds) => {
65
+ ctx.command('githubsth.render.digest.window <seconds:number>', '设置 digest 窗口秒数', { authority: 3 })
66
+ .action(async ({ session }, seconds) => {
63
67
  if (!seconds || Number.isNaN(seconds))
64
- return 'Please provide a valid seconds value.';
68
+ return session?.text('commands.githubsth.render.messages.invalid_seconds');
65
69
  config.digestWindowSec = Math.max(5, Math.min(3600, Math.floor(seconds)));
66
- return `Digest window set: ${config.digestWindowSec}s`;
70
+ return session?.text('commands.githubsth.render.messages.digest_window_set', [config.digestWindowSec]);
67
71
  });
68
- ctx.command('githubsth.render.digest.max <count:number>', 'Set digest max items', { authority: 3 })
69
- .action(async (_, count) => {
72
+ ctx.command('githubsth.render.digest.max <count:number>', '设置 digest 最大条目数', { authority: 3 })
73
+ .action(async ({ session }, count) => {
70
74
  if (!count || Number.isNaN(count))
71
- return 'Please provide a valid count.';
75
+ return session?.text('commands.githubsth.render.messages.invalid_count');
72
76
  config.digestMaxItems = Math.max(2, Math.min(100, Math.floor(count)));
73
- return `Digest max items set: ${config.digestMaxItems}`;
77
+ return session?.text('commands.githubsth.render.messages.digest_max_set', [config.digestMaxItems]);
74
78
  });
75
- ctx.command('githubsth.render.themes', 'List themes', { authority: 3 })
76
- .action(async () => `Themes:\n- ${ctx.githubsthNotifier.listThemes().join('\n- ')}`);
77
- ctx.command('githubsth.render.styles', 'List styles', { authority: 3 })
78
- .action(async () => `Styles:\n- ${ctx.githubsthNotifier.listStyles().join('\n- ')}`);
79
- ctx.command('githubsth.render.preview [event:string] [theme:string] [style:string]', 'Preview renderer', { authority: 3 })
79
+ ctx.command('githubsth.render.themes', '查看主题列表', { authority: 3 })
80
+ .action(async ({ session }) => session?.text('commands.githubsth.render.messages.themes_list', [ctx.githubsthNotifier.listThemes().join('\n- ')]));
81
+ ctx.command('githubsth.render.styles', '查看样式列表', { authority: 3 })
82
+ .action(async ({ session }) => session?.text('commands.githubsth.render.messages.styles_list', [ctx.githubsthNotifier.listStyles().join('\n- ')]));
83
+ ctx.command('githubsth.render.preview [event:string] [theme:string] [style:string]', '预览渲染效果', { authority: 3 })
80
84
  .action(async ({ session }, event, theme, style) => {
81
85
  const selectedEvent = event && events.includes(event) ? event : 'issue_comment';
82
86
  if (event && !events.includes(event))
83
- await session?.send(`Unknown event ${event}, fallback to issue_comment.`);
87
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_event', [event]) || '');
84
88
  const normalizedTheme = theme ? ctx.githubsthNotifier.normalizeTheme(theme) : null;
85
89
  if (theme && !normalizedTheme)
86
- await session?.send(`Unknown theme ${theme}, fallback to default.`);
90
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_theme', [theme]) || '');
87
91
  const normalizedStyle = style ? ctx.githubsthNotifier.normalizeStyle(style) : null;
88
92
  if (style && !normalizedStyle)
89
- await session?.send(`Unknown style ${style}, fallback to default.`);
93
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_style', [style]) || '');
90
94
  const prevTheme = config.renderTheme;
91
95
  const prevStyle = config.renderStyle;
92
96
  if (normalizedTheme)
@@ -96,82 +100,82 @@ function apply(ctx, config) {
96
100
  const preview = await ctx.githubsthNotifier.renderPreview(selectedEvent, normalizedTheme || undefined);
97
101
  config.renderTheme = prevTheme;
98
102
  config.renderStyle = prevStyle;
99
- return preview || 'Preview failed. Check puppeteer/render settings.';
103
+ return preview || session?.text('commands.githubsth.render.messages.preview_failed');
100
104
  });
101
- ctx.command('githubsth.render.repo-theme <repo:string> <theme:string>', 'Set per-subscription theme', { authority: 3 })
105
+ ctx.command('githubsth.render.repo-theme <repo:string> <theme:string>', '设置订阅专属主题', { authority: 3 })
102
106
  .action(async ({ session }, repo, theme) => {
103
107
  if (!repo)
104
- return 'Please provide owner/repo.';
108
+ return session?.text('commands.githubsth.render.messages.repo_required');
105
109
  if (!session?.channelId)
106
- return 'Run this command in a group/channel.';
110
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
107
111
  const normalized = ctx.githubsthNotifier.normalizeTheme(theme);
108
112
  if (!normalized)
109
- return 'Invalid theme. Run githubsth.render.themes.';
113
+ return session?.text('commands.githubsth.render.messages.invalid_theme');
110
114
  const target = await ctx.database.get('github_subscription', {
111
115
  repo,
112
116
  channelId: session.channelId,
113
117
  platform: session.platform || 'unknown',
114
118
  });
115
119
  if (!target.length)
116
- return 'No subscription for this repo in current channel.';
120
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
117
121
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderTheme: normalized });
118
- return `Per-subscription theme set: ${repo} -> ${normalized}`;
122
+ return session?.text('commands.githubsth.render.messages.repo_theme_set', [repo, normalized]);
119
123
  });
120
- ctx.command('githubsth.render.repo-theme.clear <repo:string>', 'Clear per-subscription theme', { authority: 3 })
124
+ ctx.command('githubsth.render.repo-theme.clear <repo:string>', '清除订阅专属主题', { authority: 3 })
121
125
  .action(async ({ session }, repo) => {
122
126
  if (!repo)
123
- return 'Please provide owner/repo.';
127
+ return session?.text('commands.githubsth.render.messages.repo_required');
124
128
  if (!session?.channelId)
125
- return 'Run this command in a group/channel.';
129
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
126
130
  const target = await ctx.database.get('github_subscription', {
127
131
  repo,
128
132
  channelId: session.channelId,
129
133
  platform: session.platform || 'unknown',
130
134
  });
131
135
  if (!target.length)
132
- return 'No subscription for this repo in current channel.';
136
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
133
137
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderTheme: null });
134
- return `Per-subscription theme cleared: ${repo}`;
138
+ return session?.text('commands.githubsth.render.messages.repo_theme_cleared', [repo]);
135
139
  });
136
- ctx.command('githubsth.render.repo-style <repo:string> <style:string>', 'Set per-subscription style', { authority: 3 })
140
+ ctx.command('githubsth.render.repo-style <repo:string> <style:string>', '设置订阅专属样式', { authority: 3 })
137
141
  .action(async ({ session }, repo, style) => {
138
142
  if (!repo)
139
- return 'Please provide owner/repo.';
143
+ return session?.text('commands.githubsth.render.messages.repo_required');
140
144
  if (!session?.channelId)
141
- return 'Run this command in a group/channel.';
145
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
142
146
  const normalized = ctx.githubsthNotifier.normalizeStyle(style);
143
147
  if (!normalized)
144
- return 'Invalid style. Run githubsth.render.styles.';
148
+ return session?.text('commands.githubsth.render.messages.invalid_style');
145
149
  const target = await ctx.database.get('github_subscription', {
146
150
  repo,
147
151
  channelId: session.channelId,
148
152
  platform: session.platform || 'unknown',
149
153
  });
150
154
  if (!target.length)
151
- return 'No subscription for this repo in current channel.';
155
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
152
156
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderStyle: normalized });
153
- return `Per-subscription style set: ${repo} -> ${normalized}`;
157
+ return session?.text('commands.githubsth.render.messages.repo_style_set', [repo, normalized]);
154
158
  });
155
- ctx.command('githubsth.render.repo-style.clear <repo:string>', 'Clear per-subscription style', { authority: 3 })
159
+ ctx.command('githubsth.render.repo-style.clear <repo:string>', '清除订阅专属样式', { authority: 3 })
156
160
  .action(async ({ session }, repo) => {
157
161
  if (!repo)
158
- return 'Please provide owner/repo.';
162
+ return session?.text('commands.githubsth.render.messages.repo_required');
159
163
  if (!session?.channelId)
160
- return 'Run this command in a group/channel.';
164
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
161
165
  const target = await ctx.database.get('github_subscription', {
162
166
  repo,
163
167
  channelId: session.channelId,
164
168
  platform: session.platform || 'unknown',
165
169
  });
166
170
  if (!target.length)
167
- return 'No subscription for this repo in current channel.';
171
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
168
172
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderStyle: null });
169
- return `Per-subscription style cleared: ${repo}`;
173
+ return session?.text('commands.githubsth.render.messages.repo_style_cleared', [repo]);
170
174
  });
171
- ctx.command('githubsth.render.repo-theme.list [repo:string]', 'List per-subscription theme/style', { authority: 3 })
175
+ ctx.command('githubsth.render.repo-theme.list [repo:string]', '查看订阅主题/样式', { authority: 3 })
172
176
  .action(async ({ session }, repo) => {
173
177
  if (!session?.channelId)
174
- return 'Run this command in a group/channel.';
178
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
175
179
  const query = {
176
180
  channelId: session.channelId,
177
181
  platform: session.platform || 'unknown',
@@ -180,9 +184,13 @@ function apply(ctx, config) {
180
184
  query.repo = repo;
181
185
  const subs = await ctx.database.get('github_subscription', query);
182
186
  if (!subs.length)
183
- return 'No matched subscriptions.';
187
+ return session?.text('commands.githubsth.render.messages.no_matched_subs');
184
188
  return subs
185
- .map((sub) => `${sub.repo} => theme=${sub.renderTheme || '(default)'} style=${sub.renderStyle || '(default)'}`)
189
+ .map((sub) => session?.text('commands.githubsth.render.messages.repo_style_item', [
190
+ sub.repo,
191
+ sub.renderTheme || '(default)',
192
+ sub.renderStyle || '(default)',
193
+ ]) || `${sub.repo}`)
186
194
  .join('\n');
187
195
  });
188
196
  }
@@ -2,35 +2,30 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.apply = apply;
4
4
  function apply(ctx, config) {
5
- ctx.command('githubsth.repo [name:string]')
5
+ ctx.command('githubsth.repo [name:string]', '获取仓库信息')
6
6
  .action(async ({ session }, name) => {
7
- if (!name && !config.defaultRepo) {
7
+ if (!name && !config.defaultRepo)
8
8
  return session?.text('.specify_repo');
9
- }
10
9
  const fullRepo = name || (config.defaultOwner ? `${config.defaultOwner}/${config.defaultRepo}` : name);
11
10
  if (!fullRepo)
12
11
  return session?.text('.specify_repo');
13
12
  try {
14
13
  let data;
15
14
  if (ctx.github && typeof ctx.github.request === 'function') {
16
- // If adapter provides a request method (hypothetical, based on common adapter patterns)
17
15
  data = await ctx.github.request('GET /repos/:owner/:repo', {
18
16
  owner: fullRepo.split('/')[0],
19
- repo: fullRepo.split('/')[1]
17
+ repo: fullRepo.split('/')[1],
20
18
  });
21
19
  }
22
20
  else {
23
- const headers = {
24
- 'User-Agent': 'Koishi-Plugin-GithubSth'
25
- };
21
+ const headers = { 'User-Agent': 'Koishi-Plugin-GithubSth' };
26
22
  data = await ctx.http.get(`https://api.github.com/repos/${fullRepo}`, { headers });
27
23
  }
28
24
  return session?.text('.repo_info', [data.owner.login, data.name, data.description || '无描述', data.stargazers_count]);
29
25
  }
30
26
  catch (e) {
31
- if (e.response?.status === 404) {
27
+ if (e.response?.status === 404)
32
28
  return session?.text('.not_found');
33
- }
34
29
  return session?.text('.error', [e.message]);
35
30
  }
36
31
  });
@@ -10,7 +10,7 @@ function apply(ctx, config) {
10
10
  'discussion', 'workflow_run',
11
11
  ];
12
12
  const defaultConfigEvents = config.defaultEvents || ['push', 'issues', 'issue_comment', 'pull_request', 'pull_request_review', 'release', 'star', 'fork'];
13
- ctx.command('githubsth.subscribe <repo> [events:text]', 'Subscribe GitHub repository events')
13
+ ctx.command('githubsth.subscribe <repo> [events:text]', '订阅 GitHub 仓库事件')
14
14
  .alias('gh.sub')
15
15
  .usage(`
16
16
  Subscribe GitHub repository notifications. If events are omitted, default events are used: ${defaultConfigEvents.join(', ')}
@@ -21,20 +21,20 @@ Examples:
21
21
  `)
22
22
  .action(async ({ session }, repo, eventsStr) => {
23
23
  if (!repo)
24
- return 'Please provide repository as owner/repo.';
24
+ return session?.text('commands.githubsth.subscribe.messages.specify_repo');
25
25
  if (!repoRegex.test(repo))
26
- return 'Invalid repository format. Expected owner/repo.';
26
+ return session?.text('commands.githubsth.subscribe.messages.invalid_repo');
27
27
  if (!session?.channelId)
28
- return 'Please run this command in a group/channel.';
28
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
29
29
  const trusted = await ctx.database.get('github_trusted_repo', { repo, enabled: true });
30
30
  if (trusted.length === 0)
31
- return 'Repository is not in trusted list. Ask admin to add it first.';
31
+ return session?.text('commands.githubsth.subscribe.messages.repo_not_trusted');
32
32
  let events;
33
33
  if (eventsStr) {
34
34
  events = eventsStr.split(/[,,\s]+/).map((e) => e.trim()).filter(Boolean).map((e) => e.replace(/-/g, '_'));
35
35
  const invalidEvents = events.filter((e) => !validEvents.includes(e) && e !== '*');
36
36
  if (invalidEvents.length) {
37
- return `Invalid events: ${invalidEvents.join(', ')}\nAllowed events: ${validEvents.join(', ')}`;
37
+ return session?.text('commands.githubsth.subscribe.messages.invalid_events', [invalidEvents.join(', '), validEvents.join(', ')]);
38
38
  }
39
39
  }
40
40
  else {
@@ -48,7 +48,7 @@ Examples:
48
48
  });
49
49
  if (existing.length > 0) {
50
50
  await ctx.database.set('github_subscription', { id: existing[0].id }, { events });
51
- return `Subscription updated: ${repo}\nEvents: ${events.join(', ')}`;
51
+ return session?.text('commands.githubsth.subscribe.messages.updated', [repo, events.join(', ')]);
52
52
  }
53
53
  await ctx.database.create('github_subscription', {
54
54
  repo,
@@ -56,42 +56,47 @@ Examples:
56
56
  platform: session.platform || 'unknown',
57
57
  events,
58
58
  });
59
- return `Subscribed: ${repo}\nEvents: ${events.join(', ')}`;
59
+ return session?.text('commands.githubsth.subscribe.messages.created', [repo, events.join(', ')]);
60
60
  }
61
61
  catch (error) {
62
62
  logger.warn(error);
63
- return 'Subscribe failed. Please try again later.';
63
+ return session?.text('commands.githubsth.subscribe.messages.failed');
64
64
  }
65
65
  });
66
- ctx.command('githubsth.unsubscribe <repo>', 'Unsubscribe GitHub repository')
66
+ ctx.command('githubsth.unsubscribe <repo>', '取消订阅 GitHub 仓库')
67
67
  .alias('gh.unsub')
68
68
  .action(async ({ session }, repo) => {
69
69
  if (!repo)
70
- return 'Please provide repository as owner/repo.';
70
+ return session?.text('commands.githubsth.unsubscribe.messages.specify_repo');
71
71
  if (!session?.channelId)
72
- return 'Please run this command in a group/channel.';
72
+ return session?.text('commands.githubsth.unsubscribe.messages.run_in_channel');
73
73
  const result = await ctx.database.remove('github_subscription', {
74
74
  repo,
75
75
  channelId: session.channelId,
76
76
  platform: session.platform || 'unknown',
77
77
  });
78
78
  if (result.matched === 0)
79
- return 'Subscription not found.';
80
- return `Unsubscribed: ${repo}`;
79
+ return session?.text('commands.githubsth.unsubscribe.messages.not_found');
80
+ return session?.text('commands.githubsth.unsubscribe.messages.success', [repo]);
81
81
  });
82
- ctx.command('githubsth.list', 'List current channel subscriptions')
82
+ ctx.command('githubsth.list', '查看当前频道订阅')
83
83
  .alias('gh.list')
84
84
  .action(async ({ session }) => {
85
85
  if (!session?.channelId)
86
- return 'Please run this command in a group/channel.';
86
+ return session?.text('commands.githubsth.list.messages.run_in_channel');
87
87
  const subs = await ctx.database.get('github_subscription', {
88
88
  channelId: session.channelId,
89
89
  platform: session.platform || 'unknown',
90
90
  });
91
91
  if (subs.length === 0)
92
- return 'No subscriptions in this channel.';
92
+ return session?.text('commands.githubsth.list.messages.empty');
93
93
  return subs
94
- .map((sub) => `${sub.repo} [${sub.events.join(', ')}] theme=${sub.renderTheme || '(default)'} style=${sub.renderStyle || '(default)'}`)
94
+ .map((sub) => session?.text('commands.githubsth.list.messages.item', [
95
+ sub.repo,
96
+ sub.events.join(', '),
97
+ sub.renderTheme || '(default)',
98
+ sub.renderStyle || '(default)',
99
+ ]) || `${sub.repo} [${sub.events.join(', ')}]`)
95
100
  .join('\n');
96
101
  });
97
102
  }
@@ -12,6 +12,73 @@ declare const _default: {
12
12
  not_found: string;
13
13
  };
14
14
  };
15
+ 'githubsth.subscribe': {
16
+ description: string;
17
+ messages: {
18
+ specify_repo: string;
19
+ invalid_repo: string;
20
+ run_in_channel: string;
21
+ repo_not_trusted: string;
22
+ invalid_events: string;
23
+ updated: string;
24
+ created: string;
25
+ failed: string;
26
+ };
27
+ };
28
+ 'githubsth.unsubscribe': {
29
+ description: string;
30
+ messages: {
31
+ specify_repo: string;
32
+ run_in_channel: string;
33
+ not_found: string;
34
+ success: string;
35
+ };
36
+ };
37
+ 'githubsth.list': {
38
+ description: string;
39
+ messages: {
40
+ run_in_channel: string;
41
+ empty: string;
42
+ item: string;
43
+ };
44
+ };
45
+ 'githubsth.render': {
46
+ description: string;
47
+ messages: {
48
+ invalid_mode: string;
49
+ mode_set: string;
50
+ invalid_theme: string;
51
+ theme_set: string;
52
+ invalid_style: string;
53
+ style_set: string;
54
+ invalid_width: string;
55
+ width_set: string;
56
+ digest_usage: string;
57
+ digest_set: string;
58
+ invalid_seconds: string;
59
+ digest_window_set: string;
60
+ invalid_count: string;
61
+ digest_max_set: string;
62
+ themes_list: string;
63
+ styles_list: string;
64
+ status_text: string;
65
+ unknown_event: string;
66
+ unknown_theme: string;
67
+ unknown_style: string;
68
+ preview_failed: string;
69
+ repo_required: string;
70
+ no_sub_in_channel: string;
71
+ repo_theme_set: string;
72
+ repo_theme_cleared: string;
73
+ repo_style_set: string;
74
+ repo_style_cleared: string;
75
+ no_matched_subs: string;
76
+ repo_style_item: string;
77
+ };
78
+ };
79
+ 'githubsth.trust': {
80
+ description: string;
81
+ };
15
82
  };
16
83
  };
17
84
  export default _default;
@@ -14,5 +14,72 @@ exports.default = {
14
14
  not_found: 'Repository not found or access denied.',
15
15
  },
16
16
  },
17
+ 'githubsth.subscribe': {
18
+ description: 'Subscribe GitHub repository events',
19
+ messages: {
20
+ specify_repo: 'Please provide repository as owner/repo.',
21
+ invalid_repo: 'Invalid repository format. Expected owner/repo.',
22
+ run_in_channel: 'Please run this command in a group/channel.',
23
+ repo_not_trusted: 'Repository is not in trusted list. Ask admin to add it first.',
24
+ invalid_events: 'Invalid events: {0}\nAllowed events: {1}',
25
+ updated: 'Subscription updated: {0}\nEvents: {1}',
26
+ created: 'Subscribed: {0}\nEvents: {1}',
27
+ failed: 'Subscribe failed. Please try again later.',
28
+ },
29
+ },
30
+ 'githubsth.unsubscribe': {
31
+ description: 'Unsubscribe GitHub repository',
32
+ messages: {
33
+ specify_repo: 'Please provide repository as owner/repo.',
34
+ run_in_channel: 'Please run this command in a group/channel.',
35
+ not_found: 'Subscription not found.',
36
+ success: 'Unsubscribed: {0}',
37
+ },
38
+ },
39
+ 'githubsth.list': {
40
+ description: 'List current channel subscriptions',
41
+ messages: {
42
+ run_in_channel: 'Please run this command in a group/channel.',
43
+ empty: 'No subscriptions in this channel.',
44
+ item: '{0} [{1}] theme={2} style={3}',
45
+ },
46
+ },
47
+ 'githubsth.render': {
48
+ description: 'Render settings',
49
+ messages: {
50
+ invalid_mode: 'Invalid mode. Allowed: {0}',
51
+ mode_set: 'Runtime render mode set to {0} (config default is {1}).',
52
+ invalid_theme: 'Invalid theme. Run githubsth.render.themes first.',
53
+ theme_set: 'Default theme set: {0}',
54
+ invalid_style: 'Invalid style. Run githubsth.render.styles first.',
55
+ style_set: 'Default style set: {0}',
56
+ invalid_width: 'Please provide a valid width number.',
57
+ width_set: 'Image width set: {0}px',
58
+ digest_usage: 'Usage: githubsth.render.digest on|off',
59
+ digest_set: 'Digest mode: {0}',
60
+ invalid_seconds: 'Please provide a valid seconds value.',
61
+ digest_window_set: 'Digest window set: {0}s',
62
+ invalid_count: 'Please provide a valid count.',
63
+ digest_max_set: 'Digest max items set: {0}',
64
+ themes_list: 'Themes:\n- {0}',
65
+ styles_list: 'Styles:\n- {0}',
66
+ status_text: 'mode: {0} (configured: {1})\nfallback: {2}\ntheme(default): {3}\nstyle(default): {4}\nwidth: {5}\ntimeout: {6}ms\ndigest: {7} ({8}s, max {9})\npuppeteer: {10}',
67
+ unknown_event: 'Unknown event {0}, fallback to issue_comment.',
68
+ unknown_theme: 'Unknown theme {0}, fallback to default theme.',
69
+ unknown_style: 'Unknown style {0}, fallback to default style.',
70
+ preview_failed: 'Preview failed. Check puppeteer or render settings.',
71
+ repo_required: 'Please provide owner/repo.',
72
+ no_sub_in_channel: 'No subscription for this repo in current channel.',
73
+ repo_theme_set: 'Per-subscription theme set: {0} -> {1}',
74
+ repo_theme_cleared: 'Per-subscription theme cleared: {0}',
75
+ repo_style_set: 'Per-subscription style set: {0} -> {1}',
76
+ repo_style_cleared: 'Per-subscription style cleared: {0}',
77
+ no_matched_subs: 'No matched subscriptions.',
78
+ repo_style_item: '{0} => theme={1} style={2}',
79
+ },
80
+ },
81
+ 'githubsth.trust': {
82
+ description: 'Manage trusted repositories',
83
+ },
17
84
  },
18
85
  };
@@ -12,6 +12,73 @@ declare const _default: {
12
12
  not_found: string;
13
13
  };
14
14
  };
15
+ 'githubsth.subscribe': {
16
+ description: string;
17
+ messages: {
18
+ specify_repo: string;
19
+ invalid_repo: string;
20
+ run_in_channel: string;
21
+ repo_not_trusted: string;
22
+ invalid_events: string;
23
+ updated: string;
24
+ created: string;
25
+ failed: string;
26
+ };
27
+ };
28
+ 'githubsth.unsubscribe': {
29
+ description: string;
30
+ messages: {
31
+ specify_repo: string;
32
+ run_in_channel: string;
33
+ not_found: string;
34
+ success: string;
35
+ };
36
+ };
37
+ 'githubsth.list': {
38
+ description: string;
39
+ messages: {
40
+ run_in_channel: string;
41
+ empty: string;
42
+ item: string;
43
+ };
44
+ };
45
+ 'githubsth.render': {
46
+ description: string;
47
+ messages: {
48
+ invalid_mode: string;
49
+ mode_set: string;
50
+ invalid_theme: string;
51
+ theme_set: string;
52
+ invalid_style: string;
53
+ style_set: string;
54
+ invalid_width: string;
55
+ width_set: string;
56
+ digest_usage: string;
57
+ digest_set: string;
58
+ invalid_seconds: string;
59
+ digest_window_set: string;
60
+ invalid_count: string;
61
+ digest_max_set: string;
62
+ themes_list: string;
63
+ styles_list: string;
64
+ status_text: string;
65
+ unknown_event: string;
66
+ unknown_theme: string;
67
+ unknown_style: string;
68
+ preview_failed: string;
69
+ repo_required: string;
70
+ no_sub_in_channel: string;
71
+ repo_theme_set: string;
72
+ repo_theme_cleared: string;
73
+ repo_style_set: string;
74
+ repo_style_cleared: string;
75
+ no_matched_subs: string;
76
+ repo_style_item: string;
77
+ };
78
+ };
79
+ 'githubsth.trust': {
80
+ description: string;
81
+ };
15
82
  };
16
83
  };
17
84
  export default _default;
@@ -14,5 +14,72 @@ exports.default = {
14
14
  not_found: '未找到仓库或无权限访问。',
15
15
  },
16
16
  },
17
+ 'githubsth.subscribe': {
18
+ description: '订阅 GitHub 仓库事件',
19
+ messages: {
20
+ specify_repo: '请指定仓库(owner/repo)。',
21
+ invalid_repo: '仓库格式错误,应为 owner/repo。',
22
+ run_in_channel: '请在群聊/频道中执行该命令。',
23
+ repo_not_trusted: '该仓库不在信任列表中,请先由管理员添加。',
24
+ invalid_events: '无效事件:{0}\n可选事件:{1}',
25
+ updated: '已更新订阅:{0}\n事件:{1}',
26
+ created: '已订阅 {0}\n事件:{1}',
27
+ failed: '订阅失败,请稍后重试。',
28
+ },
29
+ },
30
+ 'githubsth.unsubscribe': {
31
+ description: '取消订阅 GitHub 仓库',
32
+ messages: {
33
+ specify_repo: '请指定仓库(owner/repo)。',
34
+ run_in_channel: '请在群聊/频道中执行该命令。',
35
+ not_found: '未找到该订阅。',
36
+ success: '已取消订阅:{0}',
37
+ },
38
+ },
39
+ 'githubsth.list': {
40
+ description: '查看当前频道订阅',
41
+ messages: {
42
+ run_in_channel: '请在群聊/频道中执行该命令。',
43
+ empty: '当前频道没有订阅。',
44
+ item: '{0} [{1}] theme={2} style={3}',
45
+ },
46
+ },
47
+ 'githubsth.render': {
48
+ description: '渲染设置',
49
+ messages: {
50
+ invalid_mode: '无效模式。可选:{0}',
51
+ mode_set: '运行时渲染模式已设置为 {0}(配置默认值 {1})。',
52
+ invalid_theme: '无效主题。请先执行 githubsth.render.themes。',
53
+ theme_set: '默认主题已设置为:{0}',
54
+ invalid_style: '无效样式。请先执行 githubsth.render.styles。',
55
+ style_set: '默认样式已设置为:{0}',
56
+ invalid_width: '请提供有效的宽度数字。',
57
+ width_set: '图片宽度已设置为 {0}px',
58
+ digest_usage: '用法:githubsth.render.digest on|off',
59
+ digest_set: 'Digest 模式:{0}',
60
+ invalid_seconds: '请提供有效的秒数。',
61
+ digest_window_set: 'Digest 窗口已设置为 {0}s',
62
+ invalid_count: '请提供有效的数量。',
63
+ digest_max_set: 'Digest 最大条目已设置为 {0}',
64
+ themes_list: '主题列表:\n- {0}',
65
+ styles_list: '样式列表:\n- {0}',
66
+ status_text: 'mode: {0} (configured: {1})\nfallback: {2}\ntheme(default): {3}\nstyle(default): {4}\nwidth: {5}\ntimeout: {6}ms\ndigest: {7} ({8}s, max {9})\npuppeteer: {10}',
67
+ unknown_event: '未知事件 {0},已回退到 issue_comment。',
68
+ unknown_theme: '未知主题 {0},已回退到默认主题。',
69
+ unknown_style: '未知样式 {0},已回退到默认样式。',
70
+ preview_failed: '预览失败,请检查 puppeteer 或渲染设置。',
71
+ repo_required: '请提供仓库(owner/repo)。',
72
+ no_sub_in_channel: '当前频道没有该仓库订阅。',
73
+ repo_theme_set: '订阅主题已设置:{0} -> {1}',
74
+ repo_theme_cleared: '订阅主题已清除:{0}',
75
+ repo_style_set: '订阅样式已设置:{0} -> {1}',
76
+ repo_style_cleared: '订阅样式已清除:{0}',
77
+ no_matched_subs: '没有匹配的订阅。',
78
+ repo_style_item: '{0} => theme={1} style={2}',
79
+ },
80
+ },
81
+ 'githubsth.trust': {
82
+ description: '管理信任仓库',
83
+ },
17
84
  },
18
85
  };
@@ -11,41 +11,41 @@ const I18N = {
11
11
  unknownBranch: '未知分支',
12
12
  unknownResult: '未知结果',
13
13
  emptyComment: '(空评论)',
14
- hiddenMachinePayload: '检测到自动化系统签名/编码载荷,已省略原始内容。',
15
- pushTitle: '🚀 [代码推送]',
14
+ hiddenMachinePayload: '检测到自动化签名或编码负载,已隐藏原始内容。',
15
+ pushTitle: '[代码推送]',
16
16
  pushBy: '推送者',
17
17
  pushBranch: '分支',
18
18
  pushCommits: '提交',
19
19
  pushMore: '其余 {0} 条提交已省略',
20
20
  pushCompare: '比较链接',
21
- issueTitle: '🐞 [Issue 变更]',
22
- issueCommentTitle: '💬 [Issue 评论]',
23
- prCommentTitle: '💬 [PR 评论]',
21
+ issueTitle: '[Issue 变更]',
22
+ issueCommentTitle: '[Issue 评论]',
23
+ prCommentTitle: '[PR 评论]',
24
24
  issueLabel: '议题',
25
- prTitle: '🔀 [PR 变更]',
25
+ prTitle: '[PR 变更]',
26
26
  prLabel: '拉取请求',
27
27
  byUser: '发起人',
28
- reviewer: '审查者',
28
+ reviewer: '审核人',
29
29
  commenter: '评论人',
30
30
  content: '内容摘要',
31
31
  status: '状态',
32
32
  action: '动作',
33
33
  link: '链接',
34
- starTitle: '[收到 Star]',
34
+ starTitle: '[收到 Star]',
35
35
  starText: '{0} 为仓库点了 Star',
36
36
  starCount: '当前 Star',
37
- forkTitle: '🍴 [仓库 Fork]',
37
+ forkTitle: '[仓库 Fork]',
38
38
  forkText: '{0} Fork 了仓库',
39
39
  forkNewRepo: '新仓库',
40
- releaseTitle: '📦 [版本发布]',
40
+ releaseTitle: '[版本发布]',
41
41
  releaseTag: '版本号',
42
42
  releaseName: '版本标题',
43
- discussionTitle: '🧵 [Discussion 变更]',
44
- workflowTitle: '⚙️ [工作流完成]',
43
+ discussionTitle: '[Discussion 变更]',
44
+ workflowTitle: '[工作流完成]',
45
45
  workflowName: '工作流',
46
46
  workflowResult: '结果',
47
47
  workflowBranch: '分支',
48
- reviewTitle: '[PR Review]',
48
+ reviewTitle: '[PR Review]',
49
49
  actionMap: {
50
50
  opened: '已创建',
51
51
  closed: '已关闭',
@@ -57,10 +57,12 @@ const I18N = {
57
57
  submitted: '已提交',
58
58
  created: '已创建',
59
59
  synchronize: '已同步',
60
- ready_for_review: '可审查',
60
+ ready_for_review: '可审核',
61
61
  published: '已发布',
62
62
  completed: '已完成',
63
63
  started: '已开始',
64
+ merged: '已合并',
65
+ updated: '已更新',
64
66
  },
65
67
  },
66
68
  'en-US': {
@@ -72,17 +74,17 @@ const I18N = {
72
74
  unknownResult: 'Unknown result',
73
75
  emptyComment: '(empty comment)',
74
76
  hiddenMachinePayload: 'Detected automated signature/encoded payload. Raw content hidden.',
75
- pushTitle: '🚀 [Push Event]',
77
+ pushTitle: '[Push Event]',
76
78
  pushBy: 'Pusher',
77
79
  pushBranch: 'Branch',
78
80
  pushCommits: 'Commits',
79
81
  pushMore: '{0} more commits omitted',
80
82
  pushCompare: 'Compare',
81
- issueTitle: '🐞 [Issue Update]',
82
- issueCommentTitle: '💬 [Issue Comment]',
83
- prCommentTitle: '💬 [PR Comment]',
83
+ issueTitle: '[Issue Update]',
84
+ issueCommentTitle: '[Issue Comment]',
85
+ prCommentTitle: '[PR Comment]',
84
86
  issueLabel: 'Issue',
85
- prTitle: '🔀 [PR Update]',
87
+ prTitle: '[PR Update]',
86
88
  prLabel: 'Pull Request',
87
89
  byUser: 'By',
88
90
  reviewer: 'Reviewer',
@@ -91,21 +93,21 @@ const I18N = {
91
93
  status: 'Status',
92
94
  action: 'Action',
93
95
  link: 'Link',
94
- starTitle: '[New Star]',
96
+ starTitle: '[New Star]',
95
97
  starText: '{0} starred the repository',
96
98
  starCount: 'Stars',
97
- forkTitle: '🍴 [Repository Forked]',
99
+ forkTitle: '[Repository Forked]',
98
100
  forkText: '{0} forked the repository',
99
101
  forkNewRepo: 'New repository',
100
- releaseTitle: '📦 [Release Published]',
102
+ releaseTitle: '[Release Published]',
101
103
  releaseTag: 'Tag',
102
104
  releaseName: 'Release name',
103
- discussionTitle: '🧵 [Discussion Update]',
104
- workflowTitle: '⚙️ [Workflow Completed]',
105
+ discussionTitle: '[Discussion Update]',
106
+ workflowTitle: '[Workflow Completed]',
105
107
  workflowName: 'Workflow',
106
108
  workflowResult: 'Result',
107
109
  workflowBranch: 'Branch',
108
- reviewTitle: '[PR Review]',
110
+ reviewTitle: '[PR Review]',
109
111
  actionMap: {
110
112
  opened: 'opened',
111
113
  closed: 'closed',
@@ -121,6 +123,8 @@ const I18N = {
121
123
  published: 'published',
122
124
  completed: 'completed',
123
125
  started: 'started',
126
+ merged: 'merged',
127
+ updated: 'updated',
124
128
  },
125
129
  },
126
130
  };
@@ -142,7 +146,7 @@ class Formatter extends koishi_1.Service {
142
146
  const hash = commit.id?.slice(0, 7) || '0000000';
143
147
  const message = (commit.message || 'No message').split('\n')[0];
144
148
  const author = commit.author?.name || this.t('unknownUser');
145
- return `- [${hash}] ${message} ${author}`;
149
+ return `- [${hash}] ${message} - ${author}`;
146
150
  }).join('\n');
147
151
  const restCount = commits.length - 5;
148
152
  const restLine = restCount > 0 ? `\n${this.t('pushMore', [restCount])}` : '';
@@ -234,7 +238,7 @@ class Formatter extends koishi_1.Service {
234
238
  const repository = payload.repository?.full_name || this.t('unknownRepo');
235
239
  const workflow = payload.workflow_run || {};
236
240
  const result = workflow.conclusion || this.t('unknownResult');
237
- const icon = result === 'success' ? '' : (result === 'failure' ? '' : '⚠️');
241
+ const icon = result === 'success' ? '[OK]' : (result === 'failure' ? '[FAIL]' : '[INFO]');
238
242
  return this.render([
239
243
  `${this.t('workflowTitle')} ${repository}`,
240
244
  `${this.t('workflowName')}: ${workflow.name || 'Unknown'}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-githubsth",
3
- "version": "1.0.5-alpha.3",
3
+ "version": "1.0.5",
4
4
  "description": "Github Subscriptions Notifications, push notifications for GitHub subscriptions For koishi",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",