Swadhin Biswas feat: implement mervelas cli engine, built-in tools, and reactive UI · 4/3/2026
0358986
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const NO_VALUE = Symbol('NO_VALUE')
export async function lastX<A>(as: AsyncGenerator<A>): Promise<A> {
let lastValue: A | typeof NO_VALUE = NO_VALUE
for await (const a of as) {
lastValue = a
}
if (lastValue === NO_VALUE) {
throw new Error('No items in generator')
}
return lastValue
}
export async function returnValue<A>(
as: AsyncGenerator<unknown, A>,
): Promise<A> {
let e
do {
e = await as.next()
} while (!e.done)
return e.value
}
type QueuedGenerator<A> = {
done: boolean | void
value: A | void
generator: AsyncGenerator<A, void>
promise: Promise<QueuedGenerator<A>>
}
// Run all generators concurrently up to a concurrency cap, yielding values as they come in
export async function* all<A>(
generators: AsyncGenerator<A, void>[],
concurrencyCap = Infinity,
): AsyncGenerator<A, void> {
const next = (generator: AsyncGenerator<A, void>) => {
const promise: Promise<QueuedGenerator<A>> = generator
.next()
.then(({ done, value }) => ({
done,
value,
generator,
promise,
}))
return promise
}
const waiting = [...generators]
const promises = new Set<Promise<QueuedGenerator<A>>>()
// Start initial batch up to concurrency cap
while (promises.size < concurrencyCap && waiting.length > 0) {
const gen = waiting.shift()!
promises.add(next(gen))
}
while (promises.size > 0) {
const { done, value, generator, promise } = await Promise.race(promises)
promises.delete(promise)
if (!done) {
promises.add(next(generator))
// TODO: Clean this up
if (value !== undefined) {
yield value
}
} else if (waiting.length > 0) {
// Start a new generator when one finishes
const nextGen = waiting.shift()!
promises.add(next(nextGen))
}
}
}
export async function toArray<A>(
generator: AsyncGenerator<A, void>,
): Promise<A[]> {
const result: A[] = []
for await (const a of generator) {
result.push(a)
}
return result
}
export async function* fromArray<T>(values: T[]): AsyncGenerator<T, void> {
for (const value of values) {
yield value
}
}