chore: initial commit

This commit is contained in:
2026-10-22 17:07:08 +08:00
commit 0acef64f48
200 changed files with 35546 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
import type {Bot} from '@wp2508/mineflayer';
import type {data_type} from '../instance/bot_runtime.ts';
import type {WorkflowManager} from '../workflow/runtime.ts';
export interface FunctionI18n {
lang: string;
name: string;
description: string;
}
export interface FunctionArgument {
name: string;
type: data_type;
i18n: FunctionI18n;
/** A trailing boolean argument with a default may be omitted by callers. */
default?: boolean;
}
export interface FunctionExecutionContext {
workflow?: Pick<WorkflowManager, 'control'>;
}
/** Function implementations declare their metadata and validate arguments before operating on a Bot. */
export interface BaseFunction<Args extends unknown[] = unknown[]> {
readonly name: string;
readonly i18n: FunctionI18n;
readonly args: readonly FunctionArgument[];
/** Internal dispatch metadata; never included in function discovery responses. */
readonly execution?: 'workflow_control';
/** Returns true on success and false on execution failure. */
run(bot: Bot, args: Args, executionContext?: FunctionExecutionContext): Promise<boolean>;
}
+31
View File
@@ -0,0 +1,31 @@
import { ProxyOptions } from "@wp2508/mineflayer";
import { supportedVersions } from '@wp2508/minecraft-protocol'
import {bot_config_plugin} from "../plugins/plugin.ts";
import {workflow_config} from "../workflow/workflow.ts";
export type bot_status = 'offline' | 'ready' | 'connecting' | 'online'
| 'disconnecting' | 'reconnecting';
export interface bot_config {
instance_config: bot_instance_config;
plugins: bot_config_plugin<any>[];
workflow: workflow_config[];
}
export interface bot_instance_config {
username: string;
host: string;
port?: number | null;
version: string;
user_id: number;
bot_id: number;
config_revision?: number;
plugins?: bot_config_plugin<any>[];
workflow?: workflow_config[];
proxy?: ProxyOptions | null;
}
export type data_type = 'string' | 'boolean' | 'number' | 'datetime'|
'string-select' | 'number-select' |
'string-multi-select' | 'number-multi-select' |
'string-array' | 'number-array'
+68
View File
@@ -0,0 +1,68 @@
import type {data_type} from "../instance/bot_runtime";
import {isDeepStrictEqual} from 'node:util';
import type {bot_instance_context} from '../../../bot/instance/bot_instance_init.ts';
export type PluginContext = Pick<bot_instance_context<unknown>,
'on' | 'off' | 'log' | 'logger' | 'schedule_reconnect' | 'cancel_reconnect'>;
/** Constructors only define metadata; resources belong to init/dispose. */
export abstract class BasePlugin<Config = Record<string, unknown>, States = unknown> {
private states?: States;
private readonly state_listeners = new Set<() => void>();
abstract readonly name: string;
abstract readonly config_template: plugin;
abstract init(context: PluginContext, config: Config): Promise<void>;
get_status(): States | undefined { return structuredClone(this.states); }
protected set_states(states: States): void {
if (isDeepStrictEqual(this.states, states)) return;
this.states = structuredClone(states);
for (const listener of Array.from(this.state_listeners)) {
if (!this.state_listeners.has(listener)) continue;
try { listener(); } catch {}
}
}
on_states_update(callback: () => void): () => void {
const listener = () => callback();
this.state_listeners.add(listener);
return () => { this.state_listeners.delete(listener); };
}
abstract dispose(): Promise<void>;
}
export interface bot_config_plugin<T> {
name: string;
path: string;
config: T;
}
export interface plugin {
name: string;
i18n: {
lang: string;
name: string;
description: string;
}[],
version: string;
config: plugin_config[];
}
export interface plugin_config {
name: string;
i18n: {
lang: string;
name: string;
description: string;
}[]
required: boolean;
default: any;
type: data_type;
}
export interface base_define {
path: string;
i18n: {
lang: string;
name: string;
description: string;
}[]
}
+71
View File
@@ -0,0 +1,71 @@
import type {Json, WorkflowNode, WorkflowStart} from './workflow.ts';
export interface WorkflowI18n {lang: string; name: string; description: string}
export interface WorkflowField {
name: string;
i18n: WorkflowI18n[];
required: boolean;
nullable?: boolean;
type: 'string' | 'number' | 'boolean' | 'select' | 'object' | 'array' | 'map'
| 'value_source' | 'condition' | 'code';
default?: Json;
min?: number;
max?: number;
integer?: boolean;
max_length?: number;
min_length?: number;
options?: {value: string | number; i18n: WorkflowI18n[]}[];
fields?: WorkflowField[];
item?: WorkflowField;
provider?: 'function' | 'event' | 'query' | 'info';
language?: 'javascript';
}
export interface WorkflowOutputTemplate {
i18n: WorkflowI18n[];
type: 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array' | 'json';
nullable?: boolean;
optional?: boolean;
properties?: Record<string, WorkflowOutputTemplate>;
items?: WorkflowOutputTemplate;
additional_properties?: WorkflowOutputTemplate;
}
export interface WorkflowPortTemplate {name: string; i18n: WorkflowI18n[]}
interface TemplateBase {
name: string;
version: string;
i18n: WorkflowI18n[];
config: WorkflowField[];
output: WorkflowOutputTemplate;
}
export interface WorkflowNodeTemplate extends TemplateBase {
name: WorkflowNode['type'];
ports: WorkflowPortTemplate[];
provider?: 'function' | 'query';
availability?: {available: boolean; reason?: string};
}
export interface WorkflowStartTemplate extends TemplateBase {
name: WorkflowStart['type'];
}
export interface WorkflowEventTemplate extends TemplateBase {
readiness: 'spawned';
custom?: boolean;
}
export interface WorkflowQueryTemplate extends TemplateBase {provider?: 'info'}
export interface WorkflowEventDefinition {
config_template: WorkflowEventTemplate;
normalize(args: unknown[]): Record<string, Json> | undefined;
}
export interface WorkflowCatalog {
catalog_version: 1;
nodes: WorkflowNodeTemplate[];
start_nodes: WorkflowStartTemplate[];
events: WorkflowEventTemplate[];
queries: WorkflowQueryTemplate[];
common: {
node_fields: WorkflowField[];
policy_fields: WorkflowField[];
result: WorkflowOutputTemplate;
edge_input: WorkflowOutputTemplate;
references: {root: string; i18n: WorkflowI18n[]}[];
};
}
+108
View File
@@ -0,0 +1,108 @@
import type {Condition, Json, WorkflowNode, workflow_config} from './workflow.ts';
export interface WorkflowError {code: string; message: string; node_id: string}
export interface NodeResult {
status: 'success' | 'failure';
output: Json;
error?: WorkflowError;
}
export interface OutputRecord extends NodeResult {execution: number}
export interface BranchState {
trigger: Record<string, Json>;
vars: Record<string, Json>;
outputs: Record<string, OutputRecord>;
last_result: (NodeResult & {node_id: string}) | null;
inputs: Record<string, Json>;
retry_counts: Record<string, number>;
}
export interface NodeReturn {
port: string;
result: NodeResult;
vars?: Record<string, Json>;
retry_counts?: Record<string, number>;
}
export interface WorkflowDependencies {
run_function(path: string, name: string, args: Json[], signal: AbortSignal): Promise<boolean>;
query(source: string, args: Record<string, Json>, signal: AbortSignal): Promise<Json>;
sleep(mode: 'milliseconds' | 'ticks', value: number, signal: AbortSignal): Promise<void>;
log(level: 'info' | 'warning' | 'error', message: string): void;
execute_code?(source: string, state: BranchState, signal: AbortSignal): Promise<Json>;
}
export type NodeHandler = (node: WorkflowNode, state: BranchState, signal: AbortSignal,
deps: WorkflowDependencies) => Promise<NodeReturn>;
export type RunStatus = 'running' | 'stopping' | 'completed' | 'failed' | 'cancelled' | 'timed_out';
export type StopReason = 'manual' | 'disconnect' | 'timeout' | 'disposed' | 'updated' | 'reloaded';
export type WorkflowAction = 'run_once' | 'trigger_start' | 'trigger_stop' | 'stop' | 'stop_run' | 'reload';
export interface WorkflowControl {
command_id: string;
action: WorkflowAction;
workflow_id?: string;
run_id?: string;
expected_generation?: number;
input?: Record<string, Json>;
}
export interface WorkflowCommand {
command_id: string;
action: WorkflowAction;
workflow_id: string | null;
state: 'accepted' | 'completed' | 'failed';
result?: StartResult | {stopped: true} | {generation: number};
error?: {code: string; message: string};
}
export interface WorkflowRuntimeState {
workflow_id: string;
generation: number;
enabled: boolean;
start_type: 'common' | 'event' | 'timer';
trigger_state: 'stopped' | 'listening' | 'scheduled' | 'exhausted' | 'reloading' | 'error';
accepted_count: number;
max_runs: number | null;
next_fire_at: number | null;
active_run_ids: string[];
queued_count: number;
last_error: {code: string; message: string} | null;
}
export interface WorkflowRuntimeSnapshot {
source_config_revision: number;
workflows: WorkflowRuntimeState[];
commands: WorkflowCommand[];
}
export interface RunSnapshot {
run_id: string;
workflow_id: string;
status: RunStatus;
steps: number;
active_nodes: string[];
started_at: number;
ended_at: number | null;
stop_reason: StopReason | null;
error: WorkflowError | null;
trigger?: Record<string, Json>;
trigger_available?: boolean;
branches: BranchState[];
}
export type WorkflowRunEvent = {type: 'run_updated'; snapshot: RunSnapshot}
| {type: 'node_started'; run_id: string; node_id: string; execution: number}
| {type: 'node_finished'; run_id: string; node_id: string; execution: number; result: NodeResult}
| {type: 'runtime_updated'; snapshot: WorkflowRuntimeSnapshot};
export interface CompiledWorkflow {
definition: workflow_config;
nodes: Map<string, WorkflowNode>;
outgoing: Map<string, import('./workflow.ts').WorkflowEdge[]>;
incoming: Map<string, import('./workflow.ts').WorkflowEdge[]>;
join_owners: Map<string, string>;
}
export interface StartResult {status: 'started' | 'queued' | 'skipped'; run_id?: string; request_id?: string}
export interface WorkflowManager {
start(workflow_id: string, trigger?: Record<string, Json>): StartResult;
stop(run_id: string, reason?: StopReason): Promise<void>;
get_snapshot(run_id: string): RunSnapshot | undefined;
get_snapshots(): RunSnapshot[];
apply(configs: workflow_config[], source_revision?: number): Promise<void>;
control(request: WorkflowControl): WorkflowCommand;
get_command(command_id: string): WorkflowCommand | undefined;
get_runtime_snapshot(): WorkflowRuntimeSnapshot;
on_update(callback: (event: WorkflowRunEvent) => void): () => void;
dispose(): Promise<void>;
}
export type {Condition};
+56
View File
@@ -0,0 +1,56 @@
export type Json = null | boolean | number | string | Json[] | {[key: string]: Json};
export type ValueSource = {kind: 'literal'; value: Json} | {
kind: 'ref';
root: 'trigger' | 'vars' | 'outputs' | 'last_result' | 'inputs';
path: (string | number)[];
};
export type Condition = {
op: 'eq' | 'contains' | 'gt' | 'lt'; left: ValueSource; right: ValueSource;
} | {op: 'and' | 'or'; items: Condition[]} | {op: 'not'; item: Condition};
export type WorkflowStart = {type: 'common'; auto_start: 'never' | 'spawn'}
| {type: 'event'; event: string; condition?: Condition; auto_start?: boolean; mode?: 'continuous' | 'once'}
| {type: 'timer'; interval_ms: number; auto_start?: boolean; mode?: 'once' | 'repeat'; max_runs?: number | null};
interface NodeBase {id: string; name?: string; timeout_ms?: number}
export type WorkflowNode = NodeBase & (
{type: 'function'; config: {path: string; name: string; args: ValueSource[]}}
| {type: 'query'; config: {source: string; args: Record<string, ValueSource>; save_as?: string}}
| {type: 'condition'; config: {condition: Condition}}
| {type: 'sleep'; config: {mode: 'milliseconds' | 'ticks'; value: number}}
| {type: 'error'; config: {codes?: string[]}}
| {type: 'goto'; config: {max_retries: number; delay_ms: number}}
| {type: 'merge'; config: {mode: 'all' | 'any'}}
| {type: 'log'; config: {level: 'info' | 'warning' | 'error'; message: ValueSource}}
| {type: 'code'; config: {source: string}}
);
export interface WorkflowEdge {
id: string;
source: string;
port: string;
target: string;
}
export interface workflow_config {
schema_version: 1;
id: string;
name: string;
enabled: boolean;
start: WorkflowStart;
entry: string;
nodes: WorkflowNode[];
edges: WorkflowEdge[];
initial_vars?: Record<string, Json>;
policy: {
/** Concurrent instances of this definition; defaults to one. */
max_concurrent_runs?: number;
on_busy: 'skip' | 'queue';
max_queue: number;
max_steps: number;
timeout_ms: number;
};
}
+63
View File
@@ -0,0 +1,63 @@
// Node owns these wire DTOs independently of the relay and Main implementations.
import type {Json} from './bot/workflow/workflow.ts';
export type ForwardErrorCode = 'INVALID_REQUEST' | 'UNAUTHORIZED' | 'FORBIDDEN'
| 'NODE_OFFLINE' | 'RELAY_UNAVAILABLE' | 'SESSION_STALE' | 'TOKEN_EXPIRED'
| 'TIMEOUT' | 'CANCELLED' | 'NO_CONTEXT' | 'BOT_NOT_ONLINE' | 'RATE_LIMITED'
| 'RESYNC_REQUIRED' | 'INTERNAL_ERROR';
export type ForwardAck<T = unknown> = {status: 'success'; data: T} | {
status: 'error'; data: {code: ForwardErrorCode; message: string; retryable: boolean};
};
export interface EnsureForward {
forward_id: number;
forward_session_id: string;
node_session_id: string;
node_id: number;
bot_id: number;
url: string;
path: string;
namespace: string;
token: string;
expires_at: number;
deadline_at: number;
}
export type ForwardScope = Pick<EnsureForward,
'forward_id' | 'forward_session_id' | 'node_session_id' | 'node_id' | 'bot_id'>;
export type ForwardReady = ForwardScope & {node_ready: true; lease_expires_at: number};
export interface JoinReady {
forward_id: number;
forward_session_id: string;
node_session_id: string;
node_id: number;
bot_id: number;
role: 'node';
node_ready: boolean;
expires_at: number;
}
export type RelayMethod = 'bot.snapshot' | 'bot.logs' | 'bot.chat' | 'get_log_history' | 'tab_complete'
| 'get_context_info' | 'execute_function' | 'get_data_file_list' | 'get_file_data' | keyof WorkflowPayloads;
export interface WorkflowPayloads {
'workflow.start': {workflow_id: string; trigger?: Record<string, Json>};
'workflow.stop': {run_id: string};
'workflow.snapshot': {run_id?: string; include_branches?: boolean};
'workflow.catalog': {};
'workflow.runtime': {};
'workflow.control': import('./bot/workflow/runtime.ts').WorkflowControl & {context_generation: string};
'workflow.command': {command_id: string; context_generation: string};
}
export interface RelayRequest {
request_id: string;
correlation_id: string;
forward_session_id: string;
deadline_at: number;
method: RelayMethod;
payload: Record<string, unknown>;
}
+10
View File
@@ -0,0 +1,10 @@
export type font_style = 'normal' | 'italic' | 'bold' | 'light' |'underline' | 'url';
export interface log {
message: any;
font_color: string;
font_style: font_style[];
hoverEvent?: {action: 'show_text' | 'show_item' | 'show_entity'; value: string; segments?: Array<{message: string; font_color: string; font_style: font_style[]}>};
clickEvent?: {action: string; value: string};
insertion?: string;
}
+4
View File
@@ -0,0 +1,4 @@
export interface SocketResponse {
status: "success" | "error";
data: any;
}