v1.0.36
@veyyon/ai
Fixed
- Fixed tool-call arguments for a
string | numberfield being coerced to a number when the model sent a quoted numeric string (for example"123"), which changed the argument's type and lost data such as leading zeros ("007"became7). A value that already satisfies its schema is now left unchanged; the numeric-string coercion still applies tonumber | nullfields, where the raw string matches neither branch.
@veyyon/coding-agent
Changed
veyyon updatenow printsChecksum verifiedafter it validates a downloaded binary against its published.sha256sidecar, so you can see the integrity check ran and passed rather than only hearing about it when it fails. This matches theverified sha256confirmation thecurlinstaller already prints. The automatic startup update stays silent to avoid corrupting the session UI.
Fixed
- Error messages no longer show a doubled
Error:prefix. A failure while adding, removing, updating, installing, uninstalling, linking, or toggling a plugin or marketplace, applying a personality, or changing the Mermaid rendering setting now readsFailed to …: <reason>instead ofFailed to …: Error: <reason>. veyyon update --check --forceon an already-up-to-date install now reportsUp to date at X; --force would reinstall itinstead of printingForcing reinstall of Xand then exiting without reinstalling anything. Check mode installs nothing, so the message now matches what the command actually does.- A failed release-binary download now reports the URL, the HTTP status, the requested version, and the missing asset instead of the bare
Download failed: Not Found. A 404 explains that the version may not exist or its build for your platform was not published and points atveyyon update --check; a 403/429 gives the rate-limit retry hint. This most helps installing a specific older version, where a mistyped or unpublished version previously failed with no clue what went wrong. - A
keybindings.yml/.jsonthat parses cleanly but is not a mapping (a top-level sequence or a bare scalar) is now quarantined and left at defaults instead of silently corrupting the user's map. Such a file previously reduced a scalar to an empty map and turned a sequence into bogus index-keyed bindings, which the migration writer then persisted over the original file. A blank or comments-only file still loads as an empty config with no complaint. - A settings file that parses cleanly but is not a mapping (a top-level YAML sequence, a bare scalar, or a string) is now preserved and reported instead of silently discarded. The loader previously collapsed any non-mapping root to an empty config with no signal, so a mis-edited settings file erased the user's whole configuration invisibly. Such a file is now quarantined and surfaced through
quarantinedFiles, exactly like an unparseable one, while a blank or comments-only file stays silent as a legitimately empty config. - The
apply_patchdefault filesystem now commits crash-atomically. The interactive editor already wrote through the crash-atomic LSP path, but the default filesystem behind programmatic and SDKapply_patchcallers still used a truncate-then-streamBun.write, so a crash mid-write could leave the target file truncated. Create, update, and move writes through the default now write a sibling temp and rename it over the target, preserving an existing file's permission bits. - A file move that overwrites an existing destination is now crash-atomic and mode-preserving, matching the edit/write path. The destination was previously written with a truncate-then-stream
Bun.write, so a crash mid-move could corrupt the file being overwritten; it now writes a sibling temp and renames it over the destination, carrying the destination's permission bits forward. - Edits and writes now commit crash-atomically. The file was previously written with a truncate-then-stream
Bun.write, so a crash,SIGINT, out-of-memory kill, or full disk mid-write could leave your source file truncated or empty. It now writes a sibling temp file and renames it over the target, so an interrupted write leaves either the whole old file or the whole new one. The existing file's permission bits (including a script's executable bit) are preserved across the write, and a write through a symlink keeps the symlink and updates its target. - The CLI no longer hangs while printing a fatal error whose cause chain forms a cycle. A wrapped error whose
causepointed back at itself (directly or through another error) made the cause walk loop forever; it now stops at the first repeat and notes the circular reference. - The Windows installer no longer destroys local edits in the source checkout. A source update ran
git reset --hard, and uninstall deleted the checkout outright, so local edits under~/.veyyon/src(an editedAGENTS.md) were lost. It now commits any local changes to aveyyon-local-<timestamp>branch before updating, moves an existing tree aside to<dir>.bak-<timestamp>instead of deleting it before a fresh clone, and refuses to delete a checkout that holds unpushed work on uninstall. This matches the protection the POSIX installer already had.
Security
- The self-updater now verifies a downloaded release binary against its published
.sha256sidecar before installing it, the same fail-closed integrity gate thecurland PowerShell installers already enforce. Previouslyveyyon updateand the automatic startup update downloaded and swapped the binary with only a post-install--versioncheck, which catches a wrong-version binary but not a corrupted or tampered same-version one. A missing, unparseable, or mismatched checksum now aborts the update and removes the partial download instead of installing something unverified.
@veyyon/hashline
Fixed
NodeFilesystem(the shipped disk-backed default) now writes crash-atomically.writeTextand the content form ofmovestream into a sibling temp file and rename it over the target, so a process death mid-write (SIGINT, OOM kill, full disk, power loss) leaves the user's source file whole rather than truncated. An existing file's permission bits and a symlinked target are preserved.
@veyyon/mnemopi
Fixed
BankManager.renameBanknow validates the source bank name, not only the destination. Every other bank operation rejects a name containing a path separator or.., but rename validated only the new name, so a source name like../outsideescaped the bank store and silently moved an out-of-tree directory into it. Both names are now validated before any filesystem change.- Content-addressed blob storage now writes crash-atomically.
storeBlobwrote the extracted blob straight to its finalsha256-named path withwriteFileSync, so a crash mid-write left a truncated file whose bytes no longer matched its name; theexistsSyncfast-path then treated that corrupt blob as present forever and every reader silently got wrong bytes. The write now goes through a sibling temp and rename, so a blob is always either absent or the exact correct bytes. - The one-time legacy triples-database migration now copies crash-atomically. It wrote the old database into its new location with
copyFileSync, which streams bytes into the destination, so a crash mid-copy left a truncated SQLite file that theexistsSyncguard then treated as a completed migration, silently losing the triple store. The copy now goes through a sibling temp and rename, so the destination only ever appears as the whole, valid database.
@veyyon/utils
Added
- Added
atomicWriteFilePreservingMode: an atomic write that carries the target file's current permission bits forward instead of stamping the0o600default (a new file gets0o644). Use it when overwriting an existing file whose mode must not change, such as a source file an editor rewrites or a script that must stay executable. - Added
splitReadSelector,stripReadSelector, and theREAD_SELECTOR_RANGE_LIST_SRCgrammar fragment: the one shared owner of the read-tool path-selector grammar (file.ts:50-200,:raw,:conflicts, andrange:rawcompounds). This grammar was previously hand-duplicated across packages with "keep in sync" comments; consolidating it here removes the drift risk.
What changed
41 commits since v1.0.27.
Features
- feat(update): confirm 'Checksum verified' on a successful self-update
Fixes
- fix(errors): remove remaining doubled 'Error:' prefixes; generalize the source-lock
- fix(plugin-cli): stop doubling the 'Error:' prefix in plugin command errors
- fix(update): honest --check --force message when already up to date
- fix(update): verify self-update binary checksum, fail closed (parity with installers)
- fix(update): rich release-binary download-failure message
- fix(settings-test): drop wrong SettingPath cast that broke the release typecheck
- fix(mnemopi): validate the source name in renameBank to close a traversal
- fix(keybindings): quarantine wrong-shape keybindings files instead of corrupting the map
- fix(settings): quarantine wrong-shape settings files instead of dropping them silently
- fix(hashline): crash-atomic NodeFilesystem writes
- fix(mnemopi): migrate the legacy triples database crash-atomically
- fix(mnemopi): write content-addressed blobs crash-atomically
- fix(coding-agent): make apply_patch default filesystem crash-atomic
- fix(coding-agent): make file moves crash-atomic; hoist mode-preserving atomic write
- fix(coding-agent): commit edits and writes crash-atomically
- fix(install): remove a partial binary download on failure (Windows)
- fix(cli): guard fatal-error cause walk against circular cause chains
- fix(ai): stop over-coercing string|number tool args to numbers
- fix(install): preserve local src edits on Windows update/uninstall (parity with install.sh)
Refactors
- refactor(slash-commands): drop unnecessary 'as SettingPath' casts
- refactor(utils): one owner for the read-tool selector grammar
Tests
- test(atomic-write): allowlist hashline's deliberate node:fs-only temp+rename
- test(ai): give heavy idempotence property tests explicit timeouts
- test(ai): cover in-flight slot release when a provider request fails
- test(ai): lock global idempotence of validateToolArguments on valid input
- test(install): extract + cover the Windows checksum verification path
- test(install): fix ps1 backup-branch discovery (scalar-index bug) and make it robust
Build & CI
- ci(test): give packages/ai a 20s per-test timeout floor
- ci: assert the published binary reports the release version (all platforms)
- ci: verify get.veyyon.dev serves the install script post-deploy (curl|sh regression guard)
- ci: verify the published Windows binary runs (install channel had no release verification)
Chores
- chore: bump version to 1.0.36
- chore: bump version to 1.0.35
- chore: bump version to 1.0.34
- chore: bump version to 1.0.33
- chore: bump version to 1.0.32
- chore: bump version to 1.0.31
- chore: bump version to 1.0.30
- chore: bump version to 1.0.29
- chore: bump version to 1.0.28
Full Changelog: v1.0.35...v1.0.36