Repository navigation
v1.5.0
@veyyon/stats
Changed
- Removed the duplicate JavaScript build script; the TypeScript build entrypoint produces unchanged dashboard assets.
- Centralized shared request and error data table renderers across overview, requests, and errors routes.
- The per-type breakdown labels spawned sessions as "Spawned agents" while preserving the
subagentdiscriminator and historical token and cost totals. - The package directory is
apps/statsinstead ofpackages/stats; the published package name, entry points and behavior are unchanged. - Array copies that allocated with a spread now use
.slice(),.concat()orArray.from(). No user-visible behavior changes. - Repointed a doc comment at
@veyyon/kernel/session/session-entries, where the session header type now lives; no behavior change. - Array spreads over iterators in the dashboard aggregators are
Array.fromcalls and source comments referenceapps/statsandclients/web; no user-visible change. - The
/api/stats/*routes are one table of reads in the server rather than oneifblock each; every route answers the same JSON. - Every backfill reads and writes its
metasentinel through one pair of helpers, and the two file-offset re-parses share one enrol-and-wipe step; each backfill runs once, as before. - User and assistant session messages qualify for linking through one role-and-id check; a message without an id is skipped from both statistics, as before.
Fixed
- Corrected comments that named a distribution channel or runtime API the project does not use; no behavior change.
@veyyon/collab-web
Changed
- The package directory is
clients/webinstead ofpackages/collab-web; the package name, the relay and the guest client are unchanged. - Updated collaboration client to protocol v4, carrying tool execution displays on active tool state and tool result messages.
@veyyon/host
Added
@veyyon/hoststates what a host offers a plugin:HostNotificationandHostNotifier, each capability optional and absent when the host cannot honour it. The package imports nothing.
@veyyon/model
Added
Model.longContextCostdeclares the second rate card a model bills at once its prompt crossesinputThresholdtokens.@veyyon/modelstates the model and message vocabulary: theModelrow with its thinking config and theEffortladder, theMessageenvelope with its content blocks and the streamedAssistantMessageEventunion, theToolCallMetricsandAssistantTurnMetricsstudy records, and the service-tier vocabulary. A provider implements a stream and a host reads a turn without importing the catalog that resolves the model or the client that drives it. The package has no dependencies.
@veyyon/plugin
Added
@veyyon/pluginstates the plugin manifest vocabulary:PluginManifest,PluginFeature,PluginSettingSchemawith its four setting kinds andPluginSettingType. A package declares what itspackage.jsonveyyonfield contributes without importing the loader that installs it or the host that draws its settings. The package has no dependencies.
@veyyon/session
Added
@veyyon/sessionstates what a session file is made of: theSessionEntryvocabulary, theAgentMessageunion and theCustomCompactionSessionEntriesandCustomAgentMessageshooks a package augments. It imports only types from@veyyon/model.
Changed
- Doc comments refer to a spawned session as an agent and to its record as
AgentSpawnEntry; the persistedsubagent_spawnentry type is unchanged.
@veyyon/settings
Added
@veyyon/settingsstates the setting declaration vocabulary:SettingDefand its seven definition kinds,SettingTypewithSETTING_TYPESandisSettingType,SettingTab,AnyUiMetadataandSubmenuOption. A package declares a setting in this vocabulary without importing the store that persists it or the host that draws it. The package has no dependencies.
Changed
- The
SettingTabmember for the agent pages isagentsinstead ofsubagents; the tab is an in-memory id and no persisted setting key changes.
@veyyon/tool
Added
@veyyon/toolstates what a tool declares and returns:ToolSpecwith its examples, theToolTierandToolApprovalvocabulary,ToolResultandToolUpdateCallback. A tool declares itself without importing the loop that schedules it or the host that prompts for approval. The package imports the message content blocks from@veyyon/model, type-only, and nothing else.
@veyyon/view
Added
@veyyon/viewstates the host-agnostic tool view model:ToolView,StatusRowView,TextBlockView,ViewSpan,ViewTone,ViewStatusandToolViewRenderer. A tool returning one of these describes its output without importing a terminal component or receiving a theme, so any host can draw it. The package has no dependencies.ToolViewContextstates the disclosure state a host passes to a view renderer, so a tool can show a shorter summary collapsed and its full output expanded without naming a host.FramedBlockViewstates a framed panel: aStatusRowViewheader, an optionalViewStatusthe host reads for the rail colour, andViewSections ofViewLines, so a tool describes a card without negotiating a width.StatusRowView.emblemnames a symbol a host resolves from its own registry, falling back to the row's status icon when the host has no such symbol.ToolViewRenderer.renderResultreceives the call arguments alongside the result, so a card whose header states the operation still states it when the call failed and returned no details.ViewSpan.symbolnames a symbol a host resolves from its own registry for one span inside a line, drawn in that span's tone;textis what a host without such a symbol draws instead.HeadedBlockViewstates a frameless card: an optionalStatusRowViewheader,ViewLines under it, and aViewHiddenCountnaming what a preview held back, so a terse tool card describes its rows without picking an indent, a width or the gesture that reveals the rest.ViewTonecarries anoutputtone for text the tool itself produced, so a card that shows tool output states that rather than reaching for a colour name.ViewSpan.linkandStatusRowView.descriptionLinkname a target a run of text points at, so a card states where a URL leads without writing a terminal escape sequence, andViewTonecarries alinktone for text that is a target.ViewSection.hiddenstates what a section held back as aViewHiddenCount, so a framed card discloses the rows it did not draw the same way a headed card already did.FramedBlockView.contentsdistinguishes a card whose body is a status report from one whose body is fetched data, so a host paints the outcome across a report and leaves fetched content on its own ground.NoticeViewstates a short notice whose whole body carries one state — a headline, an optional tag and lines under it — so a tool describes a decision without filling a plate itself; a span inside a notice states emphasis and structure, never colour.ToolViewContext.partialstates whether the result in hand is the tool's last word or an update it will replace, so a card that streams reports running rather than reading an outcome off a half-finished result.ViewSection.tailstates that a section is a window onto the end of its lines, measured by the host in the rows the lines occupy after wrapping, so a tool that cannot know a width or a viewport height still keeps the end of a long command or a long output on screen.HeadedBlockView.tailstates that a headed card's lines are a window onto their end, the bargainViewSection.tailstrikes for a card with no sections to strike it in, so a stream of output whose newest rows matter is stated whole and cut by the host.ViewSpan.trailingstates that a run is trailing detail on its line, so a host with columns to spare places it at the line's end and pads the runs that lead it, and a host drawing one column after another writes it where it falls.StatusRowView.descriptionFileLinestates the line insidedescriptionFilea row names, so a card that read one window of a file sends a reader to that window rather than to the file's first line.ViewCodeLines.lineNumbersstates the number each line has in the file, one entry per line, for a section that is several windows onto one file: the rows are in file order and the numbers jump, and anullentry is a row standing in for an elided span.ViewSection.markdownstates that a section's lines are a document rather than source, so a tool that read a.mdfile says what the text is and leaves headings, emphasis and layout to the host.ViewSpan.markdownstates that one run of a line is Markdown written for a single line, so the label of an offered choice keeps the emphasis its author wrote without the tool deciding what bold looks like; a host with no renderer draws the source.ViewSpan.statusstates that one run is the state mark of its line, drawn from the host's own glyph set and animated while the state moves, so a card whose body is a set of things each doing something marks every row without naming a glyph.ViewSpan.badgestates that one run is a short label the host sets off in its own bracket grammar, the line-level twin ofStatusRowView.badge, so a row that marks what kind of thing it names leaves the brackets to the host.ViewSpan.livestates that the thing a run names is still in flight, so a host with a clock may animate that run alone while the settled columns beside it stand still, and a host with no clock draws it in its tone.StatusRowView.descriptionFitsstates that a row must keep its description whole by shortening it inside itself, so a card whose description is the file it acted on keeps both the path and the counts after it, and a card whose description is prose is left for the host to clip at its own edge.ViewSpan.agentIdstates a semantic agent identifier for subagent drill-down navigation in hosts that support it.UNICODE_SYMBOLSandSymbolKeyare the one table of glyphs every host draws a symbol, emblem or status mark from, moved here from the terminal's theme so the GUI and the web renderers draw the same✎fortool.edit.ToolViewContext.showResolvedModelstates whether the surface shows the model a spawned agent resolved to beside its name; the surface reads the setting and the view receives the answer, so a transcript export with no setting store draws the same card with the badge off.
Changed
- Doc comments refer to the spawned-agent wall as the agent wall. No behavior change.
ViewSpan.symbolnames a key ofUNICODE_SYMBOLS; a key no host has draws the span'stext, never the key.
@veyyon/wire
Breaking Changes
- Bumped
COLLAB_PROTOto4: tool execution display projections (ToolExecutionDisplay) are carried on tool calls, tool results, and live execution events. Old guests speaking proto v3 or below are rejected with the protocol-mismatch error.
Added
- Tool execution display metadata includes per-call grouped-read status, paths, previews and line numbers.
@veyyon/wire/presentationstates the renderer contract:PresentationContext, the transcript, status, composer and overlay view-models, theUIEventunion and an abstract hex-colour theme. A renderer implementing it draws a session without importing coding-agent. The subpath adds no dependencies.@veyyon/wire/collab-linkowns the collab link grammar:encodeBase64Url,decodeBase64Url,isLocalHostname,normalizeRelayOrigin,generateRoomId,formatCollabLinkPayload,formatCollabLinkandparseCollabLink, besideROOM_ID_BYTES,ROOM_KEY_BYTES,WRITE_TOKEN_BYTES,DEFAULT_RELAY_URLandParsedCollabLink, which moved there and are re-exported from the barrel unchanged; base64url goes throughatob/btoaso the browser guest and the host run the same code.
Changed
TextContent,ImageContent,ThinkingContent,RedactedThinkingContent,ToolCallContent,FallbackContent,WireStopReasonandWireUsagearePickprojections of the shapes@veyyon/modelowns, imported type-only, with the same fields as before; the package declares@veyyon/modeland no runtime dependency.AgentProgressPayloadandAgentLifecyclePayloadare the payloads on thetask:subagent:progressandtask:subagent:lifecyclebus channels;SubagentProgressPayloadandSubagentLifecyclePayloadremain exported as the same types, and the channel spellings are unchanged.generateRoomKeyandgenerateWriteTokenreturn the filled random buffer directly; the key and token lengths are unchanged.
@veyyon/tui
Breaking Changes
@veyyon/tuiexports rendering only. The string, escape, keyboard, mouse, motion and layout-math primitives it also carried are now@veyyon/utilsmodules, imported by subpath:@veyyon/utils/{ansi,autocomplete,bar,bracketed-paste,deccara,fuzzy,keybindings,keys,kill-ring,kitty-graphics,latex-block,latex-unicode,loop-watchdog,motion,mouse,padding,paint-columns,paint-ground,paint-surface,sgr,symbols,tab-width,text-sizing,tight-mode,tmux,width,word-nav,wrap}. The barrel re-exports none of them.MOTIONand the grow, hover, paint and settle curve tables are one module,@veyyon/utils/motion.EditorComponentis@veyyon/tui/components/editor-component.- Render engine modules are available through
@veyyon/tui/core/*:component-types,container,cursor,image-budget,mouse-routing,overlay,renderer,scroll,terminal-sessionandtui; existing TUI contract imports remain available through@veyyon/tui/tui. TUI.overlayStackis private. The overlay stack's behavior isOverlayStackin@veyyon/tui/core/overlay.getTerminalIdis@veyyon/utils/ttyid, andImageFallbackReasonis@veyyon/utils/image-fallback. Neither is rendering, and a caller that needs a session id or the name of a cause no longer depends on the terminal renderer to get it.detectTerminalIdandTerminalIdare exported from@veyyon/utils/terminal-emulatorinstead of@veyyon/tui/terminal-capabilities.
Added
- Components can provide
measureHeight(width)for layout measurement without constructing rendered rows. - Forced render requests accept
preserveViewportto paint changed rows immediately while retaining pending full-repaint and scrollback requests. TUI.frameScrollablestates whether the last composed frame had content above the viewport, so a host can render a scroll affordance without re-deriving it from row counts it cannot see.- The package is
hosts/terminal/enginein the repository, beside the other halves of the terminal host. The published package name, exports and entry points are unchanged.
Changed
Editor.setCursorclamps its line and column throughclampLowfrom@veyyon/utils/math; no behavior change.EditorandInputdeliver a chunk's typed prefix, paste payload and remainder throughBracketedPasteHandler.routewith sinks built once per component; the bytes each part reaches are unchanged.- Input drain and terminal stop pop the kitty keyboard protocol, cancel the pending modifyOtherKeys probe and reset modifyOtherKeys through one
#disableKeyboardProtocols; the bytes written at shutdown are unchanged. - The Markdown component derives the default text style's SGR prefix from the same style chain that paints its text; no behavior change.
- Cursor movement sequences and overlay percentage parsing use shared implementations without changing terminal output.
- Collapsed and deduplicated scroll math, search input filtering, border framing, cursor deletion and autocomplete helpers across engine components without changing rendering or behavior.
- Direct writes and component-scoped rendering share layout-reuse checks, and frame rendering shares cursor-marker extraction, selection and row-divergence scans without changing terminal output.
- Markdown rendering uses the shared HTML entity decoder without changing displayed text.
- Text layout and pointer-hover state use shared implementations without changing rendering or input handling.
- The overlay stack resolves its topmost painted and topmost focusable entries by one reverse scan; focus and pointer routing are unchanged.
- The ConPTY post-full-paint settle arms and cancels its trailing render timer through one pair of steps; a render requested inside the window still paints once the window closes, and a forced render still discards the pending trailing render.
- The single-line
Inputanswers its editing keybindings from one ordered table, and a key bound to two of them runs only the first. - Array copies that allocated with a spread now use
.slice(),.concat()orArray.from(). No user-visible behavior changes. onBackgroundColorChangeandonAppearanceChangeregister and replay a late subscriber through one step; a subscriber that throws during replay is logged and the others still run, as before.TerminalNotificationextendsHostNotificationfrom@veyyon/utils/host-notification, so a terminal is one host that can deliver a tool's notification and the two shapes cannot drift apart.visualColAtOffsetandoffsetAtVisualColare exported from@veyyon/utils/widthand shared byEditorandInput.- Source comments refer to the spawned-agent HUD as the agent HUD. No behavior change.
Fixed
- Disposing a
Boxdisposes its child components and their resources. - Enter submits the current message when an edit has invalidated the open file-completion popup.
- Independent offscreen edits no longer accumulate into a false history rebuild, and changes to plain components preserve committed history until an explicit replay.
- A sixel-capable terminal now renders inline images on Linux and macOS: the terminal is asked at startup instead of being matched against a list that named no sixel terminal at all, so images no longer silently fail to appear outside kitty, ghostty, wezterm, iTerm2 and Warp.
- An inline image whose top has scrolled above the viewport, or which is taller than the terminal, is left undrawn until a repaint can reach its origin, instead of being stamped at full size over the top of the live transcript.
- An inline image is handed pixels at exactly the cell box the terminal will scale it into, so the terminal's own scaler no longer smears a downscaled screenshot; the transmitted payload shrinks by more than half at the same size on screen.
- The row shown in place of a picture names the setting that undoes the reason when there is one, instead of stating the reason alone.
- A frame that shrinks below the committed boundary with the composer focused (an IRC card expiring, a displaced todo snapshot retracting, an agent sub-row or HUD row going, the ask dialog's inline editor collapsing) re-shows the frame tail without lowering the commit index, so the rows it re-shows are never appended to native scrollback a second time when the frame grows back; under a tall running tool card this appended the same rows on every insert/retract cycle and left thousands of copies of one status row in scrollback.
- A frame that grows back while its window still shows rows below the commit boundary keeps sliding the window in place until it passes that boundary, with or without a focused cursor, instead of painting a window shorter than the viewport with blank rows under it.
@veyyon/kernel
Added
@veyyon/kernelis a workspace member: the loader, the contribution registry and the session spine, moved out of@veyyon/coding-agentunchanged. It names no tool, no host and no mode, andscripts/the-kernel-names-no-tool-and-no-host.test.tsfails on the first edge that does.@veyyon/kernel/session/*publishes the session spine: entries, storage backends, persistence, migrations, listing, paths, retry policy, compaction policy, machine budget and the turn's owned resources.@veyyon/kernel/loader/*publishes plugin discovery, manifest parsing, the installed registry, the marketplace client and load-failure reporting.@veyyon/kernel/registry/*publishes generic contribution interfaces, tool proxying, widget and host-view declarations, and TypeBox schema conversion.@veyyon/kernel/registry/tool-domaindeclaresToolDomainManifest, the name and lazy-factory table a tool domain contributes, so a host reads a domain's tools without depending on the coding agent.SubagentSpawnEntryandSubagentSpawnRecordin@veyyon/kernel/session/session-entriesareAgentSpawnEntryandAgentSpawnRecord; the persistedsubagent_spawnentry type is unchanged.@veyyon/kernel/registry/message-kinddeclaresAgentMessageKind, a transcript role a tool domain records with its conversion to provider messages and to text, andToolDomainManifest.messageKindscarries a domain's kinds;@veyyon/kernel/session/message-kindsis the role-keyed table the session spine converts them through, which throws on a role no domain declared and on a second kind for one role.@veyyon/kernel/session/session-manager,session-context,session-loaderandagent-storagepublish the session manager, its context builder, its file loader and the credential store, moved from@veyyon/coding-agent/session/*unchanged;session/custom-message-payloadpublishes the custom-message payload normaliser and the rehydration sanitiser they call.@veyyon/kernel/settings/schemapublishes the settings schema registry:declareSettingsregisters a package's table and rejects a path declared twice,DeclaredSettingsmerges each table's type soSettingPathandSettingValuespan every registered table, andgetDefault,getType,getUi,hasUi,getPathsForTab,retiredBy,isSettingPath,getEnumValues,isUnsetNumberPathanddescribeSettingTypeMismatchanswer from the registry; a query before any table has registered, or for a path no table declares, throws naming the cause.@veyyon/kernel/settings/optional-numberpublishes the unset-number owner, moved from@veyyon/coding-agent/config/optional-numberunchanged.@veyyon/kernel/settings/storepublishesSettingsStore, the layered settings store moved out of@veyyon/coding-agent/config/settings: the profile, overlay and runtime layers and their merge,get,set,unset,override,getSource,isConfigured,layerValue, the YAML load with quarantine and type-mismatch collection, the debounced locked text-preserving save with its failure report,forkWithRuntimeOverrides,cloneForCwd,reloadForCwdand the one-shot migration stamp (stripLegacyUnsetSentinels,stampOwnedConfigMigrations,SETTINGS_MIGRATION_VERSION), withRawSettings,SettingsOptions,SettingSource,SettingsSaveFailure,InvalidSettingValue,QuarantinedSettingsFile,getByPath,setByPath,deleteByPathanddeepMergeSettings. The store takes aSettingsStoreHooksat construction (globalBinding,migrate,loadLegacySources,afterOwnedConfigLoaded,resolveForCwd,applyHook,applyAllHooks,notifyEffectiveChange,mergedViewRebuilt) and names no setting.@veyyon/kernel/settings/signalpublishesSettingSignal,clearSettingSignalsandsettingSignalListenerCounts, moved unchanged.
Changed
- Session listing reuses a per-directory index for files whose size and mtime are unchanged instead of rescanning every file, cutting a 4,825-session
/resumelist from 6.8 s to 185 ms when a session changed and 88 ms when none did. - Resolving a session id that no directory in the active profile holds reads the other profiles through the same per-directory index, cutting that lookup from 2.5 s to 126 ms.
- Settings mutations and session storage writers share implementations without changing persistence, hook ordering or error behavior.
- Installed plugin registry readers share JSON validation while preserving numeric-version handling and malformed-file behavior.
- Plugin runtime configuration uses the shared record validator; behavior is unchanged.
- Edit-specific event normalization remains in
@veyyon/coding-agent/extensibility/tool-event-input; event payloads are unchanged. - Settings lookups reuse immutable registry key snapshots and build derived indexes in one pass after registrations or resets.
- Settings stores share layer copying and override application while retaining profile values, per-directory resolution and isolated save-failure reports.
- Session title overlays avoid encoding and copying the full transcript when the first line occupies the fixed 256-byte slot.
- The TypeBox
unknownconverter is theanyconverter, which had the same body; emitted schemas are unchanged. - Session entry validation shares non-empty string checks, and branch labels avoid temporary identifier arrays.
@veyyon/kernel/settings/storeexportsgroupSettingPaths, memoizing prefix-grouped schema paths on the schema index with automatic invalidation on schema resets.- Array copies that allocated with a spread now use
.slice(),.concat()orArray.from(). No user-visible behavior changes. @veyyon/kernel/session/session-entriesreads the shared entry vocabulary from@veyyon/sessionand registers its own entry kinds there; every name it exported is still exported and no file format changes.- The plugin manifest vocabulary (
PluginManifest,PluginFeature,PluginSettingSchemaand its setting kinds,PluginSettingType) moved from@veyyon/kernel/loader/plugins/typesto@veyyon/plugin;InstalledPlugin, the lock-file state, the project overrides and the doctor and install option types stay. - SQL session storage consolidates parameterized queries across PostgreSQL, MySQL, and SQLite dialects.
Fixed
- Settings queries ignore inherited object properties.
Type.Pickemits the keys it was asked for in the order they were asked for, and keeps a picked key that is own-but-non-enumerable on the validated value.- A session whose recorded leaf id no longer names an entry reopens on its last entry instead of on an empty conversation.
MemorySessionStorage.deleteSessionWithArtifactsdeletes the session entry and its artifact files from memory instead of returning early as a no-op.walkBranchPathterminates when traversing cyclic parent entry chains.StringEnumoptions in the legacy plugin shim avoidany.listSessionsReadOnlywrites no session list index, so it makes no write to a directory it states it does not mutate; it still reads an existing index, which is not a mutation.
Removed
@veyyon/kernel/session/content-textis gone: the session spine calls thecontentTextowner in@veyyon/utils, which carries the separator, image,trimBlocksandtrimStringoptions that copy held.
@veyyon/natives
Added
PtyRunResult.signalnames the signal (SIGTERM,SIGKILL) that ended a PTY-run command, recovered from the wait status; a signal death also reportsexitCode1, so a consumer that attributes the death readssignalfirst.
Changed
- Shell filters share token matching and JSON field lookup while preserving exact-token matching and grep record-ending behavior.
- Shell filters share result finalization while preserving output bytes, rewrite status and original-capture accounting.
- Deduplicated tree-sitter language dispatch, filesystem isolation backend declarations, and syntect scope color matching across native crates.
- Shell builtins share cancellation and argument-error handling, and GitHub and GitLab output filters share Markdown cleanup, without changing output or exit status.
- Linux native CPU detection reads current kernel flags without consulting persisted CPU verdict files.
- Typed tuple copies use spreads rather than
.concat(), which those types do not define. No user-visible behavior changes. - The loader's diagnostic comment names the addon crate at
natives/bridge/addon/src/lib.rs, the path it moved to. No user-visible behavior changes. - The rebuild instruction in the stale-addon refusal reads
bun --cwd=natives/bridge/bindings run build, the package's path after it moved out ofpackages/. The package name@veyyon/nativesand every import specifier are unchanged.
Fixed
- Restored APFS isolation compilation on macOS and stale destination preparation for Windows block-clone isolation.
- Plain isolation diffs classify binary contents on either side of a symlink transition without dereferencing links.
IsoResolveResult.reasonis set only whenfellBackis true; a resolution that honoured the preferred backend carried the first unavailable probe's text as if it explained a fallback.
@veyyon/agent-core
Added
AgentTool.viewtakes a host-agnosticToolViewRendererfrom@veyyon/view, so a tool describes its call and result cards without receiving a theme or returning a host component; where a tool also declaresrenderCall/renderResult, the host-specific pair still wins.
Changed
- Legacy hook messages reuse custom-message fields without changing their public type signatures.
- The turn loop rejects a Harmony leak through one
rejectHarmonyLeakwhether the stream ends with adoneevent or without one; no behavior change. AgentToolResult,AgentToolUpdateCallback,ToolTier,ToolApprovalDecisionandToolApprovalare defined in@veyyon/toolasToolResult,ToolUpdateCallbackand the same approval names;@veyyon/agentexports every name it exported before, so no caller changes.- The session-entry vocabulary (
SessionEntryand every member),AgentMessageand theCustomAgentMessagesandCustomCompactionSessionEntrieshooks are defined in@veyyon/session;@veyyon/agent-coreand@veyyon/agent-core/compaction/entriesexport every name they exported before, and an augmentation now names@veyyon/session. - Typed tuple and Set copies use spreads rather than
.concat()or.slice(), which those types do not define. No user-visible behavior changes. - A source-path comment in
thinking.tsnames the coding-agent module its reader moved to; behavior is unchanged. - Doc comments refer to a child run as an agent rather than a subagent. No behavior change.
onSpanStartandonSpanEndrun through one guarded call that reports a throw as the sameon_span_start_failed/on_span_end_failedwarning, with the thrown error attached; no behavior change.- The steering and follow-up queues drain through one step that takes the first message in
one-at-a-timemode and every message inallmode; delivery order and turn count are unchanged. - A tool call's arguments and result serialize through one telemetry path keyed by the
contentSerializerfield, and anonChatUsagethrow or rejection is reported ason_chat_usage_failedfrom one place on both the agent-loop and the manual-record path; no behavior change.
Fixed
AgentTool.renderResultaccepts the optional call arguments already supported by custom and extension tool renderers.- A history summary whose single request times out, or does not fit the summarizing model's context window, is produced in stages: the span is summarized as consecutive segments of up to 32k tokens, four at a time, and the segment summaries are merged in rounds into one summary, so a 234k-token session on a model that never begins a whole-span answer still compacts;
compact()reports the segment count insummaryStagesand takessummaryStaging: "staged"to start staged. - A provider's server-side compaction runs under its own ten-minute deadline instead of the three-minute remote-summarizer deadline that cut every codex compaction of a large span.
- The staged-summary segment budget and worker count clamp through the shared
clampLow, and the engine classifies a summary timeout through the error-flag leaf modules rather than the error barrel; no behavior change.
@veyyon/ai
Breaking Changes
- Provider-specific test override setters are replaced by
setProviderModuleOverrideForTest(api, module).
Changed
- Command Code API-key validation calls the provider's default model,
claude-sonnet-4-6. - The NVIDIA, Xiaomi, Xiaomi Token Plan and Alibaba Coding Plan logins take the pasted key through the same
promptApiKeyas everycreateApiKeyLoginprovider: the key is trimmed, an empty paste isApiKeyRequiredError, an abort during the paste isLoginCancelledError, and a host withoutonPromptisOnPromptRequiredError; no behavior change. - API-key and OAuth credential ranking score usage windows and block a credential at its scoped limit through one
#rankUsageResults, an OAuth refresh reads its candidate row before and after the lease through onereadRefreshCandidate, and the plan-filter and usage-limit rejection runs before and after a refresh through oneusageRejects; no behavior change. - Tool-argument validation runs its seven pre-validation normalizations through one ordered pass table, before the first check and after every issue-driven coercion, and the two schema-agnostic value walks share one copy-on-write array step; no behavior change.
- GitLab Duo Workflow shares fresh-workflow restart handling without changing retry limits, request ordering, or surfaced errors.
- Streaming provider initialization shares assistant-message construction without changing emitted metadata or mutable-state isolation.
- Provider error projection, Google request options and Hermes/Qwen3 tool-call rendering share implementations without changing wire formats.
- Removed duplicate OpenAI Responses moderation type declarations without changing exported types or wire formats.
- OpenAI Responses computer actions share field declarations while preserving independent public namespace augmentation.
- Response input and output items share field declarations while retaining namespace-specific nested types and augmentation.
- GitLab Duo and GitLab Duo Workflow share token-response decoding and PKCE types without changing login or refresh behavior.
- API-key validators share error-body handling without changing request formats, error messages or deadlines.
- Lazy provider streams share import-promise caching while preserving provider loading and timeout behavior.
- API-key logins share credential prompting and validation with unchanged provider messages and cancellation behavior.
- Credential refresh and usage requests share cancellation handling while preserving abort reasons and independent completion of shared work.
- The GLM, Gemini, Gemma and Qwen3 in-band scanners share one outside-text step (
scanOutsideText) and Hermes and Qwen3 share one closed-body completion (emitClosedToolCall), with unchanged events at every chunking of a stream. - Provider module declarations share one typed stream signature with unchanged runtime output.
- Hermes and Qwen tool calls use one JSON decoder with unchanged repair and partial-stream recovery.
ToolextendsToolSpecfrom@veyyon/tool, which owns the schema-independent declaration and theToolExamplekinds;@veyyon/aiexports every name it exported before, so no caller changes.- The message envelope, content blocks,
AssistantMessageEvent,StopDetails, the turn and tool-call study records and the streaming partial-JSON symbol are defined in@veyyon/model;@veyyon/aire-exports every name it exported before, so no caller changes. - A source comment in the OAuth callback page names the shared sun source at
apps/site/sun-field.js; behavior is unchanged. - Typed tuple copies use spreads rather than
.concat(), which aas constarray does not define. No user-visible behavior changes. - A source-path comment in
register-builtins.tsnames the benchmark module it cites at its new path undertests/evals/; behavior is unchanged. - A source-path comment in
message-text.tsnames the coding-agent module its caller moved to; behavior is unchanged. CONTEXTUAL_USER_PREFIXESis exported from the codex compaction module so the retained-window rule is asserted against the real list rather than a copy of it.- A source-path comment and the barrel-shortcut suite name the Perplexity search provider at
tools/web/search/providers/perplexity.ts. No behavior change. - Hermes and Qwen3 share truncated-call recovery with unchanged tool names, arguments and completion events.
- The Codex responses provider parses usage through one numeric field picker, resets the websocket chain (append baseline, turn state, models etag) through one helper at every site, and the whitespace-loop, stale-response and retryable-error recoveries share one turn restart and one delayed reopen; no behavior change.
- The Qwen3, Hermes, GLM, Kimi, pi-native, Gemma and Gemini scanners and the thinking-healing scanner stream a reasoning section through one
ThinkingSectionand close a tag-delimited one through onescanThinkingTextstep, with the same events, the same held partial close tag and the same flush at end of stream. - The Cursor exec channel buffers stdout and stderr through one
ShellOutputChannelper stream, sending on a newline, past 4 KiB or 100 ms after the first byte and holding an incomplete ANSI escape until its tail arrives; no behavior change. deleteAuthCredentialanddeleteAuthCredentialsForProvidersoft-delete through one step that reports a failed statement with the credential or provider it names; no behavior change.AuthStoragedelivers its credential-disabled, credential-failover and usage-limit-withheld notices through one subscriber call that isolates a throw or a rejection and logs it against the hook, addresses a refreshed broker row through one matcher that ignores the shared refresh sentinel, and reads a report's unanimous scope account or project id through one step; no behavior change.- Doc comments refer to child runs and roles as agents rather than subagents; the Codex protocol header
x-openai-subagentand itssubagent_kindmetadata key are unchanged. - Both streaming gateway routes (the format endpoints and the pi-native fast path) abort the upstream call on a closed client response through one SSE cancel hook; no behavior change.
Fixed
- Corrected comments that named a distribution channel or runtime API the project does not use; no behavior change.
- A stream that stalls after its first event (" stream stalled while waiting for the next event") classifies as a timeout as well as transient, so auto-compaction moves to the next candidate model instead of re-sending the full context to the model that stalled up to
retry.maxRetriestimes. - A Codex websocket turn that the server accepts and then leaves without progress for the idle window is retried on the websocket once and then run over SSE, instead of spending the whole websocket retry budget on stalls, which held one compaction summary for thirty minutes per attempt.
- A codex server-side compaction cut by its deadline fails as a timeout, and one the caller cancels fails as a cancellation, instead of both reporting "stream closed before response.completed" as a backend fault.
- The codex websocket watchdog message reports the time since the last progress as of the moment it fires, instead of a value computed before the wait.
- Cursor and Devin protobuf regeneration invokes the workspace compiler, and Cursor output is written to the catalog package.
- Credential-store startup applies SQLite busy handling and WAL mode before initializing refresh leases, allowing concurrent launches to wait for database locks.
- Google's generic
RESOURCE_EXHAUSTED429 body ("Resource has been exhausted (e.g. check quota)") classifies as a per-minute throttle retried on the same account after 45-75 s, instead of a daily quota wall whose 30-minute wait exceeded the retry budget and ended the turn on the first 429; a body that states a quota keeps the quota classification. AuthStorage.disabledCredentialAccountstates which account a provider's refresh failure belongs to, so a note about a dead login can name it instead of reading as a statement about whichever account it renders beside.
@veyyon/catalog
Added
calculateCostbills a request at a model'slongContextCostrates when the prompt crosses that model's threshold, so a model the upstream charges two rate cards for is no longer reported at the cheaper one.closeModelCache()closes the shared model-cache database and permits reopening it at the current cache path.
Changed
- The
command-codeprovider defaults toclaude-sonnet-4-6, discovers models without an API key, and readsCOMMANDCODE_API_KEYafter its two existing key aliases. - GitLab Duo Workflow discovery reads a record's declared root namespace (
root_namespace_id,rootNamespaceId, or the id or path of itsroot_namespace/rootAncestorrecord) through onedeclaredRootNamespaceIdfor the explicit and nested lookups; no behavior change. - The Antigravity, Codex, Gemini and Ollama discovery readers report a non-ok status as the
statusstage and an unparseable body as thebodystage through one exportedreadDiscoveryJsonindiscovery/failure; no behavior change. - Model spec rejection checks its string, cost and limit fields from ordered tables, reporting the same field names in the same order; no behavior change.
- The canonical-id generator runs its multi-candidate expanders from one ordered table; no behavior change.
- Canonical model normalization shares ordered transformation dispatch without changing identity resolution or cache precedence.
Effort,ThinkingConfigand the model and message types are re-exported from@veyyon/model, which is their single definition; the exported names and values are unchanged.- Bundled models resolve on demand per provider while explicitly installed full-registry snapshot stores remain supported.
- Provider cache namespaces resolve without constructing discovery options; persisted cache keys are unchanged.
- Bundled model snapshots use the shared integrity-framed format without repeated JSON serialization or durability flushes, and obsolete snapshots rebuild on load.
- The model row, thinking config, effort ladder and service-tier vocabulary are defined in
@veyyon/model;@veyyon/catalog/types,@veyyon/catalog/effortand@veyyon/catalog/provider-models/wire-capabilitiesre-export every name they exported before, so no caller changes. - Typed tuple copies use spreads rather than
.concat(), which aas constarray does not define. No user-visible behavior changes. - A comment on
OPENROUTER_BASE_URLnames the Perplexity auth module attools/web/search/providers/perplexity-auth.ts. No behavior change. - An OpenAI-compatible listing's model name falls back to its id through the shared non-empty-string reader; discovered names are unchanged.
Fixed
- Command Code models carry the provider's published prices, reasoning ladders and output ceilings instead of arriving at zero cost with no thinking control; the bundled catalog grows from 3 hand-written rows to the 69 the Provider API serves.
- Case-insensitive host classification no longer treats control characters as URL punctuation.
@veyyon/coding-agent
Breaking Changes
- Agent settings use
agent.*,tier.agent,advisor.agents, andargot.agents; legacy keys migrate on load, while historical runtime export names, custom-theme color tokens, session records, and RPC spellings remain unchanged. - Account formatting helpers are exported from
@veyyon/coding-agent/session/account-formatinstead of@veyyon/coding-agent/slash-commands/helpers/format. - Screen takeover moved off
ExtensionUIContextandHookUIContextonto an optionalui.terminalcapability:custom()andsetEditorComponent()are nowctx.ui.terminal?.custom(...)andctx.ui.terminal?.setEditorComponent(...), and a component widget goes throughctx.ui.terminal?.setWidgetComponent(key, factory)whilesetWidget(key, lines)keeps the text form every host draws. A host that is not a terminal omitsui.terminalrather than declaring members with empty bodies. - Removed
ui.setHeader()andui.setFooter(), which every host implemented as an empty function, interactive mode included. - Session spine, plugin loader and contribution registry modules moved from
src/session/andsrc/extensibility/to@veyyon/kernel: affected subpath imports now use@veyyon/kernel/session/*,@veyyon/kernel/loader/*and@veyyon/kernel/registry/*; edit-specific event normalization remains at@veyyon/coding-agent/extensibility/tool-event-input. - The 152 modules under
src/tools/moved into one directory per domain —core/for the plumbing every domain reads, thenfs/,search/,shell/,web/andagent/— so a subpath import previously resolved through@veyyon/coding-agent/tools/<name>is now@veyyon/coding-agent/tools/<domain>/<name>. sanitizeStatusTextis@veyyon/utils/sanitize-status-text, so a subpath import previously resolved through@veyyon/coding-agent/modes/sanitize-status-textnames the utils module: the function is text-only and every host reduces a value to one line the same way.- The 81 site scrapers, the page loader and the Parallel extraction client moved to
@veyyon/web: a subpath import previously resolved through@veyyon/coding-agent/web/scrapers/*or@veyyon/coding-agent/web/parallelis now@veyyon/web/scrapers/*and@veyyon/web/parallel, and the search providers'withHardTimeoutis@veyyon/web/hard-timeout. escapeMarkdownTableCelland the Turndown helpers are@veyyon/utils/markdown-tableand@veyyon/utils/turndown, andhtmlToBasicMarkdownis@veyyon/utils/html-markdown, so a subpath import previously resolved through@veyyon/coding-agent/utils/markdown-table,@veyyon/coding-agent/utils/turndownor the scrapers barrel names the utils module.CliUsageErroris@veyyon/utils/cli-usage-error;@veyyon/coding-agent/cli/usage-erroris removed, so a flag the root parser rejects and one the command framework rejects are the same class.@veyyon/coding-agent/session/auth-storageis removed; the credential types andAuthStorageit re-exported are imported from@veyyon/ai/auth-storage, the module that defines them.- The setting declaration vocabulary —
SettingDefand its definition kinds,SettingType,SETTING_TYPES,isSettingType,SettingTab,AnyUiMetadataandSubmenuOption— moved from@veyyon/coding-agent/config/settings-schemato@veyyon/settings; the schema, its readers, the tab metadata and the tab groups stay where they were. - URL target parsing is exported from
tools/web/read-url-targetinstead oftools/web/fetch. - Setting-change signals are exported from
config/settings-signalsinstead ofconfig/settings. fgOrPlainis exported fromtheme/theme-bindinginstead oftheme/theme.- Diagnostic cards use
diagnosticsSectionfromtools/core/diagnosticsinstead offormatDiagnosticsfromtools/core/render-utils; diagnostic parsing and sanitisation helpers are imported directly fromtools/core/diagnostics. - Read selector helpers
parseSelandisRawSelectorare exported fromtools/core/path-utilsinstead oftools/fs/read. readSourceFsPathis exported fromtools/fs/read-viewinstead oftools/fs/readand remains available from the package root.metadataLineis exported fromtools/core/render-utilsinstead oftools/web/search/view.- Removed the unused
inheritedAgentDirkeybinding option andohMyPiXAIUserAgentalias; xAI requests continue to useveyyonXAIUserAgent. @veyyon/coding-agent/extensibility/hooksno longer exportsHookRunner,HookToolWrapper,discoverAndLoadHooks,loadHooksandexecCommand: the legacy hook runtime is removed, a plugin'shooksentry loads through the extension runner, and the subpath keeps the hook types.UNICODE_SYMBOLSis@veyyon/view's;theme/symbolsre-exports it and keeps the terminal-only Nerd Font and ASCII presets, the spinner frames and the bar ramps.
Added
- Exported
projectToolDisplayfrompresentation/web-tool-display.ts, projecting canonical tool execution displays for collab live sessions and HTML export. tools/view-registry.tsexportstoolViewDefinitions, the host-agnosticToolViewDefinitionfor every tool card the terminal drew, andtools/renderers.tsderives the terminal adapters from it; the set of cards and their chrome are unchanged.- A tool card value-imports no tool: the search card limits are
tools/search/search-card-limits.ts, the web search provider label istools/web/search/types.ts, and the launch card ownscallMetaandreadyPendingSummary; each name is exported from that one module only. Print mode and the HTML export load a card without the tool behind it, and no output changes. presentation/transcript-builder.tsis split intocontent-text.ts,custom-display.tsandsession-projection-engine.ts, each under the presentation module size ceiling; no output changes.src/presentation/builds the@veyyon/wire/presentationview-models from session state, andPresentationEventBridgeturns session events into transcript updates, so a renderer draws a session without importing one.src/modes/terminal/driver.tsimplementsPresentationContexton@veyyon/tui: it renders every transcript block kind, the status line, the composer and the dialogs from view-models alone, and reports operator input back asUIEvents.InteractiveMode.presentationapplies transcript, status, composer and overlay updates to the existing terminal surface without constructing a second terminal or composer./process-manageropens the Agent Control Center across every conversation this process is running rather than only the one on screen, andaswitches the roster, the comms stream and the transcript guard between the two scopes together.readaccepts a semicolon-delimited list of internal resources (skill://demo/one.md;skill://demo/two.md), the same list formgrepandglobtake, and returns one section per entry.@veyyon/coding-agent/session/facadeexposesAgentSessionFacade, a thirteen-member session API a front end drives — start, stop, submit, interrupt, retry, per-call tool approval, six event streams and the model, provider and context-usage readings — over a liveAgentSession; the facade owns the permission prompt while it is started, and refuses a session another host already routes through.setImageDisplayProbelets a front end state whether it draws pictures, which is what the session reports to the model about an image a tool returned; a client that installs nothing draws nothing, so a host embedding the engine no longer inherits a terminal's answer.ToolDefinition.viewlets an extension describe its tool's call and result cards as aToolViewinstead of building a terminal component, and re-exports the@veyyon/viewvocabulary (ToolView,StatusRowView,TextBlockView,ViewSpan,ViewTone,ViewStatus) so a plugin can construct one; the terminal draws it, and a tool that also declaresrenderCall/renderResultkeeps those.src/modes/terminal/draw/draw-tool-view.tsdraws aToolViewas terminal bytes through exhaustive tone-to-colour and status-to-icon records, so a tone added to the contract fails the type check until the terminal states how it looks.- A
ToolViewspan carriesfilefor a filesystem path a host opens however it can, separate from thelinka URL rides on, and the tone vocabulary addsdiffAddedanddiffRemovedfor the two sides of a change; the terminal wraps afilerun in an OSC 8 link to itsfile://URI. - Tool domains declare lazy factories in
manifest.ts, whiletools/view-registry.tsdefines their views and policies andtools/renderers.tsderives terminal adapters with shared identities for provider aliases. CustomTool.viewlets a tool authored as a custom tool describe its call and result cards as aToolView, the memberToolDefinition.viewalready offered an extension, and both adapters forward it to the host.- The
asktool emits a host-agnosticHostNotificationthroughToolSession.notifyinstead of calling the terminal, and the running host installs its delivery throughsetToolNotifier; a host that cannot reach an operator outside its own window installs nothing and the capability reads as absent. - Source-path comments in
modes/terminal/controllers/input-controller.ts,tools/render-utils.ts,utils/block-context.tsandutils/shell-snapshot.tsname the Rust modules they cite at their new paths undernatives/. No user-visible behavior changes. - A commit whose changes all sit under a grouping directory named
nativesproposes the directory below it as the scope, the waycrates,packagesandtestsalready do, instead of proposingnatives. - The
set_cwdrenderer dropsname,renderArgumentsandrenderPending: no host reads any of the three, and the tool-renderer contract declares none of them. No user-visible behavior changes. showHookInput'sinputOptions.maskis a boolean rather than the character to draw, so the host that paints the field owns the glyph and/secret addno longer names the terminal engine to ask for a hidden field; the masked prompt draws the same•it drew before.- The todo tool states where a closed task's completion strike has reached with
todoStrikeSplitand writes no SGR escape itself: the terminal draws the struck run with the theme's strikethrough attribute, so a session with terminal attributes off receives the task text without the\x1b[9mbytes it cannot render, and the transcript card sweeps the strike exactly as it did before. runCommitAgentSessionreports its run through aCommitAgentReporterinstead of writing to stdout itself, andcommit/agentic/agent-render.tsis the only module that draws it, so the commit domain names neither the terminal engine nor chalk;veyyon commitprints the same thinking line, markdown, tool tree and totals it printed before.- The
/collabQR block draws its own leading blank row instead of being presented behind a spacer, so the slash-command registry no longer imports the terminal engine; the transcript shows the same blank row above the code and above the too-narrow hint. - The compaction policy vocabulary (check outcomes, the bar a pass is measured against, the truncation edge budget, the prune cache window and idle flush, and the recovery band) lives in
@veyyon/kernel/session/agent-session-compaction-policyrather than interleaved with shutdown timeouts and credential backoffs inagent-session.ts, with no behavior change. resolveSlashCommandinslash-commands/helpers/parseresolves a parsed invocation against a command set, joining the first argument token back onto a namespaced plugin command name.SingleResult.isolationFallbackrecords the requested and actual isolation backends and the reason when an explicit mode was not honoured;isolationModeNameintask/worktreestates a backend's setting spelling.TruncationMeta.totalLinesUnknownstates that a read's scan stopped after the shown window, so the notice omits a total it does not have.PLUGIN_MANIFEST_ENTRY_KEYSandPluginManifestEntryKeyinextensibility/plugins/loaderstate the four manifest entry keys a plugin contributes through.cli/stdout-drainexportsawaitStdoutDrainandexitAfterStdoutDrain, the one way a non-interactive mode exits after its last frame is written.
Changed
- Typing a line that does not name a builtin slash command no longer loads the builtin implementations:
slash-commands/dispatch.tsanswers that from the declarations and loads the handlers only once a name matches, taking the launch graph from 1,642 modules to 1,545 and the interactive input controller from 1,296 to 1,059. No command, argument or completion behavior changes. - The 1,806-line builtin handler object moved out of
slash-commands/builtin-registry.tsinto one module per command category (builtin-setup.ts,builtin-modes.ts,builtin-session.ts,builtin-context.ts,builtin-share.ts,builtin-workspace.ts,builtin-model.ts,builtin-info.ts), with the autocomplete builders inbuiltin-completions.tsand the category map inbuiltin-categories.ts; the registry assembles the eight maps and still exports every name it carried. - The 860 lines of raw settings migrations moved out of
config/settings.tsintoconfig/settings-migrations.ts, which also drops the theme-classifier, builtin-tool-name and compaction-strategy imports from the module most of the product reaches for a setting. No setting, default, order or migration behavior changes. - Model target selection moved out of
session/agent-session.tsintosession/agent-session-model-targets.ts: role resolution, a configured target's model, the compaction candidate list and its configured thinking efforts read only the settings, a model and the available list, so they are callable without a session. No selection, ordering or fallback behavior changes. - A running tool card animates one mark: the "… (streaming)" spinner row is drawn only under a header that carries no running spinner of its own, and an agent an eval cell spawned shows the task card's static accent mark instead of a second spinner.
- The read and write cards parse their arguments and details through
@veyyon/utils/fs-tool-args, so a terminal launch no longer evaluates@veyyon/tool-render; the cards draw the same rows. - The legacy
memories.enabledkey is no longer a declared or host-defaulted setting: a config that still holds it migrates tomemory.backendon load, the key is dropped on the next rewrite, and the local memory pipeline is enabled bymemory.backend: localonly. The presentation module's error messages, read-target parsing and cursor clamping use the@veyyon/utilshelpers; no behavior change. - Reworded the Include Model in Prompt, Max Retry Delay, Hindsight Bank ID, Subagents and Subagent Delegation setting descriptions shown in
/settings. - The HTML export attaches sub-sessions, redacts and writes the file through one
finishExportfor the session-manager and file entry points, a stage-1 memory job is completed under its ownership token through onecompleteOwnedStage1Jobfor the with-output and no-output paths and the global phase-2 claim reads its row through onereadGlobalJobRow, the JavaScript eval cell builds its success, cancelled and failed results through onefinish, the GitHub commit watch reports each poll and its grace and confirm notes through onereportWatching, and a capability scope splits(,[and{groups through one keyed depth table so a closer of another kind never ends the open group; no behavior change. - The token-rate helpers are
presentation/token-rate.ts, moved frommodes/components/status-line/token-rate.tswithout a forwarding module, and the status view-model ispresentation/status-producer.tswith nopresentation/status-builder.tsbeside it; the search card limits are exported fromtools/search/search-card-limits.tsonly, andcallMetaandreadyPendingSummaryfromtools/shell/launch-view.tsonly. - The propose-commit and split-commit tools state the summary and detail limits in their verdict through one
verdictWithLimits, Enter and Ctrl+Enter run a builtin slash command and recall the line as typed through one#consumeBuiltinSlashCommand, and a read records its hashline snapshot through onerecordFullHashlineContextand renders an over-long first line through oneoversizedFirstLineTexton the ranged and whole-file paths; no behavior change. - Tool-argument repair parses a stringified payload and a parse-sentinel payload through one
repairJsonObjectArguments, the launch path resolves the prewalk strong, prewalk cheap and plan-yolo models through oneresolveLaunchModel,--resumerelocates a session whose recorded directory is gone through one block for local and cross-project matches, and the vault key scans staging entries through one boundedstagedKeyEntriesfor orphan recovery and crash-stage cleanup; no behavior change. - The models-config schema rejects an empty
id,name,baseUrl,apiKey,contextPromotionTargetorcompactionModelthrough one narrow helper, the URL fetcher assembles every render result through onebuildRenderResult, the patch mode resolves a space-separatedouter innercontext through oneresolveInnerAfterOuter, and the clipboard reads images and text from Windows through onerunPowerShellbridge; no behavior change. - The plugin manager runs every
bun install,bun update,bun uninstalland dry-run through one#runBun, the marketplace manager resolves where a plugin is installed and which scope a verb applies to through one lookup and one#scopeFor, the microphone recorder and its streaming twin walk the detected recorders through one fallback loop, the ZIP64 locator and end-of-central-directory record are parsed by one reader for the in-memory and ranged paths, and head and tail truncation build their single-line results through one helper each; no behavior change. - The profile bootstrap reads
--profileand--aliasthrough one flag reader, the vault's Linux and macOS atomic exchange share one rollback builder, the eval tool builds its cancelled, failed and completed results through onefinishCell, and the lexical bracket scanner opens quote modes from one table; no behavior change. ToolExecutionComponentrebuilds its block through one#syncBlockwhenever the spinner frame, the expansion or the freeze changes, including when the spinner starts and stops, so a card that readscontext.framein its view (the vibe composer caret) blinks from its first paint and holds still once stopped.- The terminal tool card keeps four behaviors the producer split had dropped: a settled streaming diff preview is drawn without waiting for the next spinner tick, a live-widget call that never ran (
ask) falls back to its label, a backgroundtaskresult finalizes its block while the job runs, and the write card coerces non-stringcontentto text;EventController.attachToseeds the projection engine from the engine's own message source. DapSessionManager.launchandattachshare one start sequence, and each breakpoint kind (source, function, instruction, data) replaces its list through one helper for both set and remove; no behavior change.CustomEditordispatches its twenty app-level shortcuts through one ordered table with the same precedence, deferral during early startup, bash-background fall-through and retry-yields-to-extension rules; no behavior change.- Every
ModalShellhost (tree, session, settings, model hub and model picker selectors, the agent dashboard and transcript viewer, the plan review, login, ask and MCP wizard dialogs, the extension dashboard) routes its close glyph, outside click, breadcrumb and footer chips through onerouteModalChromeprelude instead of a hand-typedhitTestModalChromesequence; no behavior change. - Goal and vibe mode context reach the model through one delivery step that keeps the hidden display, the agent attribution and the requested channel; plan-mode context is unchanged.
- The
/btwand/omfgpanels settle every outcome (complete, saved, rejected, aborted, error) through one step per panel that clears a previous error and ignores a dismissed panel; the painted rows are unchanged. - The reftable ref readers answer
nullfor a missing ref and rethrow an abort through one read-only git query, and thegithubops raise the same "unavailable"ToolErrorfor a missing repository root, primary root, branch or head through one check; no behavior change. - The legacy extension resolver's six promise caches (package root, manifest, bare dependency, native addon, addon-require scan, realpath) share one memoizer and one importer-scoped key; each result is cached once per key, as before.
veyyon setup speechpicks the speech-to-text and text-to-speech models through one step that persists only a value the setting declares and flushes it before the next pick; no behavior change.- The SearXNG endpoint, token and Basic-auth readers share one settings-then-environment lookup, with an empty endpoint or token still read as unset, and the tool result builder records match, result and head limits through one setter; no behavior change.
- ACP
session/resumeopens a stored session through the same step assession/load(same cwd check, same MCP configuration, same not-found error) without replaying history, and thesymbolPresetandcolorBlindModesettings apply to the theme through one signal hook that logs a fallback or a failed setter under the setting's name; no behavior change. - Single-range and multi-range
readclip long lines totools.outputMaxColumnsthrough one display-only clipper that records each clipped line, including a block-context line outside the window, out of the seen-lines record and reports the column cap once; no behavior change. /btw,/tanand/omfgread their argument and clear the composer through one handler; the composer'slockedandawaitingApprovalflags enter and leave their modes through one step; an agent's extensionsendMessageandsendUserMessageare tracked and error-logged through one step; theb,cand down-arrow empty-composer keys install through one listener; and thetoken_in,token_out,cache_readandcache_writestatus segments render through one counter; no behavior change.- Async job deliveries and in-flight deliveries filter by owner and suppression through one step; the projection engine's running and background-task marks toggle set membership through one step; and skill loading resolves authored and managed skill real paths through one helper, so one
SKILL.mdreached through two paths loads once without a collision warning; no behavior change. - RPC agent and session events pass one typed-set check; every streaming edit mode recovers its matcher paths and entries through one non-empty and one single-path step; and skill, rule, context-file, prompt-template, slash-command and custom-command discovery resolve their project and agent roots through one step; no behavior change.
- Streamed text and thinking segments reveal through one generic step; both Gemini search request paths build their per-attempt body through one transform step; and the cmux tab's
waitForSelectoriswaitFor; no behavior change. - The
theme.darkandtheme.lightsetting hooks republish their slot through one factory; the RPChost_tool_resultandhost_tool_updateframes pass one guard parameterised on the frame type and payload key; and the HindsightretainMode,recallBudgetandscopingenv and settings values are accepted through one listed-value picker; no behavior change. - Built-in model discovery selects its standard and special providers through one predicate (disabled set, configured discovery rows, provider filter) and resolves each provider's discovery endpoint through one lookup (runtime override,
models.yml, catalog); the!and%shortcuts present, stream into, settle and release their transcript block through one step with their own failure labels; no behavior change. - The agent executor reads a message's or event's
contentandusagethrough one field reader, and a symbol-preset or colour-blind change re-renders the committed theme through one ephemeral re-apply step; no behavior change. - The legacy
pi-coding-agentread, bash, grep, find and ls tool definitions draw their call card through one step (title, then the call's own summary), with the same bytes as before; no behavior change. - Grouped read displays and path expansion share delimiter scanning while preserving escaped separators, glob braces and selector ranges.
- Learn and Memory Edit result views share text projection while preserving titles, empty results and error formatting.
- Collab and HTML tool previews build display data without serializing discarded transcript input.
- Tab expansion imports
@veyyon/utils/tab-width; no user-facing effect. - The speech-to-text, tiny-model and TTS worker clients share one request lifecycle (
subprocess/worker-request-client) and one progress-event shape; a worker error or client shutdown settles every pending request the same way in all three, with no user-facing effect. - Collab link formatting and parsing (
formatCollabLink,parseCollabLink,generateRoomId) are@veyyon/wire's, re-exported fromcollab/protocol; a link the host mints and the browser guest parses read one grammar, with no user-facing effect. - Claude plugin hooks, tools, skills, slash commands and MCP servers resolve their plugin roots through one
pluginRootsForstep, and no loader can mutate the cached root warnings; no user-facing effect. - Terminal and presentation event handling share tool-argument correlation and retry traces, with stable block identities across streaming snapshots and session resets.
- Standalone and adopted terminal drivers share transcript updates and composer bindings with unchanged read-card presentation.
- Grouped read projections preserve per-call status, paths, previews and line numbers across serialization.
- Live and rebuilt tool cards share single-card rendering while preserving renderer precedence, streamed arguments and failure notices.
- Status-line usage fields use the shared presentation contract without changing rendered output.
- Bash and job cards load shared presentation helpers without importing their execution modules.
- Plugin discovery shares installed-registry validation and root collection without changing scope precedence or warnings.
- Runtime initialization no longer waits for first-frame replay cache publication.
- Eval bridge options share field declarations while preserving exported interfaces and runtime behavior.
- Settings selectors share list initialization, model-picker attachment and inline updates without changing input routing or persistence.
- Extension API instances no longer allocate unused flag maps and provider-registration arrays; flags and registrations remain in the shared session runtime.
- MCP commands share argument parsing without changing terminal and CLI option policies or interpreting argument text as a second command.
- DAP and LSP configuration discovery share source ordering, and Gemini and OpenCode share user-context loading, without changing precedence or warnings.
- Editor keybinding matching shares default key sets while preserving remap isolation and fallback chords.
- Autoresearch experiment tools share active-branch session resolution without changing errors or session selection.
- Autoresearch session updates share optional-column assembly without changing stored values, omitted-field handling, or database errors.
- Extension dashboard loading shares disable and shadow precedence across capability kinds without changing state or metadata.
settings-selector.tswrites its escape comparison as\x1binstead of a raw control byte. No user-visible behavior changes.- Output minimizer tool filters collapse repetitive line filtering, table formatting and subcommand routing into declarative specs with unchanged output behavior.
- GitHub search operations in the web domain and vibe mode tools use shared parameterized dispatch tables; behavior is unchanged.
- Terminal selector cards and command controllers share modal select delegation, mouse routing, subcommand dispatch, and markdown panel presentation without changing TUI behavior.
- Settings selectors share model-chain summaries, heading rows, picker targeting and candidate deletion without changing display or persistence behavior.
- Parity ledger schema validation, module specifier resolution, and workspace traversal logic are consolidated into shared script helpers without changing validation verdicts.
- Custom and legacy hook messages use the agent-core type definitions without changing message conversion or public type signatures.
- Filesystem reads and writes share range calculations, candidate probing and result assembly while preserving SQLite row-operation exports.
- Terminal code cells and tool views share row splitting, truncation summaries and text sanitization without changing rendered output.
- Image inspection, Mnemopi initialization and search-provider loading use AI subpath imports while preserving usage-provider and credential-ranking registration.
- Launch and live status rows share configuration reads, and launch redraws avoid enumerating the settings schema.
- Settings group reads reuse declaration-path membership without caching setting values.
- Filesystem and goal previews load without their tool execution modules.
- Task cards share row construction, nested traversal, finding normalization and yield labels without changing rendered output.
- Web-search providers share credential resolution and HTTP error handling, and discovery providers share equivalent scanners without changing provider behavior.
- Tool cards share hidden-count formatting and symbol presets share identical glyph definitions without changing rendered output.
- Tool cards share error rows, metadata and empty-result construction without changing rendered output.
- Python, Ruby and Julia kernels share runtime probing and subprocess initialization while preserving language-specific environment and execution behavior.
- First-frame replay recordings are written asynchronously so filesystem operations do not block editor input.
- Launch status rendering reuses repository discovery when reading branch and worktree metadata.
- Launch layout measures the fixed-height status footline without rendering it.
- Every setting in every domain states what it does and what each value selects in one to three sentences, with no design history or internal vocabulary; the idle timeout row is labelled "Park Idle Agents After", the Park and Prune groups are one "Idle Agents" group, the artifact rows are "Artifact Threshold", "Artifact Head Size" and "Artifact Tail Size" with the unit on their options, and the MCP debounce row is "MCP Notification Delay".
AgentRegistry.setStatusconsultsAGENT_TRANSITIONSand throwsAgentTransitionErrorfor a status move the lifecycle does not perform, so a turn event that arrives after a kill or a park no longer revives the agent; a collab guest mirrors the host's roster throughmirrorStatus.- An agent adopted at hand-over, revived from disk or listed from a previous run receives its idle and prune budgets through one builder, so a zero quiet budget disables pruning and a waiting budget is never shorter than the quiet one on every path; no behaviour changes on the paths that already agreed.
- A retired
agent.*setting is retired in one place:rejectedAgentModelSettingssweeps the keys the schema itself marksretiredByinstead of a second hardcoded list, and a retired key with no page hint is reported against the replacement the schema declares rather than being named asundefined;agentsEnabledis the one predicate for whether agents exist, replacing thedelegationEnabledalias that returned it unchanged. No setting changes what it does. - Interactive chat and the transcript viewer use one replay implementation without changing displayed content or live-tool lifecycle.
- Transcript rebuilds and live updates share tool-text projection without changing displayed content.
- Settings group types derive from the settings schema while preserving their existing optional fields and value types.
- JSON tree projections share bounded traversal, and code and Markdown cells share output assembly, with unchanged rendering.
- Plugin discovery, import rewriting, MCP configuration toggles, Exa responses, secret-preserving text transforms, todo state cloning and projection, and session-file discovery use shared implementations without behavioral changes.
- Tool views share progress rows, diff statistics, disclosure metadata, and task separators without changing rendered output.
- Extension kind labels use a shared function without changing list or sidebar text.
- Handbook HTML and search assets are generated during documentation and website builds instead of being tracked in Git.
- Startup reads setting-change signals and terminal formatting without constructing the settings store or unrelated tool modules.
- The terminal host constructs autoresearch screens and styled slash-command reports; headless command execution no longer imports those terminal components.
- Subagent statistics and output sanitization are shared across the task tool's view and dashboard through host-independent presentation helpers in task/agent-stats.ts without terminal imports. No user-visible behavior changes.
- Account inventory formatting no longer imports terminal progress-bar or theme helpers; displayed values are unchanged.
- Terminal mode initialization overlaps session discovery instead of loading during sequential runtime warmup.
- Interactive startup begins background model discovery after terminal initialization.
- Model registry initialization defers unused provider records until lookup or enumeration while preserving runtime provider updates and model overrides.
- Startup reads provider caches without constructing unrelated discovery options or their bundled reference maps.
- Model discovery snapshots from earlier host-classification rules rebuild before model selection.
- Resolved model snapshots no longer duplicate the bundled catalog; model selection and provider overrides are unchanged.
- Resolved model snapshots use shared byte-integrity checks and atomic replacement without durability flushes; obsolete snapshots rebuild before model selection.
- Startup imports AI streaming helpers and usage registration without evaluating the AI package barrel; usage providers and credential ranking remain available.
- Evaluator implementations load on the first enabled request instead of session or tool construction, and loaded runtimes register their own process-exit cleanup.
- URL reader initialization is deferred until an enabled URL read or search; local tools and transcript previews no longer initialize it.
- Vibe tools load on
/vibeactivation rather than during startup, and failed loading preserves the session toolset. - The settings schema registry is
@veyyon/kernel/settings/schemaandconfig/optional-numberis@veyyon/kernel/settings/optional-number;config/settings-schemacomposes the domain tables throughdeclareSettingsand still exports the queries (getDefault,getType,getUi,hasUi,getPathsForTab,retiredBy,isSettingPath,getEnumValues,isUnsetNumberPath,describeSettingTypeMismatch), theSettingPathandSettingValuetypes,SETTINGS_SCHEMA, the tab metadata and the typed groups, so importing a query loads the tables it reads. No setting, default or config file changes. Settings(config/settings) extendsSettingsStorefrom@veyyon/kernel/settings/storeand passes the product's hook set (the global setting bindings, theSETTING_HOOKStable, the config migrations, thesettings.jsonandagent.dblegacy read, the changelog-marker seed and the per-directory resolution ofenabledModels);config/settingsre-exports the store's vocabulary andSettingSignalunder the same names, so every import resolves. No setting, default, config file or write order changes.Settings.getGroupdelegates prefix path lookup togroupSettingPathsfrom the kernel store; model role dictionary normalization is consolidated across layer accessors.- The tool session, the terminal mode and the SDK read
HostNotifierfrom@veyyon/hostinstead of@veyyon/utils/host-notification; behavior is unchanged. session/messages.tsregisters its message kinds on@veyyon/session'sCustomAgentMessagesrather than@veyyon/agent-core's; behavior is unchanged.SessionManager,buildSessionContext, the session file loader andAgentStorageare@veyyon/kernel/session/*;session/messages.tsre-exports the custom-message payload helpers and the rehydration sanitiser from@veyyon/kernel/session/custom-message-payloadunder the same names.appendMessageaccepts everyAgentMessagebut a branch or compaction summary, the set it accepted before. Behavior is unchanged.BashExecutionMessage,PythonExecutionMessage,bashExecutionToTextandpythonExecutionToTextare@veyyon/coding-agent/tools/shell/execution-messages, declared on the shell domain's manifest as message kinds;session/messages.tsno longer exports them, andconvertToLlmconverts the two roles through the kind table the tool registry fills.formatGroupedDiagnosticMessagesistools/core/grouped-file-output, whichlsp/utilsre-exports. Behavior is unchanged.- The plugin loader, the plugin manager, the plugin settings dialog and the
extensibility/pluginsbarrel read the manifest vocabulary from@veyyon/plugin; the barrel exports the same names. No user-visible behavior changes. - The website source is
apps/siteand the Python clients areclients/python, the directories that werewebsiteandpython; the source-checkoutveyyonlauncher, the binary build scripts and the brand-parity checks read them there, and nothing they produce changes. veyyon updateon a source checkout regenerates the HTML export tool views fromclients/web, the directory that waspackages/collab-web, and the compiled binary reads the embedded stats dashboard fromapps/stats, the directory that waspackages/stats; the commands and their output are unchanged.- Typed tuple and Set copies use spreads rather than
.concat()or.slice(), which those types do not define. No user-visible behavior changes. web_searchis constructed fromtools/web/searchrather than the retiredweb/searchmodule. No user-visible behavior changes.normalizeRootstakes one working-directory string. No user-visible behavior changes.createCachedComponentlives inmodes/terminal/draw/utilswith the rest of the terminal drawing helpers, and the source map no longer listssrc/web/orsrc/swarm/as top-level directories. No user-visible behavior changes.- Tests that lived under retired folder names (
test/tui,test/capability,test/web,test/vibe,test/repair, and the other pre-cutover aliases) now sit next to the source they cover. No user-visible behavior changes. - ToolView cards that walk a JSON value read their bounds and scalar formatting from
json-tree-view.tsrather than loading the terminal walker that draws tree-rail glyphs. No user-visible behavior changes. - The terminal's ToolView drawer names every kind the contract declares, so a kind added to the union fails the type check instead of drawing as a one-line text row. No user-visible behavior changes.
- Session persistence, plugin loading and generic contribution registration use
@veyyon/kernel; the turn loop, prompt rendering and tool-specific extensibility remain in the coding-agent package. - Terminal drawing of a
ToolViewlives insrc/modes/terminal/draw/, and web search lives insrc/tools/web/search/. Subpath imports previously resolved through@veyyon/coding-agent/tuiand@veyyon/coding-agent/web/searchnow name those directories. No user-visible behavior changes. - Every tool module is grouped by domain under
src/tools/<domain>/, each domain importing onlycore/and itself, so the dispatch table no longer sits above 139 flat modules. No user-visible behavior changes. - Source-path comments and the gallery search fixture name the terminal renderer at its new path,
hosts/terminal/engine, and a new architecture gate records every module outsidesrc/modes/terminal/that still imports it. No user-visible behavior changes. - A source-checkout update runs the native-addon ensure step in
natives/bridge/bindings, the bindings package's path after it moved out ofpackages/. - Sixteen tool modules keep their terminal drawing in a
<tool>-render.tssibling —ask,ast-edit,bash,debug,fetch,file-search,job,launch,read,resolve,search-tool-bm25,ssh,structure-search,text-search,todoandwrite— completing the convention eight tools already followed, andtools/json-tree.tsistools/json-tree-render.ts. Twenty-four of the twenty-six modules undertools/that name@veyyon/tuiare render siblings, print mode no longer loads the renderer through the todo tool, and subpath imports of the moved renderers follow the new layout. No user-visible behavior changes. - All five autoresearch experiment tools —
init_experiment,update_notes,certify_arms,log_experimentandrun_experiment— describe their call and result cards as aToolViewinstead of building terminalText, so none of them imports@veyyon/tui; the terminal draws the same bytes it drew before, includingrun_experiment's collapsed five-line output preview and its expanded full output. ToolDefinition.viewrenderers receive aToolViewContextstating whether the card is expanded, so a tool can shorten its collapsed output without asking a host what it is.- The goal tool describes its call row and result panel as a
ToolViewinstead of constructing terminal components; panel and error formatting are unchanged. - The
report_findingtool describes its call row and its result row as aToolViewinstead of building terminalText, so it no longer imports@veyyon/tui; the terminal draws the same priority mark, tone and truncation bounds it drew before. - The
set_cwdtool describes its call row and its result frame as aToolViewinstead of building terminal components in aset-cwd-render.tssibling, which is deleted; the terminal frames the same header, rule counts and no-op wording, and the call row loses the blank row above and below it thatText's default padding added, drawing in the column every other tool's call row draws in. - The
retain,recallandreflecttools describe their cards as aToolViewinstead of building terminal components in amemory-render.tssibling, which is deleted; the terminal draws the same rows, memory bullets, preview caps and expand hints, and a memory cut to a terminal narrower than the eight-column floor the sibling clamped to now ends in an ellipsis inside its own colour instead of a hard cut mid-escape. - The
read_urltool describes its call row and its result card as aToolViewinstead of building terminal components in afetch-render.tssibling, which is deleted; the terminal draws the same panel, metadata rows, preview caps, truncation notice and OSC 8 links, and the line stating how many preview lines were held back now draws in the dim its expand hint already used instead of a lighter muted. - The
resolvetool describes its call row and its result plate as aToolViewinstead of building terminal components in aresolve-render.tssibling, which is deleted; the terminal fills the same plate in the same colour for an accepted, failed and discarded resolution, and the renderer'sinlineflag goes with it, since the only reader was the gallery CLI. - The
debugtool describes its call row and its result panel as aToolViewinstead of building terminal components in adebug-render.tssibling, which is deleted; the panel draws the same session lines, output preview and truncation note, the header states the action after the tool name instead of concatenating both untoned, and the line stating how many preview lines were held back draws in the dim its expand hint already used instead of a lighter muted. - The
sshtool renders through a host-agnosticToolViewinstead of anssh-render.tssibling, and a command or output longer than the viewport is windowed by the rows it occupies after wrapping instead of by its line count. - The
todotool describes its call row, its board and its finished line as aToolViewinstead of building terminal components in atodo-render.tssibling, which is deleted; the card draws the same rows, phase names, task marks, completion sweep and one-line summary it drew before, a task's mark and its words carry the tone as two runs instead of one, and a task whose status this build has no case for is drawn as open work rather than reaching the terminal with no colour to resolve. - The
inspect_imagetool describes its call row, its answer panel and its failure card as aToolViewinstead of building terminal components in aninspect-image-renderer.tssibling, which is deleted; the card draws the same question line, four-line collapsed and sixteen-line expanded answer windows, held-back note and sanitised failure text, the settled panel states the outcome on its rail instead of taking the muted legacy edge, and the model and media type ride on the header row rather than a second row beneath it. - The
search_tool_bm25tool describes its call row and its match list as aToolViewinstead of building terminal components in asearch-tool-bm25-render.tssibling, which is deleted; the card states the same status line, five collapsed matches, label and description truncation bounds and fallback warning, the matches are a list the terminal marks and indents rather than rows carrying their own bullet and dot separators, and the held-back count closes the list with the expand gesture left to the host. ast_editusesToolViewcards with host-managed expand hints; change content and error formatting are unchanged.- The
irctool renders through a host-agnosticToolViewinstead of anirc-render.tssibling, a message states its direction in words (IRC to AuthLoader) rather than an arrow, andcreateIrcMessageCardandircToolRendererare no longer exported from the package root. - The
writetool renders through a host-agnosticToolViewinstead of awrite-render.tssibling, the line-number gutter is three columns wide through a 999-line file instead of widening at each power of ten, and a partial result no longer leaves two blank rows between its progress line and the file. - The
file_searchtool renders through a host-agnosticToolViewinstead of afile-search-render.tssibling, and a path too long for the frame is cut to the frame's width instead of wrapping onto a second row. - The
text_searchtool renders through a host-agnosticToolViewinstead of atext-search-render.tssibling, and the rows of a card with no matches indent two columns under their header instead of starting in column zero. - The
structure_searchtool renders through a host-agnosticToolViewinstead of astructure-search-render.tssibling, and a match group is held whole or dropped rather than cut at the row the budget ran out on. - The
launchtool renders through a host-agnosticToolViewinstead of alaunch-render.tssibling, and each captured terminal row is cut to one row with an ellipsis instead of wrapping onto a second. - The
searchtool describes its dispatching card as aToolViewinstead of building terminal components in asearch-renderer.tssibling, which is deleted; a call reaches the same file, text or structure card it reached before, whether its type comes from the call or from the result's details, and the row for a call whose type is still arriving, the row naming a type that is not one of the three and the row for a failure that named no type draw in the column every other tool's row draws in instead of one column past it. - The
githubtool renders through a host-agnosticToolViewinstead of agh-renderer.tssibling, each failed job's held-back log count closes that job's own log rows instead of sitting under the last job in the group, and one held-back log line reads as1 more log line. - The
browsertool renders through a host-agnosticToolViewinstead of arender.tssibling, a spawned browser's binary path is shortened against the home directory, and a rebuilt transcript holding a result without its call states no section for the script it does not have. - The
readtool renders through a host-agnosticToolViewinstead of aread-render.tssibling, the file is the row's description so the row readsRead: src/example.ts, and the line-number gutter is a constant three columns instead of widening at the 10, 100 and 1000-line crossings. - The
asktool renders through a host-agnosticToolViewinstead of anask-render.tssibling, and an option label keeps the emphasis its author wrote through an inline-Markdown run instead of the tool colouring it. - The
web_searchtool renders through a host-agnosticToolViewinstead of arender.tssibling, andveyyon q's answer cap counts the answer's own lines rather than the rows a terminal wrapped them into. - The five
vibetools render through a host-agnosticToolViewinstead of avibe-render.tssibling, and the composer's caret blinks only on a surface that repaints and never on a message already delivered. - The
jobtool renders through a host-agnosticToolViewinstead of ajob-render.tssibling, and a collapsed card closes with one held-back note instead of a count on the closing branch of each tree it cut. - The
evaltool renders through a host-agnosticToolViewinstead of aneval-render.tssibling, a call is one card whose cells are labelled groups instead of one railed box per cell, and output that rewrote its row with a carriage return shows the row's last text instead of every draft of it. - The
lsptool renders through a host-agnosticToolViewinstead of arender.tssibling, a diagnostic is one row of location, severity and message, and references are one row per location instead of a per-file tree two levels deep. - The
bashtool renders through a host-agnosticToolViewinstead of abash-render.tssibling, and a sentence shaped like one of the tool's truncation, exit, wall-time, background or artifact notices that the program itself printed now survives instead of being deleted. - The
edittool renders through a host-agnosticToolViewinstead of anedit/renderer.tssibling, an edit spanning several files is one card whose sections are the files instead of one card per file, and the change counts are stated at the end of the row instead of a⟦+3/-1⟧suffix in the tool's name. - The
tasktool renders through a host-agnosticToolViewinstead of atask/render.tssibling, a call whose result has arrived stops repeating the brief and the agent list, and the live output under an agent is bounded to six rows instead of measured against the terminal's height. formatContextUsageis stated once in@veyyon/utils, which the status-line gauge, the subagent progress row and an eval cell's subagent tree all read, so a tool no longer imports a terminal module to format a token count. No user-visible behavior changes.- Tool cards and late diagnostic messages share diagnostic parsing, severity ranking and structured rendering, with home-directory paths shortened in late diagnostic output.
formatSessionSnapshotis stated once indebug/session-snapshot.tsfor both halves of the debug tool. No user-visible behavior changes.- A subprocess tool handler declares
renderFinalalone:renderInlinehad one producer and two readers that both skipped it by name, so nothing it returned ever reached a screen. No user-visible behavior changes. - A custom tool's
renderCallandrenderResultreturnHostViewinstead of a@veyyon/tuiComponent, so the published tool-plugin contract no longer makes every tool plugin a terminal plugin; a renderer that returns aComponentstill satisfies it unchanged. No user-visible behavior changes. - An extension's
MessageRendererandAssistantThinkingRendererand a hook'sHookMessageRendererreturnHostViewinstead of a@veyyon/tuiComponent. No user-visible behavior changes. - The autoresearch setup console and
init_experimentclamp breadth and attempts throughclamp/clampLowfrom@veyyon/utils/mathinstead of local copies of the same arithmetic. No user-visible behavior changes. - Time-Traveling Stream Rules, the todo board and thinking-effort resolution are session collaborators under
src/session/runtime/, each owning its own state behind a host interface it declares (8, 13 and 12 names), instead of 22 fields spread acrossAgentSession, which drops from 19761 to 18356 lines. No user-visible behavior changes. #processAgentEventrecords the turn's last assistant message once, in its synchronous prologue, instead of twice in the same synchronous stretch. No user-visible behavior changes.- The hidden nudge vocabulary is
session/nudges.tsalone: thecustomTypenames the session injects, the continuation cap, the plan-mode reminder budget, the plan-decision and prewalk trigger tables and the mid-run todo nudge gates, withHIDDEN_MESSAGE_TYPESnaming the set.agent-session-message-shapes.tsreads message shapes and declares no type name, andruntime/todo-runtime.tskeeps no copy of the nudge thresholds. No user-visible behavior changes. - Source-path comments in
prompts/all-registries.ts,prompts/eval-overrides.tsandtools/reroot-hint.tsname the benchmark modules they cite at their new paths undertests/evals/; behavior is unchanged. - Imports of the string, escape, keyboard, mouse and motion primitives name
@veyyon/utilsinstead of@veyyon/tui, which no longer re-exports them. No user-visible behavior changes. - No file under
session/names the terminal renderer: the session id comes from@veyyon/utils/ttyidand image visibility from the front end's probe, so@veyyon/tuiis no longer loaded on the conversation engine's account. No user-visible behavior changes. - Source directories are consolidated: memory (
memories,memory-backend,mnemopi,hindsight), discovery (tool-discovery,capability), speech (tts,stt) and debugging (dap) each live under one directory, and seventeen single-module directories fold into the concern they belong to. Subpath imports of@veyyon/coding-agentfollow the new layout. No user-visible behavior changes. - The terminal component tree is grouped by concern: the 94 modules that sat flat in
src/modes/terminal/components/now live undertranscript/,composer/,selectors/,dialogs/,chrome/,dashboard/andaccount/. Subpath imports of@veyyon/coding-agent/modes/terminal/components/*follow the new layout. No user-visible behavior changes. - The interactive terminal lives under
src/modes/terminal/, and the modes that draw no terminal —print-mode.ts,rpc/,acp/and the magic-keyword parsing inkeywords/— sit beside it rather than inside it. The palette moves tosrc/theme/and extension state aggregation tosrc/extensibility/extension-state/, both of which a headless run reads. Subpath imports of@veyyon/coding-agent/modes/*and@veyyon/coding-agent/theme/*follow the new layout. No user-visible behavior changes. - Goal mode, the working line and push-to-talk are their own modules under
src/modes/terminal/controllers/instead of living inline in the interactive mode, which drops from 5605 to 4495 lines. No user-visible behavior changes. - The session runtime's module-level declarations move out of
src/session/agent-session.tsinto six siblings —agent-session-types.ts,agent-session-permissions.ts,agent-session-queue.ts,agent-session-retry-fallback.ts,agent-session-compaction-policy.tsandagent-session-message-shapes.ts— so importing the session event union or config record no longer pulls in the 20909-line runtime, which drops to 19704 lines. Subpath imports of@veyyon/coding-agent/session/agent-sessionfollow the new layout; the package root barrel still exports every moved name. No user-visible behavior changes. - The session factory's free declarations move out of
src/sdk.tsinto six siblings undersrc/session/—factory-options.ts,factory-extensions.ts,factory-prompt.ts,factory-tools.ts,factory-mcp.tsandfactory-notices.ts— so namingCreateAgentSessionOptionsor calling a discovery helper no longer imports the composition root, which drops from 4861 to 3832 lines. Subpath imports of@veyyon/coding-agent/sdkfollow the new layout; the package root barrel still exports every moved name. No user-visible behavior changes. - Multi-target
ast_grepsearches now execute concurrently while preserving globally ordered paging, totals, parse errors, cancellation, and target-order failures. - The vibe screens, the image-inspection call and an LSP hover code block draw no border of their own inside a tool block, so a block keeps one left edge; a tree connector remains only where a row belongs to the row above it, in the eval value tree, the grep line gutter, the job tree and the LSP reference tree.
- The legacy Pi bundled-module generator states which package roots a compatibility shim serves, so the compiled-mode override sweep derives that set instead of carrying its own copy; behavior is unchanged.
- The
/agentsdashboard uses a centered, bordered card with bracketed tabs and explicit agent status words. - The status row reads its truncation limits from
tools/core/render-limits, a leaf that imports nothing, rather thantools/core/render-utils, which drops the tool renderers, path helpers and image resizing from the launch card's import graph; first-frame time is unchanged, because those modules only declare functions. - An MCP tool describes its call and result cards as a
ToolViewinstead of building terminal components inmcp/render.ts, which is deleted; the terminal states the same arguments, structure walk, raw rows, held-back count and spill warning, indented two columns under the row that heads them and without the branch glyph the call row opened with. SETTING_KIND_HANDLERSis typed per setting kind, so each handler receives the definition variant its key selects instead of the whole union widened toany. No user-visible behavior changes.- Subagent drive paths share abort-aware promise handling with unchanged cancellation behavior.
- Hook and user-message selectors share search editing without per-keystroke callback or query-array allocations.
Fixed
- Fixed the daemon broker client and broker startup exiting 0 silently mid-read:
Bun.file().text()/.json()does not ref the event loop, so a process that reached the token, lease, presence, or metadata read with nothing else pending could drain and exit before the read settled; the reads now usefs.readFile. - A pasted OAuth callback typed after a slash command that takes no arguments is consumed instead of being sent to the model as a prompt.
- Automatic maintenance cuts an oversized body until a summarization request fits a summarizer, instead of parking the session with "Compaction freed too little context to make progress" when every candidate was skipped for holding fewer tokens than the summary needed.
- Print, JSON and RPC mode flush Bun's stdout sink before exiting, so a piped consumer receives the whole last frame instead of losing up to 1 MiB of queued output.
- A spawned agent's card shows its resolved-model badge again on the live block, the registry path an extension wraps and the rebuilt transcript, per
agent.showResolvedModelBadge. - With
VEYYON_FORCE_IMAGE_PROTOCOL=sixelandVEYYON_ALLOW_SIXEL_PASSTHROUGH=1, a bash card draws an inline Sixel image row as the program wrote it instead of blanking it. - The extension graph walk reads each module file from disk once; the CommonJS check on a candidate reuses the walk's read instead of opening the file again.
veyyon --helpsummarisesworktreewith the profile-scoped path~/.veyyon/profiles/<name>/wt, matching the command's own description.- Legacy
hindsight.dynamicBankIdandhindsight.agentNamewritten as flat keys migrate tohindsight.scopingandhindsight.bankIdand are dropped on rewrite instead of surviving as dead entries. - Antigravity turns from a consumer Google account (
aicode-consumers) no longer fail with429 RESOURCE_EXHAUSTEDon every request: the backend rejects any system instruction carrying the upstream oh-my-pi conventions header, so the preamble now opensKeywords follow RFC 2119:instead ofRFC 2119:. - A Gemini or Antigravity 429 whose body is Google's generic
Resource has been exhausted (e.g. check quota)/RESOURCE_EXHAUSTEDis a per-minute throttle and retries on the same account after 45–75 seconds instead of being read as a 30-minute daily quota that exceededretry.maxDelayMsand ended the turn; the "exhausted your capacity … quota will reset" body still reads as the daily wall. - Removing the retired
providers.parallelFetchkey no longer leaves an emptyproviders:section in the rewritten config. - A nested legacy
task.isolation.enabledno longer overrides an explicittask.isolation.modeduring migration. - Corrected comments that named a distribution channel or runtime API the project does not use; no behavior change.
- A subagent that inherits the session's model shows that model and effort in its Subagents row, the task widget and the
/agentsroster, and keeps the badge when a follow-up turn wakes it. - An inherited subagent model's badge prints the effort the session settled on, so a parent running
autoshows the resolved level rather thanauto. - A subagent's row label is generated with the session's live model when no tiny, commit or smol role is configured, as a session title is, instead of the persisted default role.
- A compaction candidate whose single-request summary timed out and was completed in stages starts the next compaction on that model staged, instead of waiting out the same timeout first.
- Command-mode detection recognizes shell and Python prefixes after Unicode leading whitespace in loaded drafts.
- An MCP server that repeats a pagination cursor or never ends its pages no longer hangs
resources/list,resources/templates/listorprompts/list; every list method ends with a warning and the pages collected so far, astools/listalready did. - Tool result cards preserve raw-string and multipart text, including MCP output and grouped read previews, while runtime result cards select eval or launch from their call arguments.
- Collab reconnect snapshots preserve completed tool result text and display metadata across current and historical tool-call record formats.
- HTML export preserves provider fallback transitions and redacts their model text in primary and nested transcripts.
- Empty job results render their success or error message for every registered job alias.
- The website model catalog refreshes from its relocated repository path before using the deployed copy.
- Release validation checks native sentinels under every discovered workspace root, and shortened release notes link to the complete tagged changelog.
- Terminal input delivery continues to later subscribers when an earlier subscriber throws.
- Tool cards retain wire-provided results during expansion and sealing, and restore expanded output when subsequent updates contain raw results.
- Clearing or replacing presentation rows stops detached animations, preserves completed-call history, and keeps subsequent reads visible.
- Stopping a terminal presentation driver releases card animation clocks even when its engine is not running.
- Extension discovery resolves installed plugins from the session's selected profile.
- Python composer borders retain their mode color when an agent view is focused.
- Completed and rebuilt tool cards retain their call arguments and rendered call details.
- Disposing a tool card stops its animation clocks and detaches its presentation subscription.
- Legacy tool result renderers receive the completed call arguments for partial and final results.
- Background provider usage refreshes repaint the status line without requiring further input.
- Tool cards retain both call and result renderer failure notices with their fallback output.
- The library entry point retains read-selector functions, write-preview helpers, filesystem-source extraction and the goal view after renderer separation.
- An auto-compaction pass that finds nothing to summarize warns about a compaction dead end only while the context is still over the recovery band, so a pass that runs after maintenance already freed the context no longer advises starting a fresh session.
- The MCP add wizard retains manually entered credentials for stdio, HTTP and SSE servers and opens OAuth settings after authentication errors.
- Retry and Edit OAuth settings accept pointer input immediately after OAuth failure or cancellation in the MCP add wizard.
- Kernel codec and shutdown defaults remain active when optional configuration fields are undefined.
- Startup frame capture stops retaining terminal output after typing, recording settlement, or frame release.
- Disabled launch status rows remain blank when the terminal is narrower than the composer inset.
veyyon licensesreads the Open Sans and Source Code Pro notices from the trackeddocs/handbook/fonts/copies instead of the ignored mdbook build output, so the bundle regenerates and its test passes on a checkout without a handbook build.- A compaction that had just freed context no longer reports "Compaction freed too little context to make progress" when its entry is written in the same millisecond as the kept assistant turn; whether a turn predates the latest compaction is read from its position on the branch, not its timestamp.
- The home anchor sizes its fills, the welcome hero mounts, and the per-frame sizing pass runs on the screen the interactive mode renders on rather than the one its constructor built, and
startup.quietis read from the session's settings like the other startup reads. - An agent whose session is on screen is no longer parked under it: opening an agent pins it for as long as the main view points at it, a park deadline that elapses meanwhile is deferred, and the idle TTL counts again from the return to the main session.
- The task card lifts the missing-yield warning out of an agent's output under both its current spelling,
SYSTEM WARNING: Agent exited without calling yield tool, and theSubagentspelling a session file recorded before it; thetask:subagent:progressandtask:subagent:lifecyclebus channels a collab guest matches on keep their spelling. - Custom tools retain their declared call and result views when converted into extension tool definitions.
- Terminal tool cards shorten home-directory paths and replace tabs in metadata, notices, code, diffs, and generic argument previews before width fitting.
- Failed task results without agent details retain error text styling.
- Launch model context estimates exclude project context and clamp the remaining percentage to zero.
- Launched processes report completion even when they exit before the completion watch registers.
- Autoresearch best-result and confidence calculations exclude unmeasured placeholder zeros while retaining measured zero values.
- Configured shortcuts apply from the first editable frame, and model-selector shortcuts entered during startup preserve the draft through initialization.
- The launch composer repaints typed input before runtime initialization continues and preserves the mounted editor's change handler.
- Ordinary CLI launches no longer evaluate ACP authentication, and startup applies the configured theme once.
- Submissions entered during startup execute after initialization without waiting for a model turn, preserving later drafts and attachments through command handling and editor replacement.
- The launch composer shows the same linked-worktree location and draft-token estimate as the mounted session, avoiding a late footline repaint.
bun run gen:tool-viewsin the coding-agent package uses the relocatedclients/webgenerator.- A
web_searchrefusal, missing-credential, or provider-failure result is markedisError, so the model sees the failure as a failure. - A tool result whose image-visibility notice is unchanged is memoized across turns instead of allocating a new wrapper each time.
editandapply_patchshare one renderer object again, so a host that groups by identity (streamed-arg keys, the first-result replay) treats them as the same card. No user-visible change.- A debug adapter command resolves against the debug working directory only when it is spelled as a relative path (
./tool,../tool), restoring the prefixes a mechanical path rewrite had widened to any leading dot. - An overflow whose summary cannot fit any model no longer waits on a restore that never runs: the dead-end rescue truncates the oversized message to an artifact and the turn is retried, which the overflow-refusal suite now pins.
- A live tool card drawn from a
ToolViewspins again: a view is handed the frame it draws, so the spinner tick now rebuilds the card instead of only repainting it, and the streaming glyph on thebrowser,debug,eval,launch,sshandvibecards no longer sits frozen on the frame it was born with. - The
debug,resolve,retain,recallandreflectrenderer entries declare theinlinepolicy they declared before their cards became views. The flag reaches no reader in the terminal today, so nothing on screen changes. - A tool card's header keeps the subject it states: the middle-cut the edit card needs was applied to every framed card, so
ast_edit,file_search,text_search,structure_search,search_tool_bm25,inspect_image,launchandsshcut a query, a glob or a path to…in a narrow terminal to keep counts that already fitted. A card now asks for the cut, and the edit card is the one that asks. - A live card whose tool describes a
ToolViewobeys the merge policy its renderer entry states:debug,resolve,retain,recall,reflectandsshdrew the call row above the result card while the call was on screen, and drew one card when the transcript was rebuilt. veyyon config setandveyyon config resetcreate the profile's config directory before taking the file lock, so a first write into a profile that has no directory yet persists the setting instead of exiting 1 with ENOENT.goal-tool.tsno longer imports aViewSpantype it stopped using when the goal card became a view. No user-visible change.- A structure in a tool card stops at the nesting level its bound names: the view walk numbered a root key 0 where the terminal walk numbered it 1, so every
task,evaland argument card showed one level deeper than the collapsed and expanded bounds allow. - A JSON structure in a tool card states
1 more linewhere one line of a long string is held back, instead of1 more lines; the view walk wrote the phrase by hand where the terminal walk it replaced counted through the shared formatter. - The launch shell no longer evaluates the prompt registries:
modes/keywords/{orchestrate,ultrathink,workflow}-keyword.tskept imports ofprompts/subagent/rows,prompts/turn-control/rowsand the@veyyon/utilsbarrel after the notices they fed moved tomagic-keyword-notices.ts, which pulled 62 extra modules into the first frame's import graph. - The subagent model resolver's own precedence list no longer points at a fifth case it lost when
subagent.modelbecame the shared-switch layer. No user-visible change. - HTML export works again: the five assets
export/html/index.tsloads as strings — the markdown renderer, the template CSS, HTML and JS, and the generated tool views — lost theirwith { type: "text" }import attributes while unreleased, so each one loaded as a module and every export threwMissing 'default' export in module. - Seven published entry points the reorganization dropped are served again at their new paths:
./modes/terminal/components/*,./modes/terminal/components/extensions/*,./modes/terminal/components/status-line/*,./modes/terminal/controllers/*,./modes/terminal/setup-wizard/*,./modes/terminal/utils/*and./export/markit/*. Every subpath1.3.0published now has a successor key. - A source build of the compiled binary reaches the native addon package at
natives/bridge/bindings, its path since the bindings moved out ofpackages/, instead of failing on a chdir topackages/natives. - Tools are offered in
BUILTIN_TOOL_NAMESdeclaration order again: composing the registry from the five domain manifests reshuffled seven names, and tool order is prompt order, so every cached prompt prefix was invalidated for a session whose tool set had not changed. - The source launcher (
scripts/veyyon,scripts/veyyon.cmd) finds the native addon atnatives/bridge/bindings/nativeand provisions it through that package'sensure-native.ts, instead of dying at boot onpackages/natives/scripts/ensure-native.tsafter the bindings moved out ofpackages/. - The compiled binary builds again: its legacy-extension module surface resolved each bundled package by its directory name under
packages/, so the build died onpackages/natives/package.jsononce the bindings moved tonatives/bridge/bindingsand the terminal engine tohosts/terminal/engine. Each bundled package is now found by the name its manifest declares, wherever the member sits. - The compiled binary builds through its legacy-extension shims again: the
@veyyon/aiand TypeBox compat shims were named by hand-written paths underpackages/coding-agent/src/extensibility/, so the build reported two unresolvable entrypoints once both shims moved into@veyyon/kernel. Each shim is now resolved through its owning package's published subpath, at build time and at extension load. - The launch card states the context percentage recorded at the end of the last launch instead of
?, and falls back to?when the release, the model or the project changed. - A debug adapter that exits during startup now reports its own stderr —
pip install debugpyfor a missing debugpy — instead ofEPIPE: broken pipe, send. - A submission arriving in the tick after the terminal asks for input is no longer dropped, and loop mode's auto-submit timer no longer arms a tick late: the goal-mode exit check ran as an
awaiton every turn, and anasyncguard that returns early still yields before the input callback is installed. - A run that draws nothing no longer tells the model its picture is on screen.
-p, rpc and acp emit text, and the sentence attached to an image a tool returned was written from the launching terminal's graphics protocol, so the same read in a Kitty window reported the image as displayed to a pipe; the front end now states whether it draws, and a client that says nothing is taken at its word. - A
debuglaunch whose interpreter refuses now reports the interpreter's own exit code and stderr instead ofEPIPE: broken pipeorDAP adapter disposed: writing the first request onto an adapter that has just died fails at the pipe, and the pipe's error names nothing the user can fix.
Release notes were shortened from 430,143 characters to fit GitHub's 125,000-character body limit. Read the complete changelog and full commit range.