koishi-plugin-githubsth 1.0.5-alpha.2 → 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.
@@ -10,11 +10,9 @@
10
10
  background: {{background}};
11
11
  color: {{text}};
12
12
  font-family: {{font}};
13
+ --status-accent: {{statusAccent}};
13
14
  }
14
- .wrap {
15
- padding: 18px;
16
- position: relative;
17
- }
15
+ .wrap { padding: 18px; position: relative; }
18
16
  .wrap::before {
19
17
  content: '';
20
18
  position: absolute;
@@ -40,6 +38,12 @@
40
38
  background: {{cardTexture}};
41
39
  opacity: 0.28;
42
40
  }
41
+ .status-bar {
42
+ position: relative;
43
+ z-index: 2;
44
+ height: 3px;
45
+ background: linear-gradient(90deg, var(--status-accent), transparent);
46
+ }
43
47
  .head {
44
48
  position: relative;
45
49
  z-index: 1;
@@ -51,24 +55,18 @@
51
55
  gap: 12px;
52
56
  }
53
57
  .head-left { display: flex; align-items: center; gap: 8px; min-width: 0; }
54
- .dot {
55
- width: 10px;
56
- height: 10px;
58
+ .dot { width: 10px; height: 10px; border-radius: 999px; background: var(--status-accent); box-shadow: 0 0 0 3px {{pillBg}}; }
59
+ .repo { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: 0.2px; }
60
+ .meta { color: {{muted}}; font-size: 12px; letter-spacing: 0.3px; }
61
+ .type-badge {
62
+ display: inline-flex;
63
+ align-items: center;
64
+ padding: 2px 8px;
57
65
  border-radius: 999px;
58
- background: {{accent}};
59
- box-shadow: 0 0 0 3px {{pillBg}};
60
- }
61
- .repo {
62
- font-weight: 700;
63
- white-space: nowrap;
64
- overflow: hidden;
65
- text-overflow: ellipsis;
66
- letter-spacing: 0.2px;
67
- }
68
- .meta {
69
- color: {{muted}};
70
- font-size: 12px;
71
- letter-spacing: 0.3px;
66
+ font-size: 11px;
67
+ border: 1px solid {{border}};
68
+ color: var(--status-accent);
69
+ margin-right: 8px;
72
70
  }
73
71
  .pill {
74
72
  display: inline-flex;
@@ -81,21 +79,9 @@
81
79
  background: {{pillBg}};
82
80
  margin-left: 6px;
83
81
  }
84
- .body {
85
- position: relative;
86
- z-index: 1;
87
- padding: 14px 16px 16px;
88
- }
89
- .title {
90
- font-size: 18px;
91
- font-weight: 700;
92
- margin-bottom: 6px;
93
- letter-spacing: 0.2px;
94
- }
95
- .sub {
96
- color: {{muted}};
97
- margin-bottom: 12px;
98
- }
82
+ .body { position: relative; z-index: 1; padding: 14px 16px 16px; }
83
+ .title { font-size: 18px; font-weight: 700; margin-bottom: 6px; letter-spacing: 0.2px; }
84
+ .sub { color: {{muted}}; margin-bottom: 12px; }
99
85
  .content {
100
86
  border: 1px dashed {{border}};
101
87
  border-radius: 10px;
@@ -106,19 +92,27 @@
106
92
  margin-top: 8px;
107
93
  background: {{contentBg}};
108
94
  }
109
- .commit-list {
95
+ .detail-grid {
110
96
  margin-top: 10px;
111
- border-top: 1px solid {{border}};
112
- padding-top: 10px;
97
+ border: 1px solid {{border}};
98
+ border-radius: 10px;
99
+ background: {{contentBg}};
100
+ overflow: hidden;
113
101
  }
114
- .commit-item {
115
- display: flex;
116
- align-items: baseline;
117
- gap: 6px;
102
+ .detail-row {
103
+ display: grid;
104
+ grid-template-columns: 120px 1fr;
105
+ gap: 10px;
106
+ padding: 8px 10px;
107
+ border-bottom: 1px solid {{border}};
118
108
  font-size: 13px;
119
- margin-bottom: 6px;
120
109
  }
121
- .commit-icon { width: 18px; text-align: center; }
110
+ .detail-row:last-child { border-bottom: 0; }
111
+ .detail-key { color: {{muted}}; }
112
+ .detail-value { word-break: break-word; }
113
+ .commit-list { margin-top: 10px; border-top: 1px solid {{border}}; padding-top: 10px; }
114
+ .commit-item { display: flex; align-items: baseline; gap: 6px; font-size: 13px; margin-bottom: 6px; }
115
+ .commit-icon { width: 22px; text-align: center; color: var(--status-accent); }
122
116
  .commit-hash {
123
117
  display: inline-block;
124
118
  padding: 1px 6px;
@@ -129,67 +123,52 @@
129
123
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
130
124
  }
131
125
  .commit-author { color: {{muted}}; }
132
-
133
- body.style-glass .card {
134
- border-radius: 18px;
135
- backdrop-filter: blur(6px);
136
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
126
+ .digest-list {
127
+ margin-top: 10px;
128
+ border: 1px solid {{border}};
129
+ border-radius: 10px;
130
+ background: {{contentBg}};
131
+ overflow: hidden;
137
132
  }
138
- body.style-glass .head {
139
- background: linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0));
133
+ .digest-item {
134
+ display: grid;
135
+ grid-template-columns: 90px 1fr;
136
+ gap: 10px;
137
+ padding: 8px 10px;
138
+ border-bottom: 1px solid {{border}};
139
+ font-size: 13px;
140
140
  }
141
+ .digest-item:last-child { border-bottom: 0; }
142
+ .digest-event { color: var(--status-accent); font-weight: 600; }
141
143
 
142
- body.style-neon .card {
143
- border-width: 2px;
144
- box-shadow: 0 0 0 1px {{accent}} inset, 0 0 28px rgba(0,0,0,0.38);
145
- }
146
- body.style-neon .dot {
147
- box-shadow: 0 0 0 4px {{pillBg}}, 0 0 14px {{accent}};
148
- }
149
- body.style-neon .title {
150
- text-transform: uppercase;
151
- letter-spacing: 0.8px;
152
- }
144
+ body.style-glass .card { border-radius: 18px; backdrop-filter: blur(6px); box-shadow: 0 20px 50px rgba(0,0,0,0.35); }
145
+ body.style-glass .head { background: linear-gradient(180deg, rgba(255,255,255,0.08), rgba(255,255,255,0)); }
146
+
147
+ body.style-neon .card { border-width: 2px; box-shadow: 0 0 0 1px var(--status-accent) inset, 0 0 28px rgba(0,0,0,0.38); }
148
+ body.style-neon .dot { box-shadow: 0 0 0 4px {{pillBg}}, 0 0 14px var(--status-accent); }
149
+ body.style-neon .title { text-transform: uppercase; letter-spacing: 0.8px; }
153
150
 
154
151
  body.style-compact .wrap { padding: 10px; }
155
152
  body.style-compact .head { padding: 10px 12px; }
156
153
  body.style-compact .body { padding: 10px 12px 12px; }
157
154
  body.style-compact .title { font-size: 16px; }
158
155
  body.style-compact .content { font-size: 13px; }
156
+ body.style-compact .detail-row { grid-template-columns: 90px 1fr; padding: 6px 8px; }
159
157
 
160
- body.style-card .card {
161
- border-radius: 24px;
162
- border-width: 1px;
163
- box-shadow: 0 26px 54px rgba(0, 0, 0, 0.35);
164
- }
165
- body.style-card .head {
166
- border-bottom-style: dashed;
167
- }
168
- body.style-card .content {
169
- border-style: solid;
170
- }
158
+ body.style-card .card { border-radius: 24px; box-shadow: 0 26px 54px rgba(0,0,0,0.35); }
159
+ body.style-card .head { border-bottom-style: dashed; }
160
+ body.style-card .content { border-style: solid; }
171
161
 
172
- body.style-terminal .card {
173
- border-radius: 0;
174
- border-width: 2px;
175
- box-shadow: none;
176
- }
162
+ body.style-terminal .card { border-radius: 0; border-width: 2px; box-shadow: none; }
177
163
  body.style-terminal .head,
178
164
  body.style-terminal .content,
179
165
  body.style-terminal .pill,
180
- body.style-terminal .commit-hash {
181
- border-radius: 0;
182
- }
183
- body.style-terminal .title {
184
- font-size: 17px;
185
- letter-spacing: 0.5px;
186
- }
166
+ body.style-terminal .commit-hash,
167
+ body.style-terminal .detail-grid,
168
+ body.style-terminal .digest-list { border-radius: 0; }
169
+ body.style-terminal .title { font-size: 17px; letter-spacing: 0.5px; }
187
170
 
188
- body.style-github .repo::before {
189
- content: '#';
190
- margin-right: 4px;
191
- color: {{muted}};
192
- }
171
+ body.style-github .repo::before { content: '#'; margin-right: 4px; color: {{muted}}; }
193
172
 
194
173
  {{extraCss}}
195
174
  </style>
@@ -197,6 +176,7 @@
197
176
  <body class="theme-{{themeKey}} style-{{styleVariant}}">
198
177
  <div class="wrap">
199
178
  <div class="card">
179
+ <div class="status-bar"></div>
200
180
  <div class="head">
201
181
  <div class="head-left">
202
182
  <span class="dot"></span>
@@ -205,10 +185,12 @@
205
185
  <div class="meta">{{themeTitle}}</div>
206
186
  </div>
207
187
  <div class="body">
208
- <div class="title">{{eventTitle}}</div>
209
- <div class="sub">by {{actor}}<span class="pill">{{action}}</span>{{statusPills}}</div>
188
+ <div class="title"><span class="type-badge">{{typeLabel}}</span>{{eventTitle}}</div>
189
+ <div class="sub">by {{actor}}{{actionPill}}{{statusPills}}</div>
210
190
  <div class="content">{{content}}</div>
191
+ {{detailBlock}}
211
192
  {{commitBlock}}
193
+ {{digestBlock}}
212
194
  </div>
213
195
  </div>
214
196
  </div>
@@ -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 '未找到该信任仓库。';
@@ -2,104 +2,180 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.apply = apply;
4
4
  const modes = ['text', 'image', 'auto'];
5
- const events = ['push', 'issues', 'issue_comment', 'pull_request', 'pull_request_review', 'star', 'fork', 'release', 'discussion', 'workflow_run'];
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', '通知渲染设置(文本/图片)', { authority: 3 })
8
- .alias('gh.render');
7
+ ctx.command('githubsth.render', '渲染设置', { authority: 3 }).alias('gh.render');
9
8
  ctx.command('githubsth.render.status', '查看渲染状态', { authority: 3 })
10
- .action(async () => {
9
+ .action(async ({ session }) => {
11
10
  const status = ctx.githubsthNotifier.getRenderStatus();
12
- return [
13
- `mode: ${status.mode} (configured: ${status.configuredMode})`,
14
- `fallback: ${status.fallback}`,
15
- `theme(default): ${status.theme}`,
16
- `width: ${status.width}`,
17
- `timeout: ${status.timeoutMs}ms`,
18
- `puppeteer: ${status.hasPuppeteer ? 'ready' : 'missing'}`,
19
- ].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
+ ]);
20
24
  });
21
- ctx.command('githubsth.render.mode <mode:string>', '切换渲染模式(text/image/auto)', { authority: 3 })
22
- .action(async (_, mode) => {
25
+ ctx.command('githubsth.render.mode <mode:string>', '设置渲染模式', { authority: 3 })
26
+ .action(async ({ session }, mode) => {
23
27
  if (!mode || !modes.includes(mode)) {
24
- return `无效模式。可选:${modes.join(', ')}`;
28
+ return session?.text('commands.githubsth.render.messages.invalid_mode', [modes.join(', ')]);
25
29
  }
26
30
  ctx.githubsthNotifier.setRenderMode(mode);
27
- return `已切换运行时渲染模式为 ${mode}(重启后恢复配置值 ${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>', '设置全局默认主题', { 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
- if (!normalized) {
33
- return `无效主题。请使用 githubsth.render.themes 查看可用主题。`;
34
- }
36
+ if (!normalized)
37
+ return session?.text('commands.githubsth.render.messages.invalid_theme');
35
38
  config.renderTheme = normalized;
36
- return `已设置全局默认主题为 ${normalized}(当前进程生效)。`;
39
+ return session?.text('commands.githubsth.render.messages.theme_set', [normalized]);
40
+ });
41
+ ctx.command('githubsth.render.style <style:string>', '设置默认样式', { authority: 3 })
42
+ .action(async ({ session }, style) => {
43
+ const normalized = ctx.githubsthNotifier.normalizeStyle(style);
44
+ if (!normalized)
45
+ return session?.text('commands.githubsth.render.messages.invalid_style');
46
+ config.renderStyle = normalized;
47
+ return session?.text('commands.githubsth.render.messages.style_set', [normalized]);
37
48
  });
38
49
  ctx.command('githubsth.render.width <width:number>', '设置图片宽度', { authority: 3 })
39
- .action(async (_, width) => {
50
+ .action(async ({ session }, width) => {
40
51
  if (!width || Number.isNaN(width))
41
- return '请提供有效的数字宽度。';
52
+ return session?.text('commands.githubsth.render.messages.invalid_width');
42
53
  const normalized = Math.max(480, Math.min(1600, Math.floor(width)));
43
54
  config.renderWidth = normalized;
44
- return `已设置图片宽度为 ${normalized}px(当前进程生效)。`;
55
+ return session?.text('commands.githubsth.render.messages.width_set', [normalized]);
45
56
  });
46
- ctx.command('githubsth.render.themes', '查看主题列表', { authority: 3 })
47
- .action(async () => {
48
- const themes = ctx.githubsthNotifier.listThemes();
49
- return `可用主题:\n- ${themes.join('\n- ')}`;
57
+ ctx.command('githubsth.render.digest <enabled:string>', '切换 digest 模式(on/off)', { authority: 3 })
58
+ .action(async ({ session }, enabled) => {
59
+ const key = String(enabled || '').toLowerCase();
60
+ if (!['on', 'off', 'true', 'false', '1', '0'].includes(key))
61
+ return session?.text('commands.githubsth.render.messages.digest_usage');
62
+ config.digestEnabled = ['on', 'true', '1'].includes(key);
63
+ return session?.text('commands.githubsth.render.messages.digest_set', [config.digestEnabled ? 'on' : 'off']);
64
+ });
65
+ ctx.command('githubsth.render.digest.window <seconds:number>', '设置 digest 窗口秒数', { authority: 3 })
66
+ .action(async ({ session }, seconds) => {
67
+ if (!seconds || Number.isNaN(seconds))
68
+ return session?.text('commands.githubsth.render.messages.invalid_seconds');
69
+ config.digestWindowSec = Math.max(5, Math.min(3600, Math.floor(seconds)));
70
+ return session?.text('commands.githubsth.render.messages.digest_window_set', [config.digestWindowSec]);
50
71
  });
51
- ctx.command('githubsth.render.preview [event:string] [theme:string]', '预览通知渲染', { authority: 3 })
52
- .action(async ({ session }, event, theme) => {
72
+ ctx.command('githubsth.render.digest.max <count:number>', '设置 digest 最大条目数', { authority: 3 })
73
+ .action(async ({ session }, count) => {
74
+ if (!count || Number.isNaN(count))
75
+ return session?.text('commands.githubsth.render.messages.invalid_count');
76
+ config.digestMaxItems = Math.max(2, Math.min(100, Math.floor(count)));
77
+ return session?.text('commands.githubsth.render.messages.digest_max_set', [config.digestMaxItems]);
78
+ });
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 })
84
+ .action(async ({ session }, event, theme, style) => {
53
85
  const selectedEvent = event && events.includes(event) ? event : 'issue_comment';
54
- if (event && !events.includes(event)) {
55
- await session?.send(`未知事件 ${event},已改用默认事件 issue_comment。`);
56
- }
86
+ if (event && !events.includes(event))
87
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_event', [event]) || '');
57
88
  const normalizedTheme = theme ? ctx.githubsthNotifier.normalizeTheme(theme) : null;
58
- if (theme && !normalizedTheme) {
59
- await session?.send(`未知主题 ${theme},将使用默认主题。`);
60
- }
89
+ if (theme && !normalizedTheme)
90
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_theme', [theme]) || '');
91
+ const normalizedStyle = style ? ctx.githubsthNotifier.normalizeStyle(style) : null;
92
+ if (style && !normalizedStyle)
93
+ await session?.send(session?.text('commands.githubsth.render.messages.unknown_style', [style]) || '');
94
+ const prevTheme = config.renderTheme;
95
+ const prevStyle = config.renderStyle;
96
+ if (normalizedTheme)
97
+ config.renderTheme = normalizedTheme;
98
+ if (normalizedStyle)
99
+ config.renderStyle = normalizedStyle;
61
100
  const preview = await ctx.githubsthNotifier.renderPreview(selectedEvent, normalizedTheme || undefined);
62
- return preview || '预览失败:请检查 puppeteer 或渲染配置。';
101
+ config.renderTheme = prevTheme;
102
+ config.renderStyle = prevStyle;
103
+ return preview || session?.text('commands.githubsth.render.messages.preview_failed');
63
104
  });
64
- ctx.command('githubsth.render.repo-theme <repo:string> <theme:string>', '为当前频道某订阅设置单独主题', { authority: 3 })
105
+ ctx.command('githubsth.render.repo-theme <repo:string> <theme:string>', '设置订阅专属主题', { authority: 3 })
65
106
  .action(async ({ session }, repo, theme) => {
66
107
  if (!repo)
67
- return '请提供仓库(owner/repo)。';
108
+ return session?.text('commands.githubsth.render.messages.repo_required');
68
109
  if (!session?.channelId)
69
- return '请在群聊/频道中执行该命令。';
110
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
70
111
  const normalized = ctx.githubsthNotifier.normalizeTheme(theme);
71
112
  if (!normalized)
72
- return '主题不存在,请先执行 githubsth.render.themes。';
113
+ return session?.text('commands.githubsth.render.messages.invalid_theme');
73
114
  const target = await ctx.database.get('github_subscription', {
74
115
  repo,
75
116
  channelId: session.channelId,
76
117
  platform: session.platform || 'unknown',
77
118
  });
78
119
  if (!target.length)
79
- return '当前频道没有该仓库订阅。';
120
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
80
121
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderTheme: normalized });
81
- return `已为 ${repo} 设置专属主题:${normalized}`;
122
+ return session?.text('commands.githubsth.render.messages.repo_theme_set', [repo, normalized]);
82
123
  });
83
- ctx.command('githubsth.render.repo-theme.clear <repo:string>', '清除当前频道某订阅的专属主题', { authority: 3 })
124
+ ctx.command('githubsth.render.repo-theme.clear <repo:string>', '清除订阅专属主题', { authority: 3 })
84
125
  .action(async ({ session }, repo) => {
85
126
  if (!repo)
86
- return '请提供仓库(owner/repo)。';
127
+ return session?.text('commands.githubsth.render.messages.repo_required');
87
128
  if (!session?.channelId)
88
- return '请在群聊/频道中执行该命令。';
129
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
89
130
  const target = await ctx.database.get('github_subscription', {
90
131
  repo,
91
132
  channelId: session.channelId,
92
133
  platform: session.platform || 'unknown',
93
134
  });
94
135
  if (!target.length)
95
- return '当前频道没有该仓库订阅。';
136
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
96
137
  await ctx.database.set('github_subscription', { id: target[0].id }, { renderTheme: null });
97
- return `已清除 ${repo} 的专属主题,回退到全局主题。`;
138
+ return session?.text('commands.githubsth.render.messages.repo_theme_cleared', [repo]);
139
+ });
140
+ ctx.command('githubsth.render.repo-style <repo:string> <style:string>', '设置订阅专属样式', { authority: 3 })
141
+ .action(async ({ session }, repo, style) => {
142
+ if (!repo)
143
+ return session?.text('commands.githubsth.render.messages.repo_required');
144
+ if (!session?.channelId)
145
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
146
+ const normalized = ctx.githubsthNotifier.normalizeStyle(style);
147
+ if (!normalized)
148
+ return session?.text('commands.githubsth.render.messages.invalid_style');
149
+ const target = await ctx.database.get('github_subscription', {
150
+ repo,
151
+ channelId: session.channelId,
152
+ platform: session.platform || 'unknown',
153
+ });
154
+ if (!target.length)
155
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
156
+ await ctx.database.set('github_subscription', { id: target[0].id }, { renderStyle: normalized });
157
+ return session?.text('commands.githubsth.render.messages.repo_style_set', [repo, normalized]);
158
+ });
159
+ ctx.command('githubsth.render.repo-style.clear <repo:string>', '清除订阅专属样式', { authority: 3 })
160
+ .action(async ({ session }, repo) => {
161
+ if (!repo)
162
+ return session?.text('commands.githubsth.render.messages.repo_required');
163
+ if (!session?.channelId)
164
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
165
+ const target = await ctx.database.get('github_subscription', {
166
+ repo,
167
+ channelId: session.channelId,
168
+ platform: session.platform || 'unknown',
169
+ });
170
+ if (!target.length)
171
+ return session?.text('commands.githubsth.render.messages.no_sub_in_channel');
172
+ await ctx.database.set('github_subscription', { id: target[0].id }, { renderStyle: null });
173
+ return session?.text('commands.githubsth.render.messages.repo_style_cleared', [repo]);
98
174
  });
99
- ctx.command('githubsth.render.repo-theme.list [repo:string]', '查看当前频道订阅的专属主题', { authority: 3 })
175
+ ctx.command('githubsth.render.repo-theme.list [repo:string]', '查看订阅主题/样式', { authority: 3 })
100
176
  .action(async ({ session }, repo) => {
101
177
  if (!session?.channelId)
102
- return '请在群聊/频道中执行该命令。';
178
+ return session?.text('commands.githubsth.subscribe.messages.run_in_channel');
103
179
  const query = {
104
180
  channelId: session.channelId,
105
181
  platform: session.platform || 'unknown',
@@ -108,7 +184,13 @@ function apply(ctx, config) {
108
184
  query.repo = repo;
109
185
  const subs = await ctx.database.get('github_subscription', query);
110
186
  if (!subs.length)
111
- return '当前频道没有匹配订阅。';
112
- return subs.map((sub) => `${sub.repo} => ${sub.renderTheme || '(default)'}`).join('\n');
187
+ return session?.text('commands.githubsth.render.messages.no_matched_subs');
188
+ return subs
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}`)
194
+ .join('\n');
113
195
  });
114
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
  });