Releases: ackness/covel
Release list
Covel v0.0.13
[0.0.13] - 2026-07-10
The Windows release. The dev environment (spawn shims, plugin loading, supervised pnpm dev) now works on Windows, and CI builds Windows installers alongside the macOS bundles on every tag. Public web-only (browser IndexedDB) deployments are hardened: the shared session listing is hidden and the Render blueprint pins the memory backend explicitly.
Added
- Windows desktop CI.
release.ymlgains abuild-electron-winjob (windows-latest): full desktop build with Electron-ABI native rebuild, staged-server smoke under Electron's Node mode,electron-builder --win(NSIS + portable, x64, unsigned until a cert is configured), and.exeartefacts attached to GitHub Releases alongside the macOS bundles. Windows targets are x64-only: the staged server ships a better-sqlite3 rebuilt for the build host's arch, so an arm64 installer from an x64 runner would carry an addon the arm64 sidecar cannot load — Windows-on-ARM runs the x64 installer via emulation.
Fixed
- Windows dev environment. Dev scripts spawn through
cross-spawn(resolvespnpm.cmd-style shims with correct cmd.exe quoting); plugin/runtime dynamic imports of absolute paths go throughpathToFileURLso plugin loading works on Windows;pnpm devlaunches web + server directly with supervised teardown;--env-file-if-existstolerates a missing.env(raises the minimum Node to 22.9). - Desktop staging smoke now exercises the Electron ABI. The native rebuild runs before the smoke test and the staged server boots under
ELECTRON_RUN_AS_NODE; a missing Electron binary fails the build instead of silently downgrading the check (COVEL_SMOKE_HOST_NODE=1opts into the weaker host-Node smoke). - Electron runtime binary is materialised explicitly. electron@42 removed its postinstall hook, so
pnpm installno longer downloads the binary intonode_modules/electron/dist(whitelisting inonlyBuiltDependencieshas nothing to run). The desktop build and dev shell now runensure-electron.mjsfirst, which invokes electron'sinstall.jswhen the binary is missing — without this, every desktop CI build died at the staging smoke on both macOS and Windows. - Public web-only hosting hardening. On memory-backend production deploys without debug routes,
GET /api/sessionreturns an empty list — server-side sessions there are transient sync copies of browser-IndexedDB data, and the only callers of a shared listing would be other players.render.yamlpinsSTORE_BACKEND=memoryexplicitly (the sqlite default would pool every player's data in one shared DB), adds a health check, and disables the debug page; the Docker image regains the workspace manifests (settings,plugin-handlers-utils, and four plugins) missing from its dependency-install stage.
What's Changed
- feat: web-only (IndexedDB) public hosting hardening + Render blueprint fixes by @ackness in #13
- [codex] Fix Windows dev environment by @ackness in #14
- Release v0.0.13 by @ackness in #15
- fix: v0.0.13 CI — Electron binary download (electron@42 dropped postinstall), actions/cache v5 by @ackness in #16
- fix: Windows portable exe overwrote the NSIS installer (artifact name collision) by @ackness in #17
Full Changelog: v0.0.12...v0.0.13
Covel v0.0.12
[0.0.12] - 2026-07-06
The media-pipeline release. Speech joins images as a first-class framework primitive: ctx.speech gives function runtimes a unified TTS/STT surface with the same wire-selection, dedupe, and MediaStore-persistence guarantees as ctx.images, and every media modality (image / speech / transcription) now routes through pluggable per-modality wire registries. Plugins can ship vendor wires declaratively via the new PLUGIN.md wires field — supporting a new provider no longer requires touching bundled code.
Added
ctx.speech— unified TTS/STT for function runtimes.generate()synthesizes speech, dedupes onsha256(presetId, text, voice, format), and persists through MediaStore;transcribe()accepts aMediaRefor raw bytes and returns plain text. Assembled under the same conditions asctx.images; the plugin gateway and trace layer gainsynthesizeSpeech/transcribeAudiopassthroughs.- Plugin-declared media wires (PLUGIN.md
wiresfield). Plugins register image / speech / transcription wires declaratively; ids are namespaced<pluginId>/<wireId>and loading is trust-gated. Slots select wires viaproviderRequestMetadata.imageWire|speechWire|transcriptionWireinllm.toml. - Manifest diagnostics at bootstrap. A declared capability tag sitting one edit away from a framework-known one now warns (a misspelled tag was previously just silently never discovered), as does a plugin whose frontmatter name root differs from its directory name (a mismatch silently denies the plugin its own local tools).
Changed
- Speech/transcription move from provider adapters to pluggable wires (builtin
openai-speech/openai-transcription), completing the per-modality wire registry started with images in 0.0.11. - Plugin handlers read plugin data exclusively through
ctx.pluginData— no more store-shape sniffing; trusted and community runtimes go through the identical scoped path. Emptyrelations: {}frontmatter dropped across all bundled plugins; runtime imports moved from devDependencies to dependencies where misfiled; world-init tests relocated totests/, guide + pregame gain handler tests. - Web session view slimmed.
game-viewreads session state from the session store instead of ~20 pass-through props; a shareduseSettingsDialoghook replaces duplicated dialog state; UI primitives trimmed to the variants actually used.
Fixed
video_generationmodels derive a video output modality instead of being misclassified as text.- Commit handlers reject
state.patch/event.emitproposals with an empty table/field/topic instead of silently landing writes underdefault/unknown(JS plugins bypass the type layer, so the gate must live at commit time). POST /api/media(10 req/min) and sessionplugin-rpc(30 req/min) are rate-limited per IP — runtime-mode RPC dispatch runs a full LLM turn, the same cost class asPOST /api/actions.
What's Changed
Full Changelog: v0.0.11...v0.0.12
Covel v0.0.11
[0.0.11] - 2026-07-04
The visual-novel release. A full-screen GalGame stage mode — scene backdrops, character sprites, typewriter dialog, choice overlays — built on three new framework layers: a unified event-emission layer (events contracts + emit-event), a first-class image-generation pipeline (ctx.images + pluggable wires), and the scene-stage plugin that resolves narrative locations into stage art and generates missing backdrops on demand, mid-session. Haruka Academy ships the full asset set and plays as a visual novel out of the box.
Added
- Stage mode (
viewMode: "stage"). A full-screen visual-novel view for Playing turns: crossfading scene backdrop, bottom-anchored character sprites with active-speaker highlight, a delta-driven typewriter dialog with paragraph pauses, a classic centered choice overlay (interaction choices + scene-prompts phrases + free input), a HUD (scene badge, history drawer, auto-play, immersive toggle), and a player-clean history drawer reusingChatMessages. Worlds pick their default via the newworld.yamldefaultViewMode: stage | parsed; players can switch any time. Sprite stationing is sticky — salience decides who is on stage and who is highlighted, never where anyone stands — and sprites render inside equal-width lanes, so occlusion is impossible by construction. - Unified event layer. Plugin runtimes declare event contracts in frontmatter (
events: [{topic, schema, description, advertise}]); emitting agents declareadvertiseEvents: trueand call the new builtinemit-eventtool, whose payloads are schema-validated against the declaring plugin's contract with per-turn topic dedupe. A per-session event directory aggregates active plugins' contracts into the prompt (<available-events>), and deferred event followers are scheduled once per turn on the main loop.narrator/chat-mode-narratoremitscene.setas the reference implementation. - Framework image pipeline (
ctx.images/gateway.generateImage). One primitive for plugin image generation: wire selection (builtinopenai-imagesanddashscope-wansubmit+poll, extensible viaregisterImageWire()), MediaStore persistence, and promptHash dedupe all handled by the framework — handlers never touch bytes or provider credentials. scene-stageplugin. Resolvesscene.set(location + day/night) against the world scene registry — exact, then fuzzy, then session-generated matches — writesstage/currentfor the stage backdrop, and queues background generation for unmatched locations behind player-tunable gates (autoGenerateScenes,maxGeneratedScenes). Night variants lazy-generate on first use and reuse the day image's visual hint.- Haruka Academy visual-novel asset set. Ten scene backdrops (5 locations × day/night) plus regenerated transparent-background portraits, imported via new
worldDatamedia sources (to: media+indexTo+key: filename) and thescenes.registry.json/presence.jsonregistries;scripts/generate-scenes.mjs+scripts/emit-scenes.mjsregenerate them fromscenes.jsonspecs. requireToolUsemanifest gate. An agent runtime whose whole job is a tool call gets one corrective retry (locale-aware message) when it drifts into prose without calling anything;scene-promptsuses it.
Changed
- Media store simplified. The unused S3 backend and its SQLite/PG metadata adapters are gone; media stores gain a shared
listByMetadatafilter. The imperativebeginTx/commitTx/rollbackTxAPI and the emptyplugin_configstable are removed (all writes go throughwithTransaction; existing databases are unaffected). - ai-provider slimmed. Dead config loader, token estimator, and protocol-registry indirection removed; model capability resolution unchanged.
- Desktop auto-updater removed — releases install via the dmg; update checks return in a later cycle.
- README rewritten around stage mode with a fresh 6×-speed demo gif and play-mode stills; the
create-world/create-pluginskills now document the VN feature set (defaultViewMode, asset pipeline, events contracts,ctx.images).
Fixed
plugin-data.changedSSE now fires after transaction commit (and never on rollback), so panels re-render exactly when data is durable.- worldData sources targeting a plugin the player deselected are skipped with a warning instead of failing session creation with a 500;
indexTotargets skip only the index writes. - Stage polish batch: sprites no longer drift when the speaker or scene changes (sticky stations + lane geometry), stale
getSessionresponses can't corrupt state after a session switch, the typewriter survives same-text turns and stream-end races, artless speakers keep a name-card on stage, execution errors surface on stage with retry, and choice overlays no longer cover sprites. - A stuck "generating…" backdrop retries when the scene re-emits after a failed generation; DashScope image tasks that are CANCELED/UNKNOWN fail fast instead of polling to timeout.
- Duplicate deferred event followers are deduped per turn; enum values render in the event catalog; image cache hits stamp per-call metadata.
What's Changed
Full Changelog: v0.0.10...v0.0.11
Covel v0.0.10
[0.0.10] - 2026-06-29
A plugin-configuration pass: worlds can now preset any plugin's player-tunable settings and declare genre-specific memory dimensions, the player's per-plugin settings finally reach the scheduled turn loop, and the plugin config layer is consolidated onto a single declaration with server-enforced constraints. Behavior-unchanged for worlds and plugins that don't adopt the new fields.
Added
- World-preset plugin settings (
pluginSettings). Aworld.yamlcan now declare per-plugin defaults for any plugin'suserSettings, keyedpluginId → settingKey → value. They form the middle layer of a three-tier resolution chain — player override → world default → manifest default — merged at the turn boundary intoTurnInput.userSettingsand consumed by agent{{ userSettings.* }}templates, guards, and hooks. A dialogue world can ship "70% dialogue, short replies" as its default while players keep the freedom to override. Seedocs/reference/world-data.md. - World-declared core-memory blocks (
memoryBlocks). A world can add genre-specific memory dimensions (a detective world'sclues/suspects, a business sim'sdeals/rivals) without forking a plugin — same shape as a plugin'smemoryBlocks. The memory system resolves the block schema per session, merging a session's world blocks onto the global plugin blocks (base wins on label collision; the world only adds new labels), so the extra dimensions render and extract only for the worlds that declare them. Closes the long-documented "(or by a world package)" gap. integer/slideruser-setting types, and a consolidated design-principles page (docs/architecture/design-principles.md) that roots the framework's "kernel provides primitives, plugins carry gameplay" contract, the agent / function / composition writing styles, and the plug-vs-appliance test.- Character portraits + presence wiring for the flagship worlds. Both worlds ship a curated portrait set (mistport fog-noir, haruka GalGame-style), generated via
scripts/generate-portraits.mjs+scripts/emit-presence.mjsand wired to thecharacter-presenceplugin throughmedia+presenceworld-data sources (content-addressed by sha256) — portraits render in the right-panel character card and as dialogue sprites. The two worlds also gained tuned plugin defaults (haruka:activeSpeakerCount,npc-graph; mistport: acost-gatebudget guardrail). Prompt spec inworlds/PORTRAITS.md; shipping contract indocs/reference/world-data.md. - Hot-reload
llm.tomlwithout restarting. Settings → LLM gains a Reload config button (POST /api/llm-config/reload) that re-readsllm.tomland applies it to the live gateway in place — the provider / preset / slot registries are reconfigured rather than rebuilt, so the gateway and every adapter pick up added/removed slots without a restart. A malformedllm.toml(e.g. a key with=and no value) no longer fails silently: the file still falls back to the built-in default, but the parse error is now surfaced via the newerrorfield onGET /api/llm-configand a red banner in Settings — instead of every plugin's slot just showing as "missing" with no explanation. On desktop the reload endpoint is gated by the same one-time REST token as other config writes. Seedocs/guide/desktop-config.md. - Character portraits show as avatar badges in the character list. Each row in the char-creator character panel now leads with the character's portrait as a small avatar badge, via a new generic
CharacterAvatarjson-render component. It reads presence records from a source plugin/namespace named in the spec (char-creator wires it tocharacter-presence/presence) — keeping the framework component free of any hard-coded plugin id, mirroring howImageGallerytakes itspluginIdby prop. Matching tolerates the<sessionId>-<characterId>ids the character list uses against the barecharacterIdthe presence records key on. Characters without a portrait — and entire worlds without presence data — render exactly as before: the badge simply doesn't appear. - Worlds can declare character attributes with i18n labels (
characterAttributes).AttributeDefinition.name/descriptionnow accept anI18nText(plain string or{ "zh-CN": …, "en-US": … }record), and aworld.yamlcan ship its owncharacterAttributesarray.world-init's guard writes it verbatim as the session'scharacter-attributesschema — and does so authoritatively, ahead of cross-session reuse, so editing the declaration takes effect on new sessions instead of inheriting an older session's stale/derived schema. The right-panel character card resolves each label to the UI locale (resolveI18nText), and the prompt-injected<world-schema>is deep-resolved to one language too (resolveI18nDeep), so a custom field like Haruka'saffectionshows as 好感度 / Affection instead of a rawaffectionkey under "其他". Both flagship worlds now declare their cast fields (mistport: faction / role / tideSense / fogRot / …; haruka: club / affection / trust / …) with bilingual labels. Worlds that declare nothing are unchanged — the guard still derives generic attributes from dimensions, then falls back to the LLM. Seedocs/reference/world-data.mdanddocs/reference/plugins.md. - Click-to-enlarge for portraits, avatars, and generated images. The image-generation gallery's preview was extracted into a generic
MediaPreviewDialog. The json-renderImagecomponent gains azoomprop, the character-portrait gallery and the character-list avatar badges opt into it, and the image gallery now delegates to the same dialog — one enlarge + download surface everywhere. The avatar badge stops its click from also toggling the surrounding collapsible card. TheImagecomponent also gains aframedprop (rounded bordered card + hover) so the portrait gallery's thumbnails match the image-generation gallery's cards — the two read as one family. The enlarge view is a tight lightbox that hugs the image (w-auto) rather than a wide dialog with the image floating in empty space. branch-replyreply-swipe revived as a real feature. The GalGame "swipe between AI replies" plugin shipped active in both default worlds but was a permanently-invisible dead feature — a bootstrap deadlock where the only candidate-writer lived behind a button inside a block that never rendered. It is now a working auto-seeded swipe: after each story turn it captures the narrator's reply as the original (engine-agnostic — discovered via the narrative-output contract, no hardcodednarrator/chat-mode-narratorid), and a Regenerate control produces genuine LLM-generated alternative phrasings (fast slot, session locale) the player can compare and Accept to rewrite prompt history. The original is never re-rendered as a card, so a reply never appears twice; the old English deterministic filler is gone.
Changed
- One plugin-config declaration.
userSettingsis now the single source for player-tunable plugin settings; the dead, never-consumedconfigmanifest field is removed. A stragglerPLUGIN.mdthat still declaresconfig:is stripped with a deprecation warning rather than failing to load. ThePluginUserSettingSpectype is single-sourced in@covel/shared(two divergent copies removed), and its declared constraints (min/max/options/ type) are now enforced — client-side in the SettingsStore and server-side inresolveUserSettings, so an out-of-range world or header value degrades to the manifest default instead of reaching a guard or hook. - Plugin selection consolidated into
pluginPolicy. The deprecated top-levelrequiredPlugins/recommendedPlugins/excludedPluginsnow fold (de-duplicated) intopluginPolicyat world-load time, soWorldRecord.metadatacarries plugin selection in one place. The top-level fields remain valid inworld.yamlfor back-compat. Per-turn world reads are served from a short-TTL per-worldIdcache. - Sample worlds curated to two deeply-built flagships. The bundled set is now Mistport (traditional-story / dark-fantasy mystery) and Haruka Academy (dialogue / GalGame-style), each greatly expanded and doubling as the canonical example of the new fields. Mistport gains a seven-character seed cast, a fourth faction, bilingual lore, and
clues/relics/tidesmemory blocks; Haruka grows to eight characters across five routes withrelationships/promises/rumors/festivalmemory. The redundantcloudmereandneonridgestory worlds move toworlds/_archive/(kept for reference, not loaded).
Fixed
- Player per-plugin settings now actually reach the main turn loop.
POST /api/actions(and the resume / plugin-rpc paths) never decodedX-Plugin-User-Settings, so in the scheduled loop every runtime'suserSettingscollapsed to manifest defaults — a player's UI-tuned values (chat-mode-narrator'sdialogueRatio, cost-gate's token caps) were silently ignored while only the manual plugin-rpc path honored them. The main route now decodes the header and merges it with the world defaults. - The settings header no longer masks world defaults.
X-Plugin-User-Settingswas built from every registered plugin setting (store.get()returns the manifest default for untouched keys), so it always carried a full bucket of defaults that, sent as "player overrides," overrode the new worldpluginSettingslayer. It now carries only the keys a player explicitly set (store.has()). - Archived bundled worlds no longer linger in existing users' databases.
seedWorldsonly ever upserts, so a sample world removed from...
Covel v0.0.9
[0.0.9] - 2026-06-28
A playability-loop pass — function runtimes become visible in the trace timeline, stale suspensions expire, and player-input narrative localizes by session locale — plus a follow-up engineering batch: multi-node S3 media metadata on Postgres, plugin-utils provider-call tracing, a /debug cost panel, and community plugin uninstall/revoke. The default world and bundled plugins are behavior-unchanged.
Added
- Function-runtime trace coverage (A2-P1-5). Function runtimes were near-invisible in
/debug— nothing betweenruntime.started/completed, and zero rows forctx.gatewayprovider calls. They now emitfunction.executing/function.completed(handler boundary) and, via awithGatewayTracewrapper applied at execution time,gateway.calling/gateway.responded/gateway.failedforgenerateText/generateObject— all persisted totrace_eventsand broadcast, so a function runtime's LLM usage is as visible as an agent runtime's. The five events join the single-sourceCovelEventunion (compile-time exhaustive overCOVEL_EVENT_META+ the frontend switch). A missing handler now emits a terminalruntime.failedinstead of leaving a hangingruntime.started. - Plugin-utils provider-call trace. Closes the A2-P1-5 follow-up: image plugins (and any plugin owning its wire) call providers via
ctx.utils.fetchWithRetry, which awithUtilsTracewrapper now traces asutils.fetch.calling/responded/failed(trace-only,forwardToActionStream:false) at both the function-runtime and agent-guard injection sites. PII-safe — payloads carry only host / method / status / durationMs, never the full URL, query, or API key. - Multi-node S3 media metadata on Postgres.
createPgS3MetadataAdapter(+…FromClient) implements theS3MediaMetadataAdapterinterface over the sharedmedia_assets/media_refsPG tables, so S3-backed media survives restarts and is shared across nodes — the SQLite adapter only covered a single node. Mirrors the SQLite adapter 1:1 and passes the same media-store contract suite against a real Postgres. /debugtoken cost panel. A new Cost view aggregatesusagefromllm.responded/gateway.respondedtrace events by runtime, by turn, and session-total (zero-dependency CSS bars), aggregating generically by event type + runtime id. USD cost is a pending follow-up —llm.respondedpayloads don't yet carry the model id needed forusage × pricing.- Community plugin uninstall + approval revoke.
DELETE /api/plugins/:idremoves a third-party plugin from the user plugins dir (rejects builtin ids, returnsrestartRequired:true);DELETE /api/sessions/:id/approvals[?pluginId=]revokes cached approval grants via the newgate.revoke. The Settings → Packages pane lists installed third-party plugins with an uninstall button. Closes the only missing stage of the community discover→approve→import→active lifecycle (the import stage was already live; docs were stale).
Changed
submit-formis now locale-aware. Theconfirmation{{confirmed}}value (确认/取消) and the fallback-narrative prefixes ([玩家输入]/[玩家选择]/[玩家确认]/[玩家取消]) were hardcoded Chinese; they now resolve by session locale (threaded in via a newRpcHandlerContext.locale, sourced fromsession.localein the plugin-rpc dispatch — no executor change).en-USyieldsConfirm/Cancel+[Player input]/…; unknown locales fall back to zh-CN, byte-for-byte identical to the previous output.submit-form'sSubmission.typenow references the single-sourceInteractionTypeunion.- Dependencies bumped to latest stable. All workspace dependencies updated to their latest stable under the existing
minimumReleaseAge: 10080(1-week) gate — including the major bumps@hono/node-server1→2,electron41→42,@types/node25→26,@json-render/*0.18→0.19, andzod4.3→4.4. One breaking change handled: zod 4.4 treats a barez.unknown()inside a.strict()object as a required key, so the plugin user-settingdefaultfield gained an explicit.optional(). Verified across the full workspace lint + test (incl. real Postgres), server boot, API e2e, and the desktop (electron 42) typecheck. - Dependency-hygiene gate + scaffold alignment. Added
knipas a CIdeps:checkgate (catches unused/missing workspace deps; understands JSDoc type imports + test files, so type-only/test-only deps aren't false-flagged), cleaned 12 stale plugin devDeps, and aligned the@covel/createscaffold to emit correctly-layered minimal deps per template. The authoring guide gains a dependency-layering + extraction-threshold section.
Fixed
- Function runtimes no longer leave a hanging
runtime.startedwhen the handler is missing or throws — a terminalruntime.failed(andfunction.completed{status:failed}) is emitted on every exit path. /api/ui-specsno longer 500s when one plugin's runtime fails to load. A single bad runtime (corrupt UI spec, missing handler dep) used to take down the whole response on every world open; it is now logged and skipped while healthy plugins still resolve.app.onErroradditionally logs request context (method + full URL) for every 500.- Desktop packaging now stages plugin-only workspace deps. 5 bundled function plugins depend on
@covel/plugin-handlers-utils(used by plugins, never by@covel/server), whichpnpm deploy --filter @covel/serverleft out — so every packaged build shipped them broken withERR_MODULE_NOT_FOUND. The desktop build now scans each plugin's@covel/*runtime deps and stages any the server deploy missed; the post-staging smoke test fails on plugin-load errors instead of swallowing them.
中文(备份翻译)
一次可玩性闭环整理(function runtime 在 trace 时间线可见、陈旧挂起项过期、玩家输入叙事按会话 locale 本地化),外加一批工程收尾:Postgres 上的多节点 S3 媒体元数据、plugin-utils provider 调用 trace、/debug 成本面板、社区插件卸载/撤销。默认世界与内置插件行为不变。
Added
- Function-runtime trace 覆盖(A2-P1-5):function runtime 此前在
/debug几乎不可见——runtime.started/completed之间空白,ctx.gatewayprovider 调用零记录。现在发射function.executing/function.completed(handler 边界),并经执行期withGatewayTrace包裹对generateText/generateObject发gateway.calling/gateway.responded/gateway.failed——全部持久化到trace_events并广播,使 function runtime 的 LLM 用量与 agent runtime 同等可见。五个事件纳入单一真相CovelEventunion(对COVEL_EVENT_META与前端 switch 编译期穷尽)。缺失 handler 现在发终结runtime.failed,不再留悬空runtime.started。 - Plugin-utils provider 调用 trace:收尾 A2-P1-5 follow-up。图像插件(及任何自带 wire 的插件)经
ctx.utils.fetchWithRetry调 provider,现由withUtilsTrace包裹器在 function-runtime 与 agent-guard 注入处 trace 为utils.fetch.calling/responded/failed(trace-only,forwardToActionStream:false)。PII 安全——负载仅含 host / method / status / durationMs,绝不含完整 URL、query、api key。 - Postgres 上的多节点 S3 媒体元数据:
createPgS3MetadataAdapter(+…FromClient)在共享media_assets/media_refsPG 表上实现S3MediaMetadataAdapter接口,使 S3 媒体跨重启存活、跨节点共享——此前 SQLite 适配器只覆盖单节点。1:1 镜像 SQLite 版,并对真实 Postgres 通过同一 media-store 契约套件。 /debugtoken 成本面板:新增 Cost 视图,按 runtime / turn / 会话总计聚合llm.responded/gateway.responded的usage(零依赖 CSS 条形),按事件类型 + runtime id 通用聚合。美元成本为待办 follow-up——llm.responded负载尚未携带usage × pricing所需的 model id。- 社区插件卸载 + 审批撤销:
DELETE /api/plugins/:id从用户插件目录删除第三方插件(拒绝内置 id,返回restartRequired:true);DELETE /api/sessions/:id/approvals[?pluginId=]经新增gate.revoke撤销缓存授权。Settings → Packages 面板列出已安装第三方插件并提供卸载按钮。收尾社区 discover→approve→import→active 生命周期唯一缺失的阶段(import 阶段早已实现,文档此前陈旧)。
Changed
submit-form现按 locale 本地化:confirmation的{{confirmed}}取值(确认/取消)与回退叙事前缀([玩家输入]/[玩家选择]/[玩家确认]/[玩家取消])此前写死中文;现按会话 locale 解析(经新增的RpcHandlerContext.locale注入,来源是 plugin-rpc dispatch 的session.locale,无需改 executor)。en-US产出Confirm/Cancel+[Player input]/…;未知 locale 回落 zh-CN,与改前输出逐字一致。submit-form的Submission.type现引用单一真相InteractionTypeunion。- 依赖升级到最新 stable:全部 workspace 依赖在既有
minimumReleaseAge: 10080(1 周)门控下升到最新 stable——含跨 major 的@hono/node-server1→2、electron41→42、@types/node25→26、@json-render/*0.18→0.19、zod4.3→4.4。处理了一处 breaking:zod 4.4 把.strict()object 内裸z.unknown()当作必填 key,故插件 user-setting 的default字段显式加.optional()。已通过全 workspace lint + test(含真实 Postgres)、server 启动、API e2e 与 desktop(electron 42)typecheck 验证。 - 依赖卫生 gate + 脚手架对齐:新增
knip作为 CIdeps:check关卡(拦截 unused/missing workspace 依赖;识别 JSDoc 类型引用与测试文件,不误杀 type-only/test-only 依赖),清理 12 个 stale 插件 devDep,并让@covel/create脚手架按 template 生成正确分层的最小依赖。插件指南新增"依赖分层与复用规范"章节。
Fixed
- function runtime 在 handler 缺失或抛错时不再留悬空
runtime.started——每条退出路径都发终结runtime.failed(及function.completed{status:failed})。 /api/ui-specs不再因单个插件 runtime 加载失败而 500:一个坏 runtime(损坏的 UI spec、缺失的 handler 依赖)此前会在每次打开世界时拖垮整个响应;现在记录并跳过,健康插件照常返回。app.onError还会为每个 500 记录请求上下文(method + 完整 URL)。- 桌面打包现在 stage 插件专属的 workspace 依赖:5 个内置 function 插件依赖
@covel/plugin-handlers-utils(只被插件用、不被@covel/server用),pnpm deploy --filter @covel/server把它漏掉了——导致每个打包版本都带着ERR_MODULE_NOT_FOUND的坏插件。桌面构建现在扫描每个插件的@covel/*运行时依赖并补 stage server deploy 漏掉的;打包后的 smoke test 现在会因插件加载失败而失败,不再静默吞掉。
What's Changed
Full Changelog: v0.0.8...v0.0.9
Covel v0.0.8
[0.0.8] - 2026-06-28
Eighth public release. Finishes the v0.0.7 architecture pass — clears the remaining audit debt, makes the schema and transaction layers single-source-of-truth, and ships semantic (vector) memory recall, all verified end-to-end against a real pgvector Postgres. New game genres can declare their own memory blocks, and a session can switch storage backends without any behaviour change. The default world and bundled plugins are behavior-unchanged.
Added
- Semantic (vector) memory recall. The memory tier now embeds turn messages (recall) and lorebook + character records (archival) on write — a post-turn, best-effort sweep that never blocks the turn — and serves KNN recall over them, falling back to keyword search per-session when no embedding model is locked. Embed-on-write ingestion is incremental (a persisted cursor + content hashes) and self-heals deleted records; backfill of existing sessions runs in the same path. Wired through a single injected
embedseam so@covel/memorystill depends only onshared+store. Verified end-to-end on real pgvector Postgres. - A real-pgvector
vector-storecontract branch (PgStore) — the production vector path (upsertVector/searchVectors/deleteVectorsvia thevectortype + pgvector operators) now has automated coverage it previously lacked, plus a memory-vector × PgStore integration test. @covel/settingspackage — the unifiedSettingsStore+ its platform backends (browser localStorage, Electron-IPC json-file) split out of@covel/shared, so pure-types consumers no longer pull in browser/Electron code.
Changed
- Store schema is now single-source-of-truth. The boot DDL is derived at module load from the Drizzle schema (
buildCreateTablesSql), so a column or index is declared once and the executed DDL can never drift from it; only the bits Drizzle can't model (triggers, idempotent column migrations) stay hand-written. Identifiers are quoted uniformly. - Transactions are scoped to a single commit. Production turn-commit / session-create / world-data-sync / snapshot-fork callers moved from the global imperative
beginTx/commitTxshim towithTransaction(fn)(real pooled-Postgres transactions; nested calls on serial backends are rejected, not deadlocked), removing the all-database serialization window. runtime/src's 56 flat files are organized into 13 sub-domain directories (trigger / schedule / agent-loop / commit / session / trace / snapshot / rpc / resume / llm / retry / function-runtime); the public barrel is byte-identical.- Cleared remaining v0.0.7 audit debt: priority-band literals collapse to
isPreGamePriority()/NARRATOR_PRIORITY; the two frontend SSE channels share one event reducer;CompactorLLMAdapter+MemoryLLMAdapterconverge into a sharedSimpleCompletionAdapter; the Anthropic cache-breakpoint cap is one shared constant. - Removed the duplicate turn entrypoint.
POST /api/sessions/:id/turnwas a mounted-but-frontend-unreachable second turn pipeline;/api/actionsis now the single turn-execution route. Its tests migrated to/api/actions. - Bumped all monorepo package versions
0.0.7→0.0.8.
Fixed
- Cross-backend vector parity. A real-PG vector contract immediately surfaced two PgStore-only bugs the Memory/SQLite backends hid: a
freshSchemastore kept stale rows because the dynamicvec_mem_*tables were not dropped, and the upsert/delete paths were untested. A fresh store now starts empty on every backend — the same data, the same API, switch backend freely. - memory recall data-loss / staleness. The recall cursor no longer advances past a message that got an empty embedding (which would drop it from recall forever); short vector results during backfill are topped up with keyword hits so the most recent messages aren't missed; deleted lorebook/character vectors are purged instead of returned as stale hits.
- Snapshot-fork orphaned media refs.
mediaStore.addRef(a cross-store write the DataStore transaction can't roll back) moved to run after the fork commits, so a rolled-back fork (e.g. the cursor-missing 409 path) can no longer leave an orphan ref. - Postgres contract suite no longer races the system catalog under parallel runs (per-file database isolation + single-connection
freshSchemaDDL).
中文(备份翻译)
第八个公开版本。收尾 v0.0.7 的架构整理——清掉剩余审计债,让 schema 与事务层成为单一真相源,并交付向量语义记忆召回,全部用真实 pgvector Postgres 端到端验证。新游戏类型可声明自己的记忆块;一个会话可在不改变任何行为的前提下切换存储后端。默认世界与内置插件行为不变。
Added
- 向量语义记忆召回:记忆层在写入时把 turn 消息(recall)与 lorebook + 角色记录(archival)embedding(回合后 best-effort sweep,绝不阻塞回合),并对其做 KNN 召回;未锁定 embedding 模型时按会话回退关键词检索。写入时 ingestion 增量(持久游标 + 内容哈希)、自愈已删记录、历史会话回填走同一路径。经单一注入的
embedseam 接入,@covel/memory仍只依赖shared+store。真实 pgvector Postgres 端到端验证。 vector-store契约新增 PgStore(真 pgvector)分支——生产向量路径此前零自动化覆盖,现已补上,外加 memory 向量 × PgStore 集成测试。@covel/settings包——统一SettingsStore及平台后端(浏览器 localStorage、Electron-IPC json-file)从@covel/shared拆出,纯类型消费方不再被迫拖入浏览器/Electron 代码。
Changed
- 存储 schema 单一真相源:boot DDL 在模块加载时由 Drizzle schema 派生(
buildCreateTablesSql),列/索引只声明一次、执行的 DDL 不可能漂移;只有 Drizzle 无法建模的部分(触发器、幂等列迁移)保留手写。标识符统一加引号。 - 事务作用域绑定到单次提交:生产的回合提交/建会话/world-data 同步/快照 fork 调用方从全局命令式
beginTx/commitTx垫片迁到withTransaction(fn)(真实 Postgres 池化事务;串行后端的嵌套被拒绝而非死锁),消除全库串行化窗口。 runtime/src的 56 个扁平文件整理进 13 个子领域目录;公开 barrel 逐字节不变。- 清掉剩余 v0.0.7 审计债:priority band 字面量收成
isPreGamePriority()/NARRATOR_PRIORITY;前端两条 SSE 通道共用一个事件 reducer;CompactorLLMAdapter+MemoryLLMAdapter合并为共享SimpleCompletionAdapter;Anthropic 缓存断点上限收成单一常量。 - 移除重复的回合入口:
POST /api/sessions/:id/turn是已挂载但前端不可达的第二条回合管线;/api/actions现为唯一回合执行路由,其测试已迁移。 - 所有 monorepo 包版本
0.0.7→0.0.8。
Fixed
- 跨后端向量一致性:真 PG 向量契约立刻暴露两个 Memory/SQLite 后端掩盖的 PgStore 专属 bug——
freshSchema的 store 因动态vec_mem_*表未被 drop 而残留旧数据,且 upsert/delete 路径未测。现在 fresh store 在每个后端都从空开始——同样的数据、同样的 API、自由切换后端。 - memory 召回数据丢失/陈旧:召回游标不再越过 embedding 为空的消息(否则永久丢失);回填期向量结果不足时用关键词补足,不漏最近消息;已删 lorebook/角色向量被清除而非作为陈旧命中返回。
- 快照 fork 孤儿 media ref:
mediaStore.addRef(DataStore 事务回滚不了的跨 store 写)挪到 fork 提交后执行,回滚的 fork(如 cursor-missing 409)不再留下孤儿 ref。 - Postgres 契约套件在并行下不再竞争系统目录(每文件独立库 + 单连接
freshSchemaDDL)。
What's Changed
- chore(release): v0.0.8 — semantic vector memory + single-source schema/tx (real pgvector verified) by @ackness in #8
Full Changelog: v0.0.7...v0.0.8
Covel v0.0.7
[0.0.7] - 2026-06-27
Seventh public release. An architecture-optimization pass over the kernel and store: duplicated contracts collapse to single, compile-time-enforced sources of truth; the SQLite and Postgres store query layers unify behind one shared adapter with cross-backend parity verified against a real Postgres; and a batch of latent correctness bugs are fixed. The default world and bundled plugins are behavior-unchanged.
Added
memoryBlocksmanifest field +MemoryBlockSchema: core memory blocks are now declared as data by a plugin or world package (the default four — story state / relationships / scene / player profile — ship on the builtinmemoryplugin and are aggregated at bootstrap by trust tier). A new game genre can define its own blocks (clues/suspects/ …) without forking the framework core- cost-gate per-session token budget via
userSettings, read in-hook throughHookContext.getOwnSettings(), with aCOST_GATE_SOFT/HARD_TOKENSenv fallback for env-only deployments /api/ui-specsnow validates each panel spec against a Zod schema with aspecVersion, returns per-spec diagnostics instead of a generic error, and caches discovery by content signature instead of re-scanning + rewriting on every request- A real-Postgres-verified store contract run (713 cases) plus new parity / drift-guard tests: proposal-type ↔ commit-handler ↔ discovery alignment, the SSE event union, hook events, DDL ↔ Drizzle index consistency, table-registry coverage, cross-backend null /
compactedAtTurnIdround-trip, and the prompt cache-breakpoint limit
Changed
- Single sources of truth (compile-time exhaustive). Proposal types (payload map + discriminated union, handlers
satisfies Record<ProposalType, …>), SSE events (oneCovelEventunion driving the forward whitelist + an exhaustive frontend switch), hook events (HOOK_EVENTS), framework capabilities (typed registry), and provider protocols (ProtocolRegistry) each now live in one place — adding one is a single edit and a missing handler/case is a compile error - Store query layer unified. The mirrored SQLite/Postgres record modules collapse behind one async
SqlRunner(better-sqlite3's sync driver wrapped awaitable, postgres-js already async); SQLite snapshots / suspensions converted from hand-written SQL to drizzle, so the SQLite backend now has zero hand-written record SQL. Cascade-delete / drop-list / memory-snapshot table sets derive from a single table-registry, andwithTransaction(fn)scopes a transaction to one commit (real pooled Postgres transaction; nesting on serial backends is rejected, not deadlocked) DataStore's 82-method god-interface split into 21 domain sub-interfaces composed back intoDataStore(shape unchanged);gateway.ts's 7 operations collapse into onerunOperation;parsePluginMd's repeated lenient-field blocks become a data-driven tableLLMAdapter/LLMResponsemoved to@covel/shared, removing the only wrong-layer edge in the dependency graph (create → runtime)- Trigger modes
conditional/error-retryare explicitly marked reserved (they never fire in production); in-turn event fan-out reuses the singleshouldTriggerauthority - Deleted the never-implemented
SessionTransportinterface and unused command-protocol types; pruned unwired prompt-assembler stubs; hoisted the Anthropic cache-breakpoint cap to a single sharedMAX_CACHE_BREAKPOINTS - memory recall / archival are now honestly documented as keyword-based — the vector primitives exist but the embed-on-write ingestion path does not, so a vector searcher would query empty tables; the swap seam is reserved and documented
- Bumped all monorepo package versions
0.0.6→0.0.7; refreshed the README bundled-plugin table (16 → 19, addingcost-gate/director/story-guard)
Fixed
- Resume lost runtime resilience. A suspended-then-resumed agent runtime bypassed retry / loop-detection / streaming (it called the LLM directly); resume now folds into the shared tool loop and goes through the same retry policy as a normal turn
- Cross-backend data loss. SQLite
appendTurnMessagedroppedcompactedAtTurnIdon insert while Postgres / memory / IDB persisted it; all backends now agree (pinned by a parity contract test).createSession/updateSessionalso serialize optional fields uniformly across backends - Production Postgres now creates the
trace_eventstrace_id/turn_idindexes (declared in Drizzle but absent from the runtime DDL); a DDL ↔ Drizzle consistency test guards the drift openai-responsesstreaming now accumulates function-call deltas — agent runtimes on that protocol previously lost every tool call silently/api/discoveryno longer advertises proposal types with no commit handler (record.upsert/narrative.template, removed); theworking_memory.changedSSE event is in the shared union and is no longer dropped by the frontend- The reserved builtin plugin-id list is derived from the bundled plugins instead of a hand-kept list that had drifted to 8/19 (it guards third-party name-squatting)
- cost-gate's env-var budget fallback is reachable again — a declared
userSettingsdefault silently shadowed it, so a custom env value was ignored - The Postgres contract suite no longer races the system catalog under parallel runs (per-file database isolation + single-connection
freshSchemaDDL)
中文(备份翻译)
第七个公开版本。对内核与存储层的一次架构优化:把重复的契约收口为单一、编译期强制的真相源;将 SQLite 与 Postgres 的存储查询层统一到一个共享适配器之后,并用真实 Postgres 验证跨后端行为一致;并修复一批潜在的正确性 bug。默认世界与内置插件行为不变。
Added
memoryBlocksmanifest 字段 +MemoryBlockSchema:核心记忆块现由插件/世界包以数据形式声明(默认四块——剧情状态/关系/场景/玩家档案——随内置memory插件提供,启动时按信任层级聚合)。新游戏类型可定义自己的记忆块(clues/suspects…)而无需 fork 框架- cost-gate 每会话 token 预算改用
userSettings,hook 内经HookContext.getOwnSettings()读取,并保留COST_GATE_SOFT/HARD_TOKENS环境变量兜底 /api/ui-specs现按 Zod schema(含specVersion)校验每个面板 spec、返回逐 spec 诊断、并按内容签名缓存发现结果(不再每次请求扫盘重写)- 一次真实 Postgres 验证的 store 契约(713 用例),以及新增的 parity / 防漂移测试:proposal 类型↔commit handler↔discovery 对齐、SSE 事件 union、hook 事件、DDL↔Drizzle 索引一致性、表注册表覆盖、跨后端 null /
compactedAtTurnId往返、prompt 缓存断点上限
Changed
- 单一真相源(编译期穷尽):Proposal 类型、SSE 事件(单一
CovelEventunion)、hook 事件(HOOK_EVENTS)、框架 capability(typed registry)、provider 协议(ProtocolRegistry)各自收口到一处——新增一个只改一处,漏一个 handler/case 即编译失败 - 存储查询层统一:镜像的 SQLite/Postgres record 模块收敛到一个异步
SqlRunner之后;SQLite snapshots/suspensions 从裸 SQL 转为 drizzle,SQLite 后端现已零手写 record SQL。级联删除/落表清单/记忆快照的表集由单一表注册表派生;withTransaction(fn)将事务作用域绑定到单次提交(真实 Postgres 池化事务;串行后端的嵌套会被拒绝而非死锁) DataStore的 82 方法上帝接口拆成 21 个领域子接口再组合(形状不变);gateway.ts的 7 个操作收敛为一个runOperation;parsePluginMd的重复 lenient 块改为数据驱动的表LLMAdapter/LLMResponse移到@covel/shared,消除依赖图里唯一的错位边(create → runtime)- 触发模式
conditional/error-retry明确标注为 reserved(生产从不触发);回合内事件 fan-out 复用单一shouldTrigger - 删除从未实现的
SessionTransport接口与未用的命令协议类型;清理未接线的 prompt-assembler 残桩;把 Anthropic 缓存断点上限提成单一共享的MAX_CACHE_BREAKPOINTS - memory recall/archival 现诚实记录为关键词检索——向量原语存在但缺少写入时 embedding 的 ingestion,向量检索会查空表;扩展点已预留并文档化
- 所有 monorepo 包版本
0.0.6→0.0.7;刷新 README 内置插件表(16 → 19,补cost-gate/director/story-guard)
Fixed
- Resume 丢失运行时韧性:挂起后恢复的 agent runtime 绕过了重试/循环检测/流式(它直接调 LLM);resume 现在并入共享工具循环,走与正常回合相同的重试策略
- 跨后端数据丢失:SQLite
appendTurnMessage在 insert 时丢掉compactedAtTurnId,而 Postgres/memory/IDB 保留;现所有后端一致(由 parity 契约测试钉住)。createSession/updateSession的可选字段序列化也跨后端统一 - 生产 Postgres 现会创建
trace_events的trace_id/turn_id索引(Drizzle 声明了但运行时 DDL 缺失);DDL↔Drizzle 一致性测试守护漂移 openai-responses流式现累积 function-call 增量——此前该协议下的 agent runtime 会静默丢掉每一次工具调用/api/discovery不再广告没有 commit handler 的 proposal 类型(已删除record.upsert/narrative.template);working_memory.changedSSE 事件已纳入共享 union,前端不再丢弃- 保留的内置 plugin-id 名单改为从内置插件派生,取代漂移到 8/19 的手维护列表(它用于防第三方占名)
- cost-gate 的环境变量预算兜底重新可达——一个声明的
userSettings默认值曾静默压过它,导致自定义 env 值被忽略 - Postgres 契约套件在并行运行下不再竞争系统目录(每文件独立库隔离 + 单连接
freshSchemaDDL)
What's Changed
- chore(release): v0.0.7 — architecture optimization (contract collapse + store unification) by @ackness in #7
Full Changelog: v0.0.6...v0.0.7
Covel v0.0.6
[0.0.6] - 2026-06-26
Sixth public release. Expands the runtime hook system from 8 to 16 lifecycle events, ships the first plugins that consume them, and lands a batch of runtime-architecture refactors and static-audit fixes. The default world and bundled plugins are behavior-unchanged — the new hooks are dormant infrastructure and the three new plugins are opt-in.
Added
- Hook lifecycle expanded 8 → 16 events:
PreLLMCall/PostLLMResponse(non-destructively rewrite a per-call request / patch the response before tool dispatch),PostContextAssembly(turn-level system-prompt / history shaping),PreSchedule(narrow which runtimes run this turn),PreCompaction/PostCompaction(veto / observe history compaction),SessionStart/SessionEnd(session lifecycle), andPostToolUse.terminate(end the tool loop after recording a result) - Session-scoped hook pipeline: the global pipeline now filters hooks by the session's active plugins via
AsyncLocalStorage, so a plugin's hooks only fire for sessions where it is active HookContext.getOwnSettings(): a hook can read its own plugin's per-sessionuserSettings(turn-level, read-only, deep-frozen snapshot)- Three new opt-in plugins — the first hook consumers:
cost-gate(per-session token budget; included by default in the front-end Low Cost pack),director(PostContextAssembly— one consistent narration preamble across all story runtimes), andstory-guard(PostLLMResponsecontent sanitisation +PreToolUsehigh-risk-tool deny-list) EventBus.flush()durability barrier for the best-effort audit-event streamPostContextAssemblypayload carries a read-onlyoutputKindso handlers can target specific runtime kinds without hardcoding plugin ids
Changed
- Bumped all monorepo package versions
0.0.5→0.0.6 TurnStart/PostRuntime/PostToolUsehooks are nowsequential, so their abort / replace paths actually take effect (previously dead code underparallel)- Runtime refactors (behavior-preserving):
AgentLoopDepsnarrow seam isolating the core agent loop from orchestration deps;RuntimeInvocationoptions object replacingexecuteOneRuntime's 19 positional args; a singleresolveTurnCapabilityPluginIdssource for capability-discovered plugin ids - Registered all new hook events in the three plugin-loader whitelists (a plugin declaring them was previously dropped at parse time)
Fixed
- Session-scoped every server commit / hook entry point (turn, actions, plugin-rpc, the commit processor, resume, characters, and session routes) so a plugin's hooks never fire for sessions where it is inactive
PreSchedulecan no longer drop Pre-Game runtimes while Pre-Game is pending — a hook can shape main-loop scheduling but not break session initialization- Resume path now fires
PreLLMCall/PostLLMResponseand scopes the resumed plugin's own hooks (both were silently skipped for a suspended-then-resumed runtime) SessionStart/SessionEndhardened with local try/catch so a handler failure can never turn a committed create / end / delete into a 500- Plugin loader: an object i18n
descriptionis preserved when a plugin also declareshooks(the combination previously failed frontmatter validation) - Added unit coverage for
computeSessionTurnCount(the turn-count module had none) and clarified that an empty main-loop turn counts as a player turn
中文(备份翻译)
第六个公开版本。将运行时 hook 生命周期从 8 个扩展到 16 个事件,交付首批消费这些 hook 的插件,并落地一批运行时架构重构与静态审计修复。默认世界与内置插件行为不变——新 hook 是休眠基础设施,三个新插件均为可选启用。
Added
- hook 生命周期 8 → 16:
PreLLMCall/PostLLMResponse(按调用非破坏性改写请求 / 在工具分发前改写响应)、PostContextAssembly(回合级系统提示/历史塑形)、PreSchedule(收窄本回合运行的 runtime 集)、PreCompaction/PostCompaction(否决/观察历史压缩)、SessionStart/SessionEnd(会话生命周期)、PostToolUse.terminate(记录结果后结束工具循环) - 会话作用域 hook 管线:全局管线经
AsyncLocalStorage按会话激活插件过滤,插件 hook 只对其激活的会话触发 HookContext.getOwnSettings():hook 可读本插件本会话的只读userSettings(回合级、只读、深冻结快照)- 三个新的可选插件(首批 hook 消费者):
cost-gate(每会话 token 预算,默认进前端 Low Cost 组合包)、director(PostContextAssembly给全部 story runtime 注入统一导演前言)、story-guard(PostLLMResponse内容净化 +PreToolUse高危工具拦截) EventBus.flush()持久化屏障;PostContextAssemblypayload 增加只读outputKind
Changed
- 所有 monorepo 包版本
0.0.5→0.0.6 TurnStart/PostRuntime/PostToolUse改为sequential,其 abort/replace 分支才真正生效(此前在parallel下是死代码)- 运行时重构(行为保持):
AgentLoopDeps窄接缝隔离核心 agent 循环、RuntimeInvocation选项对象替代 19 个位置参数、resolveTurnCapabilityPluginIds单一来源 - 三个 loader 白名单注册全部新 hook 事件
Fixed
- 会话作用域覆盖所有 server commit/hook 入口(turn/actions/plugin-rpc/提交处理器/resume/characters/session 路由)
PreSchedule在 Pre-Game pending 时不能丢弃 Pre-Game runtime- resume 路径接入
PreLLMCall/PostLLMResponse并修正 resume 时被恢复插件自身 hook 的作用域 SessionStart/SessionEnd本地 try/catch 固化 observe-only- 插件加载器:i18n 对象
description与hooks并存不再校验失败 - 补
computeSessionTurnCount单测,并澄清空主循环回合计为玩家回合
What's Changed
- docs(changelog): v0.0.5 entry English-first by @ackness in #5
- Hook system expansion + runtime architecture refactors + audit fixes by @ackness in #6
Full Changelog: v0.0.5...v0.0.6
Covel v0.0.5
[0.0.5] - 2026-06-16
Fifth public release. An internal, code-quality-focused refactor: systematic de-duplication across storage backends and the plugin layer, decomposition of oversized files, unified conventions, and isolation/data-flow fixes. No user-facing behavior change (except an intentionally unified API error-response envelope).
Added
- New
@covel/plugin-handlers-utilspackage providing shared pure-function helpers for plugin function-runtime handlers (eliminates verbatim-duplicated helpers and proposal construction across 5 plugins) - New
FrameworkCapabilityconstant and type inpackages/shared, consolidating framework-consumed capability tags so bare-string typos can no longer silently disable features - Unified API error-response envelope
ApiErrorResponsewith anerrorBodyfactory
Changed
- Bumped all monorepo package versions
0.0.4→0.0.5 - Store: extracted shared cross-backend mappers/insert-values, removing PG/SQLite duplication (~1145 lines); split
types.tsandcommon/mappersby domain - Runtime/Context: extracted commit validators and LLM telemetry; split turn-agent-tool-loop / llm-retry / turn-agent-runtime / prompt-assembler
- AI-Provider: de-duplicated adapter parameter extraction / metadata sanitizing; externalized model-capability data from inline TS (950 lines) to JSON; de-duplicated gateway fallback; split env registry and plugin schema by domain
- Server: unified error envelope, replaced 37+ session-404 checks with a
resolveSessionParammiddleware, split the bootstrap/install/worlds mega-routes - Web: removed dead code, decomposed several oversized components by responsibility, unified silent error-swallowing into a visible
ignoreError
Fixed
- Fixed
characters.tshardcoding a framework plugin ID in violation of the framework↔plugin isolation rule (now usesframeworkProposalSource) - Fixed a PG
value-field NULL-semantics regression introduced by cross-backend de-duplication (restored returningnull, unified across both backends) - Fixed character-panel staleness on the char-creator write path (restored and improved the post-turn snapshot resync)
- Fixed a React anti-pattern where the confirmation dialog ran side effects inside a setState updater
Note: macOS build is unsigned/un-notarized (CI builds with
CSC_IDENTITY_AUTO_DISCOVERY: false). On first launch, right-click the app → Open. arm64 only; build Windows/Linux from source.
中文(备份翻译)
第五个公开版本。一次以代码质量为核心的内部重构:消除跨后端与插件层重复、拆分巨型文件、统一约定、修复隔离与数据流问题。对外行为保持不变(除有意统一的 API 错误响应信封)。
Added
- 新增
@covel/plugin-handlers-utils包,为插件 function-runtime handler 提供共享纯函数工具(消除 5 个插件中逐字重复的 helper 与 proposal 构造) packages/shared新增FrameworkCapability常量与类型,收敛框架消费的 capability 标签,避免裸字符串拼写漂移导致功能静默关闭- 统一 API 错误响应信封
ApiErrorResponse与errorBody工厂
Changed
- monorepo 全量版本号
0.0.4→0.0.5 - Store:抽取跨后端共享 mapper/insert-values,消除 PG/SQLite 重复(约 1145 行);
types.ts与common/mappers按域拆分 - Runtime/Context:抽取 commit 验证器与 LLM 遥测,拆分 turn-agent-tool-loop / llm-retry / turn-agent-runtime / prompt-assembler 等大文件
- AI-Provider:适配器参数提取/元数据清理去重;模型能力数据由内联 TS(950 行)外置为 JSON;gateway fallback 去重;env registry 与 plugin schema 按域拆分
- Server:错误信封统一、
resolveSessionParam中间件替换 37+ 处会话 404 检查、bootstrap/install/worlds 大路由拆分 - Web:清理死代码、按职责拆分多个巨型组件、统一静默吞错为可见的
ignoreError
Fixed
- 修复
characters.ts硬编码框架插件 ID 违反框架↔插件隔离规则(改用frameworkProposalSource) - 修复跨后端去重引入的 PG
value字段 NULL 语义回归(恢复返回null,两后端统一) - 修复角色面板在 char-creator 写入路径下的同步问题(恢复并改进 turn 完成后的快照重同步)
- 修复确认对话框在 setState updater 内执行副作用的 React 反模式
What's Changed
- fix: resolve 2026-06-04 audit findings (isolation, perf, ux, a11y) by @ackness in #1
- fix: 2026-06-04 audit — framework isolation, perf, UX, a11y + cleanups by @ackness in #2
- chore(release): v0.0.5 — 代码质量重构 by @ackness in #4
New Contributors
Full Changelog: v0.0.4...v0.0.5
Covel v0.0.4
[0.0.4] - 2026-05-28
第四个公开版本。重点收敛回合流稳定性、插件/会话解析、框架可见文本本地化、插件模板质量与发布文档。
Added
- 新增静态回合审计 skill,用于检查 turn flow、插件边界与运行时输出相关风险
- 插件模板新增 runtime cases 与可运行 note/analyst 示例,create-plugin / create-world skills 补齐验证指引
- 桌面主进程错误与启动文案补齐中英文 i18n 支持
Changed
- monorepo 全量版本号
0.0.3→0.0.4 - 加固 turn flow、插件解析、会话插件 API、snapshot / trace / working-memory 等运行时边界
- 简化 prompt context feature gates,整理 context builder、prompt assembler 与 serialization 相关实现
- 刷新 production Docker image、release docs、README 与贡献文档;移除过期本地开发草稿和废弃模板脚手架
Fixed
- 修复框架 UI 中残留的硬编码可见文本,补齐对应中英文 locale
- 修复插件 metadata、runtime loading、form submission、suspend/resume 与 post-turn memory 相关测试覆盖
- 修复 desktop asset import、IPC handler、splash/startup error 路径与 release staging 相关边界
Full Changelog: v0.0.3...v0.0.4