@zhin.js/plugin-group-suite 1.1.0 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +2 -2
  2. package/commands/{checkin.js → checkin/index.js} +3 -3
  3. package/commands/{checkin.ts → checkin/index.ts} +3 -3
  4. package/commands/{forget.js → forget/index.js} +2 -2
  5. package/commands/{forget.ts → forget/index.ts} +3 -3
  6. package/commands/keyword-add/{[keyword].js → [keyword]/index.js} +3 -3
  7. package/commands/keyword-add/{[keyword].ts → [keyword]/index.ts} +4 -4
  8. package/commands/{keyword-list.js → keyword-list/index.js} +3 -3
  9. package/commands/{keyword-list.ts → keyword-list/index.ts} +4 -4
  10. package/commands/keyword-remove/{[keyword].js → [keyword]/index.js} +3 -3
  11. package/commands/keyword-remove/{[keyword].ts → [keyword]/index.ts} +4 -4
  12. package/commands/{mypoints.js → mypoints/index.js} +2 -2
  13. package/commands/{mypoints.ts → mypoints/index.ts} +3 -3
  14. package/commands/{mystats.js → mystats/index.js} +2 -2
  15. package/commands/{mystats.ts → mystats/index.ts} +3 -3
  16. package/commands/{rank.js → rank/index.js} +3 -3
  17. package/commands/{rank.ts → rank/index.ts} +3 -3
  18. package/commands/{stats.js → stats/index.js} +4 -4
  19. package/commands/{stats.ts → stats/index.ts} +4 -4
  20. package/commands/{stats-rank.js → stats-rank/index.js} +3 -3
  21. package/commands/{stats-rank.ts → stats-rank/index.ts} +3 -3
  22. package/commands/{stats-week.js → stats-week/index.js} +3 -3
  23. package/commands/{stats-week.ts → stats-week/index.ts} +3 -3
  24. package/commands/{teach.js → teach/index.js} +3 -3
  25. package/commands/{teach.ts → teach/index.ts} +3 -3
  26. package/commands/teach-list/{[[page]].js → [[page]]/index.js} +3 -3
  27. package/commands/teach-list/{[[page]].ts → [[page]]/index.ts} +3 -3
  28. package/commands/{teach-regex.js → teach-regex/index.js} +3 -3
  29. package/commands/{teach-regex.ts → teach-regex/index.ts} +3 -3
  30. package/lib/checkin-lib.d.ts +3 -3
  31. package/lib/checkin-lib.d.ts.map +1 -1
  32. package/lib/checkin-lib.js +9 -10
  33. package/lib/checkin-lib.js.map +1 -1
  34. package/lib/db-store.d.ts +3 -10
  35. package/lib/db-store.d.ts.map +1 -1
  36. package/lib/db-store.js +7 -34
  37. package/lib/db-store.js.map +1 -1
  38. package/lib/index.d.ts +4 -4
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +4 -4
  41. package/lib/index.js.map +1 -1
  42. package/lib/keyword-store.d.ts +4 -5
  43. package/lib/keyword-store.d.ts.map +1 -1
  44. package/lib/keyword-store.js +4 -8
  45. package/lib/keyword-store.js.map +1 -1
  46. package/lib/memory-store.d.ts +1 -1
  47. package/lib/memory-store.js +1 -1
  48. package/lib/runtime-state.d.ts +3 -4
  49. package/lib/runtime-state.d.ts.map +1 -1
  50. package/lib/runtime-state.js +2 -8
  51. package/lib/runtime-state.js.map +1 -1
  52. package/lib/stats-lib.d.ts +5 -7
  53. package/lib/stats-lib.d.ts.map +1 -1
  54. package/lib/stats-lib.js +5 -10
  55. package/lib/stats-lib.js.map +1 -1
  56. package/lib/tables.js +1 -1
  57. package/lib/teach-lib.d.ts +4 -6
  58. package/lib/teach-lib.d.ts.map +1 -1
  59. package/lib/teach-lib.js +6 -11
  60. package/lib/teach-lib.js.map +1 -1
  61. package/middlewares/{keyword-reply.js → keyword-reply/index.js} +4 -4
  62. package/middlewares/{keyword-reply.ts → keyword-reply/index.ts} +4 -4
  63. package/middlewares/{stats-count.js → stats-count/index.js} +2 -2
  64. package/middlewares/{stats-count.ts → stats-count/index.ts} +3 -3
  65. package/middlewares/{teach-reply.js → teach-reply/index.js} +3 -3
  66. package/middlewares/{teach-reply.ts → teach-reply/index.ts} +3 -3
  67. package/package.json +18 -14
  68. package/plugin.js +0 -2
  69. package/skills/checkin/tools/checkin_query/index.js +42 -0
  70. package/skills/checkin/tools/checkin_query/index.ts +41 -0
  71. package/skills/checkin/tools/checkin_rank/index.js +34 -0
  72. package/skills/checkin/tools/checkin_rank/index.ts +34 -0
  73. package/skills/group-daily-analysis/SKILL.md +36 -0
  74. package/skills/group-daily-analysis/tools/group_announce/index.js +14 -0
  75. package/skills/group-daily-analysis/tools/group_announce/index.ts +14 -0
  76. package/skills/group-daily-analysis/tools/stats_query/index.js +35 -0
  77. package/skills/group-daily-analysis/tools/stats_query/index.ts +36 -0
  78. package/skills/group-daily-analysis/tools/stats_user/index.js +50 -0
  79. package/skills/group-daily-analysis/tools/stats_user/index.ts +46 -0
  80. package/src/checkin-lib.ts +15 -13
  81. package/src/db-store.ts +6 -38
  82. package/src/index.ts +0 -8
  83. package/src/keyword-store.ts +4 -10
  84. package/src/memory-store.ts +1 -1
  85. package/src/runtime-state.ts +5 -8
  86. package/src/stats-lib.ts +10 -17
  87. package/src/tables.ts +1 -1
  88. package/src/teach-lib.ts +11 -18
  89. package/agent/skills/group-daily-analysis.md +0 -29
  90. package/agent/tools/group_announce.ts +0 -12
  91. package/tools/checkin-query/checkin-query.tool.md +0 -11
  92. package/tools/checkin-query/handler.js +0 -22
  93. package/tools/checkin-query/handler.ts +0 -22
  94. package/tools/checkin-rank/checkin-rank.tool.md +0 -11
  95. package/tools/checkin-rank/handler.js +0 -15
  96. package/tools/checkin-rank/handler.ts +0 -16
  97. package/tools/stats-query/handler.js +0 -28
  98. package/tools/stats-query/handler.ts +0 -31
  99. package/tools/stats-query/stats-query.tool.md +0 -16
  100. package/tools/stats-user/handler.js +0 -29
  101. package/tools/stats-user/handler.ts +0 -29
  102. package/tools/stats-user/stats-user.tool.md +0 -12
  103. /package/{agent/skills/checkin.md → skills/checkin/SKILL.md} +0 -0
