@zhin.js/plugin-word-riddle 1.0.3 → 1.0.5

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.
@@ -0,0 +1,16 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { messageFromCommandInput, normalizeRiddleAction } from '@zhin.js/game-kit';
4
+ import { RIDDLE_HELP, runRiddleCommand } from "../../lib/riddle-command.js";
5
+ import { resolveGameServices } from "../../lib/runtime-store.js";
6
+ export default defineCommand({
7
+ description: 'Word Riddle',
8
+ async execute({ params, input, use, owner }) {
9
+ const action = normalizeRiddleAction(String(params.action ?? ''));
10
+ if (!action || action === 'help')
11
+ return RIDDLE_HELP;
12
+ const services = resolveGameServices({ use, owner });
13
+ const message = messageFromCommandInput(input);
14
+ return runRiddleCommand(services, message, action);
15
+ },
16
+ });
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from '@zhin.js/command';
2
2
  import { messageFromCommandInput, normalizeRiddleAction } from '@zhin.js/game-kit';
3
- import { RIDDLE_HELP, runRiddleCommandText } from '../../src/riddle-command.js';
3
+ import { RIDDLE_HELP, runRiddleCommand } from '../../src/riddle-command.js';
4
4
  import { resolveGameServices } from '../../src/runtime-store.js';
5
5
 
