v0.6.1: WebSocket API, Docker host mounts, DRY refactor, Windows timezone fix
ductor v0.6.1
Hotfix release for Windows timezone crash, cron result delivery, and upgrade pipeline issues discovered in v0.6.0.
Windows timezone fix
On Windows, Python's zoneinfo module requires the tzdata PyPI package because Windows has no system IANA timezone database. Without it, all ZoneInfo() calls fail — including the ZoneInfo("UTC") fallback — crashing the bot when scheduling cron jobs or checking quiet hours.
tzdata>=2024.1added as a core dependency (no-op on Linux/macOS where system tzdata exists).- Crashproof UTC fallback:
resolve_user_timezone()can now never raise, even iftzdatais somehow unavailable at runtime. - Resilient cron scheduling: A timezone error in a single job no longer crashes the entire cron observer.
Cron result delivery fix
Cron job results were silently dropped under two conditions:
- Race condition: Result delivery happened AFTER
update_run_status()wrote tocron_jobs.json. The file-watcher could detect the change, trigger a reschedule, and cancel the running task — before the Telegram message was sent. Results are now delivered before the file write. - Deleted job guard:
if self._on_result and job:silently dropped results whenget_job()returnedNone(e.g., after a manager reload). Removed thejobdependency — delivery now uses the title captured at execution start. - Unhandled exceptions:
_run_atonly caughtCancelledError, so any unexpected exception in_execute_jobsilently lost the result and prevented rescheduling. Now catches and logs all exceptions.
4 new tests verify these scenarios.
Windows upgrade pipeline fix
pipx upgrade fails on Windows with PermissionError because the running bot process locks ductor.exe. The upgrade also failed when PyPI CDN hadn't propagated the new version yet.
- Windows: Uses
pipx runpipinstead ofpipx upgradeto upgrade inside the venv without touching the locked global exe. - Always verify version: Checks installed version after upgrade regardless of exit code — pipx may report failure from exe lock while the package is actually upgraded.
- CDN propagation hint: When pip can't find the pinned version, shows "not yet available on all PyPI mirrors" instead of raw pip error.
v0.6.0 features (included)
WebSocket API server (beta)
New direct connection transport alongside Telegram — designed for the upcoming ductor mobile app.
- E2E encryption: NaCl Box (Curve25519 + XSalsa20-Poly1305) with ephemeral keypairs per connection.
- Bearer-auth HTTP endpoints:
/files(list),/files/<path>(download),/upload(multipart). - Gated behind explicit opt-in:
ductor api enable/ductor api disable.
Docker host directory mounts
Mount host project directories into the Docker sandbox. (#12)
- Config:
docker.mountslist — paths mounted at/mnt/<basename>. - CLI:
ductor docker mount/unmount/mounts.
Files module
Shared file handling for Telegram and API transports.
- Magic-bytes MIME detection via
filetypewith extension fallback. - Video/audio native upload with document fallback.
Background tasks
/bg command for fire-and-forget tasks with notification delivery.
DRY refactor
8 new shared modules, 2324 tests passing.
Other v0.6.0 changes
- Upgrade pipeline with retry and version verification
- Abort word expansion (
esc,hold,aufhören) - GitHub issue templates
- Fail-closed
file_access,/stop@botnamesupport - CancelledError propagation fix, shutdown kills active CLI processes
Upgrade
ductor upgrade
# or
pip install --upgrade ductor