refactor: add promptEnd event

This commit is contained in:
hypercross 2026-04-04 00:59:40 +08:00
parent 697d23e932
commit 6c8d6e0790
3 changed files with 33 additions and 24 deletions

View File

@ -60,25 +60,14 @@ export class GameHost<TState extends Record<string, unknown>> {
this._activePromptSchema.value = activePrompt?.schema ?? null; this._activePromptSchema.value = activePrompt?.schema ?? null;
}; };
// Wrap _tryCommit to update schema after commit
const originalTryCommit = this.commands._tryCommit.bind(this.commands);
(this.commands as any)._tryCommit = (input: string) => {
const result = originalTryCommit(input);
updateSchema();
return result;
};
// Wrap _cancel to update schema after cancel
const originalCancel = this.commands._cancel.bind(this.commands);
(this.commands as any)._cancel = (reason?: string) => {
originalCancel(reason);
updateSchema();
};
this.commands.on('prompt', () => { this.commands.on('prompt', () => {
updateSchema(); updateSchema();
}); });
this.commands.on('promptEnd', () => {
updateSchema();
});
updateSchema(); updateSchema();
} }

View File

@ -1,5 +1,5 @@
import type { Command, CommandSchema } from './types'; import type { Command, CommandSchema } from './types';
import type {CommandResult, CommandRunner, CommandRunnerContext, PromptEvent} from './command-runner'; import type {CommandResult, CommandRunner, CommandRunnerContext, CommandRunnerEvents, PromptEvent} from './command-runner';
import { parseCommand } from './command-parse'; import { parseCommand } from './command-parse';
import { applyCommandSchema } from './command-validate'; import { applyCommandSchema } from './command-validate';
import { parseCommandSchema } from './schema-parse'; import { parseCommandSchema } from './schema-parse';
@ -39,7 +39,8 @@ export function getCommand<TContext>(
return registry.get(name); return registry.get(name);
} }
type Listener = (e: PromptEvent) => void; type PromptListener = (e: PromptEvent) => void;
type PromptEndListener = () => void;
export type CommandRunnerContextExport<TContext> = CommandRunnerContext<TContext> & { export type CommandRunnerContextExport<TContext> = CommandRunnerContext<TContext> & {
registry: CommandRegistry<TContext>; registry: CommandRegistry<TContext>;
@ -54,14 +55,29 @@ export function createCommandRunnerContext<TContext>(
registry: CommandRegistry<TContext>, registry: CommandRegistry<TContext>,
context: TContext context: TContext
): CommandRunnerContextExport<TContext> { ): CommandRunnerContextExport<TContext> {
const listeners = new Set<Listener>(); const promptListeners = new Set<PromptListener>();
const promptEndListeners = new Set<PromptEndListener>();
const on = (_event: 'prompt', listener: Listener) => { const emitPromptEnd = () => {
listeners.add(listener); for (const listener of promptEndListeners) {
listener();
}
}; };
const off = (_event: 'prompt', listener: Listener) => { const on = <T extends keyof CommandRunnerEvents>(_event: T, listener: (e: CommandRunnerEvents[T]) => void) => {
listeners.delete(listener); if (_event === 'prompt') {
promptListeners.add(listener as PromptListener);
} else {
promptEndListeners.add(listener as PromptEndListener);
}
};
const off = <T extends keyof CommandRunnerEvents>(_event: T, listener: (e: CommandRunnerEvents[T]) => void) => {
if (_event === 'prompt') {
promptListeners.delete(listener as PromptListener);
} else {
promptEndListeners.delete(listener as PromptEndListener);
}
}; };
let activePrompt: PromptEvent | null = null; let activePrompt: PromptEvent | null = null;
@ -71,6 +87,7 @@ export function createCommandRunnerContext<TContext>(
const result = activePrompt.tryCommit(commandOrInput); const result = activePrompt.tryCommit(commandOrInput);
if (result === null) { if (result === null) {
activePrompt = null; activePrompt = null;
emitPromptEnd();
} }
return result; return result;
} }
@ -81,6 +98,7 @@ export function createCommandRunnerContext<TContext>(
if (activePrompt) { if (activePrompt) {
activePrompt.cancel(reason); activePrompt.cancel(reason);
activePrompt = null; activePrompt = null;
emitPromptEnd();
} }
}; };
@ -106,7 +124,7 @@ export function createCommandRunnerContext<TContext>(
}; };
activePrompt = { schema: resolvedSchema, tryCommit, cancel }; activePrompt = { schema: resolvedSchema, tryCommit, cancel };
const event: PromptEvent = { schema: resolvedSchema, tryCommit, cancel }; const event: PromptEvent = { schema: resolvedSchema, tryCommit, cancel };
for (const listener of listeners) { for (const listener of promptListeners) {
listener(event); listener(event);
} }
}); });
@ -136,7 +154,7 @@ export function createCommandRunnerContext<TContext>(
get(){ get(){
if (!promptQueue) { if (!promptQueue) {
promptQueue = new AsyncQueue(); promptQueue = new AsyncQueue();
listeners.add(async (event) => { promptListeners.add(async (event) => {
promptQueue.push(event); promptQueue.push(event);
}); });
} }

View File

@ -17,6 +17,8 @@ export type PromptEvent = {
export type CommandRunnerEvents = { export type CommandRunnerEvents = {
prompt: PromptEvent; prompt: PromptEvent;
/** 当 prompt 结束tryCommit 成功或 cancel时触发 */
promptEnd: void;
}; };
export type CommandResult<T=unknown> = { export type CommandResult<T=unknown> = {