6
6
  export default defineCommand({
@@ -10,6 +10,6 @@ export default defineCommand({
10
10
  if (!action || action === 'help') return RIDDLE_HELP;
11
11
  const services = resolveGameServices({ use, owner });
12
12
  const message = messageFromCommandInput(input);
13
- return runRiddleCommandText(services, message, action);
13
+ return runRiddleCommand(services, message, action);
14
14
  },
15
15
  });
@@ -1,11 +1,9 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
1
+ import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
2
2
  import { RIDDLE_PREFIX } from './engine.js';
3
- import type { RiddleSessionRow } from './models.js';
4
3
  import type { RiddleType } from './riddles-catalog.js';
5
4
  import { type SessionService } from './session-service.js';
6
- export declare function sendOrEditView(plugin: Plugin | null, services: SessionService, message: Message<any>, session: RiddleSessionRow, eventLines?: string[]): Promise<string | void>;
7
- export declare function startGame(plugin: Plugin | null, services: SessionService, message: Message<any>, mode: RiddleType): Promise<string | undefined>;
8
- export declare function continueGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string>;
9
- export declare function processAnswerText(plugin: Plugin | null, services: SessionService, message: Message<any>, raw: string): Promise<string | null>;
10
- export declare function handleChoice(plugin: Plugin | null, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
5
+ export declare function startGame(services: SessionService, message: GameMessageLike, mode: RiddleType): Promise<GameReply | undefined>;
6
+ export declare function continueGame(services: SessionService, message: GameMessageLike): Promise<GameReply>;
7
+ export declare function processAnswerText(services: SessionService, message: GameMessageLike, raw: string): Promise<GameReply | null>;
8
+ export declare function handleChoice(services: SessionService, message: GameMessageLike, sessionId: string, choiceId: string): Promise<GameReply | null>;
11
9
  export { RIDDLE_PREFIX };
package/lib/game-flow.js CHANGED
@@ -1,35 +1,13 @@
1
- import { plainTextFromSendContent } from '@zhin.js/game-kit';
2
- import { checkAnswer, getRiddleById, RIDDLE_PREFIX, typeLabel, } from './engine.js';
1
+ import { answersFor, checkAnswer, getRiddleById, normalizeAnswer, RIDDLE_PREFIX, typeLabel, } from './engine.js';
3
2
  import { currentRiddleId, parseQueue, } from './session-service.js';
4
3
  import { buildRiddleView, MAX_WRONG } from './view.js';
5
- export async function sendOrEditView(plugin, services, message, session, eventLines = []) {
6
- const content = buildRiddleView(session, eventLines, message.$channel.type);
7
- if (typeof content === 'string') {
8
- if (!plugin)
9
- return content;
10
- await message.$reply?.(content);
11
- return;
12
- }
13
- if (!plugin)
14
- return plainTextFromSendContent(content);
15
- const adapter = plugin.root.inject(message.$adapter);
16
- if (session.board_message_id) {
17
- const msgId = await adapter.editMessage({
18
- messageId: session.board_message_id,
19
- context: String(message.$adapter),
20
- endpoint: message.$endpoint,
21
- id: message.$channel.id,
22
- type: message.$channel.type,
23
- content,
24
- });
25
- if (msgId !== session.board_message_id) {
26
- await services.updateSession(session.id, { board_message_id: msgId });
27
- }
28
- return;
29
- }
30
- const msgId = await message.$reply?.(content);
31
- if (msgId)
32
- await services.updateSession(session.id, { board_message_id: msgId });
4
+ /**
5
+ * Plugin Runtime: render the board as text. Interactive in-place board editing
6
+ * (the old Adapter.editMessage path) is not part of the runtime flow; commands
7
+ * and the text middleware return fresh text each turn.
8
+ */
9
+ function renderView(message, session, eventLines = []) {
10
+ return buildRiddleView(session, eventLines, message.$channel.type);
33
11
  }
34
12
  async function advanceQuestion(services, session) {
35
13
  const queue = parseQueue(session.queue);
@@ -42,7 +20,7 @@ async function advanceQuestion(services, session) {
42
20
  }
43
21
  return (await services.getById(session.id));
44
22
  }
45
- export async function startGame(plugin, services, message, mode) {
23
+ export async function startGame(services, message, mode) {
46
24
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
47
25
  const active = await services.getActiveByChannel(ch);
48
26
  if (active) {
@@ -52,19 +30,15 @@ export async function startGame(plugin, services, message, mode) {
52
30
  return `本频道 ${active.player_name} 正在猜谜。`;
53
31
  }
54
32
  const session = await services.createSession(message, mode);
55
- const text = await sendOrEditView(plugin, services, message, session);
56
- return typeof text === 'string' ? text : undefined;
33
+ return renderView(message, session);
57
34
  }
58
- export async function continueGame(plugin, services, message) {
35
+ export async function continueGame(services, message) {
59
36
  const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
60
37
  if (!session)
61
38
  return '你没有进行中的猜谜,发送「猜谜 开始」。';
62
- const text = await sendOrEditView(plugin, services, message, session);
63
- if (typeof text === 'string')
64
- return text;
65
- return '已刷新猜谜界面。';
39
+ return renderView(message, session);
66
40
  }
67
- export async function processAnswerText(plugin, services, message, raw) {
41
+ export async function processAnswerText(services, message, raw) {
68
42
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
69
43
  const session = await services.getActiveForUser(ch, message.$sender.id);
70
44
  if (!session || session.status !== 'active')
@@ -73,6 +47,11 @@ export async function processAnswerText(plugin, services, message, raw) {
73
47
  const entry = riddleId ? getRiddleById(riddleId) : undefined;
74
48
  if (!entry)
75
49
  return null;
50
+ // 格式不合规(字数与答案不符)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
51
+ const normalized = normalizeAnswer(raw);
52
+ if (!answersFor(entry).some((a) => a.length === normalized.length)) {
53
+ return `本题答案应为 ${entry.answer.length} 个字(这条不算失误)。`;
54
+ }
76
55
  if (checkAnswer(entry, raw)) {
77
56
  const streak = session.streak + 1;
78
57
  const best = Math.max(session.best_streak, streak);
@@ -84,25 +63,25 @@ export async function processAnswerText(plugin, services, message, raw) {
84
63
  });
85
64
  const after = await advanceQuestion(services, (await services.getById(session.id)));
86
65
  const explain = entry.explanation ? `\n📖 ${entry.explanation}` : '';
87
- return (await sendOrEditView(plugin, services, message, after, [
66
+ return renderView(message, after, [
88
67
  `✅ 正确!答案:**${entry.answer}**${explain}`,
89
68
  `+${10 + Math.min(streak, 5)} 分`,
90
- ])) ?? null;
69
+ ]);
91
70
  }
92
71
  const wrong = session.wrong_count + 1;
93
72
  if (wrong >= MAX_WRONG) {
94
73
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
95
74
  const after = await advanceQuestion(services, (await services.getById(session.id)));
96
- return (await sendOrEditView(plugin, services, message, after, [
75
+ return renderView(message, after, [
97
76
  `❌ 本题答案:**${entry.answer}**`,
98
77
  '失误过多,自动下一题。',
99
- ])) ?? null;
78
+ ]);
100
79
  }
101
80
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
102
81
  const updated = (await services.getById(session.id));
103
- return (await sendOrEditView(plugin, services, message, updated, ['❌ 不对,再想想!'])) ?? null;
82
+ return renderView(message, updated, ['❌ 不对,再想想!']);
104
83
  }
105
- export async function handleChoice(plugin, services, message, sessionId, choiceId) {
84
+ export async function handleChoice(services, message, sessionId, choiceId) {
106
85
  const session = await services.getById(sessionId);
107
86
  if (!session)
108
87
  return '会话不存在。';
@@ -110,11 +89,11 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
110
89
  return '这是别人的猜谜。';
111
90
  if (choiceId === 'restart_char') {
112
91
  await services.updateSession(session.id, { status: 'aborted' });
113
- return startGame(plugin, services, message, 'char');
92
+ return (await startGame(services, message, 'char')) ?? null;
114
93
  }
115
94
  if (choiceId === 'restart_idiom') {
116
95
  await services.updateSession(session.id, { status: 'aborted' });
117
- return startGame(plugin, services, message, 'idiom');
96
+ return (await startGame(services, message, 'idiom')) ?? null;
118
97
  }
119
98
  if (session.status !== 'active')
120
99
  return '本轮已结束。';
@@ -126,17 +105,17 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
126
105
  const hint = entry.hint ?? `答案共 ${entry.answer.length} 个字`;
127
106
  await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
128
107
  const updated = (await services.getById(session.id));
129
- return (await sendOrEditView(plugin, services, message, updated, [
108
+ return renderView(message, updated, [
130
109
  `💡 提示:${hint}`,
131
110
  '(连击清零)',
132
- ])) ?? null;
111
+ ]);
133
112
  }
134
113
  if (choiceId === 'skip') {
135
114
  await services.updateSession(session.id, { streak: 0 });
136
115
  const after = await advanceQuestion(services, session);
137
- return (await sendOrEditView(plugin, services, message, after, [
116
+ return renderView(message, after, [
138
117
  `⏭️ 跳过,答案:**${entry.answer}**`,
139
- ])) ?? null;
118
+ ]);
140
119
  }
141
120
  if (choiceId === 'quit') {
142
121
  await services.updateSession(session.id, { status: 'aborted' });
@@ -1 +1 @@
1
- {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { RIDDLE_HELP } from './riddle-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryRiddleDb, mountRiddleMemoryServices } from './memory-db.js';
4
3
  /**
5
4
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
6
5
  * 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
package/lib/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export { RIDDLE_HELP } from './riddle-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryRiddleDb, mountRiddleMemoryServices } from './memory-db.js';
4
3
  /**
5
4
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
6
5
  * 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEnF;;;;GAIG"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E;;;;GAIG"}
package/lib/models.d.ts CHANGED
@@ -20,7 +20,6 @@ declare module '@zhin.js/core' {
20
20
  hints_used: number;
21
21
  wrong_count: number;
22
22
  status: RiddleSessionStatus;
23
- board_message_id: string;
24
23
  updated_at: number;
25
24
  created_at: number;
26
25
  };
package/lib/models.js CHANGED
@@ -17,7 +17,6 @@ export function defineHostTables(db) {
17
17
  hints_used: { type: 'integer', default: 0 },
18
18
  wrong_count: { type: 'integer', default: 0 },
19
19
  status: { type: 'text', default: 'active' },
20
- board_message_id: { type: 'text', default: '' },
21
20
  updated_at: { type: 'integer', default: 0 },
22
21
  created_at: { type: 'integer', default: 0 },
23
22
  });
package/lib/models.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAkCA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,sBAAsB,EAAE;QAChC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;QACvC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAiCA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,sBAAsB,EAAE;QAChC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;QACvC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC;AACL,CAAC"}
@@ -1,6 +1,4 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
1
+ import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
2
2
  import type { SessionService } from './session-service.js';
3
3
  export declare const RIDDLE_HELP: string;
4
- export declare function runRiddleCommand(plugin: Plugin | null, services: SessionService, message: Message<any>, action: string): Promise<string | undefined>;
5
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
6
- export declare function runRiddleCommandText(services: SessionService, message: Message<any>, action: string): Promise<string>;
4
+ export declare function runRiddleCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
@@ -1,4 +1,4 @@
1
- import { channelKey } from '@zhin.js/game-kit';
1
+ import { channelKey, } from '@zhin.js/game-kit';
2
2
  import { continueGame, startGame } from './game-flow.js';
3
3
  import { riddleCount } from './riddles-catalog.js';
4
4
  import { typeLabel } from './engine.js';
@@ -24,7 +24,7 @@ function parseMode(action) {
24
24
  return 'char';
25
25
  return null;
26
26
  }
27
- export async function runRiddleCommand(plugin, services, message, action) {
27
+ export async function runRiddleCommand(services, message, action) {
28
28
  const ch = channelKey(message);
29
29
  const userId = message.$sender.id;
30
30
  if (!action || action === 'help') {
@@ -40,9 +40,9 @@ export async function runRiddleCommand(plugin, services, message, action) {
40
40
  }
41
41
  const mode = parseMode(action);
42
42
  if (mode)
43
- return startGame(plugin, services, message, mode);
43
+ return (await startGame(services, message, mode)) ?? '';
44
44
  if (action === 'continue' || action === '继续') {
45
- return continueGame(plugin, services, message);
45
+ return continueGame(services, message);
46
46
  }
47
47
  if (action === 'quit' || action === '放弃') {
48
48
  const row = await services.getActiveForUser(ch, userId);
@@ -53,8 +53,4 @@ export async function runRiddleCommand(plugin, services, message, action) {
53
53
  }
54
54
  return `未知子命令:${action}\n\n${RIDDLE_HELP}`;
55
55
  }
56
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
57
- export async function runRiddleCommandText(services, message, action) {
58
- return (await runRiddleCommand(null, services, message, action)) ?? '';
59
- }
60
56
  //# sourceMappingURL=riddle-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"riddle-command.js","sourceRoot":"","sources":["../src/riddle-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAmB,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;AAE7B,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI;IAC5F,kBAAkB;IAClB,cAAc;IACd,cAAc;IACd,eAAe;IACf,cAAc;IACd,YAAY;IACZ,EAAE;IACF,4BAA4B;CAC7B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,SAAS,SAAS,CAAC,MAAc;IAC/B,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACxD,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IAC1D,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAkB,CAAC,SAAS,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvG,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAE5D,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAC7C,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,YAAY,CAAC;QAC9B,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,WAAW,EAAE,CAAC;AAC7C,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,OAAO,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"riddle-command.js","sourceRoot":"","sources":["../src/riddle-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAmB,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;AAE7B,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI;IAC5F,kBAAkB;IAClB,cAAc;IACd,cAAc;IACd,eAAe;IACf,cAAc;IACd,YAAY;IACZ,EAAE;IACF,4BAA4B;CAC7B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,SAAS,SAAS,CAAC,MAAc;IAC/B,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACxD,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IAC1D,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAwB,EACxB,OAAwB,EACxB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAkB,CAAC,SAAS,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvG,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,IAAI;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAElE,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QAC7C,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,YAAY,CAAC;QAC9B,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,WAAW,EAAE,CAAC;AAC7C,CAAC"}
@@ -1,18 +1,12 @@
1
- import type { Database, Message, Models } from '@zhin.js/core';
1
+ import type { Database, Models } from '@zhin.js/core';
2
+ import { BaseSessionService, type GameMessageLike } from '@zhin.js/game-kit';
2
3
  import { type RiddleType } from './riddles-catalog.js';
3
4
  import type { RiddleSessionRow } from './models.js';
4
5
  export type RiddleDatabase = Database<unknown, Models, string>;
5
6
  export declare function parseQueue(value: string | string[] | unknown): string[];
6
- export declare class SessionService {
7
- private readonly db;
7
+ export declare class SessionService extends BaseSessionService<RiddleSessionRow> {
8
8
  constructor(db: RiddleDatabase);
9
- getActiveByChannel(channel: string): Promise<RiddleSessionRow | null>;
10
- getActiveForUser(channel: string, userId: string): Promise<RiddleSessionRow | null>;
11
- getById(id: string): Promise<RiddleSessionRow | null>;
12
- getActiveByBoardMessageId(messageId: string): Promise<RiddleSessionRow | null>;
13
- createSession(message: Message<any>, mode: RiddleType): Promise<RiddleSessionRow>;
14
- updateSession(id: string, patch: Partial<RiddleSessionRow>): Promise<void>;
15
- abortStale(idleMs: number): Promise<number>;
9
+ createSession(message: GameMessageLike, mode: RiddleType): Promise<RiddleSessionRow>;
16
10
  }
17
11
  export declare function createServices(db: RiddleDatabase): SessionService;
18
12
  export declare function currentRiddleId(session: RiddleSessionRow): string | null;
@@ -1,11 +1,5 @@
1
- import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-kit';
1
+ import { BaseSessionService, channelKey, generateSessionId, } from '@zhin.js/game-kit';
2
2
  import { pickRoundQueue } from './riddles-catalog.js';
3
- function getModel(db) {
4
- const model = db.models.get('word_riddle_sessions');
5
- if (!model)
6
- throw new Error('word_riddle_sessions not registered');
7
- return model;
8
- }
9
3
  export function parseQueue(value) {
10
4
  if (Array.isArray(value))
11
5
  return value.filter((x) => typeof x === 'string');
@@ -19,33 +13,13 @@ export function parseQueue(value) {
19
13
  return [];
20
14
  }
21
15
  }
22
- export class SessionService {
23
- db;
16
+ export class SessionService extends BaseSessionService {
24
17
  constructor(db) {
25
- this.db = db;
26
- }
27
- async getActiveByChannel(channel) {
28
- const rows = await getModel(this.db).findAll({ channel_key: channel, status: 'active' });
29
- return rows[0] ?? null;
30
- }
31
- async getActiveForUser(channel, userId) {
32
- const row = await this.getActiveByChannel(channel);
33
- if (!row || row.player_id !== userId)
34
- return null;
35
- return row;
36
- }
37
- async getById(id) {
38
- return getModel(this.db).findOne({ id });
39
- }
40
- async getActiveByBoardMessageId(messageId) {
41
- if (!messageId)
42
- return null;
43
- const rows = await getModel(this.db).findAll({});
44
- for (const row of rows) {
45
- if (boardMessageMatches(row.board_message_id ?? '', messageId))
46
- return row;
47
- }
48
- return null;
18
+ super(db, {
19
+ gameId: 'riddle',
20
+ table: 'word_riddle_sessions',
21
+ userFields: ['player_id'],
22
+ });
49
23
  }
50
24
  async createSession(message, mode) {
51
25
  const now = Date.now();
@@ -68,28 +42,10 @@ export class SessionService {
68
42
  hints_used: 0,
69
43
  wrong_count: 0,
70
44
  status: 'active',
71
- board_message_id: '',
72
45
  updated_at: now,
73
46
  created_at: now,
74
47
  };
75
- await getModel(this.db).create(row);
76
- return row;
77
- }
78
- async updateSession(id, patch) {
79
- await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
80
- }
81
- async abortStale(idleMs) {
82
- const cutoff = Date.now() - idleMs;
83
- const model = getModel(this.db);
84
- const rows = await model.findAll({ status: 'active' });
85
- let n = 0;
86
- for (const row of rows) {
87
- if (row.updated_at < cutoff) {
88
- await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
89
- n++;
90
- }
91
- }
92
- return n;
48
+ return this.createRow(row);
93
49
  }
94
50
  }
95
51
  export function createServices(db) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAKvE,MAAM,UAAU,UAAU,CAAC,KAAkC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACzF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAoC;IACtE,YAAY,EAAkB;QAC5B,KAAK,CAAC,EAAsD,EAAE;YAC5D,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB,EAAE,IAAgB;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,GAAG,GAAqB;YAC5B,EAAE,EAAE,iBAAiB,EAAE;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,IAAI;YACJ,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAC5B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB;IAC/C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAGD,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AACtC,CAAC"}
@@ -0,0 +1,18 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineGameCommandAliasMiddleware, isRiddleAction, messageFromCommandInput, normalizeRiddleAction, } from '@zhin.js/game-kit';
3
+ import { RIDDLE_HELP, runRiddleCommand } from "../lib/riddle-command.js";
4
+ import { resolveGameServices } from "../lib/runtime-store.js";
5
+ export default defineGameCommandAliasMiddleware({
6
+ aliases: ['猜谜', 'riddle'],
7
+ async run(action, input, context) {
8
+ const normalized = normalizeRiddleAction(String(action ?? ''));
9
+ if (normalized === 'help')
10
+ return RIDDLE_HELP;
11
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
12
+ if (!isRiddleAction(normalized))
13
+ return null;
14
+ const services = resolveGameServices(context);
15
+ const message = messageFromCommandInput(input);
16
+ return runRiddleCommand(services, message, normalized);
17
+ },
18
+ });
@@ -1,18 +1,21 @@
1
1
  import {
2
2
  defineGameCommandAliasMiddleware,
3
+ isRiddleAction,
3
4
  messageFromCommandInput,
4
5
  normalizeRiddleAction,
5
6
  } from '@zhin.js/game-kit';
6
- import { RIDDLE_HELP, runRiddleCommandText } from '../src/riddle-command.js';
7
+ import { RIDDLE_HELP, runRiddleCommand } from '../src/riddle-command.js';
7
8
  import { resolveGameServices } from '../src/runtime-store.js';
8
9
 
9
10
  export default defineGameCommandAliasMiddleware({
10
11
  aliases: ['猜谜', 'riddle'],
11
12
  async run(action, input, context) {
12
13
  const normalized = normalizeRiddleAction(String(action ?? ''));
13
- if (!normalized || normalized === 'help') return RIDDLE_HELP;
14
+ if (normalized === 'help') return RIDDLE_HELP;
15
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
16
+ if (!isRiddleAction(normalized)) return null;
14
17
  const services = resolveGameServices(context);
15
18
  const message = messageFromCommandInput(input);
16
- return runRiddleCommandText(services, message, normalized);
19
+ return runRiddleCommand(services, message, normalized);
17
20
  },
18
21
  });
@@ -0,0 +1,66 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineMiddleware } from '@zhin.js/middleware';
3
+ import { buildChoiceFallbackMap, channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
4
+ import { resolveGameServices } from "../lib/runtime-store.js";
5
+ import { handleChoice, processAnswerText, RIDDLE_PREFIX } from "../lib/game-flow.js";
6
+ /**
7
+ * 文本入口:按钮 payload(`riddle:session:choiceId`)、数字 fallback
8
+ * (『1提示 2跳过 3结束』,对应 view 的 fallbackHint),其余按谜底作答。
9
+ */
10
+ export default defineMiddleware({
11
+ target: 'inbound',
12
+ async handle(context, next) {
13
+ const raw = context.input.content?.trim() ?? '';
14
+ if (!raw) {
15
+ await next();
16
+ return;
17
+ }
18
+ const services = resolveGameServices(context);
19
+ const message = messageFromCommandInput(context.input);
20
+ const ch = channelKey(message);
21
+ // 直接 payload(QQ 指令预填 / Sandbox action→text)
22
+ const payloadFromText = resolveGameTextPayload(raw);
23
+ if (payloadFromText?.startsWith(`${RIDDLE_PREFIX}:`)) {
24
+ const parsed = parseChoicePayload(payloadFromText, RIDDLE_PREFIX);
25
+ if (parsed) {
26
+ const session = await services.getById(parsed.sessionId);
27
+ if (session?.channel_key === ch) {
28
+ const reply = await handleChoice(services, message, parsed.sessionId, parsed.choiceId);
29
+ if (reply)
30
+ await context.input.$reply(reply);
31
+ return;
32
+ }
33
+ }
34
+ await next();
35
+ return;
36
+ }
37
+ const session = await services.getActiveForUser(ch, message.$sender.id);
38
+ if (!session) {
39
+ await next();
40
+ return;
41
+ }
42
+ if (session.status === 'active') {
43
+ const map = buildChoiceFallbackMap(RIDDLE_PREFIX, session.id, [
44
+ { id: 'hint', label: '提示' },
45
+ { id: 'skip', label: '跳过' },
46
+ { id: 'quit', label: '结束' },
47
+ ]);
48
+ const payload = resolveGameTextPayload(raw, map);
49
+ const parsed = payload ? parseChoicePayload(payload, RIDDLE_PREFIX) : null;
50
+ if (parsed?.sessionId === session.id) {
51
+ const reply = await handleChoice(services, message, session.id, parsed.choiceId);
52
+ if (reply)
53
+ await context.input.$reply(reply);
54
+ return;
55
+ }
56
+ }
57
+ // 仅把 1-8 个汉字的纯文本当谜底作答,其余放行
58
+ if (/^[\u4e00-\u9fff]{1,8}$/.test(raw)) {
59
+ const reply = await processAnswerText(services, message, raw);
60
+ if (reply)
61
+ await context.input.$reply(reply);
62
+ return;
63
+ }
64
+ await next();
65
+ },
66
+ });
@@ -33,7 +33,7 @@ export default defineMiddleware<Message>({
33
33
  if (parsed) {
34
34
  const session = await services.getById(parsed.sessionId);
35
35
  if (session?.channel_key === ch) {
36
- const reply = await handleChoice(null, services, message, parsed.sessionId, parsed.choiceId);
36
+ const reply = await handleChoice(services, message, parsed.sessionId, parsed.choiceId);
37
37
  if (reply) await context.input.$reply(reply);
38
38
  return;
39
39
  }
@@ -57,7 +57,7 @@ export default defineMiddleware<Message>({
57
57
  const payload = resolveGameTextPayload(raw, map);
58
58
  const parsed = payload ? parseChoicePayload(payload, RIDDLE_PREFIX) : null;
59
59
  if (parsed?.sessionId === session.id) {
60
- const reply = await handleChoice(null, services, message, session.id, parsed.choiceId);
60
+ const reply = await handleChoice(services, message, session.id, parsed.choiceId);
61
61
  if (reply) await context.input.$reply(reply);
62
62
  return;
63
63
  }
@@ -65,7 +65,7 @@ export default defineMiddleware<Message>({
65
65
 
66
66
  // 仅把 1-8 个汉字的纯文本当谜底作答,其余放行
67
67
  if (/^[\u4e00-\u9fff]{1,8}$/.test(raw)) {
68
- const reply = await processAnswerText(null, services, message, raw);
68
+ const reply = await processAnswerText(services, message, raw);
69
69
  if (reply) await context.input.$reply(reply);
70
70
  return;
71
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-word-riddle",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Zhin.js 猜谜 — 字谜与猜成语 (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -14,7 +14,7 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "files": [
17
- "plugin.ts",
17
+ "plugin.js",
18
18
  "schema.json",
19
19
  "commands",
20
20
  "middlewares",
@@ -25,11 +25,11 @@
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
27
  "chinese-idiom-chengyu": "^1.1.0",
28
- "@zhin.js/command": "1.0.2",
29
- "@zhin.js/core": "1.4.0",
30
- "@zhin.js/game-kit": "2.0.0",
31
- "@zhin.js/middleware": "1.0.2",
32
- "@zhin.js/plugin-runtime": "1.1.0"
28
+ "@zhin.js/command": "1.0.4",
29
+ "@zhin.js/core": "1.4.2",
30
+ "@zhin.js/game-kit": "2.0.2",
31
+ "@zhin.js/middleware": "1.0.4",
32
+ "@zhin.js/plugin-runtime": "1.1.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "typescript": "^6.0.3",
@@ -50,7 +50,7 @@
50
50
  "zhin": {
51
51
  "protocol": 1,
52
52
  "type": "plugin",
53
- "entry": "./plugin.ts",
53
+ "entry": "./plugin.js",
54
54
  "engine": "^1.0.0",
55
55
  "runtime": "trusted",
56
56
  "features": [
package/plugin.js ADDED
@@ -0,0 +1,37 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineGamePlugin } from '@zhin.js/game-kit';
3
+ import { defineHostTables } from "./lib/models.js";
4
+ import { gameServicesToken } from "./lib/runtime-store.js";
5
+ import { createServices, } from "./lib/session-service.js";
6
+ /**
7
+ * Plugin Runtime:
8
+ * - Commands under `commands/` are authoritative (help + start/continue/quit via in-memory DB).
9
+ * - DB: prefer databaseHostToken; else in-memory SessionService.
10
+ * - Text middleware under `middlewares/` handles answer payloads.
11
+ */
12
+ export default defineGamePlugin({
13
+ name: 'word-riddle',
14
+ metadata: {
15
+ displayName: 'Word Riddle',
16
+ },
17
+ game: {
18
+ id: 'riddle',
19
+ title: '猜谜',
20
+ icon: '🧩',
21
+ description: '字谜 + 成语猜谜',
22
+ commandPrefix: '/猜谜',
23
+ quickStart: '开始',
24
+ aliases: ['riddle'],
25
+ menus: [
26
+ { id: 'char', label: '🔤 字谜模式' },
27
+ { id: 'idiom', label: '📜 成语模式' },
28
+ { id: 'continue', label: '🔄 继续' },
29
+ { id: 'help', label: '📖 玩法说明' },
30
+ ],
31
+ },
32
+ tables: ['word_riddle_sessions'],
33
+ servicesToken: gameServicesToken,
34
+ defineHostTables,
35
+ createServices: (database) => createServices(database),
36
+ session: (services) => services,
37
+ });
package/src/game-flow.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { Adapter, Message, Plugin } from '@zhin.js/core';
2
- import { plainTextFromSendContent } from '@zhin.js/game-kit';
1
+ import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
3
2
  import {
3
+ answersFor,
4
4
  checkAnswer,
5
5
  getRiddleById,
6
+ normalizeAnswer,
6
7
  RIDDLE_PREFIX,
7
8
  typeLabel,
8
9
  } from './engine.js';
@@ -15,39 +16,17 @@ import {
15
16
  } from './session-service.js';
16
17
  import { buildRiddleView, MAX_WRONG } from './view.js';
17
18
 
18
- export async function sendOrEditView(
19
- plugin: Plugin | null,
20
- services: SessionService,
21
- message: Message<any>,
19
+ /**
20
+ * Plugin Runtime: render the board as text. Interactive in-place board editing
21
+ * (the old Adapter.editMessage path) is not part of the runtime flow; commands
22
+ * and the text middleware return fresh text each turn.
23
+ */
24
+ function renderView(
25
+ message: GameMessageLike,
22
26
  session: RiddleSessionRow,
23
27
  eventLines: string[] = [],
24
- ): Promise<string | void> {
25
- const content = buildRiddleView(session, eventLines, message.$channel.type);
26
- if (typeof content === 'string') {
27
- if (!plugin) return content;
28
- await message.$reply?.(content);
29
- return;
30
- }
31
- if (!plugin) return plainTextFromSendContent(content);
32
-
33
- const adapter = plugin.root.inject(message.$adapter) as Adapter;
34
- if (session.board_message_id) {
35
- const msgId = await adapter.editMessage({
36
- messageId: session.board_message_id,
37
- context: String(message.$adapter),
38
- endpoint: message.$endpoint,
39
- id: message.$channel.id,
40
- type: message.$channel.type,
41
- content,
42
- });
43
- if (msgId !== session.board_message_id) {
44
- await services.updateSession(session.id, { board_message_id: msgId });
45
- }
46
- return;
47
- }
48
-
49
- const msgId = await message.$reply?.(content);
50
- if (msgId) await services.updateSession(session.id, { board_message_id: msgId });
28
+ ): GameReply {
29
+ return buildRiddleView(session, eventLines, message.$channel.type);
51
30
  }
52
31
 
53
32
  async function advanceQuestion(
@@ -65,11 +44,10 @@ async function advanceQuestion(
65
44
  }
66
45
 
67
46
  export async function startGame(
68
- plugin: Plugin | null,
69
47
  services: SessionService,
70
- message: Message<any>,
48
+ message: GameMessageLike,
71
49
  mode: RiddleType,
72
- ): Promise<string | undefined> {
50
+ ): Promise<GameReply | undefined> {
73
51
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
74
52
  const active = await services.getActiveByChannel(ch);
75
53
  if (active) {
@@ -80,31 +58,26 @@ export async function startGame(
80
58
  }
81
59
 
82
60
  const session = await services.createSession(message, mode);
83
- const text = await sendOrEditView(plugin, services, message, session);
84
- return typeof text === 'string' ? text : undefined;
61
+ return renderView(message, session);
85
62
  }
86
63
 
87
64
  export async function continueGame(
88
- plugin: Plugin | null,
89
65
  services: SessionService,
90
- message: Message<any>,
91
- ): Promise<string> {
66
+ message: GameMessageLike,
67
+ ): Promise<GameReply> {
92
68
  const session = await services.getActiveForUser(
93
69
  `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
94
70
  message.$sender.id,
95
71
  );
96
72
  if (!session) return '你没有进行中的猜谜,发送「猜谜 开始」。';
97
- const text = await sendOrEditView(plugin, services, message, session);
98
- if (typeof text === 'string') return text;
99
- return '已刷新猜谜界面。';
73
+ return renderView(message, session);
100
74
  }
101
75
 
102
76
  export async function processAnswerText(
103
- plugin: Plugin | null,
104
77
  services: SessionService,
105
- message: Message<any>,
78
+ message: GameMessageLike,
106
79
  raw: string,
107
- ): Promise<string | null> {
80
+ ): Promise<GameReply | null> {
108
81
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
109
82
  const session = await services.getActiveForUser(ch, message.$sender.id);
110
83
  if (!session || session.status !== 'active') return null;
@@ -113,6 +86,12 @@ export async function processAnswerText(
113
86
  const entry = riddleId ? getRiddleById(riddleId) : undefined;
114
87
  if (!entry) return null;
115
88
 
89
+ // 格式不合规(字数与答案不符)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
90
+ const normalized = normalizeAnswer(raw);
91
+ if (!answersFor(entry).some((a) => a.length === normalized.length)) {
92
+ return `本题答案应为 ${entry.answer.length} 个字(这条不算失误)。`;
93
+ }
94
+
116
95
  if (checkAnswer(entry, raw)) {
117
96
  const streak = session.streak + 1;
118
97
  const best = Math.max(session.best_streak, streak);
@@ -124,45 +103,44 @@ export async function processAnswerText(
124
103
  });
125
104
  const after = await advanceQuestion(services, (await services.getById(session.id))!);
126
105
  const explain = entry.explanation ? `\n📖 ${entry.explanation}` : '';
127
- return (await sendOrEditView(plugin, services, message, after, [
106
+ return renderView(message, after, [
128
107
  `✅ 正确!答案:**${entry.answer}**${explain}`,
129
108
  `+${10 + Math.min(streak, 5)} 分`,
130
- ])) ?? null;
109
+ ]);
131
110
  }
132
111
 
133
112
  const wrong = session.wrong_count + 1;
134
113
  if (wrong >= MAX_WRONG) {
135
114
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
136
115
  const after = await advanceQuestion(services, (await services.getById(session.id))!);
137
- return (await sendOrEditView(plugin, services, message, after, [
116
+ return renderView(message, after, [
138
117
  `❌ 本题答案:**${entry.answer}**`,
139
118
  '失误过多,自动下一题。',
140
- ])) ?? null;
119
+ ]);
141
120
  }
142
121
 
143
122
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
144
123
  const updated = (await services.getById(session.id))!;
145
- return (await sendOrEditView(plugin, services, message, updated, ['❌ 不对,再想想!'])) ?? null;
124
+ return renderView(message, updated, ['❌ 不对,再想想!']);
146
125
  }
147
126
 
148
127
  export async function handleChoice(
149
- plugin: Plugin | null,
150
128
  services: SessionService,
151
- message: Message<any>,
129
+ message: GameMessageLike,
152
130
  sessionId: string,
153
131
  choiceId: string,
154
- ): Promise<string | null> {
132
+ ): Promise<GameReply | null> {
155
133
  const session = await services.getById(sessionId);
156
134
  if (!session) return '会话不存在。';
157
135
  if (session.player_id !== message.$sender.id) return '这是别人的猜谜。';
158
136
 
159
137
  if (choiceId === 'restart_char') {
160
138
  await services.updateSession(session.id, { status: 'aborted' });
161
- return startGame(plugin, services, message, 'char') as unknown as string;
139
+ return (await startGame(services, message, 'char')) ?? null;
162
140
  }
163
141
  if (choiceId === 'restart_idiom') {
164
142
  await services.updateSession(session.id, { status: 'aborted' });
165
- return startGame(plugin, services, message, 'idiom') as unknown as string;
143
+ return (await startGame(services, message, 'idiom')) ?? null;
166
144
  }
167
145
 
168
146
  if (session.status !== 'active') return '本轮已结束。';
@@ -175,18 +153,18 @@ export async function handleChoice(
175
153
  const hint = entry.hint ?? `答案共 ${entry.answer.length} 个字`;
176
154
  await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
177
155
  const updated = (await services.getById(session.id))!;
178
- return (await sendOrEditView(plugin, services, message, updated, [
156
+ return renderView(message, updated, [
179
157
  `💡 提示:${hint}`,
180
158
  '(连击清零)',
181
- ])) ?? null;
159
+ ]);
182
160
  }
183
161
 
184
162
  if (choiceId === 'skip') {
185
163
  await services.updateSession(session.id, { streak: 0 });
186
164
  const after = await advanceQuestion(services, session);
187
- return (await sendOrEditView(plugin, services, message, after, [
165
+ return renderView(message, after, [
188
166
  `⏭️ 跳过,答案:**${entry.answer}**`,
189
- ])) ?? null;
167
+ ]);
190
168
  }
191
169
 
192
170
  if (choiceId === 'quit') {
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { RIDDLE_HELP } from './riddle-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryRiddleDb, mountRiddleMemoryServices } from './memory-db.js';
4
3
 
5
4
  /**
6
5
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
package/src/models.ts CHANGED
@@ -22,7 +22,6 @@ declare module '@zhin.js/core' {
22
22
  hints_used: number;
23
23
  wrong_count: number;
24
24
  status: RiddleSessionStatus;
25
- board_message_id: string;
26
25
  updated_at: number;
27
26
  created_at: number;
28
27
  };
@@ -53,7 +52,6 @@ export function defineHostTables(
53
52
  hints_used: { type: 'integer', default: 0 },
54
53
  wrong_count: { type: 'integer', default: 0 },
55
54
  status: { type: 'text', default: 'active' },
56
- board_message_id: { type: 'text', default: '' },
57
55
  updated_at: { type: 'integer', default: 0 },
58
56
  created_at: { type: 'integer', default: 0 },
59
57
  });
@@ -1,5 +1,8 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
2
- import { channelKey } from '@zhin.js/game-kit';
1
+ import {
2
+ channelKey,
3
+ type GameMessageLike,
4
+ type GameReply,
5
+ } from '@zhin.js/game-kit';
3
6
  import { continueGame, startGame } from './game-flow.js';
4
7
  import { riddleCount, type RiddleType } from './riddles-catalog.js';
5
8
 
@@ -29,11 +32,10 @@ function parseMode(action: string): RiddleType | null {
29
32
  }
30
33
 
31
34
  export async function runRiddleCommand(
32
- plugin: Plugin | null,
33
35
  services: SessionService,
34
- message: Message<any>,
36
+ message: GameMessageLike,
35
37
  action: string,
36
- ): Promise<string | undefined> {
38
+ ): Promise<GameReply> {
37
39
  const ch = channelKey(message);
38
40
  const userId = message.$sender.id;
39
41
 
@@ -49,10 +51,10 @@ export async function runRiddleCommand(
49
51
  }
50
52
 
51
53
  const mode = parseMode(action);
52
- if (mode) return startGame(plugin, services, message, mode);
54
+ if (mode) return (await startGame(services, message, mode)) ?? '';
53
55
 
54
56
  if (action === 'continue' || action === '继续') {
55
- return continueGame(plugin, services, message);
57
+ return continueGame(services, message);
56
58
  }
57
59
 
58
60
  if (action === 'quit' || action === '放弃') {
@@ -64,12 +66,3 @@ export async function runRiddleCommand(
64
66
 
65
67
  return `未知子命令:${action}\n\n${RIDDLE_HELP}`;
66
68
  }
67
-
68
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
69
- export async function runRiddleCommandText(
70
- services: SessionService,
71
- message: Message<any>,
72
- action: string,
73
- ): Promise<string> {
74
- return (await runRiddleCommand(null, services, message, action)) ?? '';
75
- }
@@ -1,16 +1,16 @@
1
- import type { Database, Message, Models, RelatedModel } from '@zhin.js/core';
2
- import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-kit';
1
+ import type { Database, Models } from '@zhin.js/core';
2
+ import {
3
+ BaseSessionService,
4
+ channelKey,
5
+ generateSessionId,
6
+ type GameMessageLike,
7
+ type GameSessionDatabase,
8
+ } from '@zhin.js/game-kit';
3
9
  import { pickRoundQueue, type RiddleType } from './riddles-catalog.js';
4
10
  import type { RiddleSessionRow } from './models.js';
5
11
 
6
12
  export type RiddleDatabase = Database<unknown, Models, string>;
7
13
 
8
- function getModel(db: RiddleDatabase) {
9
- const model = db.models.get('word_riddle_sessions');
10
- if (!model) throw new Error('word_riddle_sessions not registered');
11
- return model as RelatedModel<unknown, Models, 'word_riddle_sessions'>;
12
- }
13
-
14
14
  export function parseQueue(value: string | string[] | unknown): string[] {
15
15
  if (Array.isArray(value)) return value.filter((x): x is string => typeof x === 'string');
16
16
  if (typeof value !== 'string' || !value) return [];
@@ -22,34 +22,16 @@ export function parseQueue(value: string | string[] | unknown): string[] {
22
22
  }
23
23
  }
24
24
 
25
- export class SessionService {
26
- constructor(private readonly db: RiddleDatabase) {}
27
-
28
- async getActiveByChannel(channel: string): Promise<RiddleSessionRow | null> {
29
- const rows = await getModel(this.db).findAll({ channel_key: channel, status: 'active' });
30
- return rows[0] ?? null;
31
- }
32
-
33
- async getActiveForUser(channel: string, userId: string): Promise<RiddleSessionRow | null> {
34
- const row = await this.getActiveByChannel(channel);
35
- if (!row || row.player_id !== userId) return null;
36
- return row;
37
- }
38
-
39
- async getById(id: string): Promise<RiddleSessionRow | null> {
40
- return getModel(this.db).findOne({ id });
25
+ export class SessionService extends BaseSessionService<RiddleSessionRow> {
26
+ constructor(db: RiddleDatabase) {
27
+ super(db as unknown as GameSessionDatabase<RiddleSessionRow>, {
28
+ gameId: 'riddle',
29
+ table: 'word_riddle_sessions',
30
+ userFields: ['player_id'],
31
+ });
41
32
  }
42
33
 
43
- async getActiveByBoardMessageId(messageId: string): Promise<RiddleSessionRow | null> {
44
- if (!messageId) return null;
45
- const rows = await getModel(this.db).findAll({});
46
- for (const row of rows) {
47
- if (boardMessageMatches(row.board_message_id ?? '', messageId)) return row;
48
- }
49
- return null;
50
- }
51
-
52
- async createSession(message: Message<any>, mode: RiddleType): Promise<RiddleSessionRow> {
34
+ async createSession(message: GameMessageLike, mode: RiddleType): Promise<RiddleSessionRow> {
53
35
  const now = Date.now();
54
36
  const queue = pickRoundQueue(mode).map((r) => r.id);
55
37
  const row: RiddleSessionRow = {
@@ -70,30 +52,10 @@ export class SessionService {
70
52
  hints_used: 0,
71
53
  wrong_count: 0,
72
54
  status: 'active',
73
- board_message_id: '',
74
55
  updated_at: now,
75
56
  created_at: now,
76
57
  };
77
- await getModel(this.db).create(row);
78
- return row;
79
- }
80
-
81
- async updateSession(id: string, patch: Partial<RiddleSessionRow>): Promise<void> {
82
- await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
83
- }
84
-
85
- async abortStale(idleMs: number): Promise<number> {
86
- const cutoff = Date.now() - idleMs;
87
- const model = getModel(this.db);
88
- const rows = await model.findAll({ status: 'active' });
89
- let n = 0;
90
- for (const row of rows) {
91
- if (row.updated_at < cutoff) {
92
- await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
93
- n++;
94
- }
95
- }
96
- return n;
58
+ return this.createRow(row);
97
59
  }
98
60
  }
99
61
 
@@ -1,6 +0,0 @@
1
- import type { DatabaseHost } from '@zhin.js/plugin-runtime';
2
- import { type RiddleDatabase, type SessionService } from './session-service.js';
3
- /** In-memory word_riddle_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
4
- export declare function createInMemoryRiddleDb(): RiddleDatabase;
5
- export declare function mountRiddleMemoryServices(): SessionService;
6
- export declare function mountRiddleHostServices(host: DatabaseHost): SessionService;
package/lib/memory-db.js DELETED
@@ -1,18 +0,0 @@
1
- import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
2
- import { defineHostTables } from './models.js';
3
- import { createServices } from './session-service.js';
4
- const RIDDLE_TABLES = ['word_riddle_sessions'];
5
- /** In-memory word_riddle_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
6
- export function createInMemoryRiddleDb() {
7
- return createInMemoryGameDb(RIDDLE_TABLES);
8
- }
9
- export function mountRiddleMemoryServices() {
10
- const services = createServices(createInMemoryRiddleDb());
11
- return services;
12
- }
13
- export function mountRiddleHostServices(host) {
14
- defineHostTables(host);
15
- const services = createServices(createHostGameDb(host, RIDDLE_TABLES));
16
- return services;
17
- }
18
- //# sourceMappingURL=memory-db.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-db.js","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAA4C,MAAM,sBAAsB,CAAC;AAEhG,MAAM,aAAa,GAAG,CAAC,sBAAsB,CAAU,CAAC;AAExD,sFAAsF;AACtF,MAAM,UAAU,sBAAsB;IACpC,OAAO,oBAAoB,CAAC,aAAa,CAA8B,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,MAAM,QAAQ,GAAG,cAAc,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAC1D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAkB;IACxD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC,IAAI,EAAE,aAAa,CAA8B,CAAC,CAAC;IACpG,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/plugin.ts DELETED
@@ -1,64 +0,0 @@
1
- import { definePlugin, databaseHostToken, scheduleHostToken } from '@zhin.js/plugin-runtime';
2
- import {
3
- registerRuntimeGame,
4
- initGameRecordHost,
5
- DEFAULT_GAME_STALE_CRON,
6
- DEFAULT_GAME_STALE_IDLE_MS,
7
- } from '@zhin.js/game-kit';
8
- import { mountRiddleHostServices, mountRiddleMemoryServices } from './src/memory-db.js';
9
- import { gameServicesToken } from './src/runtime-store.js';
10
- import type { SessionService } from './src/session-service.js';
11
-
12
- /**
13
- * Plugin Runtime:
14
- * - Commands under `commands/` are authoritative (help + start/continue/quit via in-memory DB).
15
- * - DB: prefer databaseHostToken; else in-memory SessionService.
16
- * - Text middleware under `middlewares/` handles answer payloads.
17
- */
18
- export default definePlugin({
19
- name: 'word-riddle',
20
- metadata: {
21
- displayName: 'Word Riddle',
22
- },
23
- setup(context) {
24
- let services: SessionService;
25
- if (context.resources.has(databaseHostToken)) {
26
- const host = context.resources.use(databaseHostToken);
27
- services = mountRiddleHostServices(host);
28
- context.lifecycle.add(initGameRecordHost(host));
29
- } else {
30
- services = mountRiddleMemoryServices();
31
- }
32
- context.resources.provide(gameServicesToken, services);
33
- const disposeHub = registerRuntimeGame({
34
- id: 'riddle',
35
- title: '猜谜',
36
- icon: '🧩',
37
- description: '字谜 + 成语猜谜',
38
- commandPrefix: '/猜谜',
39
- quickStart: '开始',
40
- aliases: ['riddle'],
41
- menus: [
42
- { id: 'char', label: '🔤 字谜模式' },
43
- { id: 'idiom', label: '📜 成语模式' },
44
- { id: 'continue', label: '🔄 继续' },
45
- { id: 'help', label: '📖 玩法说明' },
46
- ],
47
- });
48
- context.lifecycle.add(disposeHub);
49
-
50
- if (context.resources.has(scheduleHostToken)) {
51
- const schedule = context.resources.use(scheduleHostToken);
52
- const disposeCron = schedule.register({
53
- id: 'riddle/abort-stale',
54
- cron: DEFAULT_GAME_STALE_CRON,
55
- description: 'Abort stale word-riddle sessions',
56
- async execute() {
57
- if (!services.abortStale) return;
58
- await services.abortStale(DEFAULT_GAME_STALE_IDLE_MS);
59
- },
60
- });
61
- context.lifecycle.add(disposeCron);
62
- }
63
- },
64
- });
package/src/memory-db.ts DELETED
@@ -1,22 +0,0 @@
1
- import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
2
- import type { DatabaseHost } from '@zhin.js/plugin-runtime';
3
- import { defineHostTables } from './models.js';
4
- import { createServices, type RiddleDatabase, type SessionService } from './session-service.js';
5
-
6
- const RIDDLE_TABLES = ['word_riddle_sessions'] as const;
7
-
8
- /** In-memory word_riddle_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
9
- export function createInMemoryRiddleDb(): RiddleDatabase {
10
- return createInMemoryGameDb(RIDDLE_TABLES) as unknown as RiddleDatabase;
11
- }
12
-
13
- export function mountRiddleMemoryServices(): SessionService {
14
- const services = createServices(createInMemoryRiddleDb());
15
- return services;
16
- }
17
-
18
- export function mountRiddleHostServices(host: DatabaseHost): SessionService {
19
- defineHostTables(host);
20
- const services = createServices(createHostGameDb(host, RIDDLE_TABLES) as unknown as RiddleDatabase);
21
- return services;
22
- }