@zhin.js/plugin-answers 0.0.14 → 0.0.15
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/commands//345/245/275/346/227/240/350/201/212/index.js +4 -4
- package/commands//345/245/275/346/227/240/350/201/212/index.ts +5 -4
- package/commands//347/247/221/347/233/256/344/270/200/index.js +4 -4
- package/commands//347/247/221/347/233/256/344/270/200/index.ts +5 -4
- package/commands//347/255/224/346/241/210/344/271/213/344/271/246/index.js +4 -3
- package/commands//347/255/224/346/241/210/344/271/213/344/271/246/index.ts +5 -3
- 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 +13 -0
- package/lib/runtime.d.ts.map +1 -1
- package/lib/runtime.js +7 -0
- package/lib/runtime.js.map +1 -1
- package/package.json +8 -7
- package/plugin.js +5 -1
- package/schema.json +17 -0
- package/src/config.ts +4 -0
- package/src/runtime.ts +18 -0
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
|
@@ -53,10 +53,21 @@ import { pickBookAnswer, FUN_QUESTIONS, QuizService } from '@zhin.js/plugin-answ
|
|
|
53
53
|
const answer = pickBookAnswer({ question: '今天出门吗', senderId: 'alice', dailyStable: true, timezone: 'Asia/Shanghai' });
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
## 分层配置(ADR 0050 / 0055)
|
|
57
|
+
|
|
58
|
+
支持全部四个层级:
|
|
59
|
+
|
|
60
|
+
- 适配器、账号层可以覆盖所有字段(写在 `answers.overrides`)。
|
|
61
|
+
- 会话层可以改 `dailyStable`、`quizTimeoutSeconds`、`enableDrivingQuiz`(`conversationFields`);`timezone` 只到账号层。
|
|
62
|
+
- 开启 `features.selfService.enabled` 后,群里的 `admin` 可以用 `功能 设置 answers quizTimeoutSeconds 60` 或 `功能 设置 answers enableDrivingQuiz false` 调整本群(`selfServiceFields`),用 `功能 关闭 answers` 关闭本群。
|
|
63
|
+
- 命令按消息所在会话读取有效配置,改动原地生效,不重载插件。
|
|
64
|
+
|
|
56
65
|
## English
|
|
57
66
|
|
|
58
67
|
Fun, platform-agnostic chat toys with **original** content: `答案之书 <question>` (book of answers, optional per-day stable answers), `好无聊` (multiple-choice trivia) and `科目一` (traffic-rule quiz written from the public PRC Road Traffic Safety Law and its implementing regulations; entertainment only). Only the asker can answer, by replying a single letter in the same conversation before the timeout.
|
|
59
68
|
|
|
69
|
+
Layered configuration: all fields can be overridden per adapter / account; `dailyStable`, `quizTimeoutSeconds` and `enableDrivingQuiz` also per conversation. Group admins may change `quizTimeoutSeconds` and `enableDrivingQuiz` in chat (`feature set answers …`) once `features.selfService.enabled` is on.
|
|
70
|
+
|
|
60
71
|
## 许可
|
|
61
72
|
|
|
62
73
|
MIT
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages } from "../../lib/messages.js";
|
|
3
3
|
import { defineCommand } from 'zhin.js/command';
|
|
4
|
-
import { resolveAnswersConfig } from "../../lib/config.js";
|
|
5
4
|
import { FUN_QUESTIONS } from "../../lib/fun-quiz-data.js";
|
|
6
5
|
import { formatQuestion, quizKey } from "../../lib/quiz.js";
|
|
7
|
-
import { quizServiceToken } from "../../lib/runtime.js";
|
|
6
|
+
import { answersSettingsFor, quizServiceToken } from "../../lib/runtime.js";
|
|
8
7
|
export default defineCommand({
|
|
9
8
|
preferredAliasI18n: { en: 'boring' },
|
|
10
9
|
description: '好无聊?来一道原创趣味选择题,直接回复字母作答', descriptionI18n: { en: "Try an original trivia question; reply with an option letter" },
|
|
11
10
|
alias: ['boring'],
|
|
12
|
-
execute(
|
|
11
|
+
execute(context) {
|
|
12
|
+
const { input, use, locale } = context;
|
|
13
13
|
const key = quizKey(input);
|
|
14
14
|
if (!key)
|
|
15
15
|
return messages(locale, 'conversation');
|
|
16
|
-
const settings =
|
|
16
|
+
const settings = answersSettingsFor(context);
|
|
17
17
|
const question = use(quizServiceToken).ask({ key: key, kind: 'fun', bank: FUN_QUESTIONS, timeoutSeconds: settings.quizTimeoutSeconds, now: Date.now(), locale: locale });
|
|
18
18
|
return formatQuestion('fun', question, settings.quizTimeoutSeconds, locale);
|
|
19
19
|
},
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { messages } from '../../src/messages.js';
|
|
2
2
|
import { defineCommand } from 'zhin.js/command';
|
|
3
|
-
import {
|
|
3
|
+
import type { AnswersConfig } from '../../src/config.js';
|
|
4
4
|
import { FUN_QUESTIONS } from '../../src/fun-quiz-data.js';
|
|
5
5
|
import { formatQuestion, quizKey } from '../../src/quiz.js';
|
|
6
|
-
import { quizServiceToken } from '../../src/runtime.js';
|
|
6
|
+
import { answersSettingsFor, quizServiceToken } from '../../src/runtime.js';
|
|
7
7
|
|
|
8
8
|
export default defineCommand<AnswersConfig>({
|
|
9
9
|
preferredAliasI18n: { en: 'boring' },
|
|
10
10
|
description: '好无聊?来一道原创趣味选择题,直接回复字母作答', descriptionI18n: { en: "Try an original trivia question; reply with an option letter" },
|
|
11
11
|
alias: ['boring'],
|
|
12
|
-
execute(
|
|
12
|
+
execute(context) {
|
|
13
|
+
const { input, use, locale } = context;
|
|
13
14
|
const key = quizKey(input);
|
|
14
15
|
if (!key) return messages(locale, 'conversation');
|
|
15
|
-
const settings =
|
|
16
|
+
const settings = answersSettingsFor(context);
|
|
16
17
|
const question = use(quizServiceToken).ask({ key: key, kind: 'fun', bank: FUN_QUESTIONS, timeoutSeconds: settings.quizTimeoutSeconds, now: Date.now(), locale: locale });
|
|
17
18
|
return formatQuestion('fun', question, settings.quizTimeoutSeconds, locale);
|
|
18
19
|
},
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages } from "../../lib/messages.js";
|
|
3
3
|
import { defineCommand } from 'zhin.js/command';
|
|
4
|
-
import { resolveAnswersConfig } from "../../lib/config.js";
|
|
5
4
|
import { DRIVING_QUESTIONS } from "../../lib/driving-quiz-data.js";
|
|
6
5
|
import { formatQuestion, quizKey } from "../../lib/quiz.js";
|
|
7
|
-
import { quizServiceToken } from "../../lib/runtime.js";
|
|
6
|
+
import { answersSettingsFor, quizServiceToken } from "../../lib/runtime.js";
|
|
8
7
|
export default defineCommand({
|
|
9
8
|
alias: ['driving-quiz'],
|
|
10
9
|
preferredAliasI18n: { en: 'driving-quiz' },
|
|
11
10
|
description: '科目一交规小测(原创题面,依据公开法规整理,仅供娱乐参考)', descriptionI18n: { en: "Chinese driving theory quiz with original questions; for entertainment and reference only" },
|
|
12
|
-
execute(
|
|
13
|
-
const
|
|
11
|
+
execute(context) {
|
|
12
|
+
const { input, use, locale } = context;
|
|
13
|
+
const settings = answersSettingsFor(context);
|
|
14
14
|
if (!settings.enableDrivingQuiz)
|
|
15
15
|
return messages(locale, 'disabled');
|
|
16
16
|
const key = quizKey(input);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { messages } from '../../src/messages.js';
|
|
2
2
|
import { defineCommand } from 'zhin.js/command';
|
|
3
|
-
import {
|
|
3
|
+
import type { AnswersConfig } from '../../src/config.js';
|
|
4
4
|
import { DRIVING_QUESTIONS } from '../../src/driving-quiz-data.js';
|
|
5
5
|
import { formatQuestion, quizKey } from '../../src/quiz.js';
|
|
6
|
-
import { quizServiceToken } from '../../src/runtime.js';
|
|
6
|
+
import { answersSettingsFor, quizServiceToken } from '../../src/runtime.js';
|
|
7
7
|
|
|
8
8
|
export default defineCommand<AnswersConfig>({
|
|
9
9
|
alias: ['driving-quiz'],
|
|
10
10
|
preferredAliasI18n: { en: 'driving-quiz' },
|
|
11
11
|
description: '科目一交规小测(原创题面,依据公开法规整理,仅供娱乐参考)', descriptionI18n: { en: "Chinese driving theory quiz with original questions; for entertainment and reference only" },
|
|
12
|
-
execute(
|
|
13
|
-
const
|
|
12
|
+
execute(context) {
|
|
13
|
+
const { input, use, locale } = context;
|
|
14
|
+
const settings = answersSettingsFor(context);
|
|
14
15
|
if (!settings.enableDrivingQuiz) return messages(locale, 'disabled');
|
|
15
16
|
const key = quizKey(input);
|
|
16
17
|
if (!key) return messages(locale, 'conversation');
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { defineCommand } from 'zhin.js/command';
|
|
3
3
|
import { bookUsage, MAX_QUESTION_LENGTH, pickBookAnswer, replyBook } from "../../lib/book.js";
|
|
4
|
-
import {
|
|
4
|
+
import { answersSettingsFor } from "../../lib/runtime.js";
|
|
5
5
|
export default defineCommand({
|
|
6
6
|
preferredAliasI18n: { en: 'answerbook' },
|
|
7
7
|
description: '答案之书:心里默念问题,翻开一页得到答案', descriptionI18n: { en: "Book of Answers: think of a question and turn a page" },
|
|
8
8
|
alias: ['answerbook'],
|
|
9
9
|
params: { question: { type: 'text', optional: true, max: MAX_QUESTION_LENGTH, description: '你想问的问题', descriptionI18n: { en: "Your question" } } },
|
|
10
|
-
execute(
|
|
10
|
+
execute(context) {
|
|
11
|
+
const { params, input, locale, formatCommand } = context;
|
|
11
12
|
const question = typeof params.question === 'string' ? params.question.trim() : '';
|
|
12
13
|
if (!question)
|
|
13
14
|
return bookUsage(locale, formatCommand('答案之书'));
|
|
14
|
-
const settings =
|
|
15
|
+
const settings = answersSettingsFor(context);
|
|
15
16
|
const answer = pickBookAnswer({
|
|
16
17
|
question,
|
|
17
18
|
senderId: input?.sender?.id ?? 'anonymous',
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { defineCommand } from 'zhin.js/command';
|
|
2
2
|
import { bookUsage, MAX_QUESTION_LENGTH, pickBookAnswer, replyBook } from '../../src/book.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { AnswersConfig } from '../../src/config.js';
|
|
4
|
+
import { answersSettingsFor } from '../../src/runtime.js';
|
|
4
5
|
|
|
5
6
|
export default defineCommand<AnswersConfig>({
|
|
6
7
|
preferredAliasI18n: { en: 'answerbook' },
|
|
7
8
|
description: '答案之书:心里默念问题,翻开一页得到答案', descriptionI18n: { en: "Book of Answers: think of a question and turn a page" },
|
|
8
9
|
alias: ['answerbook'],
|
|
9
10
|
params: { question: { type: 'text', optional: true, max: MAX_QUESTION_LENGTH, description: '你想问的问题', descriptionI18n: { en: "Your question" } } },
|
|
10
|
-
execute(
|
|
11
|
+
execute(context) {
|
|
12
|
+
const { params, input, locale, formatCommand } = context;
|
|
11
13
|
const question = typeof params.question === 'string' ? params.question.trim() : '';
|
|
12
14
|
if (!question) return bookUsage(locale, formatCommand('答案之书'));
|
|
13
|
-
const settings =
|
|
15
|
+
const settings = answersSettingsFor(context);
|
|
14
16
|
const answer = pickBookAnswer({
|
|
15
17
|
question,
|
|
16
18
|
senderId: input?.sender?.id ?? 'anonymous',
|
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,sBAAsB;;;;;EAKjC,CAAC;AAEH,gIAAgI;AAChI,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;
|
|
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,sBAAsB;;;;;EAKjC,CAAC;AAEH,gIAAgI;AAChI,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;CASxB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAEhE,uGAAuG;AACvG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,SAAS,GAAG,aAAa,CAE9F"}
|
package/lib/config.js
CHANGED
|
@@ -11,6 +11,10 @@ export const answersConfig = Schema.object({
|
|
|
11
11
|
timezone: Schema.string().default(DEFAULT_ANSWERS_CONFIG.timezone).description('dailyStable 判断「同一天」所用的 IANA 时区').i18n({ "en": { "description": "IANA timezone used by dailyStable to determine the day." } }).effect('reload'),
|
|
12
12
|
quizTimeoutSeconds: Schema.number().min(15).max(600).step(1).default(DEFAULT_ANSWERS_CONFIG.quizTimeoutSeconds).description('出题后等待作答的秒数,超时题目作废').i18n({ "en": { "description": "Seconds to wait for a quiz answer; the question expires afterward." } }).effect('reload'),
|
|
13
13
|
enableDrivingQuiz: Schema.boolean().default(DEFAULT_ANSWERS_CONFIG.enableDrivingQuiz).description('启用「科目一」交规小测(原创题面,仅供娱乐参考)').i18n({ "en": { "description": "Enable the original driving-theory quiz, for entertainment and reference only." } }).effect('reload'),
|
|
14
|
+
}).featureLevels(['global', 'adapter', 'endpoint', 'conversation'], {
|
|
15
|
+
// ADR 0055: quiz fields can differ per group in the Console (timezone per adapter / account only); group admins may tune the quiz in chat.
|
|
16
|
+
conversationFields: ['dailyStable', 'quizTimeoutSeconds', 'enableDrivingQuiz'],
|
|
17
|
+
selfServiceFields: ['quizTimeoutSeconds', 'enableDrivingQuiz'],
|
|
14
18
|
});
|
|
15
19
|
/** Missing fields fall back to defaults so commands stay usable when Runtime passes a partial view. */
|
|
16
20
|
export function resolveAnswersConfig(config) {
|
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,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,WAAW,EAAE,KAAK;IAClB,QAAQ,EAAE,eAAe;IACzB,kBAAkB,EAAE,GAAG;IACvB,iBAAiB,EAAE,IAAI;CACxB,CAAC,CAAC;AAEH,gIAAgI;AAChI,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,qGAAqG,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACxQ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,yDAAyD,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC1N,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,oEAAoE,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACrQ,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,gFAAgF,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;CAC/P,CAAC,CAAC;AAIH,uGAAuG;AACvG,MAAM,UAAU,oBAAoB,CAAC,MAA0C;IAC7E,OAAO,EAAE,GAAG,sBAAsB,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAmB,CAAC;AAC3E,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,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,WAAW,EAAE,KAAK;IAClB,QAAQ,EAAE,eAAe;IACzB,kBAAkB,EAAE,GAAG;IACvB,iBAAiB,EAAE,IAAI;CACxB,CAAC,CAAC;AAEH,gIAAgI;AAChI,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,qGAAqG,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACxQ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,gCAAgC,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,yDAAyD,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC1N,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,oEAAoE,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;IACrQ,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,EAAC,aAAa,EAAE,gFAAgF,EAAC,EAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;CAC/P,CAAC,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE;IAClE,2IAA2I;IAC3I,kBAAkB,EAAE,CAAC,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,CAAC;IAC9E,iBAAiB,EAAE,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;CAC/D,CAAC,CAAC;AAIH,uGAAuG;AACvG,MAAM,UAAU,oBAAoB,CAAC,MAA0C;IAC7E,OAAO,EAAE,GAAG,sBAAsB,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAmB,CAAC;AAC3E,CAAC"}
|
package/lib/runtime.d.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import type { QuizService } from './quiz.js';
|
|
2
|
+
import { type AnswersConfig } from './config.js';
|
|
2
3
|
/** Owner-scoped quiz state consumed by discovered commands and middleware. */
|
|
3
4
|
export declare const quizServiceStore: import("zhin.js").PluginStore<QuizService, unknown>;
|
|
4
5
|
export declare const quizServiceToken: import("zhin.js").PluginStore<QuizService, unknown>;
|
|
6
|
+
/** Effective configuration per message (ADR 0050 / 0055): global < adapter < endpoint < conversation. */
|
|
7
|
+
export interface AnswersConfigResolver {
|
|
8
|
+
configFor(message: unknown): Readonly<Partial<AnswersConfig>>;
|
|
9
|
+
}
|
|
10
|
+
export declare const answersConfigStore: import("zhin.js").PluginStore<AnswersConfigResolver, unknown>;
|
|
11
|
+
/** Settings for one command call: the conversation's effective config when the resolver is provided, else the global view. */
|
|
12
|
+
export declare function answersSettingsFor(context: {
|
|
13
|
+
readonly config?: Partial<AnswersConfig>;
|
|
14
|
+
readonly input?: unknown;
|
|
15
|
+
readonly has?: (token: typeof answersConfigStore) => boolean;
|
|
16
|
+
readonly use: (token: typeof answersConfigStore) => AnswersConfigResolver;
|
|
17
|
+
}): AnswersConfig;
|
|
5
18
|
//# 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,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvE,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,qDAA4G,CAAC;AAC1I,eAAO,MAAM,gBAAgB,qDAAmB,CAAC;AAEjD,yGAAyG;AACzG,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;CAC/D;AACD,eAAO,MAAM,kBAAkB,+DAAmH,CAAC;AAEnJ,8HAA8H;AAC9H,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,kBAAkB,KAAK,OAAO,CAAC;IAC7D,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,kBAAkB,KAAK,qBAAqB,CAAC;CAC3E,GAAG,aAAa,CAGhB"}
|
package/lib/runtime.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { definePluginStore } from 'zhin.js';
|
|
2
|
+
import { resolveAnswersConfig } from './config.js';
|
|
2
3
|
/** Owner-scoped quiz state consumed by discovered commands and middleware. */
|
|
3
4
|
export const quizServiceStore = definePluginStore('zhin.answers.quiz', 'Pending quiz questions per conversation and sender');
|
|
4
5
|
export const quizServiceToken = quizServiceStore;
|
|
6
|
+
export const answersConfigStore = definePluginStore('zhin.answers.config', 'Layered answers configuration for one message');
|
|
7
|
+
/** Settings for one command call: the conversation's effective config when the resolver is provided, else the global view. */
|
|
8
|
+
export function answersSettingsFor(context) {
|
|
9
|
+
const resolver = context.input !== undefined && context.has?.(answersConfigStore) ? context.use(answersConfigStore) : undefined;
|
|
10
|
+
return resolveAnswersConfig({ ...(context.config ?? {}), ...(resolver?.configFor(context.input) ?? {}) });
|
|
11
|
+
}
|
|
5
12
|
//# 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;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAC;AAEvE,8EAA8E;AAC9E,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAc,mBAAmB,EAAE,oDAAoD,CAAC,CAAC;AAC1I,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAMjD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAwB,qBAAqB,EAAE,+CAA+C,CAAC,CAAC;AAEnJ,8HAA8H;AAC9H,MAAM,UAAU,kBAAkB,CAAC,OAKlC;IACC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChI,OAAO,oBAAoB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAC5G,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-answers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Zhin.js 答案之书、趣味选择题与交规小测(原创内容,Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -37,12 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@zhin.js/core": "1.
|
|
40
|
+
"@zhin.js/core": "1.2.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"typescript": "^6.0.3",
|
|
44
44
|
"vitest": "^4.1.10",
|
|
45
|
-
"zhin.js": "1.
|
|
45
|
+
"@zhin.js/testing": "1.0.10",
|
|
46
|
+
"zhin.js": "1.1.26"
|
|
46
47
|
},
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
@@ -75,9 +76,9 @@
|
|
|
75
76
|
"plugins": []
|
|
76
77
|
},
|
|
77
78
|
"peerDependencies": {
|
|
78
|
-
"@zhin.js/command": "^1.
|
|
79
|
-
"@zhin.js/middleware": "^1.1.
|
|
80
|
-
"zhin.js": "^1.1.
|
|
79
|
+
"@zhin.js/command": "^1.2.0",
|
|
80
|
+
"@zhin.js/middleware": "^1.1.17",
|
|
81
|
+
"zhin.js": "^1.1.26"
|
|
81
82
|
},
|
|
82
83
|
"peerDependenciesMeta": {
|
|
83
84
|
"@zhin.js/command": {
|
|
@@ -90,6 +91,6 @@
|
|
|
90
91
|
"scripts": {
|
|
91
92
|
"build": "tsc",
|
|
92
93
|
"clean": "rimraf lib",
|
|
93
|
-
"test": "
|
|
94
|
+
"test": "vitest run --root ../../.. plugins/utils/answers/tests"
|
|
94
95
|
}
|
|
95
96
|
}
|
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 { QuizService } from "./lib/quiz.js";
|
|
4
|
-
import { quizServiceStore } from "./lib/runtime.js";
|
|
4
|
+
import { answersConfigStore, quizServiceStore } from "./lib/runtime.js";
|
|
5
5
|
/**
|
|
6
6
|
* Plugin Runtime:
|
|
7
7
|
* - `commands/` 提供 答案之书 / 好无聊 / 科目一;
|
|
@@ -15,5 +15,9 @@ export default definePlugin({
|
|
|
15
15
|
},
|
|
16
16
|
setup(context) {
|
|
17
17
|
quizServiceStore.provide(context, new QuizService());
|
|
18
|
+
// ADR 0050 / 0055: quiz settings may differ per adapter / account / conversation (in place, no reload).
|
|
19
|
+
answersConfigStore.provide(context, {
|
|
20
|
+
configFor: message => context.configFor(message),
|
|
21
|
+
});
|
|
18
22
|
},
|
|
19
23
|
});
|
package/schema.json
CHANGED
|
@@ -57,5 +57,22 @@
|
|
|
57
57
|
"effect": "reload"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
},
|
|
61
|
+
"x-zhin-config": {
|
|
62
|
+
"levels": [
|
|
63
|
+
"global",
|
|
64
|
+
"adapter",
|
|
65
|
+
"endpoint",
|
|
66
|
+
"conversation"
|
|
67
|
+
],
|
|
68
|
+
"conversationFields": [
|
|
69
|
+
"dailyStable",
|
|
70
|
+
"quizTimeoutSeconds",
|
|
71
|
+
"enableDrivingQuiz"
|
|
72
|
+
],
|
|
73
|
+
"selfServiceFields": [
|
|
74
|
+
"quizTimeoutSeconds",
|
|
75
|
+
"enableDrivingQuiz"
|
|
76
|
+
]
|
|
60
77
|
}
|
|
61
78
|
}
|
package/src/config.ts
CHANGED
|
@@ -13,6 +13,10 @@ export const answersConfig = Schema.object({
|
|
|
13
13
|
timezone: Schema.string().default(DEFAULT_ANSWERS_CONFIG.timezone).description('dailyStable 判断「同一天」所用的 IANA 时区').i18n({"en": {"description": "IANA timezone used by dailyStable to determine the day."}}).effect('reload'),
|
|
14
14
|
quizTimeoutSeconds: Schema.number().min(15).max(600).step(1).default(DEFAULT_ANSWERS_CONFIG.quizTimeoutSeconds).description('出题后等待作答的秒数,超时题目作废').i18n({"en": {"description": "Seconds to wait for a quiz answer; the question expires afterward."}}).effect('reload'),
|
|
15
15
|
enableDrivingQuiz: Schema.boolean().default(DEFAULT_ANSWERS_CONFIG.enableDrivingQuiz).description('启用「科目一」交规小测(原创题面,仅供娱乐参考)').i18n({"en": {"description": "Enable the original driving-theory quiz, for entertainment and reference only."}}).effect('reload'),
|
|
16
|
+
}).featureLevels(['global', 'adapter', 'endpoint', 'conversation'], {
|
|
17
|
+
// ADR 0055: quiz fields can differ per group in the Console (timezone per adapter / account only); group admins may tune the quiz in chat.
|
|
18
|
+
conversationFields: ['dailyStable', 'quizTimeoutSeconds', 'enableDrivingQuiz'],
|
|
19
|
+
selfServiceFields: ['quizTimeoutSeconds', 'enableDrivingQuiz'],
|
|
16
20
|
});
|
|
17
21
|
|
|
18
22
|
export type AnswersConfig = Schema.Output<typeof answersConfig>;
|
package/src/runtime.ts
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { definePluginStore } from 'zhin.js';
|
|
2
2
|
import type { QuizService } from './quiz.js';
|
|
3
|
+
import { resolveAnswersConfig, type AnswersConfig } from './config.js';
|
|
3
4
|
|
|
4
5
|
/** Owner-scoped quiz state consumed by discovered commands and middleware. */
|
|
5
6
|
export const quizServiceStore = definePluginStore<QuizService>('zhin.answers.quiz', 'Pending quiz questions per conversation and sender');
|
|
6
7
|
export const quizServiceToken = quizServiceStore;
|
|
8
|
+
|
|
9
|
+
/** Effective configuration per message (ADR 0050 / 0055): global < adapter < endpoint < conversation. */
|
|
10
|
+
export interface AnswersConfigResolver {
|
|
11
|
+
configFor(message: unknown): Readonly<Partial<AnswersConfig>>;
|
|
12
|
+
}
|
|
13
|
+
export const answersConfigStore = definePluginStore<AnswersConfigResolver>('zhin.answers.config', 'Layered answers configuration for one message');
|
|
14
|
+
|
|
15
|
+
/** Settings for one command call: the conversation's effective config when the resolver is provided, else the global view. */
|
|
16
|
+
export function answersSettingsFor(context: {
|
|
17
|
+
readonly config?: Partial<AnswersConfig>;
|
|
18
|
+
readonly input?: unknown;
|
|
19
|
+
readonly has?: (token: typeof answersConfigStore) => boolean;
|
|
20
|
+
readonly use: (token: typeof answersConfigStore) => AnswersConfigResolver;
|
|
21
|
+
}): AnswersConfig {
|
|
22
|
+
const resolver = context.input !== undefined && context.has?.(answersConfigStore) ? context.use(answersConfigStore) : undefined;
|
|
23
|
+
return resolveAnswersConfig({ ...(context.config ?? {}), ...(resolver?.configFor(context.input) ?? {}) });
|
|
24
|
+
}
|