@zhin.js/plugin-idiom-chain 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, normalizeChainAction } from '@zhin.js/game-kit';
4
+ import { CHAIN_HELP, runChainCommand } from "../../lib/chain-command.js";
5
+ import { resolveGameServices } from "../../lib/runtime-store.js";
6
+ export default defineCommand({
7
+ description: 'Idiom Chain',
8
+ async execute({ params, input, use, owner }) {
9
+ const action = normalizeChainAction(String(params.action ?? ''));
10
+ if (!action || action === 'help')
11
+ return CHAIN_HELP;
12
+ const services = resolveGameServices({ use, owner });
13
+ const message = messageFromCommandInput(input);
14
+ return runChainCommand(services, message, action);
15
+ },
16
+ });
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from '@zhin.js/command';
2
2
  import { messageFromCommandInput, normalizeChainAction } from '@zhin.js/game-kit';
3
- import { CHAIN_HELP, runChainCommandText } from '../../src/chain-command.js';
3
+ import { CHAIN_HELP, runChainCommand } from '../../src/chain-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 CHAIN_HELP;
11
11
  const services = resolveGameServices({ use, owner });
12
12
  const message = messageFromCommandInput(input);
13
- return runChainCommandText(services, message, action);
13
+ return runChainCommand(services, message, action);
14
14
  },
15
15
  });
