@zhin.js/plugin-repeater 1.1.24 → 1.1.26
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/LICENSE +21 -0
- package/README.md +11 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +4 -0
- package/lib/config.js.map +1 -1
- package/lib/runtime.d.ts +6 -1
- package/lib/runtime.d.ts.map +1 -1
- package/lib/runtime.js +1 -0
- package/lib/runtime.js.map +1 -1
- package/middlewares/repeater/index.js +4 -2
- package/middlewares/repeater/index.ts +4 -2
- package/package.json +7 -13
- package/plugin.js +5 -1
- package/schema.json +15 -0
- package/src/config.ts +4 -0
- package/src/runtime.ts +11 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 凉菜
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -24,6 +24,17 @@ repeater:
|
|
|
24
24
|
|
|
25
25
|
配置声明位于 `src/config.ts`,由 `plugin.ts` 暴露给 Runtime 与 Console;默认值、类型、范围和表单说明由同一声明生成。配置不满足范围或含未知字段时,候选代不会激活;有效配置更新只重载插件。
|
|
26
26
|
|
|
27
|
+
### 按适配器 / 账号 / 群覆盖(ADR 0050 / 0055)
|
|
28
|
+
|
|
29
|
+
复读机支持全部四个层级(`global` / `adapter` / `endpoint` / `conversation`):
|
|
30
|
+
|
|
31
|
+
- 适配器、账号层的覆盖写在 `repeater.overrides`;群(会话)层的覆盖由 Console「功能」区或群内自助命令写入项目数据库,原地生效,不重载插件。
|
|
32
|
+
- 会话层可以改 `threshold` 与 `cooldown`(`conversationFields`),也可以单独关闭某个群的复读。
|
|
33
|
+
- 开启 `features.selfService.enabled` 后,群里的 `admin`(默认含群主 / 管理员)可以用 `功能 设置 repeater threshold 5` 调整本群阈值(`selfServiceFields` 只含 `threshold`),用 `功能 关闭 repeater` 关闭本群复读。
|
|
34
|
+
- 推荐用会话层开关代替自建黑白名单。
|
|
35
|
+
|
|
36
|
+
Per-group overrides: the repeater supports all four levels. In a group, an `admin` can run `feature set repeater threshold 5` (only `threshold` is self-service) or `feature disable repeater` once `features.selfService.enabled` is on; the Console can also change `cooldown` per group.
|
|
37
|
+
|
|
27
38
|
## 工作原理
|
|
28
39
|
|
|
29
40
|
1. 监听群聊消息,记录每条消息的内容和发送者
|
package/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,eAAO,MAAM,uBAAuB;;;;EAIlC,CAAC;AAEH,gIAAgI;AAChI,eAAO,MAAM,cAAc;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,eAAO,MAAM,uBAAuB;;;;EAIlC,CAAC;AAEH,gIAAgI;AAChI,eAAO,MAAM,cAAc;;;;;;;;;;;;;;CAQzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
package/lib/config.js
CHANGED
|
@@ -9,5 +9,9 @@ export const repeaterConfig = Schema.object({
|
|
|
9
9
|
threshold: Schema.number().min(2).max(10).step(1).default(DEFAULT_REPEATER_CONFIG.threshold).description('触发复读的最少人数').i18n({ "en": { "description": "Minimum distinct users needed to trigger repetition." } }).effect('reload'),
|
|
10
10
|
cooldown: Schema.number().min(5_000).max(300_000).default(DEFAULT_REPEATER_CONFIG.cooldown).description('同一群冷却时间 (ms)').i18n({ "en": { "description": "Cooldown for the same group, in milliseconds." } }).effect('reload'),
|
|
11
11
|
maxLength: Schema.number().min(10).max(1_000).step(1).default(DEFAULT_REPEATER_CONFIG.maxLength).description('消息长度上限').i18n({ "en": { "description": "Maximum message length." } }).effect('reload'),
|
|
12
|
+
}).featureLevels(['global', 'adapter', 'endpoint', 'conversation'], {
|
|
13
|
+
// ADR 0055: per-group threshold / cooldown in the Console; group admins may tune the threshold in chat.
|
|
14
|
+
conversationFields: ['threshold', 'cooldown'],
|
|
15
|
+
selfServiceFields: ['threshold'],
|
|
12
16
|
});
|
|
13
17
|
//# sourceMappingURL=config.js.map
|
package/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,MAAM,CAAC;IACnD,SAAS,EAAE,CAAC;IACZ,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,GAAG;CACf,CAAC,CAAC;AAEH,gIAAgI;AAChI,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,sDAAsD,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC5N,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,+CAA+C,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACvN,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,yBAAyB,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;CACjM,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,MAAM,CAAC;IACnD,SAAS,EAAE,CAAC;IACZ,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,GAAG;CACf,CAAC,CAAC;AAEH,gIAAgI;AAChI,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,sDAAsD,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC5N,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,+CAA+C,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACvN,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,yBAAyB,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;CACjM,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE;IAClE,wGAAwG;IACxG,kBAAkB,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC;IAC7C,iBAAiB,EAAE,CAAC,WAAW,CAAC;CACjC,CAAC,CAAC"}
|
package/lib/runtime.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import type { RepeaterEngine } from './engine.js';
|
|
1
|
+
import type { RepeaterConfig, RepeaterEngine } from './engine.js';
|
|
2
2
|
export declare const repeaterEngineToken: import("zhin.js").PluginStore<RepeaterEngine, unknown>;
|
|
3
|
+
/** Effective configuration per conversation (ADR 0055): global < adapter < endpoint < conversation. */
|
|
4
|
+
export interface RepeaterConfigResolver {
|
|
5
|
+
configFor(message: unknown): Readonly<RepeaterConfig>;
|
|
6
|
+
}
|
|
7
|
+
export declare const repeaterConfigToken: import("zhin.js").PluginStore<RepeaterConfigResolver, unknown>;
|
|
3
8
|
//# sourceMappingURL=runtime.d.ts.map
|
package/lib/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElE,eAAO,MAAM,mBAAmB,wDAG/B,CAAC;AAEF,uGAAuG;AACvG,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;CACvD;AAED,eAAO,MAAM,mBAAmB,gEAG/B,CAAC"}
|
package/lib/runtime.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { definePluginStore } from 'zhin.js';
|
|
2
2
|
export const repeaterEngineToken = definePluginStore('zhin.repeater.engine', 'Conversation repeat streak and cooldown state');
|
|
3
|
+
export const repeaterConfigToken = definePluginStore('zhin.repeater.config', 'Layered repeater configuration for one message');
|
|
3
4
|
//# sourceMappingURL=runtime.js.map
|
package/lib/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAClD,sBAAsB,EACtB,+CAA+C,CAChD,CAAC"}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAClD,sBAAsB,EACtB,+CAA+C,CAChD,CAAC;AAOF,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAClD,sBAAsB,EACtB,gDAAgD,CACjD,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
3
|
import {} from "../../lib/engine.js";
|
|
4
|
-
import { repeaterEngineToken } from "../../lib/runtime.js";
|
|
4
|
+
import { repeaterConfigToken, repeaterEngineToken } from "../../lib/runtime.js";
|
|
5
5
|
/**
|
|
6
6
|
* Runtime `Message` 是 conversation 原生:`conversation.kind/id` 直接喂给引擎
|
|
7
7
|
* (引擎契约 `RepeaterInboundFields.conversation`,私聊由引擎判 null 跳过)。
|
|
@@ -11,7 +11,9 @@ import { repeaterEngineToken } from "../../lib/runtime.js";
|
|
|
11
11
|
export default defineMiddleware({
|
|
12
12
|
target: 'inbound',
|
|
13
13
|
async handle(context, next) {
|
|
14
|
-
|
|
14
|
+
// Per-conversation effective configuration (ADR 0055); falls back to the global view.
|
|
15
|
+
const resolver = context.has(repeaterConfigToken) ? context.use(repeaterConfigToken) : undefined;
|
|
16
|
+
const config = { ...context.config, ...(resolver?.configFor(context.input) ?? {}) };
|
|
15
17
|
const engine = context.use(repeaterEngineToken);
|
|
16
18
|
const result = engine.tick({
|
|
17
19
|
conversation: context.input.conversation,
|
|
@@ -3,7 +3,7 @@ import type { Message } from '@zhin.js/core/runtime';
|
|
|
3
3
|
import {
|
|
4
4
|
type RepeaterConfig,
|
|
5
5
|
} from '../../src/engine.js';
|
|
6
|
-
import { repeaterEngineToken } from '../../src/runtime.js';
|
|
6
|
+
import { repeaterConfigToken, repeaterEngineToken } from '../../src/runtime.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Runtime `Message` 是 conversation 原生:`conversation.kind/id` 直接喂给引擎
|
|
@@ -14,7 +14,9 @@ import { repeaterEngineToken } from '../../src/runtime.js';
|
|
|
14
14
|
export default defineMiddleware<Message, RepeaterConfig>({
|
|
15
15
|
target: 'inbound',
|
|
16
16
|
async handle(context, next) {
|
|
17
|
-
|
|
17
|
+
// Per-conversation effective configuration (ADR 0055); falls back to the global view.
|
|
18
|
+
const resolver = context.has(repeaterConfigToken) ? context.use(repeaterConfigToken) : undefined;
|
|
19
|
+
const config = { ...context.config, ...(resolver?.configFor(context.input) ?? {}) } as RepeaterConfig;
|
|
18
20
|
const engine = context.use(repeaterEngineToken);
|
|
19
21
|
const result = engine.tick({
|
|
20
22
|
conversation: context.input.conversation,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-repeater",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.26",
|
|
4
4
|
"description": "Repeater plugin for Zhin.js — auto-repeat when group members echo the same content (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"middlewares",
|
|
19
19
|
"src",
|
|
20
20
|
"lib",
|
|
21
|
-
"skills",
|
|
22
21
|
"README.md",
|
|
23
22
|
"schema.json"
|
|
24
23
|
],
|
|
@@ -40,13 +39,12 @@
|
|
|
40
39
|
},
|
|
41
40
|
"license": "MIT",
|
|
42
41
|
"dependencies": {
|
|
43
|
-
"@zhin.js/core": "1.
|
|
44
|
-
"@zhin.js/skill": "1.1.16"
|
|
42
|
+
"@zhin.js/core": "1.2.0"
|
|
45
43
|
},
|
|
46
44
|
"devDependencies": {
|
|
47
45
|
"typescript": "^6.0.3",
|
|
48
46
|
"vitest": "^4.1.10",
|
|
49
|
-
"zhin.js": "1.1.
|
|
47
|
+
"zhin.js": "1.1.26"
|
|
50
48
|
},
|
|
51
49
|
"repository": {
|
|
52
50
|
"type": "git",
|
|
@@ -74,18 +72,14 @@
|
|
|
74
72
|
{
|
|
75
73
|
"package": "@zhin.js/middleware",
|
|
76
74
|
"api": "^1.0.0"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"package": "@zhin.js/skill",
|
|
80
|
-
"api": "^1.0.0"
|
|
81
75
|
}
|
|
82
76
|
],
|
|
83
77
|
"plugins": []
|
|
84
78
|
},
|
|
85
79
|
"peerDependencies": {
|
|
86
|
-
"@zhin.js/command": "^1.
|
|
87
|
-
"@zhin.js/middleware": "^1.1.
|
|
88
|
-
"zhin.js": "^1.1.
|
|
80
|
+
"@zhin.js/command": "^1.2.0",
|
|
81
|
+
"@zhin.js/middleware": "^1.1.17",
|
|
82
|
+
"zhin.js": "^1.1.26"
|
|
89
83
|
},
|
|
90
84
|
"peerDependenciesMeta": {
|
|
91
85
|
"@zhin.js/command": {
|
|
@@ -98,6 +92,6 @@
|
|
|
98
92
|
"scripts": {
|
|
99
93
|
"build": "tsc",
|
|
100
94
|
"clean": "rimraf lib",
|
|
101
|
-
"test": "
|
|
95
|
+
"test": "vitest run --root ../../.. plugins/utils/repeater/tests"
|
|
102
96
|
}
|
|
103
97
|
}
|
package/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { definePlugin } from 'zhin.js';
|
|
3
3
|
import { RepeaterEngine } from "./lib/engine.js";
|
|
4
|
-
import { repeaterEngineToken } from "./lib/runtime.js";
|
|
4
|
+
import { repeaterConfigToken, repeaterEngineToken } from "./lib/runtime.js";
|
|
5
5
|
export default definePlugin({
|
|
6
6
|
name: 'repeater',
|
|
7
7
|
metadata: {
|
|
@@ -9,5 +9,9 @@ export default definePlugin({
|
|
|
9
9
|
},
|
|
10
10
|
setup(context) {
|
|
11
11
|
repeaterEngineToken.provide(context, () => new RepeaterEngine());
|
|
12
|
+
// `threshold` etc. may be overridden per adapter / endpoint / conversation (in place, no reload).
|
|
13
|
+
repeaterConfigToken.provide(context, {
|
|
14
|
+
configFor: message => context.configFor(message),
|
|
15
|
+
});
|
|
12
16
|
},
|
|
13
17
|
});
|
package/schema.json
CHANGED
|
@@ -49,5 +49,20 @@
|
|
|
49
49
|
"effect": "reload"
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
},
|
|
53
|
+
"x-zhin-config": {
|
|
54
|
+
"levels": [
|
|
55
|
+
"global",
|
|
56
|
+
"adapter",
|
|
57
|
+
"endpoint",
|
|
58
|
+
"conversation"
|
|
59
|
+
],
|
|
60
|
+
"conversationFields": [
|
|
61
|
+
"threshold",
|
|
62
|
+
"cooldown"
|
|
63
|
+
],
|
|
64
|
+
"selfServiceFields": [
|
|
65
|
+
"threshold"
|
|
66
|
+
]
|
|
52
67
|
}
|
|
53
68
|
}
|
package/src/config.ts
CHANGED
|
@@ -11,6 +11,10 @@ export const repeaterConfig = Schema.object({
|
|
|
11
11
|
threshold: Schema.number().min(2).max(10).step(1).default(DEFAULT_REPEATER_CONFIG.threshold).description('触发复读的最少人数').i18n({"en": {"description": "Minimum distinct users needed to trigger repetition."}}).effect('reload'),
|
|
12
12
|
cooldown: Schema.number().min(5_000).max(300_000).default(DEFAULT_REPEATER_CONFIG.cooldown).description('同一群冷却时间 (ms)').i18n({"en": {"description": "Cooldown for the same group, in milliseconds."}}).effect('reload'),
|
|
13
13
|
maxLength: Schema.number().min(10).max(1_000).step(1).default(DEFAULT_REPEATER_CONFIG.maxLength).description('消息长度上限').i18n({"en": {"description": "Maximum message length."}}).effect('reload'),
|
|
14
|
+
}).featureLevels(['global', 'adapter', 'endpoint', 'conversation'], {
|
|
15
|
+
// ADR 0055: per-group threshold / cooldown in the Console; group admins may tune the threshold in chat.
|
|
16
|
+
conversationFields: ['threshold', 'cooldown'],
|
|
17
|
+
selfServiceFields: ['threshold'],
|
|
14
18
|
});
|
|
15
19
|
|
|
16
20
|
export type RepeaterConfig = Schema.Output<typeof repeaterConfig>;
|
package/src/runtime.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { definePluginStore } from 'zhin.js';
|
|
2
|
-
import type { RepeaterEngine } from './engine.js';
|
|
2
|
+
import type { RepeaterConfig, RepeaterEngine } from './engine.js';
|
|
3
3
|
|
|
4
4
|
export const repeaterEngineToken = definePluginStore<RepeaterEngine>(
|
|
5
5
|
'zhin.repeater.engine',
|
|
6
6
|
'Conversation repeat streak and cooldown state',
|
|
7
7
|
);
|
|
8
|
+
|
|
9
|
+
/** Effective configuration per conversation (ADR 0055): global < adapter < endpoint < conversation. */
|
|
10
|
+
export interface RepeaterConfigResolver {
|
|
11
|
+
configFor(message: unknown): Readonly<RepeaterConfig>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const repeaterConfigToken = definePluginStore<RepeaterConfigResolver>(
|
|
15
|
+
'zhin.repeater.config',
|
|
16
|
+
'Layered repeater configuration for one message',
|
|
17
|
+
);
|