@zhin.js/plugin-group-suite 1.1.15 → 1.1.16
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/README.md +12 -0
- package/commands/checkin/index.js +3 -3
- package/commands/checkin/index.ts +3 -3
- package/commands/forget/index.js +3 -3
- package/commands/forget/index.ts +3 -3
- package/commands/keyword-add/[keyword]/index.js +4 -3
- package/commands/keyword-add/[keyword]/index.ts +4 -3
- package/commands/keyword-list/index.js +4 -3
- package/commands/keyword-list/index.ts +4 -3
- package/commands/keyword-remove/[keyword]/index.js +5 -4
- package/commands/keyword-remove/[keyword]/index.ts +5 -4
- package/commands/mypoints/index.js +3 -3
- package/commands/mypoints/index.ts +3 -3
- package/commands/mystats/index.js +3 -3
- package/commands/mystats/index.ts +3 -3
- package/commands/rank/index.js +3 -3
- package/commands/rank/index.ts +3 -3
- package/commands/stats/index.js +6 -5
- package/commands/stats/index.ts +6 -5
- package/commands/stats-card/index.js +4 -3
- package/commands/stats-card/index.ts +4 -3
- package/commands/stats-rank/index.js +6 -5
- package/commands/stats-rank/index.ts +6 -5
- package/commands/stats-week/index.js +6 -5
- package/commands/stats-week/index.ts +6 -5
- package/commands/teach/index.js +3 -3
- package/commands/teach/index.ts +3 -3
- package/commands/teach-list/[[page]]/index.js +3 -3
- package/commands/teach-list/[[page]]/index.ts +3 -3
- package/commands/teach-regex/index.js +3 -3
- package/commands/teach-regex/index.ts +3 -3
- package/handlers/welcome/index.js +9 -1
- package/handlers/welcome/index.ts +8 -1
- package/lib/analysis-card.d.ts +1 -1
- package/lib/analysis-card.d.ts.map +1 -1
- package/lib/analysis-card.js +12 -11
- package/lib/analysis-card.js.map +1 -1
- package/lib/analysis.d.ts +2 -2
- package/lib/analysis.d.ts.map +1 -1
- package/lib/analysis.js +14 -20
- package/lib/analysis.js.map +1 -1
- package/lib/checkin-lib.d.ts +1 -1
- package/lib/checkin-lib.d.ts.map +1 -1
- package/lib/checkin-lib.js +23 -22
- package/lib/checkin-lib.js.map +1 -1
- package/lib/conversation-scope.d.ts +1 -0
- package/lib/conversation-scope.d.ts.map +1 -1
- package/lib/conversation-scope.js.map +1 -1
- package/lib/i18n.d.ts +2 -0
- package/lib/i18n.d.ts.map +1 -0
- package/lib/i18n.js +480 -0
- package/lib/i18n.js.map +1 -0
- package/lib/keywords.d.ts +1 -0
- package/lib/keywords.d.ts.map +1 -1
- package/lib/keywords.js +8 -7
- package/lib/keywords.js.map +1 -1
- package/lib/shared-runtime.d.ts +1 -0
- package/lib/shared-runtime.d.ts.map +1 -1
- package/lib/shared-runtime.js +2 -1
- package/lib/shared-runtime.js.map +1 -1
- package/lib/stats-card.d.ts +2 -2
- package/lib/stats-card.d.ts.map +1 -1
- package/lib/stats-card.js +15 -14
- package/lib/stats-card.js.map +1 -1
- package/lib/stats-data.d.ts +3 -2
- package/lib/stats-data.d.ts.map +1 -1
- package/lib/stats-data.js +13 -12
- package/lib/stats-data.js.map +1 -1
- package/lib/stats-lib.d.ts.map +1 -1
- package/lib/stats-lib.js +8 -7
- package/lib/stats-lib.js.map +1 -1
- package/lib/teach-lib.d.ts +1 -1
- package/lib/teach-lib.d.ts.map +1 -1
- package/lib/teach-lib.js +27 -26
- package/lib/teach-lib.js.map +1 -1
- package/package.json +12 -12
- package/skills/checkin/tools/checkin_query/index.js +5 -4
- package/skills/checkin/tools/checkin_query/index.ts +5 -4
- package/skills/checkin/tools/checkin_rank/index.js +4 -3
- package/skills/checkin/tools/checkin_rank/index.ts +4 -3
- package/skills/group-daily-analysis/tools/group_announce/index.js +3 -2
- package/skills/group-daily-analysis/tools/group_announce/index.ts +3 -2
- package/skills/group-daily-analysis/tools/stats_query/index.js +4 -3
- package/skills/group-daily-analysis/tools/stats_query/index.ts +4 -3
- package/skills/group-daily-analysis/tools/stats_user/index.js +4 -3
- package/skills/group-daily-analysis/tools/stats_user/index.ts +4 -3
- package/src/analysis-card.ts +13 -11
- package/src/analysis.ts +15 -13
- package/src/checkin-lib.ts +23 -21
- package/src/conversation-scope.ts +1 -0
- package/src/i18n.ts +480 -0
- package/src/keywords.ts +9 -7
- package/src/shared-runtime.ts +3 -1
- package/src/stats-card.ts +17 -16
- package/src/stats-data.ts +14 -12
- package/src/stats-lib.ts +8 -7
- package/src/teach-lib.ts +27 -26
package/src/stats-data.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Locale } from 'zhin.js/i18n';
|
|
2
|
+
import { messages as t } from './i18n.js';
|
|
1
3
|
export interface StatsRankEntry {
|
|
2
4
|
rank: number;
|
|
3
5
|
userId: string;
|
|
@@ -75,27 +77,27 @@ export function buildStatsRankReportData(
|
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
export function formatRankText(data: StatsRankReportData): string {
|
|
79
|
-
if (data.empty) return
|
|
80
|
+
export function formatRankText(data: StatsRankReportData, locale?: Locale): string {
|
|
81
|
+
if (data.empty) return t(locale, 'statsEmpty', { title: data.title });
|
|
80
82
|
const medals = ["🥇", "🥈", "🥉"];
|
|
81
83
|
const lines = data.entries.map((entry) => {
|
|
82
84
|
const prefix = entry.rank <= 3 ? medals[entry.rank - 1] : `${entry.rank}.`;
|
|
83
|
-
return
|
|
85
|
+
return t(locale, 'statsRow', { prefix, name: entry.name, count: entry.count });
|
|
84
86
|
});
|
|
85
|
-
let footer =
|
|
87
|
+
let footer = t(locale, 'statsFooter', { people: data.participantCount, messages: data.totalMessages });
|
|
86
88
|
if (data.myRank != null && data.myCount != null) {
|
|
87
|
-
footer +=
|
|
89
|
+
footer += t(locale, 'statsMyFooter', { rank: data.myRank, count: data.myCount });
|
|
88
90
|
}
|
|
89
91
|
return `${data.title}\n${lines.join("\n")}${footer}`;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
export function formatMyStatsText(data: MyStatsReportData): string {
|
|
94
|
+
export function formatMyStatsText(data: MyStatsReportData, locale?: Locale): string {
|
|
93
95
|
return [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
t(locale, 'myStatsTitle', { name: data.userName, scope: data.scope }),
|
|
97
|
+
t(locale, 'todayMessages', { count: data.todayCount }),
|
|
98
|
+
t(locale, 'weekMessages', { count: data.weekCount }),
|
|
99
|
+
t(locale, 'monthMessages', { count: data.monthCount }),
|
|
100
|
+
t(locale, 'totalMessages', { count: data.totalCount }),
|
|
101
|
+
t(locale, 'activeDays', { count: data.activeDays }),
|
|
100
102
|
].join("\n");
|
|
101
103
|
}
|
package/src/stats-lib.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
import { conversationKey, requireConversation, type ConversationInput } from './conversation-scope.js';
|
|
2
3
|
import type { GroupSuiteConfig } from './config.js';
|
|
3
4
|
import { getStatsModel } from './db-store.js';
|
|
@@ -164,20 +165,20 @@ export async function statsRankText(
|
|
|
164
165
|
const stats = await queryStats(groupId, fromDate, runtime);
|
|
165
166
|
const { id: userId } = resolveSender(input);
|
|
166
167
|
const data = buildStatsRankReportData(stats, title, cfg.rankSize, userId);
|
|
167
|
-
return formatRankText(data);
|
|
168
|
+
return formatRankText(data, input.locale);
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
export async function myStatsText(input: MessageInput, runtime: GroupSuiteRuntime): Promise<string> {
|
|
171
172
|
await flushStatsBuffer(runtime);
|
|
172
173
|
const M = getStatsModel(runtime.db);
|
|
173
|
-
if (!M) return '
|
|
174
|
+
if (!M) return t(input.locale, 'statsDb');
|
|
174
175
|
const { id: userId, name: userName } = resolveSender(input);
|
|
175
|
-
if (!userId) return '
|
|
176
|
+
if (!userId) return t(input.locale, 'senderMissing');
|
|
176
177
|
const groupId = resolveGroupId(input);
|
|
177
178
|
const rows = (groupId
|
|
178
179
|
? await M.select().where({ user_id: userId, group_id: groupId })
|
|
179
180
|
: await M.select().where({ user_id: userId })) as Record<string, unknown>[];
|
|
180
|
-
if (rows.length === 0) return '
|
|
181
|
+
if (rows.length === 0) return t(input.locale, 'myStatsEmpty');
|
|
181
182
|
const today = todayStr();
|
|
182
183
|
const weekStart = weekStartStr();
|
|
183
184
|
const monthStart = monthStartStr();
|
|
@@ -193,13 +194,13 @@ export async function myStatsText(input: MessageInput, runtime: GroupSuiteRuntim
|
|
|
193
194
|
if (row.date === today) todayCount += c;
|
|
194
195
|
}
|
|
195
196
|
const data: MyStatsReportData = {
|
|
196
|
-
userName: userName || '
|
|
197
|
-
scope: groupId ? '
|
|
197
|
+
userName: userName || t(input.locale, 'you'),
|
|
198
|
+
scope: groupId ? t(input.locale, 'thisGroup') : t(input.locale, 'global'),
|
|
198
199
|
todayCount,
|
|
199
200
|
weekCount,
|
|
200
201
|
monthCount,
|
|
201
202
|
totalCount,
|
|
202
203
|
activeDays: rows.length,
|
|
203
204
|
};
|
|
204
|
-
return formatMyStatsText(data);
|
|
205
|
+
return formatMyStatsText(data, input.locale);
|
|
205
206
|
}
|
package/src/teach-lib.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { messages as t } from './i18n.js';
|
|
1
2
|
import type { ConversationInput } from './conversation-scope.js';
|
|
2
3
|
import type { GroupSuiteConfig } from './config.js';
|
|
3
4
|
import { getTeachModel } from './db-store.js';
|
|
@@ -8,8 +9,7 @@ import {
|
|
|
8
9
|
} from './shared-runtime.js';
|
|
9
10
|
import type { GroupSuiteRuntime } from './runtime-state.js';
|
|
10
11
|
|
|
11
|
-
export const TEACH_USAGE_HINT =
|
|
12
|
-
'格式:teach 关键词 回答(回答可含空格),或 teach 问题|答案';
|
|
12
|
+
export const TEACH_USAGE_HINT = '格式:关键词 回答,或 问题|答案';
|
|
13
13
|
|
|
14
14
|
function isSafeRegex(pattern: string): boolean {
|
|
15
15
|
if (pattern.length > 200) return false;
|
|
@@ -43,12 +43,13 @@ function processAnswer(
|
|
|
43
43
|
answer: string,
|
|
44
44
|
sender: { id: string; name: string },
|
|
45
45
|
match?: RegExpMatchArray,
|
|
46
|
+
locale?: import('zhin.js/i18n').Locale,
|
|
46
47
|
): string {
|
|
47
48
|
let result = answer;
|
|
48
|
-
result = result.replace(/\{sender\}/g, sender.name || '
|
|
49
|
+
result = result.replace(/\{sender\}/g, sender.name || t(locale, 'you'));
|
|
49
50
|
result = result.replace(/\{sender\.id\}/g, sender.id || '');
|
|
50
|
-
result = result.replace(/\{time\}/g, new Date().toLocaleTimeString('zh-CN'));
|
|
51
|
-
result = result.replace(/\{date\}/g, new Date().toLocaleDateString('zh-CN'));
|
|
51
|
+
result = result.replace(/\{time\}/g, new Date().toLocaleTimeString(locale ?? 'zh-CN'));
|
|
52
|
+
result = result.replace(/\{date\}/g, new Date().toLocaleDateString(locale ?? 'zh-CN'));
|
|
52
53
|
if (match) {
|
|
53
54
|
for (let i = 1; i < match.length; i++) {
|
|
54
55
|
result = result.replace(new RegExp(`\\$${i}`, 'g'), match[i] || '');
|
|
@@ -109,14 +110,14 @@ export async function teachAdd(
|
|
|
109
110
|
runtime: GroupSuiteRuntime,
|
|
110
111
|
): Promise<string> {
|
|
111
112
|
const QA = getTeachModel(runtime.db);
|
|
112
|
-
if (!QA) return '
|
|
113
|
-
if (regex && !cfg.teachAllowRegex) return '
|
|
113
|
+
if (!QA) return t(input.locale, 'teachRetry');
|
|
114
|
+
if (regex && !cfg.teachAllowRegex) return t(input.locale, 'regexDisabled');
|
|
114
115
|
|
|
115
116
|
const parsed = parseTeachPair(payload.trim());
|
|
116
117
|
if (!parsed) {
|
|
117
118
|
return regex
|
|
118
|
-
?
|
|
119
|
-
:
|
|
119
|
+
? t(input.locale, 'regexUsage')
|
|
120
|
+
: t(input.locale, 'teachUsage');
|
|
120
121
|
}
|
|
121
122
|
const { question, answer } = parsed;
|
|
122
123
|
|
|
@@ -124,9 +125,9 @@ export async function teachAdd(
|
|
|
124
125
|
try {
|
|
125
126
|
new RegExp(question, 'i');
|
|
126
127
|
} catch (e) {
|
|
127
|
-
return
|
|
128
|
+
return t(input.locale, 'invalidRegex', { error: (e as Error).message });
|
|
128
129
|
}
|
|
129
|
-
if (!isSafeRegex(question)) return '
|
|
130
|
+
if (!isSafeRegex(question)) return t(input.locale, 'unsafeRegex');
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
@@ -138,7 +139,7 @@ export async function teachAdd(
|
|
|
138
139
|
context_id: ctxId,
|
|
139
140
|
})) as Record<string, unknown>[];
|
|
140
141
|
if (existing.length >= cfg.teachMaxPerGroup) {
|
|
141
|
-
return
|
|
142
|
+
return t(input.locale, 'teachLimit', { limit: cfg.teachMaxPerGroup });
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -157,7 +158,7 @@ export async function teachAdd(
|
|
|
157
158
|
is_regex?: number | boolean;
|
|
158
159
|
}),
|
|
159
160
|
);
|
|
160
|
-
return
|
|
161
|
+
return t(input.locale, 'teachUpdated', { question, answer });
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
await QA.insert({
|
|
@@ -174,8 +175,8 @@ export async function teachAdd(
|
|
|
174
175
|
});
|
|
175
176
|
|
|
176
177
|
return regex
|
|
177
|
-
?
|
|
178
|
-
:
|
|
178
|
+
? t(input.locale, 'regexLearned', { question, answer })
|
|
179
|
+
: t(input.locale, 'teachLearned', { question, answer });
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
export async function teachList(
|
|
@@ -185,24 +186,24 @@ export async function teachList(
|
|
|
185
186
|
runtime: GroupSuiteRuntime,
|
|
186
187
|
): Promise<string> {
|
|
187
188
|
const QA = getTeachModel(runtime.db);
|
|
188
|
-
if (!QA) return '
|
|
189
|
+
if (!QA) return t(input.locale, 'teachDb');
|
|
189
190
|
const safePage = Math.max(1, page);
|
|
190
191
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
191
192
|
const allItems = (await QA.select().where(
|
|
192
193
|
{ context_type: ctxType, context_id: ctxId },
|
|
193
194
|
)) as Record<string, unknown>[];
|
|
194
|
-
if (allItems.length === 0) return '
|
|
195
|
+
if (allItems.length === 0) return t(input.locale, 'teachEmpty');
|
|
195
196
|
const totalPages = Math.ceil(allItems.length / cfg.teachPageSize);
|
|
196
197
|
const pageNum = Math.min(safePage, totalPages);
|
|
197
198
|
const start = (pageNum - 1) * cfg.teachPageSize;
|
|
198
199
|
const pageItems = allItems.slice(start, start + cfg.teachPageSize);
|
|
199
200
|
const lines = pageItems.map((item, i) => {
|
|
200
|
-
const prefix = item.is_regex ? '
|
|
201
|
+
const prefix = item.is_regex ? t(input.locale, 'regex') : t(input.locale, 'exact');
|
|
201
202
|
const q = item.is_regex ? `/${item.question}/` : item.question;
|
|
202
203
|
return `${start + i + 1}. ${prefix} ${q} → ${item.answer}`;
|
|
203
204
|
});
|
|
204
|
-
const header = '
|
|
205
|
-
return
|
|
205
|
+
const header = t(input.locale, 'teachTitle');
|
|
206
|
+
return t(input.locale, 'teachPage', { header, lines: lines.join('\n'), page: pageNum, pages: totalPages, count: allItems.length });
|
|
206
207
|
}
|
|
207
208
|
|
|
208
209
|
export async function teachForget(
|
|
@@ -211,16 +212,16 @@ export async function teachForget(
|
|
|
211
212
|
runtime: GroupSuiteRuntime,
|
|
212
213
|
): Promise<string> {
|
|
213
214
|
const QA = getTeachModel(runtime.db);
|
|
214
|
-
if (!QA) return '
|
|
215
|
+
if (!QA) return t(input.locale, 'teachDb');
|
|
215
216
|
const question = questionRaw.trim();
|
|
216
|
-
if (!question) return '
|
|
217
|
+
if (!question) return t(input.locale, 'questionRequired');
|
|
217
218
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
218
219
|
const items = (await QA.select().where({
|
|
219
220
|
question,
|
|
220
221
|
context_type: ctxType,
|
|
221
222
|
context_id: ctxId,
|
|
222
223
|
})) as Record<string, unknown>[];
|
|
223
|
-
if (items.length === 0) return
|
|
224
|
+
if (items.length === 0) return t(input.locale, 'questionMissing', { question });
|
|
224
225
|
await QA.delete().where(
|
|
225
226
|
qaWhereKey(items[0] as {
|
|
226
227
|
question: string;
|
|
@@ -229,7 +230,7 @@ export async function teachForget(
|
|
|
229
230
|
is_regex?: number | boolean;
|
|
230
231
|
}),
|
|
231
232
|
);
|
|
232
|
-
return
|
|
233
|
+
return t(input.locale, 'questionRemoved', { question });
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
/** Try teach auto-reply; returns reply text or null. */
|
|
@@ -274,12 +275,12 @@ export async function tryTeachReply(
|
|
|
274
275
|
if (matched.is_regex) {
|
|
275
276
|
try {
|
|
276
277
|
const m = content.match(new RegExp(String(matched.question), 'i'));
|
|
277
|
-
answer = processAnswer(answer, sender, m || undefined);
|
|
278
|
+
answer = processAnswer(answer, sender, m || undefined, input.locale);
|
|
278
279
|
} catch {
|
|
279
280
|
/* ignore */
|
|
280
281
|
}
|
|
281
282
|
} else {
|
|
282
|
-
answer = processAnswer(answer, sender);
|
|
283
|
+
answer = processAnswer(answer, sender, undefined, input.locale);
|
|
283
284
|
}
|
|
284
285
|
return answer;
|
|
285
286
|
}
|