-
Notifications
You must be signed in to change notification settings - Fork 3
User Prompts
Third Party Patcher uses swiftDialog for all user-facing UI during patching. There are five distinct prompt moments across the lifecycle of a patch cycle, each serving a different purpose.
swiftDialog must be installed at /usr/local/bin/dialog. Use patcher ensure to install or update it:
sudo /usr/local/bin/tpp/patcher ensure dialogIf swiftDialog is not installed and SwiftDialogEnabled is true, the apply phase falls back to silent behavior: blocking processes are handled per BlockingProcessAction without any user interaction.
patcher always runs as root. swiftDialog always runs as the console user, launched via launchctl asuser <uid> so dialogs appear in the user's session.
| Key | Default | Description |
|---|---|---|
SwiftDialogEnabled |
true |
Show interactive apply dialogs. Set to false for fully silent operation. |
ShowScanCheckProgressDialog |
true |
Show the mini progress window when scan/check/stage phases are triggered from PatcherMenu. |
When SwiftDialogEnabled is false, all apply dialog moments are skipped. Blocking processes are handled per BlockingProcessAction without any user interaction.
When scan, check, or stage phases are triggered from PatcherMenu (or via the --user-initiated flag from the command line), a small mini progress window appears to let the user know the operation is running.
These windows are non-interactive — the user cannot cancel or defer from them. They auto-close when the phase completes.

- Appears in the position set by
DialogScreenProgressPosition(default: bottom-right corner). - Shows the title, a message like "Scanning N applications for available updates…", a progress bar, and the current label being scanned.
- The icon updates per-label to show the app currently being scanned (the app's
.appicon or a synced metadata icon if available). The overlay icon is restored when the loop finishes. - When complete: shows a summary ("N updates available to download." or "No updates available."), holds for 5 seconds, then auto-closes.
- Same layout and position as the scan window.
- Shows "Checking N applications for available updates…" and updates the current app icon as each app is checked.
- Completion summary matches scan.
- Same layout, same position.
- Shows "Downloading N updates…".
- While each file downloads, the progress bar switches to indeterminate (spinning) mode. When the download completes, it advances to a determinate bar.
- Completion summary shows how many updates are staged and ready.

Before any installations begin, the user is shown a prompt telling them that updates are ready. This is the primary opportunity to defer. The dialog is blocking — patcher waits for the user's choice (or the countdown timer) before proceeding.

-
Title:
AppTitlepreference. -
Message: "You have N software updates that are ready to be installed." Additional lines appear based on context:
- If updates have been pending for more than 0 days: "These updates have been pending for N day(s)."
- If the hard deadline has been reached: "Installation is required — the maximum deferral deadline has been reached."
- Info box (side panel): Shows the current deferral status — days pending and how many times deferred so far.
-
Countdown timer:
DeferralCountdownSeconds(default: 300 s). When it reaches zero,DeferralAutomaticActionfires. -
Defer button (left): Visible unless the hard deadline has been reached. If
DeferralTimerMenuis set, a "Defer for" dropdown appears with the configured time options. IfDeferralTimerMenuis empty, the button label shows the default duration, e.g. "Defer (4 hours)". - Continue button (right): Proceeds immediately to the progress dialog.

The "Defer for" dropdown is populated from DeferralTimerMenu. Each value is a number of minutes, formatted for display (e.g. 5 → "5 minutes", 60 → "1 hour", 1440 → "1 day"). The selected value from DeferralTimerDefault is pre-selected.
| Key | Default | Description |
|---|---|---|
DeferralTimerMenu |
"5,30,60,120,240,480,1440" |
Comma-separated list of deferral durations (in minutes) shown in the dropdown |
DeferralTimerDefault |
240 |
Pre-selected duration in the dropdown, and the duration used when no menu is shown |
DeferralCountdownSeconds |
300 |
Seconds before the countdown timer fires the automatic action |
DeferralAutomaticAction |
"defer" |
Action when the countdown expires: "defer" auto-defers for DeferralTimerDefault minutes; "continue" proceeds |
When DeadlineDaysHard days have elapsed since updates were first staged, the Defer button and dropdown are removed. The message states that installation is required. The user can only click Continue (or wait for the countdown), and the update proceeds regardless.
When AggressivePatchDayDeferral is true (the default), the available deferral options in the dropdown are progressively capped as the deadline approaches. On the final patch day, long deferral options are removed and eventually the Defer button itself disappears — leaving only Continue. See Deferral and Deadlines for the full capping schedule.
When apply is triggered directly from PatcherMenu, patcher receives the --user-initiated flag and skips the deferral prompt entirely, proceeding straight to the progress dialog. The intent is that if the user is explicitly asking to install updates now, offering to defer is unnecessary.
Once the user clicks Continue (or the countdown auto-proceeds), the full-size progress dialog launches. patcher does not wait for it to be ready — it begins installing and drives the dialog through a command file that swiftDialog watches.


-
Title:
AppTitle. -
Info box (side panel): App title, update count, and "These updates are being applied".
-
List: One row per app being updated. Each row shows the app icon, app name, and a status indicator:
Status Icon Text Not started yet Pending "Waiting" Currently installing Spinner "Installing…" Successfully installed Checkmark (green) "→ 1.2.3" (new version) Installation failed X (red) "Failed" Skipped (blocking process) Warning "Skipped" or reason -
Progress bar: advances as each app completes.
-
Progress text: "[current/total] Installing AppName…"
-
Updating… button (disabled while installs are running) → Done button when complete.
-
? help button: opens the support info panel (see below).
When all apps have finished, the dialog transitions to a completion summary:
- Info box updates to: "All waiting updates have been applied."
- Progress bar fills completely.
- Progress text shows the summary: "N update(s) applied successfully" or "N updated · M skipped · P failed".
- The Done button is enabled and brought to focus.

