@zhin.js/command 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Zhin Plugin Runtime 的约定式 Command Feature。它发现 `commands/**/*.ts(x
11
11
  ```ts
12
12
  // commands/gh/issue/list.ts -> gh issue list
13
13
  // commands/赞我.ts -> 赞我
14
- import { defineCommand } from '@zhin.js/command';
14
+ import { defineCommand } from 'zhin.js/command';
15
15
 
16
16
  export default defineCommand({
17
17
  description: 'List GitHub issues',
@@ -44,6 +44,8 @@ commands/search/[...kw].ts -> search <...kw> (params: { kw: { type: 'text
44
44
  - `adapter` / `endpoint`:适配器实例 id 与 endpoint 名。
45
45
  - `scene`:`{ id, type, name? }` 场景对象。
46
46
  - `sender`:`{ id, name?, role: string[] }` 发送者对象。
47
+ - `interaction`:可选的 `UserInteraction`。用 `ask()` 获取单个类型化结论,或用
48
+ `sequence()` 连续收集多个结论;请求可声明 `title`、`description`、`tip` 与校验规则。
47
49
 
48
50
  可选声明字段:
49
51
 
@@ -1,5 +1,6 @@
1
1
  import type { CapabilitySlot, PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
- import { type CommandDefinition, type CommandParameterDefinition, type CommandParameterType, type CommandSegment, type CommandPromptFactory } from './definition.js';
2
+ import type { UserInteractionFactory } from '@zhin.js/interaction';
3
+ import { type CommandDefinition, type CommandParameterDefinition, type CommandParameterType, type CommandSegment } from './definition.js';
3
4
  export interface CommandParameterDescriptor extends CommandParameterDefinition {
4
5
  readonly required: boolean;
5
6
  }
@@ -31,7 +32,7 @@ export declare class CommandIndex {
31
32
  list(): readonly CommandDescriptor[];
32
33
  has(name: string): boolean;
33
34
  execute(name: string, args?: readonly string[]): Promise<unknown>;
34
- dispatch(input: CommandMatchInput, source?: unknown, promptFactory?: CommandPromptFactory, commandPrefix?: string): Promise<CommandDispatchResult>;
35
+ dispatch(input: CommandMatchInput, source?: unknown, interactionFactory?: UserInteractionFactory, commandPrefix?: string): Promise<CommandDispatchResult>;
35
36
  }
36
37
  export declare function isCommandIndex(value: unknown): value is CommandIndex;
37
38
  export declare class CommandParameterValueError extends TypeError {
@@ -1,7 +1,6 @@
1
1
  import { SegmentMatcher, TypeMatcherRegistry, } from 'segment-matcher';
2
+ import { permissionHostToken, toPermissionSubject, } from '@zhin.js/permission';
2
3
  import { createCommandContext, resolveCommandSession, resolveDynamicParams, } from './definition.js';
3
- import { permissionHostToken } from '@zhin.js/permission';
4
- import { toPermissionSubject } from '@zhin.js/permission';
5
4
  const segmentFields = {
6
5
  text: 'text',
7
6
  mention: 'target',
@@ -119,7 +118,7 @@ export class CommandIndex {
119
118
  // Host / 无 session:跳过 permit;无 source 时函数默认值得到空 session。
120
119
  return match.command.slot.definition.execute(createCommandContext(this.snapshot, match.command.slot.owner, args, resolveDynamicParams(match.params, undefined)));
121
120
  }
122
- async dispatch(input, source = undefined, promptFactory, commandPrefix = '') {
121
+ async dispatch(input, source = undefined, interactionFactory, commandPrefix = '') {
123
122
  if (this.#menu) {
124
123
  const menuValue = this.#dispatchMenu(input, commandPrefix);
125
124
  if (menuValue !== undefined) {
@@ -131,13 +130,13 @@ export class CommandIndex {
131
130
  });
132
131
  }
133
132
  }
134
- const prompt = promptFactory?.(source);
133
+ const interaction = interactionFactory?.(source);
135
134
  const shortcut = this.#matchShortcut(input);
136
135
  if (shortcut) {
137
136
  if (!(await this.#permitAllows(shortcut.record, source))) {
138
137
  return Object.freeze({ matched: false });
139
138
  }
140
- const value = await shortcut.record.slot.definition.execute(createCommandContext(this.snapshot, shortcut.record.slot.owner, Object.freeze([]), resolveDynamicParams(shortcut.params, source), source, Object.freeze([]), prompt));
139
+ const value = await shortcut.record.slot.definition.execute(createCommandContext(this.snapshot, shortcut.record.slot.owner, Object.freeze([]), resolveDynamicParams(shortcut.params, source), source, Object.freeze([]), interaction));
141
140
  return Object.freeze({
142
141
  matched: true,
143
142
  command: shortcut.record.name,
@@ -152,7 +151,7 @@ export class CommandIndex {
152
151
  return Object.freeze({ matched: false });
153
152
  }
154
153
  const args = textArgs(match.remaining);
155
- const value = await match.command.slot.definition.execute(createCommandContext(this.snapshot, match.command.slot.owner, args, resolveDynamicParams(match.params, source), source, match.remaining, prompt));
154
+ const value = await match.command.slot.definition.execute(createCommandContext(this.snapshot, match.command.slot.owner, args, resolveDynamicParams(match.params, source), source, match.remaining, interaction));
156
155
  return Object.freeze({
157
156
  matched: true,
158
157
  command: match.command.name,
@@ -1,5 +1,6 @@
1
1
  import type { PluginId, RuntimeSnapshot } from '@zhin.js/plugin-runtime';
2
2
  import { type CapabilityContext } from '@zhin.js/feature-kit';
3
+ import type { UserInteraction } from '@zhin.js/interaction';
3
4
  declare const commandBrand: "zhin.command/1";
4
5
  export type CommandParameterType = 'string' | 'number' | 'integer' | 'float' | 'boolean' | 'word' | 'text' | 'mention' | 'image' | 'face' | 'reply' | 'forward' | 'dice' | 'rps';
5
6
  export type CommandParameterValue = string | number | boolean | ReadonlyArray<string | number | boolean> | Readonly<Record<string, unknown>> | null;
@@ -143,56 +144,21 @@ export interface CommandSession {
143
144
  /** 发送者对象(id / name / role[])。 */
144
145
  readonly sender?: CommandSender;
145
146
  }
146
- export interface CommandPromptOptions {
147
- readonly timeout?: number;
148
- readonly timeoutText?: string;
149
- /** Cancel the pending claim when the owning turn aborts. */
150
- readonly signal?: AbortSignal;
151
- }
152
- export interface CommandPromptListOptions extends CommandPromptOptions {
153
- readonly type?: 'text' | 'number' | 'boolean';
154
- readonly separator?: string;
155
- readonly default?: readonly (string | number | boolean)[];
156
- }
157
- export interface CommandPromptPickOptions<V = unknown> extends CommandPromptOptions {
158
- readonly options: readonly {
159
- readonly label: string;
160
- readonly value: V;
161
- }[];
162
- readonly multiple?: boolean;
163
- readonly separator?: string;
164
- readonly default?: V | readonly V[];
165
- }
166
147
  /**
167
148
  * 命令内对话式交互输入。
168
149
  *
169
- * IM 派发时自动注入(`context.prompt`);Host / CLI 无消息来源时为 `undefined`。
150
+ * IM 派发时自动注入(`context.interaction`);Host / CLI 无消息来源时为 `undefined`。
170
151
  *
171
152
  * ```ts
172
153
  * defineCommand({
173
154
  * execute: async (context) => {
174
- * const name = await context.prompt!.text('请输入你的名字');
175
- * const age = await context.prompt!.number('请输入你的年龄');
155
+ * const name = await context.interaction!.ask({ type: 'text', title: '请输入你的名字' });
156
+ * const age = await context.interaction!.ask({ type: 'number', title: '请输入你的年龄' });
176
157
  * return `你好 ${name},你 ${age} 岁了`;
177
158
  * },
178
159
  * });
179
160
  * ```
180
161
  */
181
- export interface CommandPrompt {
182
- text(tips: string, options?: CommandPromptOptions & {
183
- readonly default?: string;
184
- }): Promise<string>;
185
- number(tips: string, options?: CommandPromptOptions & {
186
- readonly default?: number;
187
- }): Promise<number>;
188
- confirm(tips: string, options?: CommandPromptOptions & {
189
- readonly condition?: string;
190
- readonly default?: boolean;
191
- }): Promise<boolean>;
192
- list(tips: string, options?: CommandPromptListOptions): Promise<readonly (string | number | boolean)[]>;
193
- pick<V = unknown>(tips: string, options: CommandPromptPickOptions<V>): Promise<V | readonly V[]>;
194
- }
195
- export type CommandPromptFactory = (source: unknown) => CommandPrompt | undefined;
196
162
  export interface CommandContext<TConfig = unknown, TInput extends CommandMessage = CommandMessage> extends CapabilityContext<TConfig>, CommandSession {
197
163
  readonly args: readonly string[];
198
164
  readonly params: Readonly<Record<string, CommandParameterValue>>;
@@ -206,7 +172,8 @@ export interface CommandContext<TConfig = unknown, TInput extends CommandMessage
206
172
  /**
207
173
  * 对话式交互输入。IM 派发时自动注入;无消息来源时为 `undefined`。
208
174
  */
209
- readonly prompt?: CommandPrompt;
175
+ /** Canonical user-facing input/confirmation/selection module. */
176
+ readonly interaction?: UserInteraction;
210
177
  }
211
178
  export interface CommandDefinition<TConfig = unknown, TResult = unknown, TInput extends CommandMessage = CommandMessage> {
212
179
  readonly $feature: typeof commandBrand;
@@ -235,7 +202,7 @@ export interface CommandDefinition<TConfig = unknown, TResult = unknown, TInput
235
202
  execute(context: CommandContext<TConfig, TInput>): TResult | Promise<TResult>;
236
203
  }
237
204
  declare module '@zhin.js/plugin-runtime' {
238
- interface PluginSetupContext<TConfig> {
205
+ interface PluginSetupContext<TConfig = unknown> {
239
206
  addCommand<TResult = unknown, TInput extends CommandMessage = CommandMessage>(localName: string, definition: CommandDefinition<TConfig, TResult, TInput>): void;
240
207
  }
241
208
  }
@@ -251,7 +218,7 @@ export declare function parseCommandDefinition(value: unknown): CommandDefinitio
251
218
  * 函数值接收从 `source`(通常是 IM Runtime `Message`)解析出的 {@link CommandSession}。
252
219
  */
253
220
  export declare function resolveDynamicParams(params: Readonly<Record<string, CommandDynamicValue>>, source: unknown): Readonly<Record<string, CommandParameterValue>>;
254
- export declare function createCommandContext(snapshot: RuntimeSnapshot, ownerId: PluginId, args: readonly string[], params?: Readonly<Record<string, CommandParameterValue>>, input?: unknown, segments?: readonly Readonly<CommandSegment>[], prompt?: CommandPrompt): CommandContext;
221
+ export declare function createCommandContext(snapshot: RuntimeSnapshot, ownerId: PluginId, args: readonly string[], params?: Readonly<Record<string, CommandParameterValue>>, input?: unknown, segments?: readonly Readonly<CommandSegment>[], interaction?: UserInteraction): CommandContext;
255
222
  /**
256
223
  * 从派发来源(通常是 Runtime `Message`)解析入站快捷字段。
257
224
  * 不依赖 `@zhin.js/core`,按 {@link CommandMessage} 结构鸭式识别。
package/lib/definition.js CHANGED
@@ -112,7 +112,7 @@ export function resolveDynamicParams(params, source) {
112
112
  }
113
113
  return Object.freeze(resolved);
114
114
  }
115
- export function createCommandContext(snapshot, ownerId, args, params = Object.freeze({}), input = undefined, segments = Object.freeze([]), prompt) {
115
+ export function createCommandContext(snapshot, ownerId, args, params = Object.freeze({}), input = undefined, segments = Object.freeze([]), interaction) {
116
116
  const context = createCapabilityContext(snapshot, ownerId);
117
117
  const session = resolveCommandSession(input);
118
118
  return Object.freeze({
@@ -122,7 +122,7 @@ export function createCommandContext(snapshot, ownerId, args, params = Object.fr
122
122
  params: Object.freeze({ ...params }),
123
123
  segments: freezeSegments(segments),
124
124
  ...(input !== undefined ? { input: input } : {}),
125
- ...(prompt !== undefined ? { prompt } : {}),
125
+ ...(interaction !== undefined ? { interaction } : {}),
126
126
  });
127
127
  }
128
128
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/command",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Convention-based Command Feature for Zhin Plugin Runtime",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -18,9 +18,10 @@
18
18
  ],
19
19
  "dependencies": {
20
20
  "segment-matcher": "^1.0.5",
21
- "@zhin.js/feature-kit": "1.0.10",
22
- "@zhin.js/permission": "1.0.2",
23
- "@zhin.js/plugin-runtime": "1.1.6"
21
+ "@zhin.js/interaction": "1.0.1",
22
+ "@zhin.js/permission": "1.0.3",
23
+ "@zhin.js/feature-kit": "1.0.12",
24
+ "@zhin.js/plugin-runtime": "1.1.7"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@types/node": "^26.1.2",
@@ -8,20 +8,22 @@ import type {
8
8
  PluginId,
9
9
  RuntimeSnapshot,
10
10
  } from '@zhin.js/plugin-runtime';
11
+ import type { UserInteractionFactory } from '@zhin.js/interaction';
12
+ import {
13
+ permissionHostToken,
14
+ toPermissionSubject,
15
+ type PermissionHost,
16
+ } from '@zhin.js/permission';
11
17
  import {
12
18
  createCommandContext,
13
19
  resolveCommandSession,
14
20
  type CommandDefinition,
15
21
  type CommandParameterDefinition,
16
22
  type CommandParameterType,
17
- type CommandParameterValue,
18
23
  type CommandSegment,
19
24
  type CommandDynamicValue,
20
- type CommandPromptFactory,
21
25
  resolveDynamicParams,
22
26
  } from './definition.js';
23
- import { permissionHostToken, type PermissionHost } from '@zhin.js/permission';
24
- import { toPermissionSubject } from '@zhin.js/permission';
25
27
 
26
28
  export interface CommandParameterDescriptor extends CommandParameterDefinition {
27
29
  readonly required: boolean;
@@ -221,7 +223,7 @@ export class CommandIndex {
221
223
  async dispatch(
222
224
  input: CommandMatchInput,
223
225
  source: unknown = undefined,
224
- promptFactory?: CommandPromptFactory,
226
+ interactionFactory?: UserInteractionFactory,
225
227
  commandPrefix = '',
226
228
  ): Promise<CommandDispatchResult> {
227
229
  if (this.#menu) {
@@ -235,7 +237,7 @@ export class CommandIndex {
235
237
  });
236
238
  }
237
239
  }
238
- const prompt = promptFactory?.(source);
240
+ const interaction = interactionFactory?.(source);
239
241
  const shortcut = this.#matchShortcut(input);
240
242
  if (shortcut) {
241
243
  if (!(await this.#permitAllows(shortcut.record, source))) {
@@ -249,7 +251,7 @@ export class CommandIndex {
249
251
  resolveDynamicParams(shortcut.params, source),
250
252
  source,
251
253
  Object.freeze([]),
252
- prompt,
254
+ interaction,
253
255
  ),
254
256
  );
255
257
  return Object.freeze({
@@ -274,7 +276,7 @@ export class CommandIndex {
274
276
  resolveDynamicParams(match.params, source),
275
277
  source,
276
278
  match.remaining,
277
- prompt,
279
+ interaction,
278
280
  ),
279
281
  );
280
282
  return Object.freeze({
package/src/definition.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  type CapabilityContext,
5
5
  } from '@zhin.js/feature-kit';
6
6
  import { assertPermitSyntax } from '@zhin.js/permission';
7
+ import type { UserInteraction } from '@zhin.js/interaction';
7
8
 
8
9
  const commandBrand = 'zhin.command/1' as const;
9
10
 
@@ -193,51 +194,21 @@ export interface CommandSession {
193
194
  readonly sender?: CommandSender;
194
195
  }
195
196
 
196
- export interface CommandPromptOptions {
197
- readonly timeout?: number;
198
- readonly timeoutText?: string;
199
- /** Cancel the pending claim when the owning turn aborts. */
200
- readonly signal?: AbortSignal;
201
- }
202
-
203
- export interface CommandPromptListOptions extends CommandPromptOptions {
204
- readonly type?: 'text' | 'number' | 'boolean';
205
- readonly separator?: string;
206
- readonly default?: readonly (string | number | boolean)[];
207
- }
208
-
209
- export interface CommandPromptPickOptions<V = unknown> extends CommandPromptOptions {
210
- readonly options: readonly { readonly label: string; readonly value: V }[];
211
- readonly multiple?: boolean;
212
- readonly separator?: string;
213
- readonly default?: V | readonly V[];
214
- }
215
-
216
197
  /**
217
198
  * 命令内对话式交互输入。
218
199
  *
219
- * IM 派发时自动注入(`context.prompt`);Host / CLI 无消息来源时为 `undefined`。
200
+ * IM 派发时自动注入(`context.interaction`);Host / CLI 无消息来源时为 `undefined`。
220
201
  *
221
202
  * ```ts
222
203
  * defineCommand({
223
204
  * execute: async (context) => {
224
- * const name = await context.prompt!.text('请输入你的名字');
225
- * const age = await context.prompt!.number('请输入你的年龄');
205
+ * const name = await context.interaction!.ask({ type: 'text', title: '请输入你的名字' });
206
+ * const age = await context.interaction!.ask({ type: 'number', title: '请输入你的年龄' });
226
207
  * return `你好 ${name},你 ${age} 岁了`;
227
208
  * },
228
209
  * });
229
210
  * ```
230
211
  */
231
- export interface CommandPrompt {
232
- text(tips: string, options?: CommandPromptOptions & { readonly default?: string }): Promise<string>;
233
- number(tips: string, options?: CommandPromptOptions & { readonly default?: number }): Promise<number>;
234
- confirm(tips: string, options?: CommandPromptOptions & { readonly condition?: string; readonly default?: boolean }): Promise<boolean>;
235
- list(tips: string, options?: CommandPromptListOptions): Promise<readonly (string | number | boolean)[]>;
236
- pick<V = unknown>(tips: string, options: CommandPromptPickOptions<V>): Promise<V | readonly V[]>;
237
- }
238
-
239
- export type CommandPromptFactory = (source: unknown) => CommandPrompt | undefined;
240
-
241
212
  export interface CommandContext<
242
213
  TConfig = unknown,
243
214
  TInput extends CommandMessage = CommandMessage,
@@ -254,7 +225,8 @@ export interface CommandContext<
254
225
  /**
255
226
  * 对话式交互输入。IM 派发时自动注入;无消息来源时为 `undefined`。
256
227
  */
257
- readonly prompt?: CommandPrompt;
228
+ /** Canonical user-facing input/confirmation/selection module. */
229
+ readonly interaction?: UserInteraction;
258
230
  }
259
231
 
260
232
  export interface CommandDefinition<
@@ -289,7 +261,7 @@ export interface CommandDefinition<
289
261
  }
290
262
 
291
263
  declare module '@zhin.js/plugin-runtime' {
292
- interface PluginSetupContext<TConfig> {
264
+ interface PluginSetupContext<TConfig = unknown> {
293
265
  addCommand<TResult = unknown, TInput extends CommandMessage = CommandMessage>(
294
266
  localName: string,
295
267
  definition: CommandDefinition<TConfig, TResult, TInput>,
@@ -420,7 +392,7 @@ export function createCommandContext(
420
392
  params: Readonly<Record<string, CommandParameterValue>> = Object.freeze({}),
421
393
  input: unknown = undefined,
422
394
  segments: readonly Readonly<CommandSegment>[] = Object.freeze([]),
423
- prompt?: CommandPrompt,
395
+ interaction?: UserInteraction,
424
396
  ): CommandContext {
425
397
  const context = createCapabilityContext(snapshot, ownerId);
426
398
  const session = resolveCommandSession(input);
@@ -431,7 +403,7 @@ export function createCommandContext(
431
403
  params: Object.freeze({ ...params }),
432
404
  segments: freezeSegments(segments),
433
405
  ...(input !== undefined ? { input: input as CommandMessage } : {}),
434
- ...(prompt !== undefined ? { prompt } : {}),
406
+ ...(interaction !== undefined ? { interaction } : {}),
435
407
  });
436
408
  }
437
409