Skip to content

feat: add Windows platform support#5

Open
stefanzvonar wants to merge 17 commits intopaddo-tech:mainfrom
stefanzvonar:windows-support
Open

feat: add Windows platform support#5
stefanzvonar wants to merge 17 commits intopaddo-tech:mainfrom
stefanzvonar:windows-support

Conversation

@stefanzvonar
Copy link
Copy Markdown
Collaborator

@stefanzvonar stefanzvonar commented Feb 10, 2026

Summary

  • Full Windows support: daemon via Task Scheduler, symlinks with copy fallback, icacls permissions, PowerShell toast notifications
  • WinGet package manager integration (list, install, uninstall, upgrade, manifest sync)
  • Cross-platform package mapping (brew ↔ winget) with builtin defaults + user overrides
  • CI test matrix (ubuntu/macos/windows) and Windows release builds (.zip + SHA256)
  • Sync lock (fs2) to prevent concurrent daemon+CLI sync, format_version for forward compat
  • DRY refactors: default trait impls for PackageManager, centralized home_dir(), resolve_program() for .cmd files

Test plan

  • Verify cargo test passes on all 3 CI platforms
  • Test tether daemon install/start/stop/uninstall on Windows (Task Scheduler)
  • Test tether sync on Windows with encrypted dotfiles
  • Test symlink fallback to copy without Developer Mode
  • Test tether packages with winget
  • Test cross-platform sync: brew machine syncs, winget machine picks up mapped packages

- WinGet package manager with cross-platform mapping
- Task Scheduler daemon with restart-on-failure
- Symlink fallback to copy without Developer Mode
- Windows file permissions via icacls
- Cross-platform path normalization
- CI matrix and release pipeline for Windows
- Force-kill detached processes directly (no graceful WM_CLOSE attempt)
- Shorten daemon stop wait on Windows (already force-killed)
- Fix is_process_running to check ESRCH instead of ErrorKind::NotFound
- Strip all ACEs before granting current user in icacls
- Handle copy-mode files in ensure_symlink on Windows
- Add winget interactivity flags for gh install
- Use platform-generic upgrade message in format_version check
NamedTempFile holds exclusive lock; use into_temp_path() to release
before schtasks reads. Also fix platform-specific "launchd" help text.
winget emits \r-based progress spinners that end up on the same line
as the header. This shifts column offsets, causing empty parse results.
Strip content before the last \r on each line before parsing.
@stefanzvonar stefanzvonar requested a review from paddo February 10, 2026 13:47
Dashboard (ratatui TUI), releases v1.6.2–v1.9.1, and team
project filtering from main merged into windows-support.
Fixed dashboard libc usage to use centralized daemon::pid module.
@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

7 similar comments
@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 5, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse 1]
Another day, another diff to review
feat: add Windows platform support
We're building features, making something new
Push to main, watch the CI turn blue

[Chorus]
Ship it, ship it, let the code flow
Every commit helps the project grow
From pull request to production we go
DiffBeats playing while we ship the show

[Verse 2]
building features, cleaning up code, testing, shipping — that's what we do
Review approved, the pipeline's running through
Green checks lighting up the queue
Another merge, another song debut

[Chorus]
Ship it, ship it, let the code flow
Every commit helps the project grow
From pull request to production we go
DiffBeats playing while we ship the show

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 5, 2026

🎵 You've hit your song limit for this month! Upgrade to keep riffing →

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 5, 2026

🎵 You've hit your song limit for this month! Upgrade to keep riffing →

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 5, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse 1]
New feature on the scene, Windows in the mix
Daemon's runnin' smooth, no more CLI tricks
Task Scheduler's the key, orchestrating the flow
Symlinks are tricky, but we got the fallback, you know

[Chorus]
Windows party, let's celebrate, the code is alive
WinGet's on the menu, keeping the features thrive
Cross-platform mapping, a beautiful thing
This indie rock anthem, the joy that we sing

[Verse 2]
Test matrix is up, Ubuntu, macOS too
Windows builds released, a SHA256 for you
Sync lock's keepin' things safe, no clashes to see
Format_version's the future, for compatibility

[Chorus]
Windows party, let's celebrate, the code is alive
WinGet's on the menu, keeping the features thrive
Cross-platform mapping, a beautiful thing
This indie rock anthem, the joy that we sing

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 5, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 5, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

Cover Art

🎧 Listen now →

Lyrics
[Verse 1]
New feature, shining bright, a brand new stage
Windows calling, turning a new page
Daemon’s running, Task Scheduler's the key now
Symlinks failing? Copy fallback, anyhow

[Chorus]
Oh, the code's alive, it's cross-platform now!
Brew and WinGet, taking a bow!
CI matrix, a testing spree
.zip releases, for you and me

[Verse 2]
Sync lock's on, fs2's the name
Format version, playing the game
Permissions granted, with icacls' grace
Home directories, finding their place
PowerShell toasts, a notification chime
.cmd files, perfectly in time

[Chorus]
Oh, the code's alive, it's cross-platform now!
Brew and WinGet, taking a bow!
CI matrix, a testing spree
.zip releases, for you and me

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 6, 2026

/songify /picify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 6, 2026

🖼️ DiffBeats couldn't generate a diagram for this PR. Try again later!

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 6, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse 1]
New PR's in, the code's alive
Windows party, let's all jive
Daemon's running, Task Scheduler's the key
Symlinks fall back, sets our spirits free
Permissions handled, with PowerShell's might
Toast notifications, shining so bright

[Chorus]
Oh, Windows support, a beautiful thing
WinGet's in the mix, let the packages sing
From brew to WinGet, a cross-platform dream
Syncing our dotfiles, it would seem
Forward compat, with format_version's grace
This code's a winner, setting the pace

