Files
oh-my-openagent/src/features/opencode-skill-loader/blocking.ts

63 lines
1.6 KiB
TypeScript

import { Worker, MessageChannel, receiveMessageOnPort } from "worker_threads"
import type { LoadedSkill, SkillScope } from "./types"
interface WorkerInput {
dirs: string[]
scopes: SkillScope[]
}
interface WorkerOutputSuccess {
ok: true
skills: LoadedSkill[]
}
interface WorkerOutputError {
ok: false
error: { message: string; stack?: string }
}
type WorkerOutput = WorkerOutputSuccess | WorkerOutputError
const TIMEOUT_MS = 30000
export function discoverAllSkillsBlocking(dirs: string[], scopes: SkillScope[]): LoadedSkill[] {
const signal = new Int32Array(new SharedArrayBuffer(4))
const { port1, port2 } = new MessageChannel()
const worker = new Worker(new URL("./discover-worker.ts", import.meta.url), {
// workerData is structured-cloned; pass the SharedArrayBuffer and recreate the view in the worker.
workerData: { signalBuffer: signal.buffer },
})
const input: WorkerInput = { dirs, scopes }
// Avoid a race where the worker hasn't attached listeners to the MessagePort yet.
worker.postMessage({ port: port2, input }, [port2])
const waitResult = Atomics.wait(signal, 0, 0, TIMEOUT_MS)
if (waitResult === "timed-out") {
worker.terminate()
port1.close()
throw new Error(`Worker timeout after ${TIMEOUT_MS}ms`)
}
const message = receiveMessageOnPort(port1)
worker.terminate()
port1.close()
if (!message) {
throw new Error("Worker did not return result")
}
const output = message.message as WorkerOutput
if (output.ok === false) {
const error = new Error(output.error.message)
error.stack = output.error.stack
throw error
}
return output.skills
}