@zhin.js/plugin-group-suite 1.1.7 → 1.1.9
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 +55 -24
- package/commands/forget/index.js +1 -0
- package/commands/forget/index.ts +1 -0
- package/commands/keyword-add/[keyword]/index.js +10 -7
- package/commands/keyword-add/[keyword]/index.ts +11 -8
- package/commands/keyword-list/index.js +8 -5
- package/commands/keyword-list/index.ts +9 -6
- package/commands/keyword-remove/[keyword]/index.js +10 -6
- package/commands/keyword-remove/[keyword]/index.ts +11 -7
- package/commands/stats-card/index.js +23 -0
- package/commands/stats-card/index.ts +24 -0
- package/commands/teach/index.js +1 -0
- package/commands/teach/index.ts +1 -0
- package/commands/teach-regex/index.js +1 -0
- package/commands/teach-regex/index.ts +1 -0
- package/handlers/welcome/index.js +25 -0
- package/handlers/welcome/index.ts +24 -0
- package/lib/checkin-lib.d.ts +4 -24
- package/lib/checkin-lib.d.ts.map +1 -1
- package/lib/checkin-lib.js +3 -4
- package/lib/checkin-lib.js.map +1 -1
- package/lib/config.d.ts +4 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +2 -0
- package/lib/config.js.map +1 -1
- package/lib/conversation-scope.d.ts +21 -0
- package/lib/conversation-scope.d.ts.map +1 -0
- package/lib/conversation-scope.js +33 -0
- package/lib/conversation-scope.js.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/keyword-store.d.ts +4 -0
- package/lib/keyword-store.d.ts.map +1 -1
- package/lib/keyword-store.js +15 -0
- package/lib/keyword-store.js.map +1 -1
- package/lib/keywords.d.ts +21 -0
- package/lib/keywords.d.ts.map +1 -0
- package/lib/keywords.js +72 -0
- package/lib/keywords.js.map +1 -0
- package/lib/runtime-state.d.ts +5 -1
- package/lib/runtime-state.d.ts.map +1 -1
- package/lib/runtime-state.js.map +1 -1
- package/lib/shared-runtime.d.ts +3 -8
- package/lib/shared-runtime.d.ts.map +1 -1
- package/lib/shared-runtime.js +4 -10
- package/lib/shared-runtime.js.map +1 -1
- package/lib/stats-lib.d.ts +5 -26
- package/lib/stats-lib.d.ts.map +1 -1
- package/lib/stats-lib.js +29 -15
- package/lib/stats-lib.js.map +1 -1
- package/lib/teach-lib.d.ts +2 -9
- package/lib/teach-lib.d.ts.map +1 -1
- package/lib/teach-lib.js +6 -8
- package/lib/teach-lib.js.map +1 -1
- package/middlewares/keyword-reply/index.js +3 -5
- package/middlewares/keyword-reply/index.ts +3 -5
- package/middlewares/stats-count/index.js +3 -7
- package/middlewares/stats-count/index.ts +3 -7
- package/package.json +30 -13
- package/plugin.js +9 -9
- package/schedules/flush-stats/index.js +11 -0
- package/schedules/flush-stats/index.ts +11 -0
- package/schema.json +51 -10
- package/skills/checkin/tools/checkin_query/index.js +5 -8
- package/skills/checkin/tools/checkin_query/index.ts +5 -9
- package/skills/checkin/tools/checkin_rank/index.js +4 -7
- package/skills/checkin/tools/checkin_rank/index.ts +4 -7
- package/skills/group-daily-analysis/tools/stats_query/index.js +3 -4
- package/skills/group-daily-analysis/tools/stats_query/index.ts +3 -4
- package/skills/group-daily-analysis/tools/stats_user/index.js +4 -5
- package/skills/group-daily-analysis/tools/stats_user/index.ts +4 -5
- package/src/checkin-lib.ts +7 -7
- package/src/config.ts +6 -0
- package/src/conversation-scope.ts +45 -0
- package/src/index.ts +1 -0
- package/src/keyword-store.ts +22 -0
- package/src/keywords.ts +72 -0
- package/src/runtime-state.ts +5 -1
- package/src/shared-runtime.ts +5 -14
- package/src/stats-lib.ts +36 -29
- package/src/teach-lib.ts +8 -17
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
3
|
import { resolveGroupSuiteConfig } from "../../lib/config.js";
|
|
4
4
|
import { matchKeyword } from "../../lib/keyword-store.js";
|
|
5
|
-
import {
|
|
5
|
+
import { keywords } from "../../lib/keywords.js";
|
|
6
6
|
/**
|
|
7
7
|
* Keyword auto-reply (enabled via config.keywordReply).
|
|
8
8
|
* Uses Runtime Message.content / metadata (legacy used $raw / $channel).
|
|
@@ -15,9 +15,7 @@ export default defineMiddleware({
|
|
|
15
15
|
await next();
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
const channelType = String(meta.type ?? meta.channelType ?? '');
|
|
20
|
-
if (channelType === 'private') {
|
|
18
|
+
if (context.input.conversation.kind !== 'group') {
|
|
21
19
|
await next();
|
|
22
20
|
return;
|
|
23
21
|
}
|
|
@@ -26,7 +24,7 @@ export default defineMiddleware({
|
|
|
26
24
|
await next();
|
|
27
25
|
return;
|
|
28
26
|
}
|
|
29
|
-
const reply = matchKeyword(text,
|
|
27
|
+
const reply = matchKeyword(text, new Map(await keywords(context.input, context).read()));
|
|
30
28
|
if (reply) {
|
|
31
29
|
await context.input.$reply(reply);
|
|
32
30
|
return;
|
|
@@ -2,7 +2,7 @@ import { defineMiddleware } from 'zhin.js/middleware';
|
|
|
2
2
|
import type { Message } from '@zhin.js/core/runtime';
|
|
3
3
|
import { resolveGroupSuiteConfig, type GroupSuiteConfig } from '../../src/config.js';
|
|
4
4
|
import { matchKeyword } from '../../src/keyword-store.js';
|
|
5
|
-
import {
|
|
5
|
+
import { keywords } from '../../src/keywords.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Keyword auto-reply (enabled via config.keywordReply).
|
|
@@ -16,9 +16,7 @@ export default defineMiddleware<Message, GroupSuiteConfig>({
|
|
|
16
16
|
await next();
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
const channelType = String(meta.type ?? meta.channelType ?? '');
|
|
21
|
-
if (channelType === 'private') {
|
|
19
|
+
if (context.input.conversation.kind !== 'group') {
|
|
22
20
|
await next();
|
|
23
21
|
return;
|
|
24
22
|
}
|
|
@@ -27,7 +25,7 @@ export default defineMiddleware<Message, GroupSuiteConfig>({
|
|
|
27
25
|
await next();
|
|
28
26
|
return;
|
|
29
27
|
}
|
|
30
|
-
const reply = matchKeyword(text,
|
|
28
|
+
const reply = matchKeyword(text, new Map(await keywords(context.input, context).read()));
|
|
31
29
|
if (reply) {
|
|
32
30
|
await context.input.$reply(reply);
|
|
33
31
|
return;
|
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
3
|
import { recordMessage } from "../../lib/stats-lib.js";
|
|
4
4
|
import { resolveGroupSuiteRuntime } from "../../lib/runtime-state.js";
|
|
5
|
-
/**
|
|
6
|
-
* Buffer inbound messages into in-memory message_stats (flushed on query).
|
|
7
|
-
* Skips command messages (legacy used `isActionMessage` to skip interactive
|
|
8
|
-
* action/command messages; the Runtime pipeline represents commands as
|
|
9
|
-
* text starting with the dispatcher prefix '/').
|
|
10
|
-
*/
|
|
5
|
+
/** Count in memory; the admitted Schedule Host flushes batches without slowing every message. */
|
|
11
6
|
export default defineMiddleware({
|
|
12
7
|
target: 'inbound',
|
|
13
8
|
async handle(context, next) {
|
|
14
9
|
const content = typeof context.input.content === 'string' ? context.input.content : '';
|
|
15
10
|
if (!content.startsWith('/')) {
|
|
16
|
-
|
|
11
|
+
const runtime = resolveGroupSuiteRuntime(context);
|
|
12
|
+
recordMessage(context.input, runtime);
|
|
17
13
|
}
|
|
18
14
|
await next();
|
|
19
15
|
},
|
|
@@ -4,18 +4,14 @@ import type { GroupSuiteConfig } from '../../src/config.js';
|
|
|
4
4
|
import { recordMessage } from '../../src/stats-lib.js';
|
|
5
5
|
import { resolveGroupSuiteRuntime } from '../../src/runtime-state.js';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Buffer inbound messages into in-memory message_stats (flushed on query).
|
|
9
|
-
* Skips command messages (legacy used `isActionMessage` to skip interactive
|
|
10
|
-
* action/command messages; the Runtime pipeline represents commands as
|
|
11
|
-
* text starting with the dispatcher prefix '/').
|
|
12
|
-
*/
|
|
7
|
+
/** Count in memory; the admitted Schedule Host flushes batches without slowing every message. */
|
|
13
8
|
export default defineMiddleware<Message, GroupSuiteConfig>({
|
|
14
9
|
target: 'inbound',
|
|
15
10
|
async handle(context, next) {
|
|
16
11
|
const content = typeof context.input.content === 'string' ? context.input.content : '';
|
|
17
12
|
if (!content.startsWith('/')) {
|
|
18
|
-
|
|
13
|
+
const runtime = resolveGroupSuiteRuntime(context);
|
|
14
|
+
recordMessage(context.input, runtime);
|
|
19
15
|
}
|
|
20
16
|
await next();
|
|
21
17
|
},
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-group-suite",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Zhin.js
|
|
3
|
+
"version": "1.1.9",
|
|
4
|
+
"description": "Zhin.js 群运营套件:签到、教学、统计、持久词库与群欢迎",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./lib/index.d.ts",
|
|
11
|
-
"development": "./src/index.ts",
|
|
12
11
|
"import": "./lib/index.js"
|
|
13
12
|
},
|
|
14
13
|
"./package.json": "./package.json"
|
|
@@ -18,6 +17,8 @@
|
|
|
18
17
|
"schema.json",
|
|
19
18
|
"commands",
|
|
20
19
|
"middlewares",
|
|
20
|
+
"handlers",
|
|
21
|
+
"schedules",
|
|
21
22
|
"src",
|
|
22
23
|
"lib",
|
|
23
24
|
"skills",
|
|
@@ -40,23 +41,25 @@
|
|
|
40
41
|
},
|
|
41
42
|
"license": "MIT",
|
|
42
43
|
"dependencies": {
|
|
43
|
-
"@zhin.js/components": "1.1.
|
|
44
|
-
"@zhin.js/core": "1.1.
|
|
45
|
-
"@zhin.js/jsx": "1.1.
|
|
46
|
-
"@zhin.js/skill": "1.1.
|
|
47
|
-
"@zhin.js/tool": "1.1.
|
|
44
|
+
"@zhin.js/components": "1.1.3",
|
|
45
|
+
"@zhin.js/core": "1.1.44",
|
|
46
|
+
"@zhin.js/jsx": "1.1.3",
|
|
47
|
+
"@zhin.js/skill": "1.1.6",
|
|
48
|
+
"@zhin.js/tool": "1.1.6"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"typescript": "^6.0.3",
|
|
51
52
|
"vitest": "^4.1.10",
|
|
52
53
|
"zod": "^4.4.3",
|
|
53
|
-
"zhin.js": "1.1.
|
|
54
|
+
"zhin.js": "1.1.9"
|
|
54
55
|
},
|
|
55
56
|
"peerDependencies": {
|
|
56
57
|
"zod": "^4.0.0",
|
|
57
|
-
"@zhin.js/command": "^1.1.
|
|
58
|
-
"@zhin.js/middleware": "^1.1.
|
|
59
|
-
"zhin.js": "^1.1.
|
|
58
|
+
"@zhin.js/command": "^1.1.7",
|
|
59
|
+
"@zhin.js/middleware": "^1.1.6",
|
|
60
|
+
"zhin.js": "^1.1.9",
|
|
61
|
+
"@zhin.js/handler": "^1.1.5",
|
|
62
|
+
"@zhin.js/schedule-feature": "^1.1.5"
|
|
60
63
|
},
|
|
61
64
|
"peerDependenciesMeta": {
|
|
62
65
|
"@zhin.js/command": {
|
|
@@ -67,6 +70,12 @@
|
|
|
67
70
|
},
|
|
68
71
|
"zod": {
|
|
69
72
|
"optional": true
|
|
73
|
+
},
|
|
74
|
+
"@zhin.js/handler": {
|
|
75
|
+
"optional": true
|
|
76
|
+
},
|
|
77
|
+
"@zhin.js/schedule-feature": {
|
|
78
|
+
"optional": true
|
|
70
79
|
}
|
|
71
80
|
},
|
|
72
81
|
"repository": {
|
|
@@ -79,7 +88,7 @@
|
|
|
79
88
|
"registry": "https://registry.npmjs.org"
|
|
80
89
|
},
|
|
81
90
|
"engines": {
|
|
82
|
-
"node": "
|
|
91
|
+
"node": ">=22.19.0"
|
|
83
92
|
},
|
|
84
93
|
"zhin": {
|
|
85
94
|
"protocol": 1,
|
|
@@ -103,6 +112,14 @@
|
|
|
103
112
|
{
|
|
104
113
|
"package": "@zhin.js/skill",
|
|
105
114
|
"api": "^1.0.0"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"package": "@zhin.js/handler",
|
|
118
|
+
"api": "^1.0.0"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"package": "@zhin.js/schedule-feature",
|
|
122
|
+
"api": "^1.0.0"
|
|
106
123
|
}
|
|
107
124
|
],
|
|
108
125
|
"plugins": []
|
package/plugin.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { definePlugin, databaseHostToken } from 'zhin.js';
|
|
3
|
+
import { resolveGroupSuiteConfig } from "./lib/config.js";
|
|
3
4
|
import { createInMemoryGroupSuiteDb } from "./lib/memory-store.js";
|
|
4
5
|
import { createGroupSuiteRuntime, groupSuiteRuntimeToken } from "./lib/runtime-state.js";
|
|
5
|
-
import { flushStatsBuffer } from "./lib/stats-lib.js";
|
|
6
6
|
import { defineGroupSuiteTables } from "./lib/tables.js";
|
|
7
7
|
/**
|
|
8
8
|
* Plugin Runtime:
|
|
9
9
|
* - checkin / teach / stats commands + keyword middleware
|
|
10
10
|
* - DB: prefer `databaseHostToken`; else in-memory fallback
|
|
11
|
-
* - Stats
|
|
11
|
+
* - Stats writes run inside admitted schedule/query operations
|
|
12
12
|
*/
|
|
13
13
|
export default definePlugin({
|
|
14
14
|
name: 'group-suite',
|
|
@@ -25,14 +25,14 @@ export default definePlugin({
|
|
|
25
25
|
}
|
|
26
26
|
return createInMemoryGroupSuiteDb();
|
|
27
27
|
})();
|
|
28
|
+
const config = resolveGroupSuiteConfig(context.config.get());
|
|
29
|
+
if (config.keywordReply && !config.ephemeralKeywords) {
|
|
30
|
+
// Fail before activation rather than claiming durable keywords in a memory fallback.
|
|
31
|
+
if (!context.resources.has(databaseHostToken))
|
|
32
|
+
throw new Error('Persistent keywords require a Database Host; demos may explicitly set ephemeralKeywords: true');
|
|
33
|
+
void context.resources.use(databaseHostToken).state;
|
|
34
|
+
}
|
|
28
35
|
const runtime = createGroupSuiteRuntime(db);
|
|
29
36
|
context.resources.provide(groupSuiteRuntimeToken, runtime);
|
|
30
|
-
const flushTimer = setInterval(() => {
|
|
31
|
-
void flushStatsBuffer(runtime);
|
|
32
|
-
}, 10_000);
|
|
33
|
-
context.lifecycle.add(async () => {
|
|
34
|
-
clearInterval(flushTimer);
|
|
35
|
-
await flushStatsBuffer(runtime);
|
|
36
|
-
});
|
|
37
37
|
},
|
|
38
38
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineSchedule } from '@zhin.js/schedule-feature';
|
|
3
|
+
import { groupSuiteRuntimeToken } from "../../lib/runtime-state.js";
|
|
4
|
+
import { flushStatsBuffer } from "../../lib/stats-lib.js";
|
|
5
|
+
export default defineSchedule({
|
|
6
|
+
cron: '*/10 * * * * *',
|
|
7
|
+
description: 'Flush owner-scoped message count batches',
|
|
8
|
+
execute(context) {
|
|
9
|
+
return flushStatsBuffer(context.use(groupSuiteRuntimeToken));
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineSchedule } from '@zhin.js/schedule-feature';
|
|
2
|
+
import { groupSuiteRuntimeToken } from '../../src/runtime-state.js';
|
|
3
|
+
import { flushStatsBuffer } from '../../src/stats-lib.js';
|
|
4
|
+
|
|
5
|
+
export default defineSchedule({
|
|
6
|
+
cron: '*/10 * * * * *',
|
|
7
|
+
description: 'Flush owner-scoped message count batches',
|
|
8
|
+
execute(context) {
|
|
9
|
+
return flushStatsBuffer(context.use(groupSuiteRuntimeToken));
|
|
10
|
+
},
|
|
11
|
+
});
|
package/schema.json
CHANGED
|
@@ -3,15 +3,56 @@
|
|
|
3
3
|
"type": "object",
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"properties": {
|
|
6
|
-
"keywordReply": {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
6
|
+
"keywordReply": {
|
|
7
|
+
"type": "boolean",
|
|
8
|
+
"default": false
|
|
9
|
+
},
|
|
10
|
+
"basePointsMin": {
|
|
11
|
+
"type": "number",
|
|
12
|
+
"default": 10
|
|
13
|
+
},
|
|
14
|
+
"basePointsMax": {
|
|
15
|
+
"type": "number",
|
|
16
|
+
"default": 30
|
|
17
|
+
},
|
|
18
|
+
"streakBonus": {
|
|
19
|
+
"type": "number",
|
|
20
|
+
"default": 5
|
|
21
|
+
},
|
|
22
|
+
"streakCap": {
|
|
23
|
+
"type": "number",
|
|
24
|
+
"default": 50
|
|
25
|
+
},
|
|
26
|
+
"rankSize": {
|
|
27
|
+
"type": "number",
|
|
28
|
+
"default": 10
|
|
29
|
+
},
|
|
30
|
+
"teachMaxPerGroup": {
|
|
31
|
+
"type": "number",
|
|
32
|
+
"default": 200
|
|
33
|
+
},
|
|
34
|
+
"teachCooldownMs": {
|
|
35
|
+
"type": "number",
|
|
36
|
+
"default": 3000
|
|
37
|
+
},
|
|
38
|
+
"teachAllowRegex": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"default": true
|
|
41
|
+
},
|
|
42
|
+
"teachPageSize": {
|
|
43
|
+
"type": "number",
|
|
44
|
+
"default": 10
|
|
45
|
+
},
|
|
46
|
+
"welcomeMessage": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"maxLength": 2000,
|
|
49
|
+
"default": "",
|
|
50
|
+
"description": "Group welcome text. Empty disables; {name}/{id} refer to the joined member."
|
|
51
|
+
},
|
|
52
|
+
"ephemeralKeywords": {
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"default": false,
|
|
55
|
+
"description": "Explicit volatile keywords. With false, automatic replies require Database Host at startup and keyword management requires its persistent state service when invoked."
|
|
56
|
+
}
|
|
16
57
|
}
|
|
17
58
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getCheckinModel } from "../../../../lib/db-store.js";
|
|
4
5
|
import { groupSuiteRuntimeToken } from "../../../../lib/runtime-state.js";
|
|
@@ -13,19 +14,18 @@ export default defineAgentTool({
|
|
|
13
14
|
},
|
|
14
15
|
},
|
|
15
16
|
requiresApproval: 'never',
|
|
17
|
+
scopes: ['group'],
|
|
16
18
|
async execute({ user_id: userId, group_id: requestedGroupId }, context) {
|
|
17
19
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
18
20
|
const model = getCheckinModel(runtime.db);
|
|
19
21
|
if (!model)
|
|
20
22
|
return '签到数据库尚未就绪';
|
|
21
|
-
const groupId =
|
|
23
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
22
24
|
const query = {
|
|
23
25
|
...(userId ? { user_id: userId } : {}),
|
|
24
|
-
|
|
26
|
+
context_type: 'group', context_id: groupId,
|
|
25
27
|
};
|
|
26
|
-
const rows =
|
|
27
|
-
? await model.select().where(query)
|
|
28
|
-
: await model.select();
|
|
28
|
+
const rows = await model.select().where(query);
|
|
29
29
|
if (userId) {
|
|
30
30
|
if (rows.length === 0)
|
|
31
31
|
return `用户 ${userId} 没有签到记录`;
|
|
@@ -37,6 +37,3 @@ export default defineAgentTool({
|
|
|
37
37
|
return `签到系统统计\n总用户: ${rows.length}\n总积分: ${totalPoints}\n今日签到: ${todayCount}人`;
|
|
38
38
|
},
|
|
39
39
|
});
|
|
40
|
-
function currentGroupId(origin) {
|
|
41
|
-
return origin.kind === 'im' && origin.scope !== 'private' ? origin.sceneId : '';
|
|
42
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { getCheckinModel } from '../../../../src/db-store.js';
|
|
3
4
|
import { groupSuiteRuntimeToken } from '../../../../src/runtime-state.js';
|
|
@@ -13,18 +14,17 @@ export default defineAgentTool<{ user_id?: string; group_id?: string }>({
|
|
|
13
14
|
},
|
|
14
15
|
},
|
|
15
16
|
requiresApproval: 'never',
|
|
17
|
+
scopes: ['group'],
|
|
16
18
|
async execute({ user_id: userId, group_id: requestedGroupId }, context) {
|
|
17
19
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
18
20
|
const model = getCheckinModel(runtime.db);
|
|
19
21
|
if (!model) return '签到数据库尚未就绪';
|
|
20
|
-
const groupId =
|
|
22
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
21
23
|
const query = {
|
|
22
24
|
...(userId ? { user_id: userId } : {}),
|
|
23
|
-
|
|
25
|
+
context_type: 'group', context_id: groupId,
|
|
24
26
|
};
|
|
25
|
-
const rows =
|
|
26
|
-
? await model.select().where(query)
|
|
27
|
-
: await model.select();
|
|
27
|
+
const rows = await model.select().where(query);
|
|
28
28
|
if (userId) {
|
|
29
29
|
if (rows.length === 0) return `用户 ${userId} 没有签到记录`;
|
|
30
30
|
const user = rows[0]!;
|
|
@@ -35,7 +35,3 @@ export default defineAgentTool<{ user_id?: string; group_id?: string }>({
|
|
|
35
35
|
return `签到系统统计\n总用户: ${rows.length}\n总积分: ${totalPoints}\n今日签到: ${todayCount}人`;
|
|
36
36
|
},
|
|
37
37
|
});
|
|
38
|
-
|
|
39
|
-
function currentGroupId(origin: import('@zhin.js/tool').ToolInvocationOrigin): string {
|
|
40
|
-
return origin.kind === 'im' && origin.scope !== 'private' ? origin.sceneId : '';
|
|
41
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getCheckinModel } from "../../../../lib/db-store.js";
|
|
4
5
|
import { groupSuiteRuntimeToken } from "../../../../lib/runtime-state.js";
|
|
@@ -12,17 +13,13 @@ export default defineAgentTool({
|
|
|
12
13
|
},
|
|
13
14
|
},
|
|
14
15
|
requiresApproval: 'never',
|
|
16
|
+
scopes: ['group'],
|
|
15
17
|
async execute({ limit, group_id: requestedGroupId }, context) {
|
|
16
18
|
const model = getCheckinModel(context.use(groupSuiteRuntimeToken).db);
|
|
17
19
|
if (!model)
|
|
18
20
|
return '签到数据库尚未就绪';
|
|
19
|
-
const groupId = requestedGroupId
|
|
20
|
-
|
|
21
|
-
? context.origin.sceneId
|
|
22
|
-
: '');
|
|
23
|
-
const rows = groupId
|
|
24
|
-
? await model.select().where({ context_type: 'group', context_id: groupId })
|
|
25
|
-
: await model.select();
|
|
21
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
22
|
+
const rows = await model.select().where({ context_type: 'group', context_id: groupId });
|
|
26
23
|
const count = Math.min(Math.max(Number(limit) || 10, 1), 50);
|
|
27
24
|
const ranked = [...rows]
|
|
28
25
|
.sort((left, right) => Number(right.points ?? 0) - Number(left.points ?? 0))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { getCheckinModel } from '../../../../src/db-store.js';
|
|
3
4
|
import { groupSuiteRuntimeToken } from '../../../../src/runtime-state.js';
|
|
@@ -12,16 +13,12 @@ export default defineAgentTool<{ limit?: number; group_id?: string }>({
|
|
|
12
13
|
},
|
|
13
14
|
},
|
|
14
15
|
requiresApproval: 'never',
|
|
16
|
+
scopes: ['group'],
|
|
15
17
|
async execute({ limit, group_id: requestedGroupId }, context) {
|
|
16
18
|
const model = getCheckinModel(context.use(groupSuiteRuntimeToken).db);
|
|
17
19
|
if (!model) return '签到数据库尚未就绪';
|
|
18
|
-
const groupId = requestedGroupId
|
|
19
|
-
|
|
20
|
-
? context.origin.sceneId
|
|
21
|
-
: '');
|
|
22
|
-
const rows = groupId
|
|
23
|
-
? await model.select().where({ context_type: 'group', context_id: groupId })
|
|
24
|
-
: await model.select();
|
|
20
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
21
|
+
const rows = await model.select().where({ context_type: 'group', context_id: groupId });
|
|
25
22
|
const count = Math.min(Math.max(Number(limit) || 10, 1), 50);
|
|
26
23
|
const ranked = [...rows]
|
|
27
24
|
.sort((left, right) => Number(right.points ?? 0) - Number(left.points ?? 0))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { groupSuiteRuntimeToken } from "../../../../lib/runtime-state.js";
|
|
4
5
|
import { flushStatsBuffer, monthStartStr, queryStats, weekStartStr } from "../../../../lib/stats-lib.js";
|
|
@@ -13,13 +14,11 @@ export default defineAgentTool({
|
|
|
13
14
|
},
|
|
14
15
|
},
|
|
15
16
|
requiresApproval: 'never',
|
|
17
|
+
scopes: ['group'],
|
|
16
18
|
async execute({ group_id: requestedGroupId, period = 'today' }, context) {
|
|
17
19
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
18
20
|
await flushStatsBuffer(runtime);
|
|
19
|
-
const groupId = requestedGroupId
|
|
20
|
-
?? (context.origin.kind === 'im' && context.origin.scope !== 'private'
|
|
21
|
-
? context.origin.sceneId
|
|
22
|
-
: '');
|
|
21
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
23
22
|
const fromDate = period === 'week'
|
|
24
23
|
? weekStartStr()
|
|
25
24
|
: period === 'month' ? monthStartStr() : todayStr();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { groupSuiteRuntimeToken } from '../../../../src/runtime-state.js';
|
|
3
4
|
import { flushStatsBuffer, monthStartStr, queryStats, weekStartStr } from '../../../../src/stats-lib.js';
|
|
@@ -15,13 +16,11 @@ export default defineAgentTool<{ group_id?: string; period?: Period }>({
|
|
|
15
16
|
},
|
|
16
17
|
},
|
|
17
18
|
requiresApproval: 'never',
|
|
19
|
+
scopes: ['group'],
|
|
18
20
|
async execute({ group_id: requestedGroupId, period = 'today' }, context) {
|
|
19
21
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
20
22
|
await flushStatsBuffer(runtime);
|
|
21
|
-
const groupId = requestedGroupId
|
|
22
|
-
?? (context.origin.kind === 'im' && context.origin.scope !== 'private'
|
|
23
|
-
? context.origin.sceneId
|
|
24
|
-
: '');
|
|
23
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
25
24
|
const fromDate = period === 'week'
|
|
26
25
|
? weekStartStr()
|
|
27
26
|
: period === 'month' ? monthStartStr() : todayStr();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { conversationKey, toolGroupConversation } from "../../../../lib/conversation-scope.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { getStatsModel } from "../../../../lib/db-store.js";
|
|
4
5
|
import { groupSuiteRuntimeToken } from "../../../../lib/runtime-state.js";
|
|
@@ -15,19 +16,17 @@ export default defineAgentTool({
|
|
|
15
16
|
required: ['user_id'],
|
|
16
17
|
},
|
|
17
18
|
requiresApproval: 'never',
|
|
19
|
+
scopes: ['group'],
|
|
18
20
|
async execute({ user_id: userId, group_id: requestedGroupId }, context) {
|
|
19
21
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
20
22
|
await flushStatsBuffer(runtime);
|
|
21
23
|
const model = getStatsModel(runtime.db);
|
|
22
24
|
if (!model)
|
|
23
25
|
return '统计数据库尚未就绪';
|
|
24
|
-
const groupId = requestedGroupId
|
|
25
|
-
?? (context.origin.kind === 'im' && context.origin.scope !== 'private'
|
|
26
|
-
? context.origin.sceneId
|
|
27
|
-
: '');
|
|
26
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
28
27
|
const rows = await model.select().where({
|
|
29
28
|
user_id: userId,
|
|
30
|
-
|
|
29
|
+
group_id: groupId,
|
|
31
30
|
});
|
|
32
31
|
if (rows.length === 0)
|
|
33
32
|
return `用户 ${userId} 暂无消息记录`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { conversationKey, toolGroupConversation } from '../../../../src/conversation-scope.js';
|
|
1
2
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
2
3
|
import { getStatsModel } from '../../../../src/db-store.js';
|
|
3
4
|
import { groupSuiteRuntimeToken } from '../../../../src/runtime-state.js';
|
|
@@ -15,18 +16,16 @@ export default defineAgentTool<{ user_id: string; group_id?: string }>({
|
|
|
15
16
|
required: ['user_id'],
|
|
16
17
|
},
|
|
17
18
|
requiresApproval: 'never',
|
|
19
|
+
scopes: ['group'],
|
|
18
20
|
async execute({ user_id: userId, group_id: requestedGroupId }, context) {
|
|
19
21
|
const runtime = context.use(groupSuiteRuntimeToken);
|
|
20
22
|
await flushStatsBuffer(runtime);
|
|
21
23
|
const model = getStatsModel(runtime.db);
|
|
22
24
|
if (!model) return '统计数据库尚未就绪';
|
|
23
|
-
const groupId = requestedGroupId
|
|
24
|
-
?? (context.origin.kind === 'im' && context.origin.scope !== 'private'
|
|
25
|
-
? context.origin.sceneId
|
|
26
|
-
: '');
|
|
25
|
+
const groupId = conversationKey(toolGroupConversation(context, requestedGroupId));
|
|
27
26
|
const rows = await model.select().where({
|
|
28
27
|
user_id: userId,
|
|
29
|
-
|
|
28
|
+
group_id: groupId,
|
|
30
29
|
});
|
|
31
30
|
if (rows.length === 0) return `用户 ${userId} 暂无消息记录`;
|
|
32
31
|
const today = todayStr();
|
package/src/checkin-lib.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConversationInput } from './conversation-scope.js';
|
|
1
2
|
import type { GroupSuiteConfig } from './config.js';
|
|
2
3
|
import { getCheckinModel } from './db-store.js';
|
|
3
4
|
import {
|
|
@@ -64,7 +65,7 @@ function serializedCheckin<T>(
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
export async function doCheckin(
|
|
67
|
-
input:
|
|
68
|
+
input: ConversationInput,
|
|
68
69
|
cfg: GroupSuiteConfig,
|
|
69
70
|
runtime: GroupSuiteRuntime,
|
|
70
71
|
): Promise<string> {
|
|
@@ -113,7 +114,7 @@ export async function doCheckin(
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
export async function myPoints(
|
|
116
|
-
input:
|
|
117
|
+
input: ConversationInput,
|
|
117
118
|
runtime: GroupSuiteRuntime,
|
|
118
119
|
): Promise<string> {
|
|
119
120
|
const M = getCheckinModel(runtime.db);
|
|
@@ -139,7 +140,7 @@ export async function myPoints(
|
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
export async function pointsRank(
|
|
142
|
-
input:
|
|
143
|
+
input: ConversationInput,
|
|
143
144
|
cfg: GroupSuiteConfig,
|
|
144
145
|
runtime: GroupSuiteRuntime,
|
|
145
146
|
): Promise<string> {
|
|
@@ -147,9 +148,7 @@ export async function pointsRank(
|
|
|
147
148
|
if (!M) return '签到数据库尚未就绪';
|
|
148
149
|
const { type: ctxType, id: ctxId } = resolveContextKey(input);
|
|
149
150
|
const all = (await M.select().where(
|
|
150
|
-
ctxType
|
|
151
|
-
? { context_type: 'global' }
|
|
152
|
-
: { context_type: ctxType, context_id: ctxId },
|
|
151
|
+
{ context_type: ctxType, context_id: ctxId },
|
|
153
152
|
)) as Record<string, unknown>[];
|
|
154
153
|
if (all.length === 0) return '还没有人签到过哦~';
|
|
155
154
|
const sorted = all.sort((a, b) => Number(b.points || 0) - Number(a.points || 0));
|
|
@@ -159,7 +158,8 @@ export async function pointsRank(
|
|
|
159
158
|
const prefix = i < 3 ? medals[i] : `${i + 1}.`;
|
|
160
159
|
return `${prefix} ${u.user_name || u.user_id} — ${u.points}分 (${u.total_checkins}天)`;
|
|
161
160
|
});
|
|
162
|
-
const title = ctxType === 'group' ? '本群积分排行'
|
|
161
|
+
const title = ctxType === 'group' ? '本群积分排行'
|
|
162
|
+
: ctxType === 'channel' ? '本频道积分排行' : '当前私聊积分排行';
|
|
163
163
|
const { id: userId } = resolveSender(input);
|
|
164
164
|
const myRank = sorted.findIndex((u) => u.user_id === userId);
|
|
165
165
|
const footer = myRank >= 0 ? `\n你的排名: 第${myRank + 1}名` : '';
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export interface GroupSuiteConfig {
|
|
2
2
|
keywordReply: boolean;
|
|
3
|
+
/** Explicitly volatile keywords for demos without a persistent Database Host. */
|
|
4
|
+
ephemeralKeywords: boolean;
|
|
5
|
+
/** Empty disables group member welcomes. {name} and {id} are literal placeholders. */
|
|
6
|
+
welcomeMessage: string;
|
|
3
7
|
basePointsMin: number;
|
|
4
8
|
basePointsMax: number;
|
|
5
9
|
streakBonus: number;
|
|
@@ -13,6 +17,8 @@ export interface GroupSuiteConfig {
|
|
|
13
17
|
|
|
14
18
|
export const DEFAULT_GROUP_SUITE_CONFIG: GroupSuiteConfig = {
|
|
15
19
|
keywordReply: false,
|
|
20
|
+
ephemeralKeywords: false,
|
|
21
|
+
welcomeMessage: '',
|
|
16
22
|
basePointsMin: 10,
|
|
17
23
|
basePointsMax: 30,
|
|
18
24
|
streakBonus: 5,
|