@zhin.js/plugin-rps 1.0.3 → 1.0.4

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.
@@ -1,6 +1,6 @@
1
1
  import { defineCommand } from '@zhin.js/command';
2
2
  import { messageFromCommandInput, normalizeRpsAction } from '@zhin.js/game-kit';
3
- import { RPS_HELP, runRpsCommandText } from '../../src/rps-command.js';
3
+ import { RPS_HELP, runRpsCommand } from '../../src/rps-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 RPS_HELP;
11
11
  const services = resolveGameServices({ use, owner });
12
12
  const message = messageFromCommandInput(input);
13
- return runRpsCommandText(services, message, action);
13
+ return runRpsCommand(services, message, action);
14
14
  },
15
15
  });
@@ -1,13 +1,7 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
2
- import type { RpsSessionRow } from './models.js';
3
- import { RPS_PREFIX, type RpsMove } from './engine.js';
1
+ import { type GameMessageLike } from '@zhin.js/game-kit';
2
+ import { RPS_PREFIX } from './engine.js';
4
3
  import type { SessionService } from './session-service.js';
5
- export declare function sendOrEditView(plugin: Plugin | null, services: SessionService, message: Message<any>, session: RpsSessionRow, lastRound?: {
6
- player: RpsMove;
7
- bot: RpsMove;
8
- result: 0 | 1 | 2;
9
- }): Promise<string | void>;
10
- export declare function startGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string | undefined>;
11
- export declare function handleChoice(plugin: Plugin | null, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
12
- export declare function continueGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string>;
4
+ export declare function startGame(services: SessionService, message: GameMessageLike): Promise<string | undefined>;
5
+ export declare function handleChoice(services: SessionService, message: GameMessageLike, sessionId: string, choiceId: string): Promise<string | null>;
6
+ export declare function continueGame(services: SessionService, message: GameMessageLike): Promise<string>;
13
7
  export { RPS_PREFIX };
package/lib/game-flow.js CHANGED
@@ -1,30 +1,15 @@
1
1
  import { plainTextFromSendContent, recordGameOutcome } from '@zhin.js/game-kit';
2
2
  import { RPS_PREFIX, WIN_TARGET, randomBotMove, resolveRound, } from './engine.js';
3
3
  import { buildRpsView } from './view.js';
4
- export async function sendOrEditView(plugin, services, message, session, lastRound) {
5
- const content = buildRpsView(session, lastRound, message.$channel.type);
6
- if (!plugin)
7
- return plainTextFromSendContent(content);
8
- const adapter = plugin.root.inject(message.$adapter);
9
- if (session.board_message_id) {
10
- const msgId = await adapter.editMessage({
11
- messageId: session.board_message_id,
12
- context: String(message.$adapter),
13
- endpoint: message.$endpoint,
14
- id: message.$channel.id,
15
- type: message.$channel.type,
16
- content,
17
- });
18
- if (msgId !== session.board_message_id) {
19
- await services.updateSession(session.id, { board_message_id: msgId });
20
- }
21
- return;
22
- }
23
- const msgId = await message.$reply?.(content);
24
- if (msgId)
25
- 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 choice middleware return fresh text each turn.
8
+ */
9
+ function renderView(session, message, lastRound) {
10
+ return plainTextFromSendContent(buildRpsView(session, lastRound, message.$channel.type));
26
11
  }
27
- export async function startGame(plugin, services, message) {
12
+ export async function startGame(services, message) {
28
13
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
29
14
  const active = await services.getActiveByChannel(ch);
30
15
  if (active) {
@@ -34,10 +19,9 @@ export async function startGame(plugin, services, message) {
34
19
  return `本频道 ${active.player_name} 正在猜拳对决中。`;
35
20
  }
36
21
  const session = await services.createSession(message);
37
- const text = await sendOrEditView(plugin, services, message, session);
38
- return typeof text === 'string' ? text : undefined;
22
+ return renderView(session, message);
39
23
  }
40
- export async function handleChoice(plugin, services, message, sessionId, choiceId) {
24
+ export async function handleChoice(services, message, sessionId, choiceId) {
41
25
  const session = await services.getById(sessionId);
42
26
  if (!session)
43
27
  return '对局不存在。';
@@ -48,8 +32,7 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
48
32
  return '这是别人的对局。';
49
33
  if (choiceId === 'restart') {
50
34
  await services.updateSession(session.id, { status: 'aborted' });
51
- // text-only 模式(plugin===null)下 startGame 的唯一输出就是返回文本
52
- return (await startGame(plugin, services, message)) ?? null;
35
+ return (await startGame(services, message)) ?? null;
53
36
  }
54
37
  const player = choiceId;
55
38
  if (!['rock', 'paper', 'scissors'].includes(player))
@@ -78,17 +61,13 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
78
61
  void recordGameOutcome(message, 'rps', 'won', playerWins * 10);
79
62
  else if (status === 'lost')
80
63
  void recordGameOutcome(message, 'rps', 'lost');
81
- const text = await sendOrEditView(plugin, services, message, updated, { player, bot, result });
82
- return typeof text === 'string' ? text : null;
64
+ return renderView(updated, message, { player, bot, result });
83
65
  }
84
- export async function continueGame(plugin, services, message) {
66
+ export async function continueGame(services, message) {
85
67
  const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
86
68
  if (!session)
87
69
  return '你没有进行中的猜拳,发送「猜拳 开始」。';
88
- const text = await sendOrEditView(plugin, services, message, session);
89
- if (typeof text === 'string')
90
- return text;
91
- return '已刷新猜拳界面。';
70
+ return renderView(session, message);
92
71
  }
93
72
  export { RPS_PREFIX };
94
73
  //# sourceMappingURL=game-flow.js.map
@@ -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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"}
@@ -1,6 +1,4 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
1
+ import { type GameMessageLike } from '@zhin.js/game-kit';
2
2
  import type { SessionService } from './session-service.js';
3
3
  export declare const RPS_HELP: string;
4
- export declare function runRpsCommand(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 runRpsCommandText(services: SessionService, message: Message<any>, action: string): Promise<string>;
4
+ export declare function runRpsCommand(services: SessionService, message: GameMessageLike, action: string): Promise<string>;
@@ -7,7 +7,7 @@ export const RPS_HELP = [
7
7
  '猜拳 继续 — 刷新界面',
8
8
  '猜拳 放弃 — 结束对局',
9
9
  ].join('\n');
10
- export async function runRpsCommand(plugin, services, message, action) {
10
+ export async function runRpsCommand(services, message, action) {
11
11
  const ch = channelKey(message);
12
12
  const userId = message.$sender.id;
13
13
  if (!action || action === 'help') {
@@ -22,9 +22,9 @@ export async function runRpsCommand(plugin, services, message, action) {
22
22
  return lines.join('\n');
23
23
  }
24
24
  if (action === 'start')
25
- return startGame(plugin, services, message);
25
+ return (await startGame(services, message)) ?? '';
26
26
  if (action === 'continue')
27
- return continueGame(plugin, services, message);
27
+ return continueGame(services, message);
28
28
  if (action === 'quit') {
29
29
  const row = await services.getActiveForUser(ch, userId);
30
30
  if (!row)
@@ -34,8 +34,4 @@ export async function runRpsCommand(plugin, services, message, action) {
34
34
  }
35
35
  return `未知子命令:${action}\n\n${RPS_HELP}`;
36
36
  }
37
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
38
- export async function runRpsCommandText(services, message, action) {
39
- return (await runRpsCommand(null, services, message, action)) ?? '';
40
- }
41
37
  //# sourceMappingURL=rps-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rps-command.js","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGzD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,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,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,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,OAAO;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpE,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,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,OAAO,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACtE,CAAC"}
1
+ {"version":3,"file":"rps-command.js","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAwB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGzD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,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,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,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,OAAO;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,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,QAAQ,EAAE,CAAC;AAC1C,CAAC"}
@@ -1,4 +1,5 @@
1
- import type { Database, Message, Models } from '@zhin.js/core';
1
+ import type { Database, Models } from '@zhin.js/core';
2
+ import { type GameMessageLike } from '@zhin.js/game-kit';
2
3
  import type { RpsSessionRow } from './models.js';
3
4
  export type RpsDatabase = Database<unknown, Models, string>;
4
5
  export declare class SessionService {
@@ -8,7 +9,7 @@ export declare class SessionService {
8
9
  getActiveForUser(channel: string, userId: string): Promise<RpsSessionRow | null>;
9
10
  getById(id: string): Promise<RpsSessionRow | null>;
10
11
  getActiveByBoardMessageId(messageId: string): Promise<RpsSessionRow | null>;
11
- createSession(message: Message<any>): Promise<RpsSessionRow>;
12
+ createSession(message: GameMessageLike): Promise<RpsSessionRow>;
12
13
  updateSession(id: string, patch: Partial<RpsSessionRow>): Promise<void>;
13
14
  abortStale(idleMs: number): Promise<number>;
14
15
  }
@@ -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":"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"}
@@ -1,18 +1,21 @@
1
1
  import {
2
2
  defineGameCommandAliasMiddleware,
3
+ isRpsAction,
3
4
  messageFromCommandInput,
4
5
  normalizeRpsAction,
5
6
  } from '@zhin.js/game-kit';
6
- import { RPS_HELP, runRpsCommandText } from '../src/rps-command.js';
7
+ import { RPS_HELP, runRpsCommand } from '../src/rps-command.js';
7
8
  import { resolveGameServices } from '../src/runtime-store.js';
8
9
 
9
10
  export default defineGameCommandAliasMiddleware({
10
11
  aliases: ['猜拳', 'rps'],
11
12
  async run(action, input, context) {
12
13
  const normalized = normalizeRpsAction(String(action ?? ''));
13
- if (!normalized || normalized === 'help') return RPS_HELP;
14
+ if (normalized === 'help') return RPS_HELP;
15
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
16
+ if (!isRpsAction(normalized)) return null;
14
17
  const services = resolveGameServices(context);
15
18
  const message = messageFromCommandInput(input);
16
- return runRpsCommandText(services, message, normalized);
19
+ return runRpsCommand(services, message, normalized);
17
20
  },
18
21
  });
@@ -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
  }
@@ -60,7 +60,7 @@ export default defineMiddleware<Message>({
60
60
  return;
61
61
  }
62
62
 
63
- const reply = await handleChoice(null, services, message, session.id, parsed.choiceId);
63
+ const reply = await handleChoice(services, message, session.id, parsed.choiceId);
64
64
  if (reply) await context.input.$reply(reply);
65
65
  },
66
66
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-rps",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Zhin.js 猜拳游戏 — 石头剪刀布三局两胜 (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -24,11 +24,11 @@
24
24
  ],
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "@zhin.js/command": "1.0.2",
28
- "@zhin.js/core": "1.4.0",
29
- "@zhin.js/game-kit": "2.0.0",
30
- "@zhin.js/middleware": "1.0.2",
31
- "@zhin.js/plugin-runtime": "1.1.0"
27
+ "@zhin.js/command": "1.0.3",
28
+ "@zhin.js/core": "1.4.1",
29
+ "@zhin.js/game-kit": "2.0.1",
30
+ "@zhin.js/middleware": "1.0.3",
31
+ "@zhin.js/plugin-runtime": "1.1.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "typescript": "^6.0.3",
package/src/game-flow.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { Adapter, Message, Plugin } from '@zhin.js/core';
2
- import { plainTextFromSendContent, recordGameOutcome } from '@zhin.js/game-kit';
1
+ import { plainTextFromSendContent, recordGameOutcome, type GameMessageLike } from '@zhin.js/game-kit';
3
2
  import type { RpsSessionRow } from './models.js';
4
3
  import {
5
4
  RPS_PREFIX,
@@ -11,41 +10,22 @@ import {
11
10
  import type { SessionService } from './session-service.js';
12
11
  import { buildRpsView } from './view.js';
13
12
 
14
- export async function sendOrEditView(
15
- plugin: Plugin | null,
16
- services: SessionService,
17
- message: Message<any>,
13
+ /**
14
+ * Plugin Runtime: render the board as text. Interactive in-place board editing
15
+ * (the old Adapter.editMessage path) is not part of the runtime flow; commands
16
+ * and the choice middleware return fresh text each turn.
17
+ */
18
+ function renderView(
18
19
  session: RpsSessionRow,
20
+ message: GameMessageLike,
19
21
  lastRound?: { player: RpsMove; bot: RpsMove; result: 0 | 1 | 2 },
20
- ): Promise<string | void> {
21
- const content = buildRpsView(session, lastRound, message.$channel.type);
22
- if (!plugin) return plainTextFromSendContent(content);
23
-
24
- const adapter = plugin.root.inject(message.$adapter) as Adapter;
25
-
26
- if (session.board_message_id) {
27
- const msgId = await adapter.editMessage({
28
- messageId: session.board_message_id,
29
- context: String(message.$adapter),
30
- endpoint: message.$endpoint,
31
- id: message.$channel.id,
32
- type: message.$channel.type,
33
- content,
34
- });
35
- if (msgId !== session.board_message_id) {
36
- await services.updateSession(session.id, { board_message_id: msgId });
37
- }
38
- return;
39
- }
40
-
41
- const msgId = await message.$reply?.(content);
42
- if (msgId) await services.updateSession(session.id, { board_message_id: msgId });
22
+ ): string {
23
+ return plainTextFromSendContent(buildRpsView(session, lastRound, message.$channel.type));
43
24
  }
44
25
 
45
26
  export async function startGame(
46
- plugin: Plugin | null,
47
27
  services: SessionService,
48
- message: Message<any>,
28
+ message: GameMessageLike,
49
29
  ): Promise<string | undefined> {
50
30
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
51
31
  const active = await services.getActiveByChannel(ch);
@@ -56,14 +36,12 @@ export async function startGame(
56
36
  return `本频道 ${active.player_name} 正在猜拳对决中。`;
57
37
  }
58
38
  const session = await services.createSession(message);
59
- const text = await sendOrEditView(plugin, services, message, session);
60
- return typeof text === 'string' ? text : undefined;
39
+ return renderView(session, message);
61
40
  }
62
41
 
63
42
  export async function handleChoice(
64
- plugin: Plugin | null,
65
43
  services: SessionService,
66
- message: Message<any>,
44
+ message: GameMessageLike,
67
45
  sessionId: string,
68
46
  choiceId: string,
69
47
  ): Promise<string | null> {
@@ -76,8 +54,7 @@ export async function handleChoice(
76
54
 
77
55
  if (choiceId === 'restart') {
78
56
  await services.updateSession(session.id, { status: 'aborted' });
79
- // text-only 模式(plugin===null)下 startGame 的唯一输出就是返回文本
80
- return (await startGame(plugin, services, message)) ?? null;
57
+ return (await startGame(services, message)) ?? null;
81
58
  }
82
59
 
83
60
  const player = choiceId as RpsMove;
@@ -104,23 +81,19 @@ export async function handleChoice(
104
81
  const updated = (await services.getById(session.id))!;
105
82
  if (status === 'won') void recordGameOutcome(message, 'rps', 'won', playerWins * 10);
106
83
  else if (status === 'lost') void recordGameOutcome(message, 'rps', 'lost');
107
- const text = await sendOrEditView(plugin, services, message, updated, { player, bot, result });
108
- return typeof text === 'string' ? text : null;
84
+ return renderView(updated, message, { player, bot, result });
109
85
  }
110
86
 
111
87
  export async function continueGame(
112
- plugin: Plugin | null,
113
88
  services: SessionService,
114
- message: Message<any>,
89
+ message: GameMessageLike,
115
90
  ): Promise<string> {
116
91
  const session = await services.getActiveForUser(
117
92
  `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
118
93
  message.$sender.id,
119
94
  );
120
95
  if (!session) return '你没有进行中的猜拳,发送「猜拳 开始」。';
121
- const text = await sendOrEditView(plugin, services, message, session);
122
- if (typeof text === 'string') return text;
123
- return '已刷新猜拳界面。';
96
+ return renderView(session, message);
124
97
  }
125
98
 
126
99
  export { RPS_PREFIX };
@@ -1,5 +1,4 @@
1
- import type { Message, Plugin } from '@zhin.js/core';
2
- import { channelKey } from '@zhin.js/game-kit';
1
+ import { channelKey, type GameMessageLike } from '@zhin.js/game-kit';
3
2
  import { continueGame, startGame } from './game-flow.js';
4
3
  import type { SessionService } from './session-service.js';
5
4
 
@@ -12,11 +11,10 @@ export const RPS_HELP = [
12
11
  ].join('\n');
13
12
 
14
13
  export async function runRpsCommand(
15
- plugin: Plugin | null,
16
14
  services: SessionService,
17
- message: Message<any>,
15
+ message: GameMessageLike,
18
16
  action: string,
19
- ): Promise<string | undefined> {
17
+ ): Promise<string> {
20
18
  const ch = channelKey(message);
21
19
  const userId = message.$sender.id;
22
20
 
@@ -31,8 +29,8 @@ export async function runRpsCommand(
31
29
  return lines.join('\n');
32
30
  }
33
31
 
34
- if (action === 'start') return startGame(plugin, services, message);
35
- if (action === 'continue') return continueGame(plugin, services, message);
32
+ if (action === 'start') return (await startGame(services, message)) ?? '';
33
+ if (action === 'continue') return continueGame(services, message);
36
34
 
37
35
  if (action === 'quit') {
38
36
  const row = await services.getActiveForUser(ch, userId);
@@ -43,12 +41,3 @@ export async function runRpsCommand(
43
41
 
44
42
  return `未知子命令:${action}\n\n${RPS_HELP}`;
45
43
  }
46
-
47
- /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
48
- export async function runRpsCommandText(
49
- services: SessionService,
50
- message: Message<any>,
51
- action: string,
52
- ): Promise<string> {
53
- return (await runRpsCommand(null, services, message, action)) ?? '';
54
- }
@@ -1,5 +1,5 @@
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, RelatedModel } from '@zhin.js/core';
2
+ import { channelKey, generateSessionId, boardMessageMatches, type GameMessageLike } from '@zhin.js/game-kit';
3
3
  import type { RpsSessionRow } from './models.js';
4
4
 
5
5
  export type RpsDatabase = Database<unknown, Models, string>;
@@ -37,7 +37,7 @@ export class SessionService {
37
37
  return null;
38
38
  }
39
39
 
40
- async createSession(message: Message<any>): Promise<RpsSessionRow> {
40
+ async createSession(message: GameMessageLike): Promise<RpsSessionRow> {
41
41
  const now = Date.now();
42
42
  const row: RpsSessionRow = {
43
43
  id: generateSessionId(),