import test from 'brittle'
import { DaemonRuntime } from '../lib/runtime.js'
import { tmpdir } from 'os'
import { join } from 'path'
import { randomBytes } from 'crypto'
function tmpStorage () {
return join(tmpdir(), 'hyper-daemon-test-' + randomBytes(8).toString('hex'))
}
test('DaemonRuntime - load and fire script', async (t) => {
const logs = []
const runtime = new DaemonRuntime(tmpStorage(), {
onLog: (msg) => logs.push(msg)
})
await runtime.ready()
let actionCalled = false
await runtime.load('greet', {
trigger: { type: 'message', filter: { contains: 'hello' } },
actions: [{
type: 'log',
message: 'Greeting detected!'
}],
enabled: true
})
// Override action for testing — fire triggers the registered action
const results = await runtime.fire('message', { text: 'hello world' })
t.is(results.length, 1)
t.ok(results[0].ok)
t.ok(logs.some(l => l.includes('Loaded script: greet')))
await runtime.close()
})
test('DaemonRuntime - list scripts', async (t) => {
const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
await runtime.ready()
await runtime.load('script-a', {
trigger: { type: 'message' },
actions: [{ type: 'log', message: 'a' }]
})
await runtime.load('script-b', {
trigger: { type: 'file-change' },
actions: [{ type: 'log', message: 'b' }]
})
const list = runtime.list()
t.is(list.length, 2)
t.ok(list.find(s => s.id === 'script-a'))
t.ok(list.find(s => s.id === 'script-b'))
await runtime.close()
})
test('DaemonRuntime - unload script', async (t) => {
const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
await runtime.ready()
await runtime.load('temp', {
trigger: { type: 'message' },
actions: [{ type: 'log', message: 'temp' }]
})
t.is(runtime.list().length, 1)
await runtime.unload('temp')
t.is(runtime.list().length, 0)
// Verify no triggers fire
const results = await runtime.fire('message', {})
t.is(results.length, 0)
await runtime.close()
})
test('DaemonRuntime - enable/disable', async (t) => {
const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
await runtime.ready()
await runtime.load('toggle', {
trigger: { type: 'message' },
actions: [{ type: 'log', message: 'toggled' }]
})
runtime.disable('toggle')
const r1 = await runtime.fire('message', { text: 'test' })
t.is(r1.length, 0)
runtime.enable('toggle')
const r2 = await runtime.fire('message', { text: 'test' })
t.is(r2.length, 1)
await runtime.close()
})
test('DaemonRuntime - filter matching', async (t) => {
const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
await runtime.ready()
await runtime.load('filtered', {
trigger: { type: 'message', filter: { author: 'alice' } },
actions: [{ type: 'log', message: 'alice said something' }]
})
const r1 = await runtime.fire('message', { author: 'alice', text: 'hi' })
t.is(r1.length, 1)
const r2 = await runtime.fire('message', { author: 'bob', text: 'hi' })
t.is(r2.length, 0)
await runtime.close()
})
test('DaemonRuntime - event logging', async (t) => {
const runtime = new DaemonRuntime(tmpStorage(), { onLog: () => {} })
await runtime.ready()
await runtime.load('logged', {
trigger: { type: 'message' },
actions: [{ type: 'log', message: 'event' }]
})
await runtime.fire('message', { text: 'first' })
await runtime.fire('message', { text: 'second' })
const log = await runtime.getLog('logged')
t.is(log.length, 2)
t.ok(log[0].timestamp > 0)
t.is(log[0].trigger, 'message')
await runtime.close()
})
test('DaemonRuntime - persistence (loadAll)', async (t) => {
const storage = tmpStorage()
// Save scripts
const rt1 = new DaemonRuntime(storage, { onLog: () => {} })
await rt1.ready()
await rt1.load('persistent', {
trigger: { type: 'message' },
actions: [{ type: 'log', message: 'persistent' }]
})
await rt1.close()
// Reload
const rt2 = new DaemonRuntime(storage, { onLog: () => {} })
await rt2.ready()
const loaded = await rt2.loadAll()
t.is(loaded, 1)
const list = rt2.list()
t.is(list.length, 1)
t.is(list[0].id, 'persistent')
await rt2.close()
})