11# rsync builder - PRD
22
3- Status: v1.2 shipped (Phases 1-2 of the expansion done). This document records the
4- current state and the planned expansion so nothing gets lost.
3+ Status: v1.3 shipped (Phases 1-2 of the expansion done, plus terminal-free run + password auth).
4+ This document records the current state and the planned expansion so nothing gets lost.
55
66Last updated: 2026-07-04
77
@@ -14,7 +14,7 @@ folders to servers and wants the correct command without memorising flags.
1414Non-goals: multi-source lists (decided against), code signing/notarization,
1515being a general file manager.
1616
17- ## 2. Current state (shipped, v1.2 .0)
17+ ## 2. Current state (shipped, v1.3 .0)
1818
1919### UX
2020- Menu bar only app (` MenuBarExtra ` , ` .window ` style, ` LSUIElement ` ): no Dock icon,
@@ -31,28 +31,38 @@ being a general file manager.
3131 ` --rsync-path="sudo rsync" ` ) and an upload-only post-sync command appended as
3232 ` rsync … && ssh -p N user@host '<cmd>' ` . (v1.2)
3333- Live command with shell-safe quoting of every path (` shellQuote ` ).
34- - Copy to clipboard; Run in a separate terminal window (SwiftTerm), where SSH
35- password/passphrase prompts work.
36- - Buttons in a top bar (direction + Copy + Run + "•••" menu with Settings / About / Quit).
34+ - Optional SSH password field (` SecureField ` , in-memory only, never persisted). Run/Preview
35+ execute inline via ` Process ` (` /bin/sh -c ` ) with no terminal; the password is fed to ssh
36+ through an ` SSH_ASKPASS ` helper reading it from the child env (` RSYNC_BUILDER_PASS ` ), never
37+ written to disk. Empty password = key-based login. Host key auto-accepted via
38+ ` RSYNC_RSH=ssh -o StrictHostKeyChecking=accept-new ` . (v1.3)
39+ - Run state shown inline: a spinner in the Run/Preview button (doubling as cancel), a brief
40+ green success check for Run, or an in-panel error banner with the exit code + output.
41+ Preview surfaces its dry-run output in that banner. (v1.3)
42+ - Copy to clipboard; a "Run in terminal" fallback (SwiftTerm) stays in the "•••" menu for
43+ 2FA / host-key confirmation. (v1.3)
44+ - Buttons in a top bar (direction + Preview + Copy + Run + "•••" menu).
3745- Localization EN / RU, language switch in the Settings window (default EN).
38- - "Check for updates" in Settings : queries the GitHub Releases API (native ` URLSession ` ,
46+ - "Check for updates" in the "•••" menu : queries the GitHub Releases API (native ` URLSession ` ,
3947 no new dependency) and compares ` tag_name ` against the app version. A silent auto-check
40- runs at most once a day and surfaces only when an update is available.
48+ runs at most once a day and surfaces only when an update is available. (v1.3: moved from Settings)
4149- Native Liquid Glass, Pow button effects (gated by Reduce Motion), accessibility
4250 labels, ` @FocusState ` , incomplete-command guard (Run disabled until server + both paths).
4351- Form state persisted between launches (` @AppStorage ` ); server profiles and exclude
4452 list persisted via Defaults; real servers live only in local ` UserDefaults ` , never in source.
4553
4654### Architecture
47- - ` Command.swift ` : pure ` buildCommand(...) ` , ` shellQuote ` , ` ServerProfile ` , ` ExcludeItem ` ,
48- ` Direction ` , ` defaultProfiles ` (single ` example ` profile), ` defaultExcludes ` .
49- - ` App.swift ` : ` ContentView ` (the popover) + ` RsyncBuilderApp ` scene (` MenuBarExtra ` + ` Settings ` ).
50- - ` Terminal.swift ` : ` TerminalWindow ` (SwiftTerm run window).
51- - ` Persistence.swift ` : Defaults key for profiles.
52- - ` Localization.swift ` , ` Settings.swift ` , ` Menu.swift ` .
55+ - ` Command.swift ` : pure ` buildCommand(...) ` , ` shellQuote ` , ` runTransport ` , ` runEnvironment ` ,
56+ ` askpassScript ` , ` ServerProfile ` , ` ExcludeItem ` , ` Direction ` , defaults.
57+ - ` Runner.swift ` : ` CommandRunner ` (runs rsync via ` Process ` , publishes state/output; no window).
58+ - ` App.swift ` : ` ContentView ` (the popover, spinner-in-button + result banner) + ` RsyncBuilderApp ` scene.
59+ - ` Terminal.swift ` : ` TerminalWindow ` (SwiftTerm fallback run window).
60+ - ` Persistence.swift ` : Defaults keys for profiles/excludes.
61+ - ` Localization.swift ` , ` Settings.swift ` , ` Menu.swift ` , ` Update.swift ` .
5362- Deps: SwiftTerm, Pow, Defaults. Requires macOS 26+.
54- - Tests: assert-based logic check for ` buildCommand ` (` tests/main.swift ` ).
55- - CI: ` ci ` (build + logic test), ` lint ` (swift-format, non-blocking), ` release `
63+ - Tests: assert-based logic (` tests/main.swift ` ) + server-free smoke (` tests/smoke.swift ` :
64+ local rsync run + ` SSH_ASKPASS ` password delivery).
65+ - CI: ` ci ` (build + logic + smoke), ` lint ` (swift-format, non-blocking), ` release `
5666 (DMG on tag ` v* ` ), ` stale ` , ` dependency-review ` . Public repo, BSD-3.
5767
5868## 3. Planned expansion
0 commit comments