[Verse 2]
CI's humming, on Ubuntu's breeze
MacOS is happy, if you please
Windows builds too, .zip files so neat
SHA256 checksum, can't be beat
Sync lock's in place, to keep things in line
Default traits and home dirs, a design so fine

[Chorus]
Oh, Windows support, a beautiful thing
WinGet's in the mix, let the packages sing
From brew to WinGet, a cross-platform dream
Syncing our dotfiles, it would seem
Forward compat, with format_version's grace
This code's a winner, setting the pace

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 6, 2026

/picify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 6, 2026

🖼️ DiffBeats visualized this PR!

PR Diagram

Wes Anderson style changeset diagram for "feat: add Windows platform support"

…indows

Single-instance guard in run_daemon() ensures scheduled task and manual
start can't spawn duplicates. Skip second taskkill /F on Windows since
terminate_process already force-kills.
diff_package_lists used linear scan per element; restore HashSet lookup.
ensure_symlink deleted and re-copied identical content on Windows
copy-mode when checkout was newer — skip the cycle since atomic_write
already synced canonical.
…t parser

- Use whoami /user SID instead of spoofable USERNAME env var for icacls
- Write sensitive files to temp, restrict ACLs, then rename into place
- Derive winget column positions from separator+header layout instead
  of hardcoded English column names
…port

- Use well-known SID *S-1-5-32-544 instead of localized
  BUILTIN\Administrators group name in icacls
- sync_all() before persist() in write_file_secure for crash durability
- Allow copy-mode files to upgrade to symlinks when Developer Mode is
  enabled later (symlinks_available probe)
OnceLock avoids repeated temp file create/delete per sync cycle.
PID suffix prevents races between concurrent tether processes.
terminate_process already uses taskkill /F; the force_kill path is
unix-only so the Windows impl was unreachable.
@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 22, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 22, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse 1]
New feature's here, a Windows breeze
No more build failures, finally at ease
Daemon's running, Task Scheduler's the key
Symlinks fall back, you and me, we're free

[Chorus]
Oh, Windows, Windows, we've got you now
WinGet packages, taking a bow
Cross-platform sync, a beautiful sight
Building on all platforms, day and night

[Verse 2]
Sync lock's the bouncer, fs2 in the code
Format version's watching, down the road
Default trait impls, refactors so neat
Home dir's central, can't be beat

[Chorus]
Oh, Windows, Windows, we've got you now
WinGet packages, taking a bow
Cross-platform sync, a beautiful sight
Building on all platforms, day and night

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 27, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 27, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse]
New feature, now we're cruisin'
Windows support, no more losin'

[Chorus]
W-I-N, we're in it to win
Task scheduler, let the daemon spin
Symlinks copy, it's the new style
Windows wins, put down that file!

[Verse 2]
Packages mapping, a cross-platform dream
Sync lock active, it would seem

[Chorus]
W-I-N, we're in it to win
Task scheduler, let the daemon spin
Symlinks copy, it's the new style
Windows wins, put down that file!

@paddo
Copy link
Copy Markdown
Contributor

paddo commented Mar 28, 2026

/songify

@diffbeats
Copy link
Copy Markdown

diffbeats bot commented Mar 28, 2026

🎵 DiffBeats just dropped a track for this PR!

"feat: add Windows platform support"

🎧 Listen now →

Lyrics
[Verse]
New world order, Windows on the scene
Task Scheduler's calling, the daemon's keen
Symlink shuffle, copy's the last resort
PowerShell toasts, giving the report

[Chorus]
Windows wonderland, building up the code
WinGet package party, down the download road
Cross-platform mapping, a brew to WinGet plea
Sync lock protection, for you and for me

[Verse 2]
C I tests, a matrix in the sky
Ubuntu, Mac, and Windows, reaching high
DRY refactors, code's getting clean
Format version, the future's seen

[Chorus]
Windows wonderland, building up the code
WinGet package party, down the download road
Cross-platform mapping, a brew to WinGet plea
Sync lock protection, for you and for me

- team cleanup removes copied files, not just symlinks
- write_decrypted restricts ACLs on Windows (was default perms)
- cache current_user_sid in OnceLock (was shelling out every call)
- extract winget_cmd() builder to deduplicate Command construction
- extract generate_schtasks_xml() with tests for XML escaping
- add tests for write_file_secure, restrict_file_permissions, copy_dir_recursive
- allow clippy::too_many_arguments on status::render
@stefanzvonar
Copy link
Copy Markdown
Collaborator Author

Review fixes

Ran an architecture review on the Windows support code. Found and fixed:

Security

  • write_decrypted now restricts ACLs on Windows — decrypted dotfiles were landing with default permissions instead of user-only access
  • current_user_sid() cached in OnceLock — was spawning whoami on every write_file_secure call

Correctness

  • cleanup_team() now removes copied files/dirs, not just symlinks — on Windows without Developer Mode, create_symlink falls back to copy, so tether team remove was leaving orphaned files
  • Added winget case to config.is_manager_enabled() — was falling through to _ => true default

Code quality

  • Extracted winget_cmd() builder — 5 methods were constructing Command::new(resolve_program("winget")) independently
  • Extracted generate_schtasks_xml() from daemon install — testable, with XML escaping tests
  • Added #[allow(clippy::too_many_arguments)] on status::render (8th param installing added during merge)

Tests (+6)

  • write_file_secure creates file with correct content
  • restrict_file_permissions doesn't break file access
  • current_user_sid returns valid SID and caches result
  • generate_schtasks_xml produces valid XML structure
  • generate_schtasks_xml escapes &, <, >, " in paths
  • copy_dir_recursive preserves file contents and empty dirs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants