Skip to content

Cel Standard Library

cel.lua is the unified standard library for the ZERG project. It provides JSON, OOP, collections, vectors, shell quoting, and utilities through a single import that works identically on both LuaJIT (Luna agent) and Luerl (Sol plugin sandbox).

Import

lua
local cel = require("core.cel")

cel.json -- JSON Encode/Decode

JSON encoding and decoding with automatic backend selection. Prefers dkjson on LuaJIT, falls back to JSON_luerl in the plugin sandbox.

lua
local cel = require("core.cel")

local encoded = cel.json.encode({name = "zerg", version = "0.91.0"})
-- '{"name":"zerg","version":"0.91.0"}'

local decoded, _, err = cel.json.decode('{"ok":true}')
-- {ok = true}

local bad, _, err = cel.json.decode("invalid")
-- nil, nil, "parse error"

API

FunctionSignatureReturns
encodecel.json.encode(table)JSON string
decodecel.json.decode(string)table, nil, nil on success; nil, nil, error on failure

The decode function returns three values for compatibility with dkjson's error reporting convention.

cel.class -- Object-Oriented Programming

Provides middleclass v4.1.1 for class-based OOP with inheritance, mixins, and metamethods.

lua
local cel = require("core.cel")

local Animal = cel.class("Animal")

function Animal:initialize(name)
  self.name = name
end

function Animal:speak()
  return "..."
end

local Dog = cel.class("Dog", Animal)

function Dog:speak()
  return self.name .. " says woof"
end

local d = Dog:new("Rex")
d:speak()
-- "Rex says woof"

API

FunctionDescription
cel.class(name)Define a new class
cel.class(name, parent)Define a subclass
Class:initialize(...)Constructor
instance = Class:new(...)Create instance
instance:isInstanceOf(Class)Type check
Sub:subclassOf(Parent)Inheritance check
Class:include(mixin)Include a mixin

cel.vec -- 2D Vector Math

A 2D vector library for spatial calculations. Uses a plain metatable (no __call) for Luerl compatibility.

lua
local cel = require("core.cel")

local v1 = cel.vec.new(3, 4)
cel.vec.mag(v1)
-- 5

local v2 = cel.vec.from_angle(math.pi / 2)
cel.vec.heading(v2)
-- 1.5707...

local sum = cel.vec.add(v1, v2)
local scaled = cel.vec.mul(2, v1)
local normalized = cel.vec.norm(v1)
local limited = cel.vec.limit(v1, 3)

API

FunctionSignatureReturns
newvec.new(x, y)Vector {x, y}
from_anglevec.from_angle(theta)Unit vector at angle
randomvec.random()Random unit vector
isvec.is(t)Boolean
to_tablevec.to_table(v){x=, y=}
from_tablevec.from_table(t)Vector
clonevec.clone(v)New vector copy
magvec.mag(v)Magnitude
mag_sqvec.mag_sq(v)Squared magnitude
set_magvec.set_mag(v, m)Vector with new magnitude
normvec.norm(v)Unit vector
limitvec.limit(v, max)Clamped vector
addvec.add(a, b)Component-wise sum
subvec.sub(a, b)Component-wise difference
mulvec.mul(a, b)Scalar or component-wise multiply
divvec.div(v, s)Scalar division
negvec.neg(v)Negated vector
eqvec.eq(a, b)Boolean equality
dotvec.dot(a, b)Dot product
distvec.dist(a, b)Euclidean distance
headingvec.heading(v)Angle in radians
rotatevec.rotate(v, theta)Rotated vector

Eager Collections

Collection operations backed by lume. These process entire tables immediately.

lua
local cel = require("core.cel")

local items = {1, 2, 3, 4, 5}

local doubled = cel.map(items, function(x) return x * 2 end)
-- {2, 4, 6, 8, 10}

local evens = cel.filter(items, function(x) return x % 2 == 0 end)
-- {2, 4}

local sum = cel.reduce(items, function(acc, x) return acc + x end, 0)
-- 15

cel.each(items, function(x) print(x) end)

API

FunctionSignatureDescription
mapcel.map(t, fn)Transform each element
filtercel.filter(t, fn)Keep matching elements
eachcel.each(t, fn)Iterate with side effects
reducecel.reduce(t, fn, init)Fold into single value
anycel.any(t, fn)True if any element matches
allcel.all(t, fn)True if all elements match

Lazy Iterators

Lazy pipeline operations backed by fun.lua. These create iterators that compute values on demand.

lua
local cel = require("core.cel")

local pipeline = cel.iter.range(1, 100)
pipeline = cel.iter.filter(function(x) return x % 3 == 0 end, pipeline)
pipeline = cel.iter.map(function(x) return x ^ 2 end, pipeline)
pipeline = cel.iter.take(5, pipeline)

local results = cel.iter.to_table(pipeline)
-- {9, 36, 81, 144, 225}

API

FunctionDescription
iter.range(start, stop)Integer range iterator
iter.map(fn, iter)Transform iterator
iter.filter(fn, iter)Filter iterator
iter.reduce(fn, init, iter)Fold iterator
iter.each(fn, iter)Consume iterator
iter.take(n, iter)First n elements
iter.drop(n, iter)Skip first n elements
iter.zip(it1, it2)Pair elements from two iterators
iter.chain(it1, it2)Concatenate iterators
iter.enumerate(iter)Index-value pairs
iter.cycle(iter)Infinite repetition
iter.duplicate(val)Infinite value
iter.wrap(it)Wrap as iterator
iter.unwrap(it)Unwrap iterator
iter.to_table(iter)Collect into array table

String Utilities

lua
local cel = require("core.cel")

cel.split("a,b,c", ",")
-- {"a", "b", "c"}

cel.trim("  hello  ")
-- "hello"

cel.keys({a = 1, b = 2})
-- {"a", "b"}

cel.values({a = 1, b = 2})
-- {1, 2}

cel.clamp(15, 0, 10)
-- 10

cel.lerp(0, 100, 0.5)
-- 50

API

FunctionDescription
split(str, sep)Split string by separator
trim(str)Remove leading/trailing whitespace
format(str, ...)String formatting
wordwrap(str, width)Word-wrap text
keys(t)Table keys as array
values(t)Table values as array
clone(t)Shallow table copy
find(t, value)Find value in table
pick(t, ...)Select keys from table
extend(t, ...)Merge tables
clamp(val, min, max)Clamp to range
lerp(a, b, t)Linear interpolation
uuid()Generate UUID string
serialize(t)Serialize table to string
deserialize(str)Deserialize string to table
random(t)Random element from table

cel.shell_quote -- Shell Argument Safety

Wraps shell arguments in single quotes to prevent injection from LLM-generated parameters. Required for all os.execute and shell command calls.

lua
local cel = require("core.cel")

local user_input = '$(rm -rf /)'
local safe = cel.shell_quote(user_input)
-- "'$(rm -rf /)'"

os.execute("echo " .. cel.shell_quote(user_input))

The function wraps arguments in single quotes and escapes any embedded single quotes using '\''. This prevents $(), backticks, $VAR, and other shell expansions.

Utility Functions

deep_copy

lua
local copy = cel.deep_copy(original)

Recursive deep copy of a table.

deep_merge

lua
local merged = cel.deep_merge(base, overlay)

Recursive deep merge. Arrays are concatenated; maps are merged recursively.

is_array

lua
cel.is_array({1, 2, 3})
-- true

cel.is_array({a = 1})
-- false

split_lines

lua
local lines = cel.split_lines("line1\nline2\nline3")
-- {"line1", "line2", "line3"}

Split text into lines, handling trailing newlines correctly.

Released under the MIT License.