Skip to content

v0.6.1: WebSocket API, Docker host mounts, DRY refactor, Windows timezone fix

Choose a tag to compare

@PleasePrompto PleasePrompto released this 26 Feb 05:35
· 331 commits to main since this release

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.1 added as a core dependency (no-op on Linux/macOS where system tzdata exists).
  • Crashproof UTC fallback: resolve_user_timezone() can now never raise, even if tzdata is 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:

  1. Race condition: Result delivery happened AFTER update_run_status() wrote to cron_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.
  2. Deleted job guard: if self._on_result and job: silently dropped results when get_job() returned None (e.g., after a manager reload). Removed the job dependency — delivery now uses the title captured at execution start.
  3. Unhandled exceptions: _run_at only caught CancelledError, so any unexpected exception in _execute_job silently 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 runpip instead of pipx upgrade to 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.mounts list — 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 filetype with 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@botname support
  • CancelledError propagation fix, shutdown kills active CLI processes

Upgrade

ductor upgrade
# or
pip install --upgrade ductor