v3.5.0
Added
- Automatic
.envloading and aKP2BW_KEEPASS_FILEenv var for the database path --kp2bwnow loads a.env
file (searched upward from the current working directory) into the environment on startup, so settings can live in a
file instead of your shell history; a real shell variable still overrides a.enventry, keeping the documented CLI
flag > env var > default precedence. The KeePass database path -- previously CLI-only -- can now be supplied via
KP2BW_KEEPASS_FILE, making the positionalFILEoptional. A new.env.exampledocuments every supported variable. - Always-on DEBUG log file -- a complete DEBUG trace (including third-party
httpx/bw servedetail) is now always
written to a per-user log file regardless of console verbosity --%LOCALAPPDATA%\kp2bw\logson Windows, the platform
data dir elsewhere -- so a failed run leaves a full record to share without re-running with-v/-d. Override the
file withKP2BW_LOG_FILEor the directory withKP2BW_LOG_DIR. The console stays as quiet as before by default. - A heads-up when the
bw serveserver and CLI versions disagree -- a server/CLI version mismatch (a common source
of confusingbw servefailures) is flagged up front instead of surfacing later as an opaque error.
Changed
- KeePass tags and expiry now fold into a single
KP2BW_METAfield;Created/Modifiedare no longer migrated --
the metadata Bitwarden has no native slot for is serialised as YAML into oneKP2BW_METAcustom field (PyYAML
safe_dump, so control characters and the U+0085/2028/2029 line breaks are escaped, not silently corrupted) instead
of several separateTags/Expires/date fields, and the field is omitted entirely when an entry has neither tags nor
an expiry. Creation/modification timestamps are dropped: Bitwarden manages its own creation/revision dates and the API
cannot backdate them (a client-supplied date is ignored on create and rejected on update), so they had no real home.
Removed
- The unused legacy
bitwardenclientandbw_importmodules -- the deprecated subprocess-per-operation CLI wrapper
and the file-basedbw importpath, both long superseded by thebw serveHTTP transport and reachable from no
supported entry point, were removed (git history retains them for reference).
Fixed
kp2bw --version(and usage/error messages) now printkp2bw, not the launcher path. Python 3.14's argparse
derives the default program name from how the script was launched, so a console-script run through uv's trampoline
printedpython.exe C:\...\Scripts\kp2bw 3.4.1. The program name is now pinned tokp2bw.- Distinct entries sharing a title no longer collapse onto one Bitwarden item (silent data loss) -- deduplication
keyed on(folder, title), so several different logins that happened to share a title (e.g. four accounts all named
192.168.2.67) merged into a single item and re-runs churned non-idempotently. Every migrated item now carries its
source KeePass entry UUID in aKP2BW_IDfield and dedup keys on that: a match by UUID stays idempotent across
title/folder edits, an unstamped legacy item is adopted once and back-stamped, and only a genuinely new entry creates
a new item. - A single slow or dropped
bw serverequest no longer aborts the whole migration (#24) -- a create that timed out
or hit a dropped keep-alive connection (httpx.ReadTimeout/ReadError) crashed the run and stranded every entry
after it. Idempotent requests (including the startup sync/unlock) are now retried on a transient transport error, and
a per-entry create, folder, or collection failure is reported and skipped rather than fatal -- so the migration
finishes, the summary counts what failed, and a re-run safely adopts anything a timed-out request already created
server-side. bw serveHTTP errors now carry the server's actual message -- a failed request surfaces the response body
(Bitwarden/Vaultwarden's realmessage/ validation error) instead of an opaqueHTTP 400.- Windows: orphaned
bw serveprocesses are reaped reliably -- a shim-launchedbw serveruns as anode
grandchild thattaskkill /Tdid not always reap, leaving orphans that deadlocked the sharedbwapp-data on later
runs. Teardown now also kills whatever still listens on the serve port, regardless of process-tree shape.
Full Changelog: v3.4.1...v3.5.0