package/src/stats-lib.ts CHANGED
@@ -25,8 +25,6 @@ export function monthStartStr(): string {
25
25
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`;
26
26
  }
27
27
 
28
- const buffer = new Map<string, PendingStatsIncrement>();
29
-
30
28
  function bufferKey(userId: string, groupId: string, date: string): string {
31
29
  return `${userId}:${groupId}:${date}`;
32
30
  }
@@ -50,8 +48,8 @@ export function recordMessage(input: {
50
48
  sender?: { readonly id: string; readonly name?: string };
51
49
  conversation?: { readonly kind?: string; readonly id?: string };
52
50
  metadata?: Readonly<Record<string, unknown>>;
53
- }, runtime?: GroupSuiteRuntime): void {
54
- const targetBuffer = runtime?.statsBuffer ?? buffer;
51
+ }, runtime: GroupSuiteRuntime): void {
52
+ const targetBuffer = runtime.statsBuffer;
55
53
  const { id: userId, name: userName } = resolveSender(input);
56
54
  if (!userId) return;
57
55
  const groupId = resolveGroupId(input);
@@ -71,9 +69,9 @@ export function recordMessage(input: {
71
69
  }
72
70
  }
73
71
 
74
- export async function flushStatsBuffer(runtime?: GroupSuiteRuntime): Promise<void> {
75
- const targetBuffer = runtime?.statsBuffer ?? buffer;
76
- const M = getStatsModel(runtime?.db);
72
+ export async function flushStatsBuffer(runtime: GroupSuiteRuntime): Promise<void> {
73
+ const targetBuffer = runtime.statsBuffer;
74
+ const M = getStatsModel(runtime.db);
77
75
  if (!M || targetBuffer.size === 0) return;
78
76
  for (const [key, entry] of [...targetBuffer.entries()]) {
79
77
  // 快照本次要落库的计数;flush 期间新累计的部分留在缓冲
@@ -116,9 +114,9 @@ export async function flushStatsBuffer(runtime?: GroupSuiteRuntime): Promise<voi
116
114
  export async function queryStats(
117
115
  groupId: string,
118
116
  fromDate: string,
119
- runtime?: GroupSuiteRuntime,
117
+ runtime: GroupSuiteRuntime,
120
118
  ): Promise<Map<string, { name: string; count: number }>> {
121
- const M = getStatsModel(runtime?.db);
119
+ const M = getStatsModel(runtime.db);
122
120
  if (!M) return new Map();
123
121
  const all = (groupId
124
122
  ? await M.select().where({ group_id: groupId })
@@ -152,7 +150,7 @@ export async function statsRankText(
152
150
  cfg: GroupSuiteConfig,
153
151
  fromDate: string,
154
152
  title: string,
155
- runtime?: GroupSuiteRuntime,
153
+ runtime: GroupSuiteRuntime,
156
154
  ): Promise<string> {
157
155
  await flushStatsBuffer(runtime);
158
156
  const groupId = resolveGroupId(input);
@@ -162,9 +160,9 @@ export async function statsRankText(
162
160
  return formatRankText(data);
163
161
  }
164
162
 
165
- export async function myStatsText(input: MessageInput, runtime?: GroupSuiteRuntime): Promise<string> {
163
+ export async function myStatsText(input: MessageInput, runtime: GroupSuiteRuntime): Promise<string> {
166
164
  await flushStatsBuffer(runtime);
167
- const M = getStatsModel(runtime?.db);
165
+ const M = getStatsModel(runtime.db);
168
166
  if (!M) return '统计数据库尚未就绪';
169
167
  const { id: userId, name: userName } = resolveSender(input);
170
168
  if (!userId) return '无法获取用户信息';
@@ -198,8 +196,3 @@ export async function myStatsText(input: MessageInput, runtime?: GroupSuiteRunti
198
196
  };
199
197
  return formatMyStatsText(data);
200
198
  }
201
-
202
- /** Test helper */
203
- export function resetStatsBuffer(): void {
204
- buffer.clear();
205
- }
package/src/tables.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Group-suite table schemas for DatabaseHost / legacy DatabaseFeature.
2
+ * Group-suite table schemas for DatabaseHost.
3
3
  */
4
4
  import {
5
5
  CHECKIN_TABLE,
package/src/teach-lib.ts CHANGED
@@ -7,8 +7,6 @@ import {
7
7
  } from './shared-runtime.js';
8
8
  import type { GroupSuiteRuntime } from './runtime-state.js';
9
9
 
10
- const cooldownMap = new Map<string, number>();
11
-
12
10
  export const TEACH_USAGE_HINT =
13
11
  '格式:teach 关键词 回答(回答可含空格),或 teach 问题|答案';
14
12
 
@@ -84,9 +82,9 @@ async function findMatch(
84
82
  ctxType: string,
85
83
  ctxId: string,
86
84
  cfg: GroupSuiteConfig,
87
- runtime?: GroupSuiteRuntime,
85
+ runtime: GroupSuiteRuntime,
88
86
  ): Promise<Record<string, unknown> | null> {
89
- const QA = getTeachModel(runtime?.db);
87
+ const QA = getTeachModel(runtime.db);
90
88
  if (!QA) return null;
91
89
  const allItems = (await QA.select()) as Record<string, unknown>[];
92
90
  const candidates = allItems.filter(
@@ -115,9 +113,9 @@ export async function teachAdd(
115
113
  cfg: GroupSuiteConfig,
116
114
  payload: string,
117
115
  regex = false,
118
- runtime?: GroupSuiteRuntime,
116
+ runtime: GroupSuiteRuntime,
119
117
  ): Promise<string> {
120
- const QA = getTeachModel(runtime?.db);
118
+ const QA = getTeachModel(runtime.db);
121
119
  if (!QA) return '问答数据库尚未就绪,请稍后重试';
122
120
  if (regex && !cfg.teachAllowRegex) return '管理员已禁用正则问答';
123
121
 
@@ -191,9 +189,9 @@ export async function teachList(
191
189
  input: MessageInput,
192
190
  cfg: GroupSuiteConfig,
193
191
  page = 1,
194
- runtime?: GroupSuiteRuntime,
192
+ runtime: GroupSuiteRuntime,
195
193
  ): Promise<string> {
196
- const QA = getTeachModel(runtime?.db);
194
+ const QA = getTeachModel(runtime.db);
197
195
  if (!QA) return '问答数据库尚未就绪';
198
196
  const safePage = Math.max(1, page);
199
197
  const { type: ctxType, id: ctxId } = resolveContextKey(input);
@@ -219,9 +217,9 @@ export async function teachList(
219
217
  export async function teachForget(
220
218
  input: MessageInput,
221
219
  questionRaw: string,
222
- runtime?: GroupSuiteRuntime,
220
+ runtime: GroupSuiteRuntime,
223
221
  ): Promise<string> {
224
- const QA = getTeachModel(runtime?.db);
222
+ const QA = getTeachModel(runtime.db);
225
223
  if (!QA) return '问答数据库尚未就绪';
226
224
  const question = questionRaw.trim();
227
225
  if (!question) return '请提供要删除的问题';
@@ -247,7 +245,7 @@ export async function teachForget(
247
245
  export async function tryTeachReply(
248
246
  input: MessageInput,
249
247
  cfg: GroupSuiteConfig,
250
- runtime?: GroupSuiteRuntime,
248
+ runtime: GroupSuiteRuntime,
251
249
  ): Promise<string | null> {
252
250
  const content = typeof input.content === 'string' ? input.content.trim() : '';
253
251
  if (!content) return null;
@@ -256,12 +254,12 @@ export async function tryTeachReply(
256
254
  if (!matched) return null;
257
255
 
258
256
  const cooldownKey = `${matched.question}:${ctxType}:${ctxId}:${matched.is_regex ?? 0}`;
259
- const cooldowns = runtime?.teachCooldowns ?? cooldownMap;
257
+ const cooldowns = runtime.teachCooldowns;
260
258
  const last = cooldowns.get(cooldownKey);
261
259
  if (last && Date.now() - last < cfg.teachCooldownMs) return null;
262
260
  cooldowns.set(cooldownKey, Date.now());
263
261
 
264
- const QA = getTeachModel(runtime?.db);
262
+ const QA = getTeachModel(runtime.db);
265
263
  if (QA) {
266
264
  try {
267
265
  await QA.update({
@@ -294,8 +292,3 @@ export async function tryTeachReply(
294
292
  }
295
293
  return answer;
296
294
  }
297
-
298
- /** Test helper */
299
- export function resetTeachCooldown(): void {
300
- cooldownMap.clear();
301
- }
@@ -1,29 +0,0 @@
1
- ---
2
- name: group-daily-analysis
3
- description: >-
4
- 群日常分析:基于收件箱统计群消息数量、参与人数、活跃时段,
5
- 支持按群启用/禁用和定时分析报告。通过命令和定时任务运行,无 AI 工具。
6
- keywords:
7
- - 群分析
8
- - 日常分析
9
- - 群统计
10
- - 活跃
11
- - 报告
12
- tags:
13
- - group
14
- - analysis
15
- - stats
16
- - inbox
17
- tools: []
18
- ---
19
-
20
- # 群日常分析
21
-
22
- 基于收件箱数据自动分析群活跃度。无 AI 工具可调用。
23
-
24
- ## 能力
25
-
26
- - 统计群消息数量、参与人数、活跃时段分布
27
- - 支持按群启用/禁用分析功能
28
- - 定时任务自动生成分析报告推送到群内
29
- - 通过聊天命令管理分析设置
@@ -1,12 +0,0 @@
1
- import { defineAgentTool } from '@zhin.js/agent/tools';
2
- import { z } from 'zod';
3
-
4
- export default defineAgentTool<{ message: string }>({
5
- description: '向群聊发送公告/通知消息',
6
- inputSchema: z.object({ message: z.string().min(1) }),
7
- keywords: ['群公告', '通知', 'announce'],
8
- async execute({ message }) {
9
- if (!message?.trim()) return '公告内容不能为空';
10
- return `📢 群公告:\n${message}`;
11
- },
12
- });
@@ -1,11 +0,0 @@
1
- ---
2
- name: checkin_query
3
- description: 查询用户的签到积分信息
4
- parameters:
5
- user_id:
6
- type: string
7
- description: 用户ID(可选,不填则返回统计摘要)
8
- tags: [签到, 积分, 查询]
9
- keywords: [签到, 积分, 查询积分]
10
- handler: ./handler.ts
11
- ---
@@ -1,22 +0,0 @@
1
- // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { getCheckinModel } from "../../lib/db-store.js";
3
- import { todayStr } from "../../lib/shared-runtime.js";
4
- export default async function (args) {
5
- const M = getCheckinModel();
6
- if (!M)
7
- return '签到数据库尚未就绪';
8
- const userId = args.user_id;
9
- if (userId) {
10
- const rows = await M.select().where({ user_id: userId });
11
- if (rows.length === 0)
12
- return `用户 ${userId} 没有签到记录`;
13
- const u = rows[0];
14
- return `${u.user_name}: 积分=${u.points}, 累计=${u.total_checkins}天, 连续=${u.streak}天, 最长=${u.max_streak}天, 上次=${u.last_checkin}`;
15
- }
16
- const all = await M.select();
17
- const totalUsers = all.length;
18
- const totalPoints = all.reduce((s, u) => s + (u.points || 0), 0);
19
- const today = todayStr();
20
- const todayCount = all.filter((u) => u.last_checkin === today).length;
21
- return `签到系统统计\n总用户: ${totalUsers}\n总积分: ${totalPoints}\n今日签到: ${todayCount}人`;
22
- }
@@ -1,22 +0,0 @@
1
- import { getCheckinModel } from '../../src/db-store.js';
2
- import { todayStr } from '../../src/shared-runtime.js';
3
-
4
- export default async function (args: { user_id?: string }) {
5
- const M = getCheckinModel();
6
- if (!M) return '签到数据库尚未就绪';
7
-
8
- const userId = args.user_id;
9
- if (userId) {
10
- const rows: any[] = await M.select().where({ user_id: userId });
11
- if (rows.length === 0) return `用户 ${userId} 没有签到记录`;
12
- const u = rows[0];
13
- return `${u.user_name}: 积分=${u.points}, 累计=${u.total_checkins}天, 连续=${u.streak}天, 最长=${u.max_streak}天, 上次=${u.last_checkin}`;
14
- }
15
-
16
- const all: any[] = await M.select();
17
- const totalUsers = all.length;
18
- const totalPoints = all.reduce((s: number, u: any) => s + (u.points || 0), 0);
19
- const today = todayStr();
20
- const todayCount = all.filter((u: any) => u.last_checkin === today).length;
21
- return `签到系统统计\n总用户: ${totalUsers}\n总积分: ${totalPoints}\n今日签到: ${todayCount}人`;
22
- }
@@ -1,11 +0,0 @@
1
- ---
2
- name: checkin_rank
3
- description: 获取积分排行榜数据
4
- parameters:
5
- limit:
6
- type: number
7
- description: 返回前 N 名(默认10)
8
- tags: [签到, 排行]
9
- keywords: [排行, 积分排行, 签到排行]
10
- handler: ./handler.ts
11
- ---
@@ -1,15 +0,0 @@
1
- // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { getCheckinModel } from "../../lib/db-store.js";
3
- export default async function (args) {
4
- const M = getCheckinModel();
5
- if (!M)
6
- return '签到数据库尚未就绪';
7
- const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 50);
8
- const all = await M.select();
9
- const sorted = all.sort((a, b) => (b.points || 0) - (a.points || 0)).slice(0, limit);
10
- if (sorted.length === 0)
11
- return '暂无排行数据';
12
- return sorted
13
- .map((u, i) => `${i + 1}. ${u.user_name || u.user_id} — ${u.points}分 (连续${u.streak}天)`)
14
- .join('\n');
15
- }
@@ -1,16 +0,0 @@
1
- import { getCheckinModel } from '../../src/db-store.js';
2
-
3
- export default async function (args: { limit?: number }) {
4
- const M = getCheckinModel();
5
- if (!M) return '签到数据库尚未就绪';
6
-
7
- const limit = Math.min(Math.max(Number(args.limit) || 10, 1), 50);
8
- const all: any[] = await M.select();
9
- const sorted = all.sort((a: any, b: any) => (b.points || 0) - (a.points || 0)).slice(0, limit);
10
-
11
- if (sorted.length === 0) return '暂无排行数据';
12
-
13
- return sorted
14
- .map((u: any, i: number) => `${i + 1}. ${u.user_name || u.user_id} — ${u.points}分 (连续${u.streak}天)`)
15
- .join('\n');
16
- }
@@ -1,28 +0,0 @@
1
- // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { flushStatsBuffer, queryStats, weekStartStr, monthStartStr, } from "../../lib/stats-lib.js";
3
- import { todayStr } from "../../lib/shared-runtime.js";
4
- export default async function (args) {
5
- await flushStatsBuffer();
6
- const groupId = args.group_id || '';
7
- const period = args.period || 'today';
8
- let fromDate;
9
- switch (period) {
10
- case 'week':
11
- fromDate = weekStartStr();
12
- break;
13
- case 'month':
14
- fromDate = monthStartStr();
15
- break;
16
- default:
17
- fromDate = todayStr();
18
- break;
19
- }
20
- const stats = await queryStats(groupId, fromDate);
21
- if (stats.size === 0)
22
- return `${period} 暂无消息统计数据`;
23
- const sorted = [...stats.entries()].sort((a, b) => b[1].count - a[1].count);
24
- const total = sorted.reduce((s, [, v]) => s + v.count, 0);
25
- const top10 = sorted.slice(0, 10);
26
- const lines = top10.map(([, v], i) => `${i + 1}. ${v.name} — ${v.count}条`);
27
- return `消息统计 (${period})\n总消息: ${total}条, 活跃用户: ${stats.size}人\n${lines.join('\n')}`;
28
- }
@@ -1,31 +0,0 @@
1
- import {
2
- flushStatsBuffer,
3
- queryStats,
4
- weekStartStr,
5
- monthStartStr,
6
- } from '../../src/stats-lib.js';
7
- import { todayStr } from '../../src/shared-runtime.js';
8
-
9
- export default async function (args: { group_id?: string; period?: string }) {
10
- await flushStatsBuffer();
11
- const groupId = args.group_id || '';
12
- const period = args.period || 'today';
13
-
14
- let fromDate: string;
15
- switch (period) {
16
- case 'week': fromDate = weekStartStr(); break;
17
- case 'month': fromDate = monthStartStr(); break;
18
- default: fromDate = todayStr(); break;
19
- }
20
-
21
- const stats = await queryStats(groupId, fromDate);
22
- if (stats.size === 0) return `${period} 暂无消息统计数据`;
23
-
24
- const sorted = [...stats.entries()].sort((a, b) => b[1].count - a[1].count);
25
- const total = sorted.reduce((s, [, v]) => s + v.count, 0);
26
-
27
- const top10 = sorted.slice(0, 10);
28
- const lines = top10.map(([, v], i) => `${i + 1}. ${v.name} — ${v.count}条`);
29
-
30
- return `消息统计 (${period})\n总消息: ${total}条, 活跃用户: ${stats.size}人\n${lines.join('\n')}`;
31
- }
@@ -1,16 +0,0 @@
1
- ---
2
- name: stats_query
3
- description: 查询消息统计数据
4
- parameters:
5
- group_id:
6
- type: string
7
- description: 群ID(可选,不填查全局)
8
- period:
9
- type: string
10
- description: "时段: today/week/month(默认today)"
11
- enum: [today, week, month]
12
- default: today
13
- tags: [统计, 消息]
14
- keywords: [统计, 消息统计, 消息量]
15
- handler: ./handler.ts
16
- ---
@@ -1,29 +0,0 @@
1
- // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
- import { flushStatsBuffer, weekStartStr } from "../../lib/stats-lib.js";
3
- import { getStatsModel } from "../../lib/db-store.js";
4
- import { todayStr } from "../../lib/shared-runtime.js";
5
- export default async function (args) {
6
- await flushStatsBuffer();
7
- const M = getStatsModel();
8
- if (!M)
9
- return '统计数据库尚未就绪';
10
- const userId = args.user_id;
11
- if (!userId)
12
- return '请提供用户ID';
13
- const rows = await M.select().where({ user_id: userId });
14
- if (rows.length === 0)
15
- return `用户 ${userId} 暂无消息记录`;
16
- const today = todayStr();
17
- const weekStart = weekStartStr();
18
- let todayCount = 0, weekCount = 0, totalCount = 0;
19
- for (const row of rows) {
20
- const c = row.count || 0;
21
- totalCount += c;
22
- if (row.date >= weekStart)
23
- weekCount += c;
24
- if (row.date === today)
25
- todayCount += c;
26
- }
27
- const name = rows[0].user_name || userId;
28
- return `${name} 的统计\n今日: ${todayCount}条\n本周: ${weekCount}条\n总计: ${totalCount}条\n活跃天数: ${rows.length}天`;
29
- }
@@ -1,29 +0,0 @@
1
- import { flushStatsBuffer, weekStartStr } from '../../src/stats-lib.js';
2
- import { getStatsModel } from '../../src/db-store.js';
3
- import { todayStr } from '../../src/shared-runtime.js';
4
-
5
- export default async function (args: { user_id: string }) {
6
- await flushStatsBuffer();
7
- const M = getStatsModel();
8
- if (!M) return '统计数据库尚未就绪';
9
-
10
- const userId = args.user_id;
11
- if (!userId) return '请提供用户ID';
12
-
13
- const rows: any[] = await M.select().where({ user_id: userId });
14
- if (rows.length === 0) return `用户 ${userId} 暂无消息记录`;
15
-
16
- const today = todayStr();
17
- const weekStart = weekStartStr();
18
- let todayCount = 0, weekCount = 0, totalCount = 0;
19
-
20
- for (const row of rows) {
21
- const c = row.count || 0;
22
- totalCount += c;
23
- if (row.date >= weekStart) weekCount += c;
24
- if (row.date === today) todayCount += c;
25
- }
26
-
27
- const name = rows[0].user_name || userId;
28
- return `${name} 的统计\n今日: ${todayCount}条\n本周: ${weekCount}条\n总计: ${totalCount}条\n活跃天数: ${rows.length}天`;
29
- }
@@ -1,12 +0,0 @@
1
- ---
2
- name: stats_user
3
- description: 查询指定用户的消息统计
4
- parameters:
5
- user_id:
6
- type: string
7
- description: 用户ID
8
- required: true
9
- tags: [统计, 用户]
10
- keywords: [用户统计, 消息统计, 个人统计]
11
- handler: ./handler.ts
12
- ---