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
+173
View File
@@ -0,0 +1,173 @@
import assert from 'node:assert/strict';
import {randomUUID} from 'node:crypto';
import {EventEmitter} from 'node:events';
import {fileURLToPath} from 'node:url';
import test from 'node:test';
import {build} from 'esbuild';
const compiled = await build({
entryPoints: [fileURLToPath(new URL('../bot/info/bot/workflow_states.ts', import.meta.url))],
bundle: true, platform: 'node', format: 'cjs', write: false,
});
const module = {exports: {}};
new Function('require', 'module', 'exports', compiled.outputFiles[0].text)(specifier => {
assert.fail(`Unexpected workflow info runtime dependency: ${specifier}`);
}, module, module.exports);
const WorkflowStates = module.exports.init;
function fixture(t, legacy = false) {
const command = {command_id: randomUUID(), action: 'trigger_start', workflow_id: 'gather', state: 'accepted'};
const runtime = {source_config_revision: 5, workflows: [{workflow_id: 'gather', generation: 2, enabled: true,
start_type: 'event', trigger_state: 'listening', accepted_count: 0, max_runs: null,
next_fire_at: null, active_run_ids: [], queued_count: 0, last_error: null}], commands: [command]};
const run = {run_id: randomUUID(), workflow_id: 'gather', status: 'running', steps: 1, active_nodes: ['query'],
started_at: 1, ended_at: null, stop_reason: null, error: null,
...(!legacy ? {trigger: {secret: 'PRIVATE_RUN_TRIGGER'}, trigger_available: true} : {}),
branches: [{trigger: {secret: 'PRIVATE_TRIGGER'}, vars: {secret: 'PRIVATE_VARS'},
outputs: {secret: 'PRIVATE_OUTPUT'}, inputs: {secret: 'PRIVATE_INPUT'}, last_result: null, retry_counts: {}}]};
const runs = [run];
const listeners = new Set();
let unsubscribes = 0;
const source = {get_snapshots: () => runs,
...(!legacy ? {get_runtime_snapshot: () => runtime} : {}),
on_update(callback) {
listeners.add(callback);
return () => { unsubscribes++; listeners.delete(callback); };
},
};
const bot = new EventEmitter();
const info = new WorkflowStates(bot, {workflow_source: source});
t.after(() => info.dispose());
return {info, bot, source, runtime, command, run, runs, listeners,
unsubscribes: () => unsubscribes,
emit(event) { for (const listener of [...listeners]) listener(event); },
};
}
test('workflow_states reads runtime workflows and commands and excludes run branch state from streamed info', t => {
t.mock.timers.enable({apis: ['setTimeout']});
const app = fixture(t);
assert.equal(app.info.name, 'workflow_states');
assert.equal(app.bot.listenerCount('end'), 0);
assert.equal(app.listeners.size, 1);
const {branches, trigger, ...summary} = app.run;
const initial = app.info.get_info();
assert.deepEqual(initial, {available: true, ...app.runtime, runs: [summary]});
assert.equal(initial.runs[0].trigger_available, true);
assert.equal(Object.hasOwn(initial.runs[0], 'trigger'), false);
assert.equal(Object.hasOwn(initial.runs[0], 'branches'), false);
assert.equal(JSON.stringify(initial).includes('PRIVATE_'), false);
initial.workflows[0].active_run_ids.push('mutated');
initial.commands[0].state = 'failed'; initial.runs[0].active_nodes.push('mutated');
assert.deepEqual(app.runtime.workflows[0].active_run_ids, []);
assert.equal(app.command.state, 'accepted');
assert.deepEqual(app.run.active_nodes, ['query']);
const updates = [];
app.info.on_update(() => { throw Error('listener failure'); });
app.info.on_update(value => { value.commands[0].state = 'failed'; value.runs.length = 0; });
app.info.on_update(value => updates.push(value));
app.run.status = 'completed'; app.run.ended_at = 2; app.run.active_nodes = [];
app.command.state = 'completed'; app.command.result = {generation: 2};
app.emit({type: 'run_updated', snapshot: app.run});
assert.equal(updates.length, 0);
t.mock.timers.tick(250);
assert.equal(updates.length, 1);
assert.equal(updates[0].runs[0].status, 'completed');
assert.equal(updates[0].commands[0].state, 'completed');
assert.equal(Object.hasOwn(updates[0].runs[0], 'branches'), false);
assert.equal(Object.hasOwn(updates[0].runs[0], 'trigger'), false);
assert.equal(updates[0].runs[0].trigger_available, true);
assert.equal(JSON.stringify(updates[0]).includes('PRIVATE_'), false);
updates[0].commands[0].result.generation = 99;
assert.equal(app.info.get_info().commands[0].result.generation, 2);
});
test('runtime_updated publishes trigger and command changes with no runs and ignores node-only events', t => {
t.mock.timers.enable({apis: ['setTimeout']});
const app = fixture(t);
app.runs.length = 0;
const updates = [];
const unsubscribe = app.info.on_update(value => updates.push(value));
assert.deepEqual(updates, []);
app.runtime.source_config_revision = 6;
app.runtime.workflows[0].trigger_state = 'stopped';
app.command.state = 'completed'; app.command.result = {generation: 2};
app.emit({type: 'runtime_updated', snapshot: app.runtime});
t.mock.timers.tick(250);
assert.deepEqual(updates, [{available: true, ...app.runtime, runs: []}]);
app.emit({type: 'node_started', run_id: app.run.run_id, node_id: 'query', execution: 1});
app.emit({type: 'node_finished', run_id: app.run.run_id, node_id: 'query', execution: 1,
result: {status: 'success', output: true}});
assert.equal(updates.length, 1);
unsubscribe(); unsubscribe();
app.emit({type: 'runtime_updated', snapshot: app.runtime});
assert.equal(updates.length, 1);
});
test('workflow info disposes only its own source subscription once and preserves its last detached snapshot', t => {
const app = fixture(t);
const updates = [];
app.info.on_update(value => updates.push(value));
const late = [...app.listeners][0];
const before = app.info.get_info();
app.info.dispose(); app.info.dispose();
assert.equal(app.unsubscribes(), 1);
assert.equal(app.listeners.size, 0);
late({type: 'runtime_updated', snapshot: app.runtime});
app.emit({type: 'run_updated', snapshot: app.run});
assert.deepEqual(updates, []);
assert.deepEqual(app.info.get_info(), before);
const detached = app.info.get_info(); detached.workflows.length = 0;
assert.deepEqual(app.info.get_info(), before);
assert.throws(() => app.info.on_update(() => {}), /disposed/);
});
test('workflow info preserves optional legacy source fallback and distinguishes absent from empty sources', t => {
const missing = new WorkflowStates(new EventEmitter());
t.after(() => missing.dispose());
assert.deepEqual(missing.get_info(), {available: false, source_config_revision: 0, workflows: [], commands: [], runs: []});
const app = fixture(t, true);
const {branches, ...summary} = app.run;
assert.deepEqual(app.info.get_info(), {available: true, source_config_revision: 0, workflows: [], commands: [],
runs: [{...summary, trigger_available: false}]});
app.runs.length = 0;
app.emit({type: 'run_updated', snapshot: app.run});
assert.deepEqual(app.info.get_info(), {available: true, source_config_revision: 0, workflows: [], commands: [], runs: []});
});
test('live state includes only 20 completed commands while preserving accepted controls', t => {
const app = fixture(t);
const commands = Array.from({length: 100}, () => ({command_id: randomUUID(), action: 'run_once',
workflow_id: 'gather', state: 'completed'}));
const pending = [app.command, {...app.command, command_id: randomUUID()}];
app.runtime.commands = [pending[0], ...commands, pending[1]];
app.emit({type: 'runtime_updated', snapshot: app.runtime});
const state = app.info.get_info();
assert.equal(state.commands.length, 22);
assert.deepEqual(state.commands.filter(command => command.state === 'completed'), commands.slice(-20));
assert.deepEqual(state.commands.filter(command => command.state === 'accepted'), pending);
assert.equal(app.runtime.commands.length, 102);
});
test('workflow pushes coalesce a burst into its latest snapshot and skip unchanged duplicates', t => {
t.mock.timers.enable({apis: ['setTimeout']});
const app = fixture(t), updates = [];
app.info.on_update(value => updates.push(value));
let baseline_bytes = 0;
for (let index = 1; index <= 1000; index++) {
app.run.steps = index;
app.emit({type: 'run_updated', snapshot: app.run});
baseline_bytes += Buffer.byteLength(JSON.stringify(app.info.get_info()));
}
assert.equal(updates.length, 0);
assert.equal(app.info.get_info().runs[0].steps, 1000);
t.mock.timers.tick(250);
assert.equal(updates.length, 1);
assert.equal(updates[0].runs[0].steps, 1000);
const optimized_bytes = Buffer.byteLength(JSON.stringify(updates[0]));
assert.ok(optimized_bytes < baseline_bytes / 100);
for (let index = 0; index < 1000; index++) app.emit({type: 'runtime_updated', snapshot: app.runtime});
t.mock.timers.tick(250);
assert.equal(updates.length, 1);
t.diagnostic(`Synthetic 1000-update burst: ${baseline_bytes} JSON bytes -> ${optimized_bytes} JSON bytes; duplicate burst: 0 extra pushes`);
});