When UnattendedExit is true (the default), patcher sends a quit: command to swiftDialog after UnattendedExitSeconds seconds (default: 60) if the user has not clicked Done. The dialog closes automatically.
Set UnattendedExit to false to require the user to explicitly click Done before the dialog closes.
| Key | Default | Description |
|---|---|---|
UnattendedExit |
true |
Auto-close the progress dialog after completion |
UnattendedExitSeconds |
60 |
Seconds to wait before auto-closing |
Clicking the ? button opens a help panel in the progress dialog. It shows:
- Support team name, phone, email, and website (from the
SupportTeam*preferences). - Computer serial number.
- The timestamp when the apply phase started.
- Version information: Third Party Patcher, Installomator, swiftDialog, macOS.

During the apply phase, patcher checks each label's blockingProcesses list before installing. If a blocking process is found to be running, BlockingProcessAction determines what happens next.
The blocking process check is skipped entirely. The installer runs even if the blocking app is open. Use this when the installer handles open files gracefully.
The blocking process is terminated with pkill -x without any user notification. Installation proceeds immediately. The app is not relaunched afterward.
The label is skipped this cycle. No dialog is shown. The update will be retried on the next apply cycle. This is counted as a deferral for deadline purposes.
A brief notification banner is shown:
- Title: "Update Pending: AppName"
- Message: "[AppName] needs to be quit to apply an update. Please close it when convenient."
- Icon: caution, with the blocking app's icon as overlay.
The banner auto-dismisses. The label is then skipped for this cycle. Useful for a softer touch than prompt when the update is not yet urgent.

A separate swiftDialog window appears, pausing the progress dialog while waiting for the user's choice.

What it shows:
- Title: "[AppName] Update Paused"
- Message: "[AppName] needs to be updated, but [processName] is currently running. Please save your work and quit [processName] before the timer expires, or click Skip Update to postpone this update."
- Icon: caution, with the blocking app's icon as overlay.
-
Countdown timer:
BlockingProcessCountdownSeconds(default: 120 s). - Skip Update button (left): Skips this label for this cycle.
- Quit [processName] button (right): Force-quits the blocking process and proceeds with the install.
Outcomes:
| Exit condition | What happens |
|---|---|
| User clicks "Skip Update" | Label skipped; counted as a deferral |
| Timer expires (exit 4) | Blocking process is force-quit; installation proceeds |
| User clicks "Quit [App]" | Blocking process is force-quit; installation proceeds; app is relaunched after install |
| Key | Default | Description |
|---|---|---|
BlockingProcessAction |
"prompt" |
One of: ignore, kill, defer, notify, prompt
|
BlockingProcessCountdownSeconds |
120 |
Seconds shown on the blocking process prompt countdown |
applyQuiet is a separate subcommand used by the scheduler when QuietApplyEnabled is true. It runs with no dialogs of any kind. Labels whose blocking process is currently running are silently skipped — they are not counted as deferrals and will appear in the next interactive apply pass. This lets patcher opportunistically install updates in the background between scheduled interactive apply cycles.
When FocusCheckEnabled is true (the default) and Focus mode, Do Not Disturb, or a display assertion (e.g. screen sharing, presentation software) is active, patcher skips all dialog moments and defers silently for DeferralTimerFocus minutes. Focus deferrals do not increment the deferral counter and do not advance the deadline.
The Focus check is disabled after DeadlineDaysFocus days of pending updates (default: 4 days), so a Focus deferral cannot be used indefinitely to avoid a hard deadline.
| Key | Default | Description |
|---|---|---|
FocusCheckEnabled |
true |
Respect Focus / DND / display assertions |
DeferralTimerFocus |
60 |
Minutes to defer automatically when Focus is detected |
See Deferral and Deadlines for when Focus deferrals are disabled.
All dialogs share a consistent appearance controlled by these preferences:
| Key | Default | Description |
|---|---|---|
AppTitle |
"Third Party Patcher" |
Title shown in all dialog windows |
DialogIcon |
(empty) | Path to a custom .png or .icns, or an SF=<symbolName> string. When empty, patcher generates a hardware-accurate computer icon with a red arrow badge and caches it at Config/dialog_icon.png. |
UseOverlayIcon |
true |
Show a small MDM or management agent badge on the dialog icon |
OverlayIcon |
(empty) | Path to the overlay image. When empty, auto-detected from known MDM agent paths (Jamf, Intune, Company Portal, Kandji, Workspace ONE, Addigy, FileWave, App Store) |
DialogOnTop |
true |
Keep dialog windows above all other windows |
DialogScreenPosition |
"center" |
Position of the deferral and progress dialogs. Options: center, top, bottom, topleft, topright, bottomleft, bottomright
|
DialogScreenProgressPosition |
"bottomright" |
Position of the mini scan/check/stage progress windows |
When DialogIcon is not set, patcher composes a 512×512 PNG from the system's hardware-accurate computer image (NSImage.computerName — renders the correct Mac model: MacBook, iMac, Mac mini, Mac Pro, etc.) with a red download arrow overlaid at the top center. The result is cached at /Library/Application Support/Patcher/Config/dialog_icon.png after the first run. To force a refresh, delete that file.
Contact information appears in the ? help panel of the apply progress dialog so users know who to contact if they have questions.
| Key | Default | Description |
|---|---|---|
SupportTeamName |
"IT Support Team" |
Team name heading |
SupportTeamEmail |
"support@company.com" |
Email address (shown as plain text) |
SupportTeamPhone |
"None" |
Phone number; omitted if set to "None"
|
SupportTeamWebsite |
"None" |
Website URL; omitted if set to "None" or empty |
