Skip to content
Warlock.js v4.8.2

Change Log

Shipped releases across the @warlock.js/* packages — one shared version line, newest first.

Filter
4.8.2
July 22, 2026

@warlock.js/ai-panoptic's dashboard gains an "Evaluate system prompt" drawer action — its first write-capable route — plus a round of dashboard reliability fixes (auth-token forwarding, a silent cache-store failure hook) and a @warlock.js/ai peer-dependency / redact() hardening pass.

@warlock.js/ai-panoptic Added 2 Fixed 2
  • Added DashboardOptions.evaluate — an "Evaluate system prompt" drawer action that grades a trace's last captured system prompt via an LLM judge, editable per-run instructions included; the dashboard's first and only write-capable route (POST .../spans/:spanId/evaluate), off unless configured and gated by the same authToken / allowedHosts checks as every other route
  • Added evaluateSystemPrompt / extractLastSystemPrompt / findSpanById — the building blocks behind the drawer action, exported for scripting a grade outside the UI
  • Fixed The dashboard's client-side poll (GET {basePath}api/aggregate / api/traces) now carries the page's ?token= as an Authorization: Bearer header on every request — previously, once authToken was configured the initial page load succeeded (the browser's navigation request carries the query string) but every subsequent 2s poll had no auth attached and 401'd forever, leaving the dashboard stuck on an empty/error state despite loading successfully
  • Fixed PanopticConfig.cache failures (hydrate-on-startup or write-through — bad URL, unreachable Redis, auth failure) are no longer swallowed into total silence: a new PanopticConfig.onError hook fires on every failure, defaulting to log.error("ai-panoptic", "cacheStore", error) when not supplied, so a misconfigured cache driver now surfaces in logs instead of leaving the dashboard permanently empty with zero diagnostic
@warlock.js/ai Added 1 Fixed 2
  • Added judgePromptBody / formatCriteria / JudgeOutcome — the LLM-as-judge building blocks ai.prompts().validate() already used internally are now public, so other packages (@warlock.js/ai-panoptic's trace-level system-prompt evaluation) can grade arbitrary prompt text against a model + rubric without a second judging implementation
  • Fixed redact() no longer collapses a raw Error (or an Error nested in a cause chain) to {}name / message / stack aren't own-enumerable on Error instances, so the previous Object.entries() walk saw none of them. This was silently dropping tool/agent error cause detail wherever redact() runs it, including @warlock.js/ai-panoptic's trace cause field (a failed tool's ToolExecutionError.cause showed as an empty object in the dashboard instead of the underlying thrown error)
  • Fixed @warlock.js/ai-openai and pdf-parse declared as optional peerDependencies — both are lazily import()ed (the skills-catalog embedder probe; ai.rag.loadPdf) but weren't listed in either dependencies or peerDependencies, so pkgist's bundler vendored their source directly into ai's own build instead of leaving them external (the same split-brain class of bug as core's missing @warlock.js/ai peerDependency, fixed in 4.8.1). For @warlock.js/ai-openai specifically this meant the skills-catalog embedder-installed probe always resolved against the vendored copy bundled into ai, so it reported an embedder provider as "installed" even when the app never installed @warlock.js/ai-openai itself
4.8.1
July 21, 2026

Fixes a split-brain bug where @warlock.js/core's bundler vendored its own disconnected copy of @warlock.js/ai (and the same gap for @warlock.js/access / @warlock.js/notifications) because they weren't declared as peer dependencies — the vendored copy's config never reached listeners (e.g. ai-panoptic's dashboard) registered against the real installed package. Also logs previously-swallowed onConfigApplied listener errors in @warlock.js/ai.

@warlock.js/core Fixed 1
  • Fixed @warlock.js/ai, @warlock.js/access, and @warlock.js/notifications declared as optional peerDependencies (matching the existing @warlock.js/herald pattern) so pkgist's bundler leaves them external instead of vendoring their source into core's own build — a vendored @warlock.js/ai copy was a disconnected module instance whose config listeners (e.g. ai-panoptic's dashboard wiring) never received ai.config(...) calls routed through the real, separately-installed package
@warlock.js/ai Fixed 1
  • Fixed setAIConfig's onConfigApplied listener notification no longer swallows a misbehaving listener's exception silently — it's now logged via log.error("ai", "configListener", error)
4.8.0
July 19, 2026

A new reasoning: { effort: "none" } level in @warlock.js/ai runs a reasoning model without reasoning, explicitly — @warlock.js/ai-openai emits reasoning_effort: "none" so OpenAI gpt-5 / o-series models accept function tools instead of returning empty replies, and the budget-based adapters (@warlock.js/ai-anthropic, @warlock.js/ai-google, @warlock.js/ai-ollama) map it to reasoning-off.

@warlock.js/ai-openai Added 1
  • Added reasoning: { effort: "none" } now emits reasoning_effort: "none" on the wire — unblocks function tools on gpt-5 / o-series reasoning models, which otherwise reject tools on Chat Completions while reasoning is active and return empty replies.
@warlock.js/ai Added 1
  • Added reasoning: { effort: "none" } — a neutral "run without reasoning, explicitly" level on ReasoningEffort; OpenAI emits reasoning_effort: "none" so gpt-5 / o-series accept function tools, and budget-based adapters (Anthropic / Bedrock / Google / Ollama) disable thinking.
@warlock.js/ai-anthropic Changed 1
  • Changed reasoning: { effort: "none" } disables extended thinking (emits no thinking block) — the neutral "run without reasoning" level, consistent across adapters.
@warlock.js/ai-google Changed 1
  • Changed reasoning: { effort: "none" } maps to thinkingBudget: 0 — Gemini's native reasoning-off switch, the neutral "run without reasoning" level.
@warlock.js/ai-ollama Changed 1
  • Changed reasoning: { effort: "none" } maps to think: false — the neutral "run without reasoning" level, consistent across adapters.
4.7.0
July 6, 2026

@warlock.js/ai gains the prompt compiler — systemPrompt().refined({ model, criteria, store }) lazily rewrites human-authored prompt text into a model-optimized version, pinned like a lockfile with machine-enforced placeholder parity and an always-safe fallback to the original — plus ai.prompts.validate({ criteria }) to grade a prompt against your own rules. @warlock.js/fs gains an ergonomic async fs facade — fs.files.* / fs.dirs.* grouping, lazy File / Directory handles, read-modify-write helpers (edit / editJson / mergeJson), recursive walk, and zero-dependency schema-validated JSON. @warlock.js/cascade lands a driver-correctness pass — a dozen real Postgres/MongoDB driver fixes (multi-row findAndUpdate, where-scoped update / unset / deleteOne, pivot detach, MongoDB with() eager-loading, per-subclass global scopes) plus new lockForUpdate({ skipLocked }) row locking (FOR UPDATE SKIP LOCKED).

@warlock.js/ai Added 2
  • Added systemPrompt().refined({ model, criteria, store }) — the prompt compiler. Humans keep writing human prompt text; the refined wrapper lazily rewrites it into a model-optimized version on first agent use and pins the result like a lockfile (re-compiled only when the source text, refiner model, criteria, or recipe version change — never silently). await refined.refine() returns the compiled template string (placeholders intact — routes / previews / warmup / CI; throws PromptRefinementError on failure) and await refined.refinePrompt() returns a composable prompt with meta.refinedFrom / meta.refinerModel provenance (register it to diff original vs refined). Placeholder parity is machine-enforced (one repair re-ask, then rejected); the lazy agent path never throws — it warns once and serves the original.
  • Added ai.prompts.validate({ criteria }) — validate a prompt against your own rules. Pass criteria (a string or a list of short rules) and, when a judge model is supplied, it replaces the built-in quality rubric so the judge's score / issues reflect your criteria (a failed rule is named in issues). Advisory only — never flips the deterministic ok; folded into the judgeCache key so different rules re-run.
@warlock.js/fs Added 7
  • Added fs shorthand facade — an async, ergonomic surface over the primitives: fs.files.* (file ops), fs.dirs.* (directory ops), lazy fs.file(path) / fs.dir(path) handles (File / Directory classes), and fs.exists(path) (type-agnostic). Delegates to the existing *Async primitives; synchronous callers keep using the bare primitives (the bare = sync / *Async = async charter is unchanged)
  • Added New file ops on the facade: append / prepend / appendLine / appendJsonLine (NDJSON), size, isEmpty, ensure (create-if-missing, never truncates), touch, edit (read → transform → write), editJson, mergeJson (shallow, or { deep: true }), ensureJson (get-or-create), checksumMatches, readLines (streaming async iterator), and an EXDEV-safe move (creates the destination parent, falls back to copy+unlink across devices)
  • Added New directory ops on the facade: empty (emptyDir), size (recursive byte sum), count, isEmpty, walk (constant-memory async iterator of { path, name, type }), a recursive option on list / listFiles / listDirs, and hash (stable directory fingerprint)
  • Added fs.files.getJson(path, { schema }) — validate parsed JSON against any Standard Schema validator (seal / zod / valibot) with zero dependency (calls the schema's own ~standard.validate); throws JsonSchemaValidationError on failure. { default } returns a fallback when the file is missing
  • Added File / Directory handles are lazy (no IO in the constructor) and immutable (copy / move / rename / copyTo / moveTo return a NEW handle); pure-path helpers name / basename / extension / parent() and child file(...) / dir(...); Directory.listFiles() / listDirs() return File[] / Directory[]
  • Added fs.hash namespace — fs.hash.string / fs.hash.buffer (sync, pure/in-memory) and fs.hash.file / fs.hash.dir (async, read from disk)
  • Added fs.files.get() is overloaded: a text read returns string (no cast); pass { encoding: null } for a Buffer
@warlock.js/cascade Added 2 Fixed 11
  • Added lockForUpdate({ skipLocked?, noWait? }) — row locking on SELECT (FOR UPDATE [SKIP LOCKED | NOWAIT]), the concurrent job-queue claim shape; Postgres-only, the MongoDB driver throws
  • Added DatabaseDriverContract.supportsSqlSerialization — capability flag (default true); false routes the MigrationRunner through direct migration-driver execution
  • Fixed Postgres model-level sum/avg/min/max/distinct/countDistinct/pluck/value no longer return 0/undefined — the hydration callback is reset before reading, matching MongoDB
  • Fixed Postgres Model.findAndUpdate / Model.atomic now update every matching row instead of one arbitrary row (a hidden LIMIT 1; MongoDB was already multi-row)
  • Fixed Postgres query-builder update() / unset() now honor the chained where filter — previously they updated the whole table
  • Fixed Postgres query-builder deleteOne() deletes exactly one row — the internal limit(1) was silently ignored, deleting every matching row
  • Fixed Postgres pivot detach(ids) (and sync / toggle) works — the driver translates Mongo-style filter operators ($in, $nin, $eq, $ne, $gt, $gte, $lt, $lte) instead of binding the operator object literally
  • Fixed CHECK constraints are no longer silently dropped on the MigrationRunner SQL path — the Postgres serializer emits ADD CONSTRAINT ... CHECK for this.check(...) and column .check(...)
  • Fixed MongoDB with() eager loading is no longer a silent no-op — get() runs the relation loader, same wiring as Postgres
  • Fixed MongoDB pipelines order $match before $project (SQL semantics), so select() before where() no longer strips the filter column and returns [] — fixes pivot attach de-duplication and sync / toggle deltas
  • Fixed The MigrationRunner works on MongoDB — migrations execute directly through the migration driver; exportSQL stays SQL-only with a clear unsupported error
  • Fixed MongoDB dropIndex(table, name) honors the literal index name — the string form is no longer rewritten to <name>_1 (the columns-array form keeps the convention name)
  • Fixed addGlobalScope / addLocalScope register per-subclass — a scope added on one model (e.g. a soft-delete notDeleted) no longer leaks onto every other model
create-warlock Added 2 Changed 1
  • Added Non-interactive scaffolding — create-warlock <name> --yes (with --db, --pm, --features, --ai, --git, --jwt) scaffolds the entire app in a single command, no prompts
  • Added --db=none / --no-db and a None option in the database prompt — scaffold with no database: the driver, its package, and src/config/database.ts are all skipped
  • Changed Starter models drop the baked-in globalColumnsSchema audit columns (createdBy / updatedBy / deletedBy / isActive) — global columns are left to the developer
4.6.1
July 1, 2026

A production-hardening patch across @warlock.js/core, @warlock.js/logger, and @warlock.js/cascade — a fatal boot error now fails loudly instead of exiting 0, native Postgres array columns (TEXT[] / JSONB[]) work with no configuration, and a nested transaction() joins the active transaction instead of opening an isolated one that can't see its writes.

@warlock.js/cascade Fixed 2
  • Fixed Native Postgres array columns (TEXT[] / JSONB[], from arrayText() / arrayJson()) are now auto-detected by introspecting the schema on connect and bound as raw arrays — no more "malformed array literal" on insert and no need to hand-list nativeArrayColumns (which stays as an optional per-connection override, now consulted per-table)
  • Fixed transaction() now flat-nests: a nested transaction() joins the active one (same session, sees its uncommitted writes) instead of opening a second, independent transaction — fixes phantom foreign-key violations when a service that opens its own transaction is called inside an outer one (e.g. a seeder creating a row, then a service inserting a child that references it). MongoDB joins too, replacing its "nested not supported" throw
@warlock.js/core Fixed 1
  • Fixed a fatal uncaughtException at production boot (e.g. a config file that throws) is no longer swallowed into a silent exit 0 — bootstrap now wires the crash handler to exit non-zero in production so warlock start surfaces the failure; the dev server still logs-and-continues for HMR
@warlock.js/logger Changed 1
  • Changed captureAnyUnhandledRejection() now exits the process non-zero after an uncaughtException (and prints the stack to console.error when no terminal channel is configured) so a fatal error at boot is never silently swallowed into a clean exit 0 — opt out with { exitOnUncaughtException: false } where the process recovers on its own (e.g. a dev server using HMR). unhandledRejection is unchanged (logged at error, never exits).
4.6.0
July 1, 2026

The AI framework closes every remaining capability gap. Output modalities land — ai.image(), ai.speech(), and ai.transcribe(), plus the new @warlock.js/ai-live package for ai.realtime() duplex voice + ai.video(). RAG gains first-party vector stores and document loaders (ai.rag.pgVectorStore on Postgres/pgvector, ai.rag.loadWeb / loadPdf / loadHtml / loadText). Durable mid-run crash-resume comes to agents and planners (agent.resume() / planner.resume() via an opt-in durable store). And provider breadth doubles with four new OpenAI-compatible adapters — @warlock.js/ai-mistral, ai-groq, ai-deepseek, and ai-xai.

@warlock.js/ai Added 9
  • Added ai.image(params) — image generation, the first verb of the output-modality track (Theme I). Wraps an ImageModelContract in the uniform never-throws { data, error, usage, report } envelope, with cost-truth (per-token for gpt-image, per-image for DALL·E / Imagen) folded into the same Usage.cost rollup and a type: "image" report routed to observers. Ships on the OpenAI + Google adapters.
  • Added SDKAdapterContract.image?(config) — the image-model capability seam, mirroring embedder?(). Adds ImageModelContract, GeneratedImage (discriminated base64 | url), ImageModelPricing, and ImageGenerationOptions.
  • Added MockSDK().image(...) + MockImageModel — deterministic image doubles (scriptable responses, recorded calls, pricing) for tests.
  • Added ai.speech(params) + ai.transcribe(params) — text-to-speech and speech-to-text, the audio verbs of the modality track. Same uniform never-throws envelope + cost-truth (per-character / per-minute / per-token). New SpeechModelContract / TranscriptionModelContract on SDKAdapterContract.speech?() / transcribe?(), plus MockSpeechModel / MockTranscriptionModel.
  • Added ai.audioFromFile(path) / ai.audioFromBuffer(bytes, mediaType) / ai.audioMediaTypeForFilename(name) — non-AI utilities that package audio (WhatsApp .ogg/.opus, iOS .m4a, …) into the AudioInput shape ai.transcribe consumes.
  • Added ai.rag.pgVectorStore({ client }) — a Postgres + pgvector vector store satisfying VectorStoreContract (upsert / query / removeNamespace), with an ensureSchema() DDL helper and a lazy pg optional peer.
  • Added ai.rag.loadText / loadHtml / loadWeb / loadPdf — document loaders producing RagDocuments for .index(). loadWeb is SSRF-safe (routes through guardedFetch / OutboundPolicy); loadPdf uses a lazy pdf-parse optional peer.
  • Added Durable mid-run crash-resume — opt-in durable: { store, deleteOnComplete? } on ai.agent / ai.planner with a stable runId + agent.resume(runId) / planner.resume(runId). Per-trip (agent) / per-node (planner) checkpoints reuse ai.snapshot.{memory,pg,redis}; drift detection via AgentDriftError / PlannerDriftError (bypass with { force: true }); completed work never re-runs its tools and usage is never double-counted.
  • Added **ai.rag.* namespace** now also carries chunk, cacheVectorStore, pgVectorStore, loadText/loadHtml/loadWeb/loadPdf, bm25Rank, reciprocalRankFusion, hybridRank, multiQuery (previously standalone-only exports), for ai.*-namespace consistency.
@warlock.js/ai-live Added 5
  • Added First release — the live & generative rich-media add-on for @warlock.js/ai, kept in its own package so core text/image/speech stay dependency-light. A side-effect import (import "@warlock.js/ai-live") mounts ai.video + ai.realtime onto the shared Ai facade.
  • Added ai.video(params) — text-to-video (Sora / Veo / Kling-class); the provider's async submit→poll job hidden behind the uniform never-throws { data, error, usage, report } envelope, with per-second cost-truth folded into Usage.cost and a type: "video" report routed to observers.
  • Added ai.realtime(options) — a stateful duplex voice session over a pluggable RealtimeTransport: sendAudio / sendText / events() out, close()RealtimeReport for the cost/observability surfaces.
  • Added ContractsVideoModelContract, GeneratedVideo, VideoModelPricing, VideoOptions; RealtimeSession, RealtimeTransport, RealtimeConnection, RealtimeEvent, RealtimeReport, RealtimeOptions.
  • Added MocksMockVideoModel + MockRealtimeTransport for deterministic, HTTP- and socket-free tests (scripted responses / event streams, recorded calls).
@warlock.js/ai-openai Added 4 Fixed 1
  • Added openai.image({ name }) — image generation for the gpt-image-* (token-metered) and dall-e-* (per-image) families, for use with ai.image(). A non-image model id is rejected at construction.
  • Added PDF + audio input. pdf and audio content parts now map to OpenAI file (base64 file_data) and input_audio (wav / mp3) parts — opt in with model({ pdf: true }) / { audio: true }. A remote-URL pdf/audio source raises a typed InvalidRequestError up front.
  • Added openai.speech({ name }) — text-to-speech for the tts-1 / tts-1-hd / gpt-4o-mini-tts families (audio.speech.create), for use with ai.speech().
  • Added openai.transcribe({ name }) — speech-to-text for the whisper-1 / gpt-4o-transcribe families (audio.transcriptions.create), for use with ai.transcribe(). whisper-1 defaults to verbose_json (duration + segments); a non-TTS/STT model id is rejected at construction.
  • Fixed Non-text content parts are no longer coerced to image_url. The message mapper now branches per modality (image → image_url, pdf → file, audio → input_audio) instead of forcing every attachment through the image path.
@warlock.js/ai-mistral Added 3
  • Added First release. MistralSDK — a thin wrapper over @warlock.js/ai-openai that points one internal OpenAISDK at Mistral's OpenAI-compatible endpoint (https://api.mistral.ai/v1) with provider: "mistral", delegating transport, streaming, tool calls, structured output, error wrapping, and token accounting to the battle-tested adapter. Exposes .model(), .embedder() (mistral-embed), and .count().
  • Added Mistral-aware capability inferencevision is auto-set for the pixtral family and recent multimodal generations (mistral-large, mistral-medium, ministral-3); reasoning for the magistral family and the hybrid mistral-small generation. An explicit vision / reasoning on .model() always wins. Exported as inferVisionCapability / inferReasoningCapability, with the -latest aliases grouped under MISTRAL_MODELS.
  • Added Default pricing registry (MISTRAL_DEFAULT_PRICING, USD per 1,000,000 tokens) merged under any caller-supplied pricing so cost truth works out of the box; per-model > SDK-level > default > undefined. No image() — Mistral has no OpenAI-compatible image endpoint.
@warlock.js/ai-google Added 1 Fixed 1
  • Added google.image({ name }) — Imagen (imagen-*) image generation for use with ai.image(). Per-image-metered; when every candidate is safety-filtered the run surfaces a typed ContentFilterError. A non-Imagen model id is rejected at construction.
  • Fixed PDF + audio input are now explicitly mapped and tested. The content-part mapper documents and proves that pdf / audio parts route to Gemini inlineData (the pdf / audio capabilities the adapter advertises are backed by a real mapper, not an accident of the image path), and the remote-URL rejection now names the actual modality instead of always saying "images".
@warlock.js/core Added 11 Changed 1 Fixed 4
  • Added release-hygiene tests: version↔changelog invariant + generator-stub import check
  • Added router.routeCount() exposes the number of registered routes as a boot/readiness signal
  • Added health.addRoutesRegisteredCheck(getRouteCount) registers a readiness check that reports not-ready when a booted HTTP app has zero routes
  • Added seeders now receive a { track } context — track(model), track(models[]), and track(table, id) register created records (each call returns its argument so it can be chained inline); recordsCreated is auto-derived from the track count
  • Added seed_records table (created via the new SeedRecordsTableMigration) records every tracked seed reference within the same transaction the seed runs in; only the last run's refs are kept per seeder
  • Added warlock seed --drop [name] undoes a seed: deletes its tracked records in reverse run/insertion order inside a transaction, then resets the matching seeds-log rows so once: true seeds re-run; scope to one seeder with --drop=<name>
  • Added Seeder.dependsOn is now resolved — seeders are topologically sorted so dependencies run before dependents, layered over the numeric order tie-break; throws UnknownSeederDependencyError for a missing dependency and SeederDependencyCycleError for a cycle
  • Added seeders receive an injectable clock and a meaningful batch size — run({ track, now, batchSize }); now() (default () => new Date()) drives both seed data and the seeds-log timestamps so historical/back-fill runs are deterministic, and batchSize surfaces the seeder's own batchSize for Model.createMany(rows, { batchSize })
  • Added repository-level aggregation — aggregate(), sum(), avg(), min(), max(), and groupBy() on RepositoryManager, each reusing filterBy (and its operator-injection guard), where, and scopes before the aggregate, exactly like count()
  • Added warlock doctor — a read-only diagnostics command that runs routes / config / connectors / optional-peers / health / release-hygiene checks and prints a pass/warn/fail report (exits non-zero on any failure, never opens a DB/cache/socket connection)
  • Added warlock routes — a read-only command that lists the registered HTTP routes as a verb-colored table (method / path / name / action / middleware-count / source); filter with --method / --path / --name, or emit the normalized rows as JSON with --json. Boots app code to register routes but starts no connectors
  • Changed Seeder.run now receives a SeedContext (run(ctx)) — backward compatible, an existing zero-arg run() keeps working unchanged
  • Fixed route-module load/registration failures are no longer swallowed: a route file that throws on import or registration now surfaces loudly instead of silently 404'ing the whole surface
  • Fixed ModuleLoader.loadModule rethrows after logging (wrapped in a new ModuleLoadError carrying the failing file + cause), so a broken module aborts boot and is caught loudly by the HMR batch-reload handler in dev
  • Fixed ModuleLoader.loadAll aggregates per-file failures and throws an AggregateError at the end, so one broken module no longer hides the others
  • Fixed router.withSourceFile rethrows the callback error after logging instead of consuming it with a bare console.log (the try/finally source-file stack cleanup is preserved)
@warlock.js/cascade Added 10 Changed 1 Fixed 4
  • Added Fast bulk Model.createMany(data, options?: { batchSize?; bulk? }) — both paths chunk by batchSize (default 500); bulk: true routes each chunk to the driver's native multi-row insertMany for 10–100× throughput (skips per-row hooks/events; default path preserves them)
  • Added IdGeneratorContract.generateNextIds({ table, count }) — reserve a contiguous block of auto-increment ids in a SINGLE atomic op (MongoDB). Model.createMany (default + bulk) now reserves one id block per chunk instead of one counter round-trip per row; engages only for fixed-increment, auto-generated, id-less rows (random-increment or caller-supplied-id rows fall back to per-row generation)
  • Added QueryBuilder.groupByDate(column, unit, aggregates?) — portable date-bucketed GROUP BY (day/week/month/year) across Postgres date_trunc and MongoDB $dateTrunc
  • Added $agg.sum(expr) now also accepts a typed column expression ($expr.mul/$expr.add/$expr.sub/$expr.div/$expr.col/$expr.lit) so you can sum price * quantity; bare-string payload is unchanged. Added $agg.sumRaw(expression) raw escape hatch (Postgres SUM(<raw>); throws on MongoDB)
  • Added Column-expression DSL grouped under a single $expr object (mirroring $agg) — $expr.col / $expr.lit / $expr.mul / $expr.add / $expr.sub / $expr.div / $expr.raw — plus isColumnExpression / toColumnExpression and the ColumnExpression / ColumnExpressionInput types
  • Added MongoDB id counter (MasterMind) now has a lazily-ensured unique index on { collection: 1 } plus a bounded retry on duplicate-key (E11000), closing the cold-start race where two concurrent first inserts into a new collection could reserve overlapping ids/blocks
  • Added $agg.countDistinct(field) — a cross-driver grouped distinct-count aggregate (Postgres COUNT(DISTINCT col); MongoDB $addToSet in $group finalized with $size in the renaming $project)
  • Added Model.raw<T>(sql, params) — typed, transaction-aware raw query that auto-joins the active transaction() scope and returns RawQueryResult<T>
  • Added DataSource.raw<T>(sql, params) — thin transaction-aware passthrough to driver.query
  • Added Postgres connection option nativeArrayColumns — opt out listed columns (JSONB[]/TEXT[]/…) from JSON-text encoding so genuine native-array columns keep their {...} literal form
  • Changed DriverContract.query<T>() is now typed Promise<RawQueryResult<T>> (new rows + rowCount result type) instead of Promise<any>
  • Fixed Postgres json/jsonb columns no longer corrupt: object-arrays, string-arrays, mixed arrays, empty [] (previously stored as {}), and plain objects are now JSON-encoded before binding instead of falling through to a Postgres array literal; the same encoding is applied on the UPDATE $set path. The pgvector all-number array form is preserved.
  • Fixed Insert no longer overwrites a caller-supplied createdAt — a backdated value (imports/migrations) is now honored, mirroring the upsert guard, while updatedAt is always stamped at persist time
  • Fixed Insert validation now whitelists the system columns (id/_id/timestamps/deletedAt) like the update path, so a backdated createdAt survives strict strip/fail mode instead of being dropped before reaching the writer
  • Fixed Corrected the MongoDB id-generator docs that falsely claimed the counter write "participates in active transactions" — it is a standalone, immediately-durable write (no transaction session is attached), so a rolled-back insert leaves the consumed id as a gap, exactly like SQL SERIAL
@warlock.js/ai-deepseek Added 5
  • Added First release. DeepSeek adapter for @warlock.js/ai — a thin wrapper over @warlock.js/ai-openai's OpenAISDK pinned to https://api.deepseek.com (provider: "deepseek"), so all wire behavior (streaming, tool calls, structured output, error wrapping) is inherited unchanged.
  • Added DeepSeekSDK.model() / .embedder() / .image() / .count() delegated to the wrapped client. baseURL and provider are optional (default to DeepSeek's endpoint / label); every other openai ClientOptions value is forwarded verbatim.
  • Added DeepSeek-specific capability inference (inferReasoningCapability / inferVisionCapability) — reasoning is auto-true for deepseek-reasoner and the *-pro tier, auto-false for deepseek-chat / *-flash; vision is false for every id (no documented vision surface). An explicit reasoning / vision per model always wins.
  • Added Built-in DeepSeek pricing defaults (USD per 1M tokens) for deepseek-chat, deepseek-reasoner, deepseek-v4-flash, deepseek-v4-pro, so usage.cost is computed out of the box; overridable per model or per SDK.
  • Added DEEPSEEK_CHAT_MODELS — informational list of the documented chat model ids.
@warlock.js/ai-xai Added 5
  • Added First release. xAI Grok adapter for @warlock.js/ai — a thin wrapper over @warlock.js/ai-openai's OpenAISDK pinned to https://api.x.ai/v1 (provider: "xai"), so all wire behavior (streaming, tool calls, structured output, error wrapping) is inherited unchanged.
  • Added XaiSDK.model() / .embedder() / .image() / .count() delegated to the wrapped client. baseURL and provider are optional (default to xAI's endpoint / label); every other openai ClientOptions value is forwarded verbatim.
  • Added xAI-specific capability inference (inferVisionCapability / inferReasoningCapability, exported alongside XAI_VISION_MODEL_PREFIXES / XAI_REASONING_MODEL_PREFIXES) — Grok ids don't match OpenAI's gpt-* / o* prefixes, so vision is auto-true for grok-4 / grok-2-vision and reasoning for grok-4 / grok-3-mini. An explicit vision / reasoning per model always wins.
  • Added XAI_CHAT_MODELS — convenience list of current public Grok chat ids (grok-4, grok-3, grok-3-mini, grok-2-vision, grok-2).
  • Added Optional per-model pricing registry — resolution at model() time is per-model pricing > SDK registry > undefined.
@warlock.js/ai-groq Added 3
  • Added First release. GroqSDK — a thin wrapper over @warlock.js/ai-openai that points one internal OpenAISDK at Groq's OpenAI-compatible endpoint (https://api.groq.com/openai/v1) with provider: "groq", delegating transport, streaming, structured output, error wrapping, and token accounting to the battle-tested adapter. Serves Groq-hosted open models (llama-3.3-70b-versatile, llama-3.1-8b-instant, openai/gpt-oss-*, deepseek-r1-distill-llama-70b) on LPU hardware via .model() and .count(). GROQ_BASE_URL / GROQ_PROVIDER / GROQ_KNOWN_MODELS exported.
  • Added Groq-aware capability inference — because Groq ids are upstream open-weight names, not OpenAI's, the wrapper carries its own lists: vision is auto-set for gpt-oss / llama-4 / llama-3.2-*-vision; reasoning for gpt-oss / deepseek-r1 / qwq / qwen3. An explicit vision / reasoning / structuredOutput always wins. Exported as inferVisionCapability / inferReasoningCapability.
  • Added Default pricing registry (USD per 1,000,000 tokens) for the known Groq models as the final fallback; resolution per-model > SDK-level pricing[name] > built-in default > undefined. No embeddings endpoint on Groq (.embedder() is delegated for symmetry but calls fail upstream) and no image().
@warlock.js/scheduler Fixed 1
  • Fixed Warn in development when jobs are registered but start() is never called — a one-shot deferred check logs N job(s) registered but scheduler.start() was never called, is suppressed once start() runs or in production (NODE_ENV=production), and is unref'd so it never holds the process open.
4.5.0
July 1, 2026

The biggest AI release yet — the agent-platform, prompt-unification, and team-identity milestones plus a security-hardening pass, consolidated into one release. @warlock.js/ai grows from a primitive ladder into a full agent platform: ai.rag(), ai.team(), ai.skills(), a unified ai.prompts registry (ai.prompt is now a facade over it), ai.dataset() / ai.vcr(), a planner that runs DAGs and can pause for approval, a generic observe seam, the former ai-human + ai-guard satellites folded into core, and a security pass (SSRF-safe outbound I/O, redaction, attachment policy, SSE serving, streaming structured output). @warlock.js/ai-panoptic becomes batteries-included with a redesigned, auth-gated local dashboard (group-by-type, cost heatmap, timeline, search / filter, restart-persistent store) and first-class team-type traces. The first releases of @warlock.js/ai-tools (ready-made tools + MCP) and @warlock.js/ai-workspace (a policy-jailed coding workspace), plus a broad @warlock.js/core hardening pass.

@warlock.js/ai Added 18 Changed 3 Fixed 3 Security 4
  • Added ai.rag(config) — retrieval-augmented generation in core: a chunk → embed → retrieve → cite pipeline that reuses your existing embedder and cache, with zero new dependencies. Includes hybrid retrieval (dense + BM25 reciprocal-rank fusion), keyword / LLM rerankers, and multi-query expansion.
  • Added ai.team(config) — manager-led multi-agent teams: thin sugar over ai.supervisor for the review-then-fix and test-then-fix shapes.
  • Added ai.skills(config) — runtime agent skills with progressive disclosure: a cheap always-injected catalog plus an on-demand loadSkill tool. Adds a skills option on ai.agent.
  • Added ai.streamObject(...) — structured-output streaming: partial-object snapshots as tokens arrive, with a strict final parse against the response schema.
  • Added ai.serve(executable, options) — serve any agent / workflow / supervisor as an SSE HTTP endpoint.
  • Added Multimodal attachmentsContentPart gains pdf and audio variants alongside text / image, resolved to provider-ready parts (PDF wired on the Anthropic and Bedrock adapters).
  • Added Planner DAG execution, re-planning, and plan-only approval — run independent steps concurrently, revise the plan when a step fails, or return a plan for approval before it executes.
  • Added Generic Observer seam — route any flow's run report to pluggable observers (e.g. @warlock.js/ai-panoptic) without coupling core to a backend.
  • Added ai.prompts + ai.prompt — a process-wide registry of named, versioned systemPrompt(...) builders (resolved by name@version / name@tag) with define / tag / diff / export / import and a unified validate (deterministic missing-placeholder check plus an optional Nova-safe LLM-judge); ai.prompt is a thin facade over it.
  • Added SystemPromptContract identity + provenance.meta({ name, version, description, required }) (a name auto-registers in ai.prompts), .merge(...blocks) / .merge(contract) / .merge(name, { fromVersion }), and deterministic meta.composedFrom labels.
  • Added ai.dataset(options) — filterable, shardable evaluation case sets that feed agent.eval, with baseline / regression detection and CI reporters.
  • Added ai.vcr(model, options) — record / replay any model against an on-disk cassette for deterministic, offline tests, with recordRequest modes and redactRequest / redactResponse / redactError hooks.
  • Added ai.agent.judge(config) — judge-safe agent preset (also ai.agent({ judge: true })): lenient JSON parsing, bounded repair re-asks, and never-throw verdicts on Nova-class models.
  • Added Human-in-the-loop approval now ships in core (ai.human.*, formerly @warlock.js/ai-human) — a tool-approval gate plus durable interrupt / resume.
  • Added Content guardrails now ship in core (ai.guardrail.*, formerly @warlock.js/ai-guard) — PII / topic / injection / moderation detectors.
  • Added Orchestrator sessionLock — per-session turn serialization (default in-process mutex keyed by sessionId, pluggable distributed lock) so concurrent same-session turns can't lose a checkpoint update.
  • Added Sub-agent trace nesting — a supervisor / team / orchestrator callback that calls agent.execute() directly now nests callback → agent → tool with rolled-up usage / cost.
  • Added AgentReport.systemPrompt — the resolved system prompt sent to the model is now recorded on the agent report.
  • Changed ai.team runs report type: "team" — a first-class ReportType (was "supervisor") so observers distinguish team runs on the wire.
  • Changed Deterministic parallel workflow state merge — parallel children merge into the parent in declaration order (last-declared wins on a conflicting key) instead of completion order; an optional per-step mergeState reducer overrides it.
  • Changed Safer batch / RAG defaultsai.batch warns once on a large unbounded run (pass an explicit concurrency or "unbounded"); ai.rag accepts limits (maxDocuments / maxChunks / maxBytes) that fail before any embedding spend.
  • Fixed Cancellation propagates through composite tools — a cancelled outer agent now aborts a nested agent / workflow / supervisor invoked via .asTool() (the run signal threads into the nested execute).
  • Fixed Observer / event-handler errors are surfaced, not swallowed — a throwing observer or on handler stays isolated (never crashes the run) but is now warned once / routed to a hook instead of disappearing silently.
  • Fixed budget({ maxCostUSD }) fail-open closed — a cost cap with no matching model pricing now warns once (naming the model) instead of silently never tripping.
  • Security Shared OutboundPolicy + redact() — one SSRF-safe outbound-fetch guard (scheme + host allowlist, post-DNS private-IP deny, max-bytes, timeout, injectable fetch) and one redaction utility, consumed across attachments, URL skills, VCR, and the error path.
  • Security Attachment trust boundary (AttachmentPolicy) — remote-text attachment fetch is default-deny (opt in with a policy), local reads honor an allowedRoots sandbox, and bare-string local paths warn (staged deprecation).
  • Security URL skill sources hardened — the manifest fetch runs through OutboundPolicy and every record is runtime-validated before it enters model context; adds cache-TTL controls.
  • Security Guardrail coverage documented — input detectors inspect text only; non-text attachment content needs an attachment-level policy.
@warlock.js/ai-panoptic Added 9 Changed 1 Fixed 1 Security 2
  • Added Zero-setup local dashboarddashboard(store, options) serves a loopback-only mini-Langfuse (default 127.0.0.1:4319) with no Docker and no account: light / dark / system theme, a two-pane drawer (nested call tree / detail), a metadata panel, colour-coded Title-case type labels, arrow-coded token rollups (↓input · ↑output · total), per-node rollup cost, and the Warlock logo.
  • Added Dashboard search / filter / grouping — client-side free-text search, status / type / session / prompt filter chips, an errors-only toggle, and group-by Session / Prompt / Type with a per-type aggregate-stats panel (count, failure rate, p50 / p95 latency, tokens, cost).
  • Added Cost heatmap, timeline view, and deep-links — each node carries a cost-tinted accent; the drawer toggles between the call tree and a Gantt timeline (critical path highlighted); the open trace + span are reflected in the URL hash for shareable views.
  • Added Prompt-version linkage — agent spans stamp agent.promptName / agent.promptVersion; the dashboard filters and groups by the resolved name@version key.
  • Added Cache-backed persistent trace storecreateCacheTraceStore(cache, options) persists traces through any @warlock.js/cache driver, serves reads from an in-memory mirror, and re-hydrates on ready() so traces survive a restart; ai.config({ panoptic: { cache } }) wires it.
  • Added Declarative ai.config({ panoptic }) — configure panoptic once; it registers on core's observer registry and starts the dashboard. Per-flow observe + observeAll opt flows into observation.
  • Added ContentCaptureOptions.fullHistory — capture the agent's complete message history on the span; agent content is emitted as a [system, user] chat array; Langfuse gets trace-level input / output.
  • Added onError hook — handle isolated exporter failures on panoptic() / createCollector().
  • Added Pure trace-list helpers exported from the package root (filterTraces / groupBySession / groupByPrompt / groupByType / aggregateByType / rollupCost / …) so your own views mirror the dashboard's rules.
  • Changed Title-case status & type labels across rows, drawer, chips, and group headers (underlying filter keys stay lowercase); team is a first-class dashboard type; type chips show only present types; drawer metadata keys are humanized; the group-by toggles became a single Group dropdown.
  • Fixed Isolated exporter failures no longer fail silently — a failing exporter still never crashes the run, but now warns once (or calls onError).
  • Security Dashboard hardening — bearer-token auth (authToken, required when binding off-loopback), a Host-header allowlist (DNS-rebinding guard), and security response headers (nosniff / X-Frame-Options: DENY / locked-down CSP) on every response.
  • Security Error redaction — captured error message / stack are scrubbed of secrets (Bearer tokens, API keys) and a retained cause is deep-redacted (auth / cookie headers stripped) before a trace is stored or exported.
@warlock.js/ai-tools Added 5
  • Added **Five ready-made agent tools, attached to the shared ai object under ai.tools.* via a declare module "@warlock.js/ai" augmentation, so a bare import "@warlock.js/ai-tools" makes them available and statically typed. Each returns a ToolContract that drops straight into ai.agent({ tools: [...] }): - ai.tools.webSearch(options) (web_search) — web search via a chosen provider (tavily / brave / serpapi) over the global fetch; the API key falls back to TAVILY_API_KEY / BRAVE_API_KEY / SERPAPI_API_KEY; maxResults is clamped per call. - ai.tools.fetchUrl(options?) (fetch_url) — fetch a URL and return its content as readability-extracted text (default), raw html, or markdown, with a host allowlist (SSRF guardrail), a byte cap (truncated flag), and a request timeout. - ai.tools.http(options?) (http_request) — a guarded HTTP/REST client: method + host allowlists enforced before the network call, optional baseUrl join, static-header merge, byte cap, and timeout; JSON-parses a JSON response body. - ai.tools.calculator(options?)** (calculator) — a SAFE arithmetic evaluator (+ - * / % ^, unary signs, parentheses, decimal/scientific literals) implemented with a shunting-yard pass — it never calls eval/Function. - ai.tools.dateTime(options?) (date_time) — clock/calendar operations: now / add / diff / format over ISO-8601 instants, with millisecond-based units and IANA time-zone rendering. diff accepts from as an alias for the start instant (iso wins when both are set).
  • Added MCP client — ai.mcp(server, options?) (Direction A). Connects to an external MCP server over a stdio (node:child_process + node:readline, no dependency) or Streamable HTTP transport, runs the initialize handshake + tools/list, and adapts each remote tool into a native ToolContract (its JSON Schema wrapped as a Standard Schema, tools/call as execute). Supports namePrefix, filter, and a per-call timeoutMs; an isError result surfaces as { error } data.
  • Added MCP server — ai.mcp.serve(source, options) (Direction B). Exposes a built agent / supervisor / orchestrator (or a raw ToolContract[]) AS an MCP server: tools/list emits each tool's inputSchema via extractJsonSchema at the configured schemaTarget (default draft-2020-12), and tools/call routes to contract.invoke(), mapping data to a text content block and error to an isError: true result. The stdio transport is auto-pumped over process.stdin / process.stdout; the pure protocol core is also exported as createServeHandler for a host's own HTTP wiring.
  • Added Typed error classesWebToolError, HttpPolicyError, CalculatorError, DateTimeError, and McpTransportError, each extending the @warlock.js/ai AIError base with a type discriminator. Every tool follows the errors-as-data contract: failures are thrown inside execute, wrapped by tool(), and reach the model as { error } so the agent self-corrects instead of crashing the run.
  • Added Optional peers, lazily imported. Heavy dependencies — a search provider (@tavily/core), the readability scraper (@mozilla/readability + jsdom), the MCP SDK (@modelcontextprotocol/sdk), and the JSON-Schema validator (ajv) — are optional peers, import()ed only when the relevant path runs, surfacing a curated npm install string when absent rather than crashing at import time. The only required runtime peer is @warlock.js/ai; everything else is Node built-ins + the global fetch (Node 18+).
@warlock.js/ai-workspace Added 16
  • Added ai.workspace(policy) — the workspace verb, registered on the shared ai object via a declare module "@warlock.js/ai" augmentation + a runtime side-effect on import (no edit to @warlock.js/ai's own source). Exported as the workspace factory; WorkspaceCapableAi is the typed view consumers cast ai through.
  • Added Policy jail — every path is realpath-resolved and must sit under cwd (or an allowPaths root); denyPaths globs are blocked even inside cwd; the shell allow/deny list gates each command's leading executable basename (deny wins, fail-closed); per-command timeout + output byte cap; and process.env is never inherited wholesale (opt-in shell.inheritEnv, plus explicit shell.env).
  • Added Seven agent-facing tools under ws.tools.*, each a ToolContract built on the core tool() factory: read_file, edit_file, write_file, run_shell, run_tests, grep, glob. Each factory takes an optional { name } (and run_tests a { command }) override.
  • Added tools.all() — every tool in canonical order — and tools.pick(...names) — a least-privilege subset (e.g. pick("readFile", "grep", "glob") for a reviewer).
  • Added Direct programmatic methods sharing the same policy seam: readFile / writeFile / editFile / exec / grep / glob / exists / mkdir / remove.
  • Added readonly() — a projection that vends only the read/grep/glob tools and rejects every mutating direct method with a WorkspacePolicyError.
  • Added scope(subdir) — a sub-jailed workspace rooted at subdir (narrowed cwd, same sub-policies and backend selection).
  • Added Read-before-edit guardread_file / readFile return a SHA-256 content hash (via @warlock.js/fs hashString); edit_file requires an exact, unique oldString (or replaceAll) and rejects a mismatched expectHash as stale.
  • Added BackendscreateLocalBackend (default "local"; @warlock.js/fs for IO + node:child_process for the shell) and createMockBackend (in-memory Map + scripted exec, for hermetic disk-free tests), behind the WorkspaceBackend contract.
  • Added Policy engine seam exports: resolveInJail, isCommandAllowed, buildEnv, and the ResolvedPath type.
  • Added Ops layer export createOps — the single policy-enforced operation layer both the tools and the direct methods funnel through.
  • Added Typed errors WorkspacePolicyError (type: "path-escape" | "denied-command") and WorkspaceEditError (type: "not-found" | "not-unique" | "stale-hash"), both extending the @warlock.js/ai AIError base (code TOOL_EXEC_FAILED) so failures surface to the agent as tool-error data, never thrown run-killers.
  • Added Public type surface re-exported from the barrel: Workspace, WorkspaceTools, WorkspacePolicy, WorkspaceShellPolicy, WorkspaceReadPolicy, WorkspaceBackendType, WorkspaceToolName, WorkspaceOps, WorkspaceBackend (+ WorkspaceBackendExecOptions / WorkspaceBackendExecResult), and the per-tool IO shapes (ReadFileInput/Result, EditFileInput/Result, WriteFileInput/Result, RunShellInput/Result, RunTestsInput, GrepInput/Match/Result, GlobInput/Result).
  • Added scripts/generate-llms.mjs and the generated llms.txt / llms-full.txt projections of skills/.
  • Added skills/use-a-workspace/SKILL.md — building a jailed workspace and operating it (policy, the seven tools, the direct methods, readonly / scope).
  • Added skills/build-loop-agent/SKILL.md — wiring ws.tools.all() into a coding agent that reads → edits → runs tests until green.
@warlock.js/core Changed 4 Fixed 24 Removed 1
  • Changed dev-server update notice now fires immediately on warlock dev — the check is spawned in parallel with server startup instead of awaiting it, so the notice surfaces as soon as npm responds
  • Changed raised the update check's npm registry timeout from 2.5s to 30s, so a slow connection no longer drops the notice
  • Changed repository lifecycle hooks (onCreating / onCreate / onUpdating / onSaving / onDeleting / …) now run on create / update / delete — they were defined but never invoked
  • Changed repository.list() / all() now honor the sortBy, sortDirection, and purgeCache options — previously accepted but silently ignored
  • Fixed response.sendFile({ filename }) and response.download() no longer 500 on non-ASCII file names — the Content-Disposition header is now RFC 6266-encoded (a sanitized ASCII filename fallback plus an RFC 5987 filename*=UTF-8''…), so an Arabic / emoji / UTF-8 download name streams correctly instead of throwing Node's ERR_INVALID_CHAR
  • Fixed local storage paths are contained to their disk root — ../ traversal segments and absolute paths can no longer escape the configured directory
  • Fixed storage.putFromUrl adds SSRF guards — private / loopback / link-local hosts are rejected and the fetched body is size-capped
  • Fixed S3 / R2 / DigitalOcean Spaces url() no longer produces a malformed double-host URL when urlPrefix is set
  • Fixed cloud deleteDirectory paginates via the list continuation cursor instead of re-listing the first page
  • Fixed local-storage metadata cache is invalidated on write / delete — it was serving a stale size / modified-time
  • Fixed the cloud driver no longer reports a misleading "SDK not installed" error when the AWS SDK is in fact present (driver load race)
  • Fixed repository countCached / countActiveCached now cache and return correctly — a null cache miss was being returned as the count
  • Fixed repository firstCached / lastCached no longer fetch and cache the entire table to return a single row
  • Fixed repository boolean filters no longer coerce false / 0 to true
  • Fixed repository cache keys are now order-independent (stable key serialization)
  • Fixed router groups restore prefix / name / middleware state via try/finally even when the group callback throws
  • Fixed router.any() / all routes now match every HTTP verb under the dev server — they previously matched only GET and POST, diverging from production
  • Fixed the HTTP concurrency limiter releases its slot on every response path (noContent, redirect, file, buffer) — a throwing or non-send handler no longer leaks a permit and permanently 429s the route
  • Fixed the cached-response middleware replays a hit through response.replay() instead of re-sending an already-sent reply, preserving status and content-type
  • Fixed onSent cache writes in the idempotency and cache middleware are error-handled — a cache-backend failure no longer surfaces as an unhandled rejection
  • Fixed X-Forwarded-For is parsed to its first hop, so IP-filter / rate-limit / idempotency scoping cannot be spoofed with extra header hops
  • Fixed the maintenance middleware allowlist matches request paths that carry a query string
  • Fixed use-cases run their after middleware and broadcast for a void handler, and a failed history write no longer fails an otherwise-successful call
  • Fixed the use-case retry counter reports the correct count on total failure
  • Fixed the socket connector no longer double-closes the shared HTTP server during graceful shutdown
  • Fixed the cache connector disconnects its drivers on shutdown — an open Redis connection was left dangling
  • Fixed generator stubs import v / Infer from @warlock.js/seal (core never re-exported them), so generated models compile and run
  • Fixed warlock dev hot-reloads when a file is emptied or saved with no trailing newline — a stale no-op-change check was silently dropping those saves before they reached HMR
  • Removed presigned-upload maxSize option — a presigned PUT URL cannot enforce a size cap, so the option was a false guarantee
@warlock.js/ai-anthropic Fixed 1
  • Fixed All upstream ClientOptions now reach the Anthropic client. The SDK constructor peels off the framework-only provider / pricing keys and forwards the rest (timeout, maxRetries, defaultHeaders, custom fetch, baseURL, …) verbatim, instead of dropping everything but apiKey / baseURL.
@warlock.js/ai-openai Fixed 1
  • Fixed All upstream ClientOptions now reach the OpenAI client. The SDK constructor peels off the framework-only provider / pricing keys and forwards the rest (timeout, maxRetries, defaultHeaders, custom fetch, organization, project, …) verbatim, instead of dropping everything but apiKey / baseURL.
4.4.0
June 21, 2026

@warlock.js/core completes the production lifecycle — a booted hook, a shutdown hook, graceful HTTP draining, and built-in /health + /ready endpoints for zero-downtime deploys. Plus AI fixes across @warlock.js/ai, @warlock.js/ai-openai, and @warlock.js/ai-panoptic (opt-in content capture, corrected Langfuse token accounting).

@warlock.js/core Added 8 Fixed 1
  • Added Application.onceBooted(cb) — run a callback once the app is fully booted (fires immediately if already booted)
  • Added Application.whenBooted() — promise that resolves with the boot context when the app is fully booted
  • Added Application.isBooted — whether the app has finished booting
  • Added Application.onShutdown(cb) — run teardown once on shutdown, before connectors stop (mirror of onceBooted)
  • Added Application.isShuttingDown — whether shutdown has begun
  • Added built-in /health (liveness) and /ready (readiness) endpoints with a health check registry (health.addCheck)
  • Added graceful HTTP shutdown — drains in-flight requests on shutdown, bounded by http.gracefulShutdown.timeout
  • Added http.health.* config to toggle or rename the health endpoints
  • Fixed connector shutdown no longer reverses the connector list in place (could corrupt order on a repeated shutdown)
@warlock.js/ai Fixed 2
  • Fixed Planner: OpenAI strict structured-output 400. The generated plan schema now lists every property in required and drops minItems / maxItems, so ai.planner() no longer fails against OpenAI strict json_schema mode.
  • Fixed Report / result types no longer collapse to never under strict TypeScript. The narrowing report / result types now override the discriminant via Omit<…> instead of intersection. Type-only — no runtime change.
@warlock.js/ai-panoptic Added 1 Fixed 1
  • Added Opt-in content capture. panoptic({ captureContent, redactContent }) copies the agent prompt / response and each tool's args / result onto spans, surfaced by the console (io), file, OTel (gen_ai.prompt / gen_ai.completion), and Langfuse exporters. Off by default; a ContentRedactor masks each value.
  • Fixed Langfuse token accounting — generations now meter their own usage (rolled-up minus children) and the root execution is metered, so the trace total no longer double-counts nested spans.
@warlock.js/ai-openai Fixed 1
  • Fixed Strict structured-output compatibility check is now recursive. A schema that omits a required property anywhere in the tree degrades to loose json_object instead of 400-ing; client-side validation still enforces the full shape.
@warlock.js/cascade Changed 1
  • Changed Documented model.uuid — the accessor returns the model's primary id as string (where model.id is string | number); the name is historical and performs no UUID validation.
4.3.0
June 21, 2026

Self-update tooling — @warlock.js/core gains the warlock update command and a new-release notice in warlock dev. @warlock.js/ai caps the primitive ladder with ai.orchestrator(), ai.planner(), and ai.memory(), plus a cost-truth pass across every provider. The new @warlock.js/ai-panoptic package adds observability. ⚠ Breaking: snapshot persistence moves from a CacheDriver to the dedicated SnapshotStore.

@warlock.js/core Added 4 Fixed 1
  • Added warlock update — update every @warlock.js/* package in package.json to its latest version (operator preserved), then run the detected package manager's install
  • Added dev-server update notice — warlock dev checks npm on start and prints a one-line notice when a newer @warlock.js/core is published
  • Added devServer.checkForUpdates config flag (default true) to toggle the dev-server update notice
  • Added fetchLatestVersion() and isNewerVersion() registry/version utilities
  • Fixed warlock dev --skip-typings and --skip-health long-form flags now work (were silently ignored)
@warlock.js/ai ⚠ BREAKING 1 Added 8
  • ⚠ BREAKING Supervisor + workflow snapshot persistence moved from CacheDriver to the dedicated SnapshotStore contract. The per-primitive fallback is now ai.config({ defaultSnapshotStore }). Migration: replace snapshotStore: cache.driver("redis", { client }) with snapshotStore: ai.snapshot.redis({ client }) (and ai.snapshot.{memory,pg} for the other tiers).
  • Added ai.orchestrator() — stateful session manager over a supervisor: durable session / history / context, drift detection, history compaction, resume, and a command surface (orchestrator.asTool(), a 3-tier event surface, and OrchestratorContract / config / error types).
  • Added ai.checkpoint.{memory,pg,redis}() and ai.snapshot.{memory,pg,redis}() — durable orchestrator-session and supervisor / workflow run stores, with matching defaultCheckpointStore / defaultSnapshotStore config fields.
  • Added ai.memory() — agent-memory store with four tiers: working (in-run scratch), semantic (durable facts), episodic (durable, recency-blended events), and procedural (durable, reinforcement-blended how-tos). Wired into the orchestrator via a memory? field.
  • Added ai.planner() — an LLM generates an ordered plan over your registered capabilities, then executes it step-by-step.
  • Added ai.spawnSubAgent() — one-shot delegation to a fresh single-use agent with an optional per-task budget; usable from a planner step, a tool, or a workflow.
  • Added Cost-truth contract surface across all five adapters — Usage.reasoningTokens, per-channel ModelPricing, and ModelCallOptions.{reasoning, cacheControl} (ignored by adapters that lack the capability).
  • Added DX helpers — ai.router(), ai.fanOut(), ai.batch(), ai.fallbackModel(), ai.mockRouter(), agent.eval() + built-in ai.eval.* scorers, Vitest matchers (registerAiMatchers()), supervisor-level middleware, and ai.systemPrompt.fromFile(path).
  • Added Executables passed in an agent's tools: [...] are auto-adapted into tools (workflows / supervisors / orchestrators compose directly via .asTool()).
@warlock.js/ai-panoptic Added 4 Fixed 3
  • Added panoptic() — the one-call subscriber factory: builds a collector, registers exporters, and feeds traces via attach(), middleware(), or collect().
  • Added Exporters — consoleExporter(), fileExporter() (JSON-Lines), otelExporter() (GenAI semantic conventions), and langfuseExporter(). @opentelemetry/* and langfuse are optional peers, lazily imported.
  • Added createInMemoryTraceStore() — a queryable in-memory trace store (query / aggregate by runId, sessionId, status, time window; optional capacity FIFO cap) that doubles as an exporter.
  • Added Vendor-neutral trace contracts (Trace / TraceSpan / CollectorContract / ExporterContract) derived 1:1 from the core BaseReport tree, plus skills for observing, exporting, and querying traces.
  • Fixed Failed root runs now carry their error in every export (threaded from the result envelope onto the root span).
  • Fixed Per-span exporters now receive every span (the collector walks the finalized tree).
  • Fixed panoptic().middleware() now works on a supervisor (the middleware declares a supervisor hook map).
@warlock.js/ai-anthropic Added 4
  • Added Usage accountingusage.cacheWriteTokens is populated from Anthropic's cache_creation_input_tokens (alongside cachedTokens); reasoningTokens is left unset because Anthropic bills thinking inside output_tokens.
  • Added Extended thinkingModelCallOptions.reasoning maps to Anthropic's thinking budget (reasoning.effort → a tiered budget, floored at 1024); temperature is dropped when thinking is enabled.
  • Added System-prompt prompt cachingcacheControl.breakpoints >= 1 emits the system prompt with cache_control: { type: "ephemeral" }.
  • Added Capabilitiesreasoning, promptCaching, and pdf are now advertised; audio stays absent.
@warlock.js/ai-bedrock Added 4
  • Added Cost-truth capabilitiesreasoning, promptCaching, pdf, and audio are reported truthfully per model family (inferred from the model id, overridable via bedrock.model(...)).
  • Added Reasoning / extended thinkingModelCallOptions.reasoning maps to Converse thinking for reasoning-capable models, and no-ops elsewhere so unsupported params never reach the wire.
  • Added Prompt-cache write breakpointscacheControl.breakpoints appends a Converse cachePoint block for caching-capable models.
  • Added Usage.cacheWriteTokens populated from Converse cacheWriteInputTokens; reasoningTokens is left unset (Bedrock reports no reasoning channel).
@warlock.js/ai-google Added 3
  • Added Usage.reasoningTokens is populated from Gemini's thoughtsTokenCount (alongside cachedTokens), surfaced only when reported > 0.
  • Added ModelCallOptions.reasoning maps to Gemini's thinkingConfig (maxTokensthinkingBudget, effort → a bucketed budget) for reasoning-capable models.
  • Added ModelCapabilities now reports reasoning, promptCaching, audio, and pdf; cacheControl is accepted as a graceful no-op.
@warlock.js/ai-openai Added 3
  • Added Usage.reasoningTokens is populated from completion_tokens_details.reasoning_tokens (o-series / gpt-5 hidden reasoning channel), emitted only when > 0.
  • Added ModelCallOptions.reasoning.effort maps to the native reasoning_effort param for reasoning-capable models; reasoning.maxTokens has no Chat Completions equivalent.
  • Added ModelCapabilities.reasoning is inferred from the model name (overridable via .model(...)); promptCaching is always true (OpenAI caches automatically), and cacheControl write breakpoints are a no-op.
@warlock.js/ai-ollama Added 2
  • Added ModelCapabilities.reasoning is inferred from thinking-capable model tags (overridable via ollama.model({ name, reasoning })); promptCaching / audio / pdf report false.
  • Added ModelCallOptions.reasoning maps onto Ollama's native think flag for reasoning-capable models; reasoning.maxTokens and cacheControl are graceful no-ops.
4.2.11
June 17, 2026

Soft deletes go end-to-end in @warlock.js/cascade. @warlock.js/core adds warlock add notifications, and @warlock.js/notifications gains model-driven column mapping, read-state, and multi-tenant support.

@warlock.js/cascade Added 1 Changed 1 Fixed 2
  • Added Migration.create auto-wires the deletedAt column when the model's delete strategy is "soft" (opt out with { softDeletes: false })
  • Changed Require @mongez/reinforcements ≥ 3.3.0 — the update validator now uses its new when helper for conditional schema fields
  • Fixed Soft destroy() now sets deletedAt on the in-memory model — the instance was left stale before
  • Fixed Update validation no longer strips or rejects the deletedAt column under strict mode (now whitelisted like the timestamps)
@warlock.js/core Added 3 Changed 3 Fixed 1
  • Added lowerStage3Decorators() — Vite/Vitest plugin that lowers TC39 Stage-3 decorators with esbuild before oxc / the SSR rewrite mangles them; drop it first in plugins so model-decorated files load under Vitest 4 / Vite 8.
  • Added warlock add notifications — installs @warlock.js/notifications (+ the mail feature), ejects config/notifications.ts, and scaffolds the app-owned Notification model + migration (idempotent).
  • Added Notifications connector — a built-in, config-gated connector that lazy-imports @warlock.js/notifications, so core keeps no hard dependency on it.
  • Changed warlock add test now scaffolds a vite.config.ts that includes lowerStage3Decorators(), so a fresh project can test decorated models out of the box.
  • Changed warlock add test test / test:coverage scripts now run one-shot (vitest run) instead of watch mode — CI-safe by default.
  • Changed Bumped @mongez/reinforcements to 3.3.0
  • Fixed startHttpTestServer now starts early-phase connectors (database, cache, logger, …) before app modules, then late-phase (http, socket) after — mirroring dev/prod boot order; fixes a MissingDataSourceError under the Vitest integration harness.
@warlock.js/notifications Changed 5
  • Changed In-app column mapping moved onto the model as static columnMap (recipient / tenant / readAt / isRead); accessors, repository, and channels all derive from it. New NotificationColumnMap type.
  • Changed Read-state is presence-based — declaring readAt, isRead, or both selects the representation (default read_at); the mode-agnostic unread filter replaces isRead.
  • Changed Multi-tenant support — when the model declares a tenant column, the database channel reads it off the recipient and createFor(...) writes it.
  • Changed inApp.list / inApp.listUnread now forward full list options (page / limit / orderBy + filters).
  • Changed notificationColumns(model) derives its columns from columnMap; the SQL-vs-MongoDB dataSource branch is removed.
@warlock.js/auth Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0
@warlock.js/cache Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0
@warlock.js/herald Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0
@warlock.js/logger Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0
@warlock.js/seal Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0
create-warlock Changed 1
  • Changed Bumped @mongez/reinforcements to 3.3.0 (package dependency + project template)
4.2.10
June 17, 2026

Patch: @warlock.js/auth moves its internal @mongez/* utilities from peer to regular dependencies, clearing the install warnings. @warlock.js/logger softens its console timestamp to gray.

@warlock.js/auth Fixed 1
  • Fixed @mongez/copper, @mongez/events, and @mongez/reinforcements are now regular dependencies instead of peerDependencies — they're framework-internal utilities your app never imports, so declaring them as peers produced unmet peer dependency warnings on install.
@warlock.js/logger Changed 1
  • Changed ConsoleLog's timestamp (and the context arrow) switch from bright-black gray to the 256-color slate — recessive but cleanly legible where bright-black read muddy.
create-warlock Changed 1
  • Changed The project template now pins the latest @mongez/* versions (@mongez/reinforcements@^3.2.0, @mongez/agent-kit@^1.2.0) so freshly scaffolded apps start on current dependencies. (@warlock.js/* versions are still rewritten to the scaffolder's own version at install time.)
4.2.9
June 17, 2026

Patch: @warlock.js/logger's console output is retuned for scannability — a dimmed time-only timestamp, aligned level columns, and a restored white-on-red fatal badge.

@warlock.js/logger Changed 1
  • Changed ConsoleLog output retuned for scannability — a time-only HH:mm:ss.SSS timestamp dimmed to gray, fixed-width level tags so the columns align, and fatal restored to a white-on-bright-red background badge. (FileLog / JSONFileLog keep the full ISO timestamp.)
4.2.8
June 17, 2026

Patch: @warlock.js/logger now prints each level's name beside its icon (ℹ info, ⚠ warn, ✗ error, …) for at-a-glance reading.

@warlock.js/logger Changed 1
  • Changed ConsoleLog now prints each level's name beside its icon (⚙ debug, ℹ info, ⚠ warn, ✗ error, ✓ success, ☠ fatal) for at-a-glance reading.
4.2.7
June 17, 2026

Patch: create-warlock now ships its templates/ folder, fixing the "Something went wrong" error when scaffolding a new project.

create-warlock Fixed 1
  • Fixed The published package now ships its templates/ folder, so scaffolding a new project works from the installed package — it was missing from the build, which failed the wizard with "Something went wrong" at the template-copy step.
4.2.6
June 17, 2026

Patch: create-warlock ships its bin folder again, restoring the CLI that was dropped from 4.2.5.

create-warlock Fixed 1
  • Fixed The published package now ships its bin folder again, so the create-warlock CLI works from the installed package — it was omitted from the 4.2.5 build.
4.2.5
June 15, 2026

Patch: warlock add notifications now scaffolds the in-app notifications HTTP surface — routes plus a list / mark-read / clear controller, gated by auth.

@warlock.js/core Added 1
  • Added warlock add notifications now scaffolds the in-app read/dismiss HTTP surface — routes.ts + a notifications.controller.ts (list / unread-count / mark-read / mark-all-read / clear / delete), gated by authMiddleware and recipient-scoped via inApp. Pulls @warlock.js/auth.
4.2.4
June 15, 2026

Patch: corrects a worker-loader build path in @warlock.js/core that 4.2.3 left broken.

@warlock.js/core Fixed 1
  • Fixed Fix the worker-loader path in the build entry points — a wrong path in 4.2.3 left the worker entry broken (and blocked the 4.2.3 publish for some packages).
4.2.3
June 15, 2026

Patch: ships the worker scripts as @warlock.js/core build entry points. A wrong path here blocked publishing for some packages — fixed in 4.2.4.

@warlock.js/core Fixed 1
  • Fixed Add the worker scripts as build entry points so they ship in the published package.
4.2.2
June 15, 2026

Patch: ships the warlock CLI entry (cli/start) in @warlock.js/core's build.

@warlock.js/core Fixed 1
  • Fixed Add cli/start to the build entry points so the warlock CLI entry ships in the published package.
4.2.1
June 15, 2026

Patch: @warlock.js/core and @warlock.js/cascade ship their bin folders, restoring the warlock and cascade CLIs dropped from 4.2.0.

@warlock.js/core Fixed 1
  • Fixed Ship the bin folder so the warlock CLI works from the published package — it was omitted from the 4.2.0 build.
@warlock.js/cascade Fixed 1
  • Fixed Ship the bin folder so the cascade CLI works from the published package — it was omitted from the 4.2.0 build.
4.2.0
June 15, 2026

A security overhaul of @warlock.js/auth — brute-force throttling, atomic refresh-token rotation, and CSPRNG secrets (the jwt config gives way to accessToken / refreshToken). Introduces two packages: @warlock.js/notifications (multi-channel notifications) and @warlock.js/access (RBAC + ABAC authorization).

@warlock.js/notifications New 1
  • New Shipped Warlock.js Notifications Package.
@warlock.js/access New 1
  • New Shipped Warlock.js Access Package.
@warlock.js/auth Added 5 Fixed 6 Deprecated 1 Removed 2 Security 2
  • Added loginThrottleMiddleware — failure-aware brute-force / credential-stuffing protection: counts only failed logins, locks per-account and per-IP, and rejects pre-controller with 429 (cache-backed, fails open). Adds AuthErrorCodes.TooManyAttempts (EC004).
  • Added accessToken / refreshToken configuration blocks, making a separate refresh-token secret first-class.
  • Added Overridable token storage — register a custom model under config.auth.accessToken.model / refreshToken.model and .extend() the exported schemas to add columns (e.g. a multi-tenant organization_id).
  • Added tokenType (access | refresh) claim, stamped on issue and verified on read, so an access token can't be presented as a refresh token.
  • Added expires_at on access tokens; warlock auth.cleanup now purges expired access tokens too.
  • Fixed Default access-token lifetime was ~3.6 seconds (a numeric expiresIn read as milliseconds) and is now 1 hour.
  • Fixed Targeted revocation queried userId instead of the user_id column, so logout / refresh-token removal threw on Postgres and silently no-oped on MongoDB; token queries now route through named model statics.
  • Fixed Token deletions were fire-and-forget (false success for callers, uncatchable rejections) and are now awaited.
  • Fixed The route middleware matched on userType instead of the user_type column.
  • Fixed revokeAllTokens / revokeTokenFamily reported an empty set, so token.revoked / token.familyRevoked never fired; the revoked rows are now captured before revocation.
  • Fixed A throwing synchronous auth-event listener no longer turns a completed login into a 500.
  • Deprecated The auth.jwt.* configuration block. Use accessToken / refreshToken instead — the legacy shape is still read and mapped forward with a one-time deprecation warning.
  • Removed Unread access_tokens columns is_active and last_access.
  • Removed The unused auth.password.salt configuration key.
  • Security warlock jwt.generate now derives JWT_SECRET / JWT_REFRESH_SECRET from a CSPRNG (Random.token) instead of Math.random().
  • Security Refresh-token rotation is atomic — a guarded conditional UPDATE means two concurrent rotations can't both succeed, and a replayed token revokes its entire family.
@warlock.js/logger Added 4 Changed 3 Fixed 1
  • Added log.flush() — awaitable async counterpart to flushSync(), draining every channel via Promise.allSettled with per-channel isolation. Implemented by FileLog / JSONFileLog.
  • Added SentryLog channel — forwards entries to Sentry (eventLevels become events, others breadcrumbs; module / action as tags). @sentry/node is an optional, lazily-imported peer.
  • Added log.fatal() + fatal level — ranked strictly above error for unrecoverable failures; does not auto-flush or exit.
  • Added ConsoleLog renders fatal with a icon on a bright-red background, distinct from error's .
  • Changed captureAnyUnhandledRejection() now escalates uncaughtException to log.fatal (was error); unhandledRejection stays at error.
  • Changed LoggingData.type is now typed as LogLevel (was a duplicated inline union).
  • Changed LogContract / LogChannel now expose an optional flush?() alongside flushSync?().
  • Fixed @sentry/node is referenced only via local types + an indirect dynamic import, so source-served consumers no longer get TS2307: Cannot find module '@sentry/node' when they don't install the optional peer.
@warlock.js/cascade Changed 1 Fixed 1
  • Changed MongoDB and PostgreSQL drivers now log a failed initial connect() at log.fatal (was log.error) — a boot-time database connection failure is unrecoverable, so fatal keeps "page on fatal only" alerting clean. Per-query and disconnect failures stay at error.
  • Fixed PostgreSQL increment / decrement (and the *Many variants) bound the amount as $1, colliding with the first filter placeholder (SET n = n + $1 WHERE id = $1) so every filtered counter update wrote the wrong number; the amount now binds after the filter params.
@warlock.js/ai Fixed 1
  • Fixed No-argument tools (declared without an input schema) no longer crash on invocation — tool.invoke now skips validation when no schema is present and passes the raw input to the handler.
@warlock.js/ai-anthropic Added 1
  • Added Opt-in promptCaching flag on the model config — marks tool definitions with cache_control: { type: "ephemeral" } so multi-trip agents reuse the static tool schemas at the cache-read rate. Off by default.
@warlock.js/cache Changed 1
  • Changed Redis driver now logs a failed initial connect() at log.fatal (was log.error) — a boot-time cache connection failure is unrecoverable, so fatal keeps "page on fatal only" alerting clean.
@warlock.js/core Changed 1
  • Changed herald-connector and http-connector now log a failed boot-time connection at log.fatal (was log.error) — an unrecoverable broker connection or HTTP port-bind failure makes "page on fatal only" alerting clean; the HTTP connector flushes logs before process.exit(1). Disconnect / shutdown failures stay at error.
4.1.15
June 4, 2026

The first public release of Warlock.js — 17 packages published together at 4.1.15. Every change from here on is recorded per package and aggregated on this page.