@@ -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 CHAIN_HELP: string;
4
- export declare function runChainCommand(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 runChainCommandText(services: SessionService, message: Message<any>, action: string): Promise<string>;
4
+ export declare function runChainCommand(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 { idiomCount, modeLabel, promptLine } from './engine.js';
4
4
  export const CHAIN_HELP = [
@@ -13,7 +13,7 @@ export const CHAIN_HELP = [
13
13
  '进行中:直接回复四字成语',
14
14
  '按钮:提示 · 跳过 · 认输(失误 3 次判负)',
15
15
  ].join('\n');
16
- export async function runChainCommand(plugin, services, message, action) {
16
+ export async function runChainCommand(services, message, action) {
17
17
  const ch = channelKey(message);
18
18
  const userId = message.$sender.id;
19
19
  if (!action || action === 'help') {
@@ -31,11 +31,11 @@ export async function runChainCommand(plugin, services, message, action) {
31
31
  return lines.join('\n');
32
32
  }
33
33
  if (action === 'start_pinyin')
34
- return startGame(plugin, services, message, 'pinyin');
34
+ return (await startGame(services, message, 'pinyin')) ?? '';
35
35
  if (action === 'start_char')
36
- return startGame(plugin, services, message, 'char');
36
+ return (await startGame(services, message, 'char')) ?? '';
37
37
  if (action === 'continue')
38
- return continueGame(plugin, services, message);
38
+ return continueGame(services, message);
39
39
  if (action === 'quit') {
40
40
  const row = await services.getActiveForUser(ch, userId);
41
41
  if (!row)
@@ -45,8 +45,4 @@ export async function runChainCommand(plugin, services, message, action) {
45
45
  }
46
46
  return `未知子命令:${action}\n\n${CHAIN_HELP}`;
47
47
  }
48
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
49
- export async function runChainCommandText(services, message, action) {
50
- return (await runChainCommand(null, services, message, action)) ?? '';
51
- }
52
48
  //# sourceMappingURL=chain-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chain-command.js","sourceRoot":"","sources":["../src/chain-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,UAAU,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AAIhF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,sBAAsB;IACtB,QAAQ,UAAU,EAAE,eAAe;IACnC,iBAAiB;IACjB,8BAA8B;IAC9B,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,EAAE;IACF,cAAc;IACd,2BAA2B;CAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,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,UAAU,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAc,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzE,KAAK,CAAC,IAAI,CACR,OAAO,MAAM,CAAC,WAAW,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,CACvH,CAAC;YACF,IAAI,MAAM,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,cAAc;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACrF,IAAI,MAAM,KAAK,YAAY;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACjF,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE1E,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,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,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,UAAU,EAAE,CAAC;AAC5C,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,OAAO,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACxE,CAAC"}
1
+ {"version":3,"file":"chain-command.js","sourceRoot":"","sources":["../src/chain-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,UAAU,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AAIhF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,sBAAsB;IACtB,QAAQ,UAAU,EAAE,eAAe;IACnC,iBAAiB;IACjB,8BAA8B;IAC9B,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,EAAE;IACF,cAAc;IACd,2BAA2B;CAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,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,UAAU,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAc,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzE,KAAK,CAAC,IAAI,CACR,OAAO,MAAM,CAAC,WAAW,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,CACvH,CAAC;YACF,IAAI,MAAM,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,cAAc;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,MAAM,KAAK,YAAY;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvF,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,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,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,UAAU,EAAE,CAAC;AAC5C,CAAC"}
@@ -1,10 +1,10 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
1
+ import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
2
2
  import { CHAIN_PREFIX, type MatchMode } from './engine.js';
3
3
  import type { ChainSessionRow } from './models.js';
4
4
  import { type SessionService } from './session-service.js';
5
- export declare function sendOrEditView(plugin: Plugin | null, services: SessionService, message: Message<any>, session: ChainSessionRow, eventLines?: string[]): Promise<string | void>;
6
- export declare function startGame(plugin: Plugin | null, services: SessionService, message: Message<any>, matchMode?: MatchMode): Promise<string | undefined>;
7
- export declare function continueGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string>;
8
- export declare function processIdiomText(plugin: Plugin | null, services: SessionService, message: Message<any>, raw: string): Promise<string | null>;
9
- export declare function handleChoice(plugin: Plugin | null, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
5
+ export declare function sendOrEditView(services: SessionService, message: GameMessageLike, session: ChainSessionRow, eventLines?: string[]): Promise<GameReply>;
6
+ export declare function startGame(services: SessionService, message: GameMessageLike, matchMode?: MatchMode): Promise<GameReply | undefined>;
7
+ export declare function continueGame(services: SessionService, message: GameMessageLike): Promise<GameReply>;
8
+ export declare function processIdiomText(services: SessionService, message: GameMessageLike, raw: string): Promise<GameReply | null>;
9
+ export declare function handleChoice(services: SessionService, message: GameMessageLike, sessionId: string, choiceId: string): Promise<GameReply | null>;
10
10
  export { CHAIN_PREFIX };
package/lib/game-flow.js CHANGED
@@ -1,32 +1,12 @@
1
- import { plainTextFromSendContent } from '@zhin.js/game-kit';
2
1
  import { CHAIN_PREFIX, getGloss, lastChar, modeLabel, normalizeInput, pickBotIdiom, pickHintIdiom, pickStarterIdiom, promptLine, validatePlayerIdiom, } from './engine.js';
3
2
  import { parseUsed } from './session-service.js';
4
3
  import { buildChainView, MAX_WRONG } from './view.js';
5
4
  function sessionMode(session) {
6
5
  return session.match_mode === 'char' ? 'char' : 'pinyin';
7
6
  }
8
- export async function sendOrEditView(plugin, services, message, session, eventLines = []) {
7
+ export async function sendOrEditView(services, message, session, eventLines = []) {
9
8
  const content = buildChainView(session, eventLines, message.$channel.type);
10
- if (!plugin)
11
- return plainTextFromSendContent(content);
12
- const adapter = plugin.root.inject(message.$adapter);
13
- if (session.board_message_id) {
14
- const msgId = await adapter.editMessage({
15
- messageId: session.board_message_id,
16
- context: String(message.$adapter),
17
- endpoint: message.$endpoint,
18
- id: message.$channel.id,
19
- type: message.$channel.type,
20
- content,
21
- });
22
- if (msgId !== session.board_message_id) {
23
- await services.updateSession(session.id, { board_message_id: msgId });
24
- }
25
- return;
26
- }
27
- const msgId = await message.$reply?.(content);
28
- if (msgId)
29
- await services.updateSession(session.id, { board_message_id: msgId });
9
+ return content;
30
10
  }
31
11
  async function botTurn(services, session, used) {
32
12
  const mode = sessionMode(session);
@@ -55,7 +35,7 @@ async function botTurn(services, session, used) {
55
35
  ];
56
36
  return { session: updated, lines, playerWon: false };
57
37
  }
58
- export async function startGame(plugin, services, message, matchMode = 'pinyin') {
38
+ export async function startGame(services, message, matchMode = 'pinyin') {
59
39
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
60
40
  const active = await services.getActiveByChannel(ch);
61
41
  if (active) {
@@ -74,22 +54,18 @@ export async function startGame(plugin, services, message, matchMode = 'pinyin')
74
54
  matchMode,
75
55
  });
76
56
  const gloss = starter.gloss ?? getGloss(starter.text);
77
- const text = await sendOrEditView(plugin, services, message, session, [
57
+ return sendOrEditView(services, message, session, [
78
58
  `🎬 ${modeLabel(matchMode)}开局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
79
59
  promptLine(starter.text, matchMode),
80
60
  ]);
81
- return typeof text === 'string' ? text : undefined;
82
61
  }
83
- export async function continueGame(plugin, services, message) {
62
+ export async function continueGame(services, message) {
84
63
  const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
85
64
  if (!session)
86
65
  return '你没有进行中的接龙,发送「接龙 开始」。';
87
- const text = await sendOrEditView(plugin, services, message, session);
88
- if (typeof text === 'string')
89
- return text;
90
- return '已刷新接龙界面。';
66
+ return sendOrEditView(services, message, session);
91
67
  }
92
- export async function processIdiomText(plugin, services, message, raw) {
68
+ export async function processIdiomText(services, message, raw) {
93
69
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
94
70
  const session = await services.getActiveForUser(ch, message.$sender.id);
95
71
  if (!session || session.status !== 'active')
@@ -97,6 +73,10 @@ export async function processIdiomText(plugin, services, message, raw) {
97
73
  const mode = sessionMode(session);
98
74
  const used = parseUsed(session.used_idioms);
99
75
  const idiom = normalizeInput(raw);
76
+ // 格式不合规(非四字)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
77
+ if (!/^[\u4e00-\u9fff]{4}$/.test(idiom)) {
78
+ return '接龙请输入**四字成语**(这条不算失误)。';
79
+ }
100
80
  const check = validatePlayerIdiom(idiom, session.last_idiom, mode, used);
101
81
  if (!check.ok) {
102
82
  const wrong = session.wrong_count + 1;
@@ -108,14 +88,14 @@ export async function processIdiomText(plugin, services, message, raw) {
108
88
  streak: 0,
109
89
  });
110
90
  const updated = (await services.getById(session.id));
111
- return (await sendOrEditView(plugin, services, message, updated, [
91
+ return (await sendOrEditView(services, message, updated, [
112
92
  check.reason,
113
93
  '失误过多,本局结束。',
114
94
  ])) ?? null;
115
95
  }
116
96
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
117
97
  const updated = (await services.getById(session.id));
118
- return (await sendOrEditView(plugin, services, message, updated, [check.reason])) ?? null;
98
+ return (await sendOrEditView(services, message, updated, [check.reason])) ?? null;
119
99
  }
120
100
  used.add(idiom);
121
101
  const streak = session.streak + 1;
@@ -133,12 +113,12 @@ export async function processIdiomText(plugin, services, message, raw) {
133
113
  const current = (await services.getById(session.id));
134
114
  const userLine = `✅ 你:${idiom}${gloss ? `(${gloss})` : ''}`;
135
115
  const botResult = await botTurn(services, current, used);
136
- return (await sendOrEditView(plugin, services, message, botResult.session, [
116
+ return (await sendOrEditView(services, message, botResult.session, [
137
117
  userLine,
138
118
  ...botResult.lines,
139
119
  ])) ?? null;
140
120
  }
141
- export async function handleChoice(plugin, services, message, sessionId, choiceId) {
121
+ export async function handleChoice(services, message, sessionId, choiceId) {
142
122
  const session = await services.getById(sessionId);
143
123
  if (!session)
144
124
  return '对局不存在。';
@@ -157,11 +137,10 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
157
137
  wrong_count: 0,
158
138
  turn: 'player',
159
139
  status: 'active',
160
- board_message_id: '',
161
140
  });
162
141
  const updated = (await services.getById(session.id));
163
142
  const gloss = starter.gloss ?? getGloss(starter.text);
164
- return (await sendOrEditView(plugin, services, message, updated, [
143
+ return (await sendOrEditView(services, message, updated, [
165
144
  `🎬 新一局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
166
145
  promptLine(starter.text, mode),
167
146
  ])) ?? null;
@@ -173,15 +152,17 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
173
152
  if (choiceId === 'hint') {
174
153
  const hint = pickHintIdiom(session.last_idiom, mode, used);
175
154
  if (!hint) {
176
- await sendOrEditView(plugin, services, message, session, ['💡 词库中暂无可用提示,你赢了!']);
155
+ // 先更新状态再单次发送终局视图,避免旧 session「你赢了」与终局视图双发
177
156
  await services.updateSession(session.id, { status: 'won', player_score: session.player_score + 1 });
178
157
  const updated = (await services.getById(session.id));
179
- return (await sendOrEditView(plugin, services, message, updated)) ?? null;
158
+ return (await sendOrEditView(services, message, updated, [
159
+ '💡 词库中暂无可用提示,你赢了!',
160
+ ])) ?? null;
180
161
  }
181
162
  const gloss = getGloss(hint);
182
163
  await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
183
164
  const updated = (await services.getById(session.id));
184
- return (await sendOrEditView(plugin, services, message, updated, [
165
+ return (await sendOrEditView(services, message, updated, [
185
166
  `💡 提示:可试 **${hint}**${gloss ? `(${gloss})` : ''}`,
186
167
  '(使用提示会清零连击)',
187
168
  ])) ?? null;
@@ -193,14 +174,14 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
193
174
  streak: 0,
194
175
  });
195
176
  const updated = (await services.getById(session.id));
196
- return (await sendOrEditView(plugin, services, message, updated, [
177
+ return (await sendOrEditView(services, message, updated, [
197
178
  '⏭️ 你选择跳过,机器人得一分。',
198
179
  ])) ?? null;
199
180
  }
200
181
  if (choiceId === 'quit') {
201
182
  await services.updateSession(session.id, { status: 'lost', bot_score: session.bot_score + 1 });
202
183
  const updated = (await services.getById(session.id));
203
- return (await sendOrEditView(plugin, services, message, updated, ['🏳️ 你认输了。'])) ?? null;
184
+ return (await sendOrEditView(services, message, updated, ['🏳️ 你认输了。'])) ?? null;
204
185
  }
205
186
  return '未知操作。';
206
187
  }
@@ -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 { CHAIN_HELP } from './chain-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryChainDb, mountChainMemoryServices } 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 { CHAIN_HELP } from './chain-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryChainDb, mountChainMemoryServices } 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,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAEjF;;;;GAIG"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E;;;;GAIG"}
package/lib/models.d.ts CHANGED
@@ -24,7 +24,6 @@ declare module '@zhin.js/core' {
24
24
  hints_used: number;
25
25
  turn: string;
26
26
  status: ChainSessionStatus;
27
- board_message_id: string;
28
27
  updated_at: number;
29
28
  created_at: number;
30
29
  };
package/lib/models.js CHANGED
@@ -20,7 +20,6 @@ export function defineHostTables(db) {
20
20
  hints_used: { type: 'integer', default: 0 },
21
21
  turn: { type: 'text', default: 'player' },
22
22
  status: { type: 'text', default: 'active' },
23
- board_message_id: { type: 'text', default: '' },
24
23
  updated_at: { type: 'integer', default: 0 },
25
24
  created_at: { type: 'integer', default: 0 },
26
25
  });
package/lib/models.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAsCA,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,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACzC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACxC,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC5C,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QACzC,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":"AAqCA,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,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACzC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACxC,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC5C,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QACzC,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,23 +1,17 @@
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 { MatchMode } from './engine.js';
3
4
  import type { ChainSessionRow } from './models.js';
4
5
  export type ChainDatabase = Database<unknown, Models, string>;
5
6
  export declare function parseUsed(value: string | string[] | unknown): Set<string>;
6
7
  export declare function serializeUsed(set: Set<string>): string;
7
- export declare class SessionService {
8
- private readonly db;
8
+ export declare class SessionService extends BaseSessionService<ChainSessionRow> {
9
9
  constructor(db: ChainDatabase);
10
- getActiveByChannel(channel: string): Promise<ChainSessionRow | null>;
11
- getActiveForUser(channel: string, userId: string): Promise<ChainSessionRow | null>;
12
- getById(id: string): Promise<ChainSessionRow | null>;
13
- getActiveByBoardMessageId(messageId: string): Promise<ChainSessionRow | null>;
14
- createSession(message: Message<any>, starter: {
10
+ createSession(message: GameMessageLike, starter: {
15
11
  text: string;
16
12
  nextChar: string;
17
13
  used: string[];
18
14
  matchMode: MatchMode;
19
15
  }): Promise<ChainSessionRow>;
20
- updateSession(id: string, patch: Partial<ChainSessionRow>): Promise<void>;
21
- abortStale(idleMs: number): Promise<number>;
22
16
  }
23
17
  export declare function createServices(db: ChainDatabase): SessionService;
@@ -1,10 +1,4 @@
1
- import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-kit';
2
- function getModel(db) {
3
- const model = db.models.get('idiom_chain_sessions');
4
- if (!model)
5
- throw new Error('idiom_chain_sessions not registered');
6
- return model;
7
- }
1
+ import { BaseSessionService, channelKey, generateSessionId, } from '@zhin.js/game-kit';
8
2
  export function parseUsed(value) {
9
3
  if (Array.isArray(value))
10
4
  return new Set(value.filter((x) => typeof x === 'string'));
@@ -21,33 +15,13 @@ export function parseUsed(value) {
21
15
  export function serializeUsed(set) {
22
16
  return JSON.stringify([...set]);
23
17
  }
24
- export class SessionService {
25
- db;
18
+ export class SessionService extends BaseSessionService {
26
19
  constructor(db) {
27
- this.db = db;
28
- }
29
- async getActiveByChannel(channel) {
30
- const rows = await getModel(this.db).findAll({ channel_key: channel, status: 'active' });
31
- return rows[0] ?? null;
32
- }
33
- async getActiveForUser(channel, userId) {
34
- const row = await this.getActiveByChannel(channel);
35
- if (!row || row.player_id !== userId)
36
- return null;
37
- return row;
38
- }
39
- async getById(id) {
40
- return getModel(this.db).findOne({ id });
41
- }
42
- async getActiveByBoardMessageId(messageId) {
43
- if (!messageId)
44
- return null;
45
- const rows = await getModel(this.db).findAll({});
46
- for (const row of rows) {
47
- if (boardMessageMatches(row.board_message_id ?? '', messageId))
48
- return row;
49
- }
50
- return null;
20
+ super(db, {
21
+ gameId: 'chain',
22
+ table: 'idiom_chain_sessions',
23
+ userFields: ['player_id'],
24
+ });
51
25
  }
52
26
  async createSession(message, starter) {
53
27
  const now = Date.now();
@@ -72,28 +46,10 @@ export class SessionService {
72
46
  hints_used: 0,
73
47
  turn: 'player',
74
48
  status: 'active',
75
- board_message_id: '',
76
49
  updated_at: now,
77
50
  created_at: now,
78
51
  };
79
- await getModel(this.db).create(row);
80
- return row;
81
- }
82
- async updateSession(id, patch) {
83
- await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
84
- }
85
- async abortStale(idleMs) {
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;
52
+ return this.createRow(row);
97
53
  }
98
54
  }
99
55
  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;AAM3B,MAAM,UAAU,SAAS,CAAC,KAAkC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;IAClG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAgB;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAmC;IACrE,YAAY,EAAiB;QAC3B,KAAK,CAAC,EAAqD,EAAE;YAC3D,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAwB,EACxB,OAAiF;QAEjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAoB;YAC3B,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,UAAU,EAAE,OAAO,CAAC,IAAI;YACxB,SAAS,EAAE,OAAO,CAAC,QAAQ;YAC3B,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,WAAW,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjD,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,IAAI,EAAE,QAAQ;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,EAAiB;IAC9C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,18 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineGameCommandAliasMiddleware, isChainAction, messageFromCommandInput, normalizeChainAction, } from '@zhin.js/game-kit';
3
+ import { CHAIN_HELP, runChainCommand } from "../lib/chain-command.js";
4
+ import { resolveGameServices } from "../lib/runtime-store.js";
5
+ export default defineGameCommandAliasMiddleware({
6
+ aliases: ['接龙', 'chain'],
7
+ async run(action, input, context) {
8
+ const normalized = normalizeChainAction(String(action ?? ''));
9
+ if (normalized === 'help')
10
+ return CHAIN_HELP;
11
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
12
+ if (!isChainAction(normalized))
13
+ return null;
14
+ const services = resolveGameServices(context);
15
+ const message = messageFromCommandInput(input);
16
+ return runChainCommand(services, message, normalized);
17
+ },
18
+ });
@@ -1,18 +1,21 @@
1
1
  import {
2
2
  defineGameCommandAliasMiddleware,
3
+ isChainAction,
3
4
  messageFromCommandInput,
4
5
  normalizeChainAction,
5
6
  } from '@zhin.js/game-kit';
6
- import { CHAIN_HELP, runChainCommandText } from '../src/chain-command.js';
7
+ import { CHAIN_HELP, runChainCommand } from '../src/chain-command.js';
7
8
  import { resolveGameServices } from '../src/runtime-store.js';
8
9
 
9
10
  export default defineGameCommandAliasMiddleware({
10
11
  aliases: ['接龙', 'chain'],
11
12
  async run(action, input, context) {
12
13
  const normalized = normalizeChainAction(String(action ?? ''));
13
- if (!normalized || normalized === 'help') return CHAIN_HELP;
14
+ if (normalized === 'help') return CHAIN_HELP;
15
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
16
+ if (!isChainAction(normalized)) return null;
14
17
  const services = resolveGameServices(context);
15
18
  const message = messageFromCommandInput(input);
16
- return runChainCommandText(services, message, normalized);
19
+ return runChainCommand(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 { CHAIN_PREFIX, handleChoice, processIdiomText } from "../lib/game-flow.js";
6
+ /**
7
+ * 文本入口:按钮 payload(`chain: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(`${CHAIN_PREFIX}:`)) {
24
+ const parsed = parseChoicePayload(payloadFromText, CHAIN_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(CHAIN_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, CHAIN_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
+ // 仅把 2-8 个汉字的纯文本当成语作答,其余放行
58
+ if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
59
+ const reply = await processIdiomText(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, CHAIN_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
  // 仅把 2-8 个汉字的纯文本当成语作答,其余放行
67
67
  if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
68
- const reply = await processIdiomText(null, services, message, raw);
68
+ const reply = await processIdiomText(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-idiom-chain",
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 idiom answer payloads.
11
+ */
12
+ export default defineGamePlugin({
13
+ name: 'idiom-chain',
14
+ metadata: {
15
+ displayName: 'Idiom Chain',
16
+ },
17
+ game: {
18
+ id: 'chain',
19
+ title: '成语接龙',
20
+ icon: '📜',
21
+ description: '四字成语接龙(同音/同字)',
22
+ commandPrefix: '/接龙',
23
+ quickStart: 'start_pinyin',
24
+ aliases: ['chain'],
25
+ menus: [
26
+ { id: 'start_pinyin', label: '🎮 同音接龙' },
27
+ { id: 'start_char', label: '📝 同字接龙' },
28
+ { id: 'continue', label: '🔄 继续' },
29
+ { id: 'help', label: '📖 玩法说明' },
30
+ ],
31
+ },
32
+ tables: ['idiom_chain_sessions'],
33
+ servicesToken: gameServicesToken,
34
+ defineHostTables,
35
+ createServices: (database) => createServices(database),
36
+ session: (services) => services,
37
+ });
@@ -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 { idiomCount, modeLabel, promptLine, type MatchMode } from './engine.js';
5
8
 
@@ -19,11 +22,10 @@ export const CHAIN_HELP = [
19
22
  ].join('\n');
20
23
 
21
24
  export async function runChainCommand(
22
- plugin: Plugin | null,
23
25
  services: SessionService,
24
- message: Message<any>,
26
+ message: GameMessageLike,
25
27
  action: string,
26
- ): Promise<string | undefined> {
28
+ ): Promise<GameReply> {
27
29
  const ch = channelKey(message);
28
30
  const userId = message.$sender.id;
29
31
 
@@ -42,9 +44,9 @@ export async function runChainCommand(
42
44
  return lines.join('\n');
43
45
  }
44
46
 
45
- if (action === 'start_pinyin') return startGame(plugin, services, message, 'pinyin');
46
- if (action === 'start_char') return startGame(plugin, services, message, 'char');
47
- if (action === 'continue') return continueGame(plugin, services, message);
47
+ if (action === 'start_pinyin') return (await startGame(services, message, 'pinyin')) ?? '';
48
+ if (action === 'start_char') return (await startGame(services, message, 'char')) ?? '';
49
+ if (action === 'continue') return continueGame(services, message);
48
50
 
49
51
  if (action === 'quit') {
50
52
  const row = await services.getActiveForUser(ch, userId);
@@ -55,12 +57,3 @@ export async function runChainCommand(
55
57
 
56
58
  return `未知子命令:${action}\n\n${CHAIN_HELP}`;
57
59
  }
58
-
59
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
60
- export async function runChainCommandText(
61
- services: SessionService,
62
- message: Message<any>,
63
- action: string,
64
- ): Promise<string> {
65
- return (await runChainCommand(null, services, message, action)) ?? '';
66
- }
package/src/game-flow.ts CHANGED
@@ -1,5 +1,4 @@
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 {
4
3
  CHAIN_PREFIX,
5
4
  getGloss,
@@ -22,34 +21,13 @@ function sessionMode(session: ChainSessionRow): MatchMode {
22
21
  }
23
22
 
24
23
  export async function sendOrEditView(
25
- plugin: Plugin | null,
26
24
  services: SessionService,
27
- message: Message<any>,
25
+ message: GameMessageLike,
28
26
  session: ChainSessionRow,
29
27
  eventLines: string[] = [],
30
- ): Promise<string | void> {
28
+ ): Promise<GameReply> {
31
29
  const content = buildChainView(session, eventLines, message.$channel.type);
32
- if (!plugin) return plainTextFromSendContent(content);
33
-
34
- const adapter = plugin.root.inject(message.$adapter) as Adapter;
35
-
36
- if (session.board_message_id) {
37
- const msgId = await adapter.editMessage({
38
- messageId: session.board_message_id,
39
- context: String(message.$adapter),
40
- endpoint: message.$endpoint,
41
- id: message.$channel.id,
42
- type: message.$channel.type,
43
- content,
44
- });
45
- if (msgId !== session.board_message_id) {
46
- await services.updateSession(session.id, { board_message_id: msgId });
47
- }
48
- return;
49
- }
50
-
51
- const msgId = await message.$reply?.(content);
52
- if (msgId) await services.updateSession(session.id, { board_message_id: msgId });
30
+ return content;
53
31
  }
54
32
 
55
33
  async function botTurn(
@@ -86,11 +64,10 @@ async function botTurn(
86
64
  }
87
65
 
88
66
  export async function startGame(
89
- plugin: Plugin | null,
90
67
  services: SessionService,
91
- message: Message<any>,
68
+ message: GameMessageLike,
92
69
  matchMode: MatchMode = 'pinyin',
93
- ): Promise<string | undefined> {
70
+ ): Promise<GameReply | undefined> {
94
71
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
95
72
  const active = await services.getActiveByChannel(ch);
96
73
  if (active) {
@@ -111,34 +88,29 @@ export async function startGame(
111
88
  });
112
89
 
113
90
  const gloss = starter.gloss ?? getGloss(starter.text);
114
- const text = await sendOrEditView(plugin, services, message, session, [
91
+ return sendOrEditView(services, message, session, [
115
92
  `🎬 ${modeLabel(matchMode)}开局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
116
93
  promptLine(starter.text, matchMode),
117
94
  ]);
118
- return typeof text === 'string' ? text : undefined;
119
95
  }
120
96
 
121
97
  export async function continueGame(
122
- plugin: Plugin | null,
123
98
  services: SessionService,
124
- message: Message<any>,
125
- ): Promise<string> {
99
+ message: GameMessageLike,
100
+ ): Promise<GameReply> {
126
101
  const session = await services.getActiveForUser(
127
102
  `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
128
103
  message.$sender.id,
129
104
  );
130
105
  if (!session) return '你没有进行中的接龙,发送「接龙 开始」。';
131
- const text = await sendOrEditView(plugin, services, message, session);
132
- if (typeof text === 'string') return text;
133
- return '已刷新接龙界面。';
106
+ return sendOrEditView(services, message, session);
134
107
  }
135
108
 
136
109
  export async function processIdiomText(
137
- plugin: Plugin | null,
138
110
  services: SessionService,
139
- message: Message<any>,
111
+ message: GameMessageLike,
140
112
  raw: string,
141
- ): Promise<string | null> {
113
+ ): Promise<GameReply | null> {
142
114
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
143
115
  const session = await services.getActiveForUser(ch, message.$sender.id);
144
116
  if (!session || session.status !== 'active') return null;
@@ -146,6 +118,10 @@ export async function processIdiomText(
146
118
  const mode = sessionMode(session);
147
119
  const used = parseUsed(session.used_idioms);
148
120
  const idiom = normalizeInput(raw);
121
+ // 格式不合规(非四字)只提示、不扣失误:避免闲聊(「好的」「谢谢」)被累计判负
122
+ if (!/^[\u4e00-\u9fff]{4}$/.test(idiom)) {
123
+ return '接龙请输入**四字成语**(这条不算失误)。';
124
+ }
149
125
  const check = validatePlayerIdiom(idiom, session.last_idiom, mode, used);
150
126
  if (!check.ok) {
151
127
  const wrong = session.wrong_count + 1;
@@ -157,14 +133,14 @@ export async function processIdiomText(
157
133
  streak: 0,
158
134
  });
159
135
  const updated = (await services.getById(session.id))!;
160
- return (await sendOrEditView(plugin, services, message, updated, [
136
+ return (await sendOrEditView(services, message, updated, [
161
137
  check.reason!,
162
138
  '失误过多,本局结束。',
163
139
  ])) ?? null;
164
140
  }
165
141
  await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
166
142
  const updated = (await services.getById(session.id))!;
167
- return (await sendOrEditView(plugin, services, message, updated, [check.reason!])) ?? null;
143
+ return (await sendOrEditView(services, message, updated, [check.reason!])) ?? null;
168
144
  }
169
145
 
170
146
  used.add(idiom);
@@ -186,19 +162,18 @@ export async function processIdiomText(
186
162
  const userLine = `✅ 你:${idiom}${gloss ? `(${gloss})` : ''}`;
187
163
 
188
164
  const botResult = await botTurn(services, current, used);
189
- return (await sendOrEditView(plugin, services, message, botResult.session, [
165
+ return (await sendOrEditView(services, message, botResult.session, [
190
166
  userLine,
191
167
  ...botResult.lines,
192
168
  ])) ?? null;
193
169
  }
194
170
 
195
171
  export async function handleChoice(
196
- plugin: Plugin | null,
197
172
  services: SessionService,
198
- message: Message<any>,
173
+ message: GameMessageLike,
199
174
  sessionId: string,
200
175
  choiceId: string,
201
- ): Promise<string | null> {
176
+ ): Promise<GameReply | null> {
202
177
  const session = await services.getById(sessionId);
203
178
  if (!session) return '对局不存在。';
204
179
  if (session.player_id !== message.$sender.id) return '这是别人的接龙。';
@@ -217,11 +192,10 @@ export async function handleChoice(
217
192
  wrong_count: 0,
218
193
  turn: 'player',
219
194
  status: 'active',
220
- board_message_id: '',
221
195
  });
222
196
  const updated = (await services.getById(session.id))!;
223
197
  const gloss = starter.gloss ?? getGloss(starter.text);
224
- return (await sendOrEditView(plugin, services, message, updated, [
198
+ return (await sendOrEditView(services, message, updated, [
225
199
  `🎬 新一局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
226
200
  promptLine(starter.text, mode),
227
201
  ])) ?? null;
@@ -236,15 +210,17 @@ export async function handleChoice(
236
210
  if (choiceId === 'hint') {
237
211
  const hint = pickHintIdiom(session.last_idiom, mode, used);
238
212
  if (!hint) {
239
- await sendOrEditView(plugin, services, message, session, ['💡 词库中暂无可用提示,你赢了!']);
213
+ // 先更新状态再单次发送终局视图,避免旧 session「你赢了」与终局视图双发
240
214
  await services.updateSession(session.id, { status: 'won', player_score: session.player_score + 1 });
241
215
  const updated = (await services.getById(session.id))!;
242
- return (await sendOrEditView(plugin, services, message, updated)) ?? null;
216
+ return (await sendOrEditView(services, message, updated, [
217
+ '💡 词库中暂无可用提示,你赢了!',
218
+ ])) ?? null;
243
219
  }
244
220
  const gloss = getGloss(hint);
245
221
  await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
246
222
  const updated = (await services.getById(session.id))!;
247
- return (await sendOrEditView(plugin, services, message, updated, [
223
+ return (await sendOrEditView(services, message, updated, [
248
224
  `💡 提示:可试 **${hint}**${gloss ? `(${gloss})` : ''}`,
249
225
  '(使用提示会清零连击)',
250
226
  ])) ?? null;
@@ -257,7 +233,7 @@ export async function handleChoice(
257
233
  streak: 0,
258
234
  });
259
235
  const updated = (await services.getById(session.id))!;
260
- return (await sendOrEditView(plugin, services, message, updated, [
236
+ return (await sendOrEditView(services, message, updated, [
261
237
  '⏭️ 你选择跳过,机器人得一分。',
262
238
  ])) ?? null;
263
239
  }
@@ -265,7 +241,7 @@ export async function handleChoice(
265
241
  if (choiceId === 'quit') {
266
242
  await services.updateSession(session.id, { status: 'lost', bot_score: session.bot_score + 1 });
267
243
  const updated = (await services.getById(session.id))!;
268
- return (await sendOrEditView(plugin, services, message, updated, ['🏳️ 你认输了。'])) ?? null;
244
+ return (await sendOrEditView(services, message, updated, ['🏳️ 你认输了。'])) ?? null;
269
245
  }
270
246
 
271
247
  return '未知操作。';
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { CHAIN_HELP } from './chain-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryChainDb, mountChainMemoryServices } from './memory-db.js';
4
3
 
5
4
  /**
6
5
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
package/src/models.ts CHANGED
@@ -26,7 +26,6 @@ declare module '@zhin.js/core' {
26
26
  hints_used: number;
27
27
  turn: string;
28
28
  status: ChainSessionStatus;
29
- board_message_id: string;
30
29
  updated_at: number;
31
30
  created_at: number;
32
31
  };
@@ -60,7 +59,6 @@ export function defineHostTables(
60
59
  hints_used: { type: 'integer', default: 0 },
61
60
  turn: { type: 'text', default: 'player' },
62
61
  status: { type: 'text', default: 'active' },
63
- board_message_id: { type: 'text', default: '' },
64
62
  updated_at: { type: 'integer', default: 0 },
65
63
  created_at: { type: 'integer', default: 0 },
66
64
  });
@@ -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 type { MatchMode } from './engine.js';
4
10
  import type { ChainSessionRow } from './models.js';
5
11
 
6
12
  export type ChainDatabase = Database<unknown, Models, string>;
7
13
 
8
- function getModel(db: ChainDatabase) {
9
- const model = db.models.get('idiom_chain_sessions');
10
- if (!model) throw new Error('idiom_chain_sessions not registered');
11
- return model as RelatedModel<unknown, Models, 'idiom_chain_sessions'>;
12
- }
13
-
14
14
  export function parseUsed(value: string | string[] | unknown): Set<string> {
15
15
  if (Array.isArray(value)) return new Set(value.filter((x): x is string => typeof x === 'string'));
16
16
  if (typeof value !== 'string' || !value) return new Set();
@@ -26,35 +26,17 @@ export function serializeUsed(set: Set<string>): string {
26
26
  return JSON.stringify([...set]);
27
27
  }
28
28
 
29
- export class SessionService {
30
- constructor(private readonly db: ChainDatabase) {}
31
-
32
- async getActiveByChannel(channel: string): Promise<ChainSessionRow | null> {
33
- const rows = await getModel(this.db).findAll({ channel_key: channel, status: 'active' });
34
- return rows[0] ?? null;
35
- }
36
-
37
- async getActiveForUser(channel: string, userId: string): Promise<ChainSessionRow | null> {
38
- const row = await this.getActiveByChannel(channel);
39
- if (!row || row.player_id !== userId) return null;
40
- return row;
41
- }
42
-
43
- async getById(id: string): Promise<ChainSessionRow | null> {
44
- return getModel(this.db).findOne({ id });
45
- }
46
-
47
- async getActiveByBoardMessageId(messageId: string): Promise<ChainSessionRow | null> {
48
- if (!messageId) return null;
49
- const rows = await getModel(this.db).findAll({});
50
- for (const row of rows) {
51
- if (boardMessageMatches(row.board_message_id ?? '', messageId)) return row;
52
- }
53
- return null;
29
+ export class SessionService extends BaseSessionService<ChainSessionRow> {
30
+ constructor(db: ChainDatabase) {
31
+ super(db as unknown as GameSessionDatabase<ChainSessionRow>, {
32
+ gameId: 'chain',
33
+ table: 'idiom_chain_sessions',
34
+ userFields: ['player_id'],
35
+ });
54
36
  }
55
37
 
56
38
  async createSession(
57
- message: Message<any>,
39
+ message: GameMessageLike,
58
40
  starter: { text: string; nextChar: string; used: string[]; matchMode: MatchMode },
59
41
  ): Promise<ChainSessionRow> {
60
42
  const now = Date.now();
@@ -79,34 +61,13 @@ export class SessionService {
79
61
  hints_used: 0,
80
62
  turn: 'player',
81
63
  status: 'active',
82
- board_message_id: '',
83
64
  updated_at: now,
84
65
  created_at: now,
85
66
  };
86
- await getModel(this.db).create(row);
87
- return row;
88
- }
89
-
90
- async updateSession(id: string, patch: Partial<ChainSessionRow>): Promise<void> {
91
- await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
92
- }
93
-
94
- async abortStale(idleMs: number): Promise<number> {
95
- const cutoff = Date.now() - idleMs;
96
- const model = getModel(this.db);
97
- const rows = await model.findAll({ status: 'active' });
98
- let n = 0;
99
- for (const row of rows) {
100
- if (row.updated_at < cutoff) {
101
- await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
102
- n++;
103
- }
104
- }
105
- return n;
67
+ return this.createRow(row);
106
68
  }
107
69
  }
108
70
 
109
71
  export function createServices(db: ChainDatabase): SessionService {
110
72
  return new SessionService(db);
111
73
  }
112
-
@@ -1,6 +0,0 @@
1
- import type { DatabaseHost } from '@zhin.js/plugin-runtime';
2
- import { type ChainDatabase, type SessionService } from './session-service.js';
3
- /** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
4
- export declare function createInMemoryChainDb(): ChainDatabase;
5
- export declare function mountChainMemoryServices(): SessionService;
6
- export declare function mountChainHostServices(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 CHAIN_TABLES = ['idiom_chain_sessions'];
5
- /** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
6
- export function createInMemoryChainDb() {
7
- return createInMemoryGameDb(CHAIN_TABLES);
8
- }
9
- export function mountChainMemoryServices() {
10
- const services = createServices(createInMemoryChainDb());
11
- return services;
12
- }
13
- export function mountChainHostServices(host) {
14
- defineHostTables(host);
15
- const services = createServices(createHostGameDb(host, CHAIN_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,EAA2C,MAAM,sBAAsB,CAAC;AAE/F,MAAM,YAAY,GAAG,CAAC,sBAAsB,CAAU,CAAC;AAEvD,sFAAsF;AACtF,MAAM,UAAU,qBAAqB;IACnC,OAAO,oBAAoB,CAAC,YAAY,CAA6B,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,QAAQ,GAAG,cAAc,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAkB;IACvD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAA6B,CAAC,CAAC;IAClG,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 { mountChainHostServices, mountChainMemoryServices } 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 idiom answer payloads.
17
- */
18
- export default definePlugin({
19
- name: 'idiom-chain',
20
- metadata: {
21
- displayName: 'Idiom Chain',
22
- },
23
- setup(context) {
24
- let services: SessionService;
25
- if (context.resources.has(databaseHostToken)) {
26
- const host = context.resources.use(databaseHostToken);
27
- services = mountChainHostServices(host);
28
- context.lifecycle.add(initGameRecordHost(host));
29
- } else {
30
- services = mountChainMemoryServices();
31
- }
32
- context.resources.provide(gameServicesToken, services);
33
- const disposeHub = registerRuntimeGame({
34
- id: 'chain',
35
- title: '成语接龙',
36
- icon: '📜',
37
- description: '四字成语接龙(同音/同字)',
38
- commandPrefix: '/接龙',
39
- quickStart: 'start_pinyin',
40
- aliases: ['chain'],
41
- menus: [
42
- { id: 'start_pinyin', label: '🎮 同音接龙' },
43
- { id: 'start_char', 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: 'chain/abort-stale',
54
- cron: DEFAULT_GAME_STALE_CRON,
55
- description: 'Abort stale idiom-chain 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 ChainDatabase, type SessionService } from './session-service.js';
5
-
6
- const CHAIN_TABLES = ['idiom_chain_sessions'] as const;
7
-
8
- /** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
9
- export function createInMemoryChainDb(): ChainDatabase {
10
- return createInMemoryGameDb(CHAIN_TABLES) as unknown as ChainDatabase;
11
- }
12
-
13
- export function mountChainMemoryServices(): SessionService {
14
- const services = createServices(createInMemoryChainDb());
15
- return services;
16
- }
17
-
18
- export function mountChainHostServices(host: DatabaseHost): SessionService {
19
- defineHostTables(host);
20
- const services = createServices(createHostGameDb(host, CHAIN_TABLES) as unknown as ChainDatabase);
21
- return services;
22
- }