diff --git a/ee/maintained-apps/inputs/homebrew/tabby.json b/ee/maintained-apps/inputs/homebrew/tabby.json new file mode 100644 index 0000000000..79b5e84bda --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tabby.json @@ -0,0 +1,10 @@ +{ + "name": "Tabby", + "unique_identifier": "org.tabby", + "token": "tabby", + "installer_format": "zip", + "slug": "tabby/darwin", + "default_categories": [ + "Developer tools" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tableau-prep.json b/ee/maintained-apps/inputs/homebrew/tableau-prep.json new file mode 100644 index 0000000000..8576ada837 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tableau-prep.json @@ -0,0 +1,10 @@ +{ + "name": "Tableau Prep", + "unique_identifier": "com.tableau.Tableau-Prep-tableau-2026-1", + "token": "tableau-prep", + "installer_format": "dmg", + "slug": "tableau-prep/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tabtab.json b/ee/maintained-apps/inputs/homebrew/tabtab.json new file mode 100644 index 0000000000..4ec161fa24 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tabtab.json @@ -0,0 +1,10 @@ +{ + "name": "TabTab", + "unique_identifier": "riccqi.TabTab", + "token": "tabtab", + "installer_format": "dmg", + "slug": "tabtab/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/taskade.json b/ee/maintained-apps/inputs/homebrew/taskade.json new file mode 100644 index 0000000000..d64ecd522c --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/taskade.json @@ -0,0 +1,10 @@ +{ + "name": "Taskade", + "unique_identifier": "com.taskade", + "token": "taskade", + "installer_format": "dmg", + "slug": "taskade/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/taskbar.json b/ee/maintained-apps/inputs/homebrew/taskbar.json new file mode 100644 index 0000000000..6db1d75753 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/taskbar.json @@ -0,0 +1,10 @@ +{ + "name": "Taskbar", + "unique_identifier": "com.fpfxtknjju.wbgcdolfev", + "token": "taskbar", + "installer_format": "zip", + "slug": "taskbar/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/teacode.json b/ee/maintained-apps/inputs/homebrew/teacode.json new file mode 100644 index 0000000000..854c9a2a0e --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/teacode.json @@ -0,0 +1,10 @@ +{ + "name": "TeaCode", + "unique_identifier": "com.apptorium.TeaCode-dm", + "token": "teacode", + "installer_format": "zip", + "slug": "teacode/darwin", + "default_categories": [ + "Developer tools" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/termius.json b/ee/maintained-apps/inputs/homebrew/termius.json new file mode 100644 index 0000000000..93735e0c97 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/termius.json @@ -0,0 +1,10 @@ +{ + "name": "Termius", + "unique_identifier": "com.termius-dmg.mac", + "token": "termius", + "installer_format": "dmg", + "slug": "termius/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tex-live-utility.json b/ee/maintained-apps/inputs/homebrew/tex-live-utility.json new file mode 100644 index 0000000000..63a7874dfb --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tex-live-utility.json @@ -0,0 +1,10 @@ +{ + "name": "TeX Live Utility", + "unique_identifier": "com.googlecode.mactlmgr.tlu", + "token": "tex-live-utility", + "installer_format": "zip", + "slug": "tex-live-utility/darwin", + "default_categories": [ + "Utilities" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/texshop.json b/ee/maintained-apps/inputs/homebrew/texshop.json new file mode 100644 index 0000000000..dffaf163cc --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/texshop.json @@ -0,0 +1,10 @@ +{ + "name": "TeXShop", + "unique_identifier": "edu.uo.texshop.tex", + "token": "texshop", + "installer_format": "zip", + "slug": "texshop/darwin", + "default_categories": [ + "Productivity" + ] +} diff --git a/ee/maintained-apps/inputs/homebrew/thaw.json b/ee/maintained-apps/inputs/homebrew/thaw.json new file mode 100644 index 0000000000..e7a34890d1 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/thaw.json @@ -0,0 +1,10 @@ +{ + "name": "Thaw", + "unique_identifier": "com.stonerl.Thaw", + "token": "thaw", + "installer_format": "zip", + "slug": "thaw/darwin", + "default_categories": [ + "Utilities" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/thorium.json b/ee/maintained-apps/inputs/homebrew/thorium.json new file mode 100644 index 0000000000..a46fe0bbfd --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/thorium.json @@ -0,0 +1,10 @@ +{ + "name": "Thorium Reader", + "unique_identifier": "io.github.edrlab.thorium", + "token": "thorium", + "installer_format": "dmg", + "slug": "thorium/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/threema.json b/ee/maintained-apps/inputs/homebrew/threema.json new file mode 100644 index 0000000000..634a2abeee --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/threema.json @@ -0,0 +1,10 @@ +{ + "name": "Threema", + "unique_identifier": "threema-consumer-web", + "token": "threema", + "installer_format": "dmg", + "slug": "threema/darwin", + "default_categories": [ + "Communication" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/thumbsup.json b/ee/maintained-apps/inputs/homebrew/thumbsup.json new file mode 100644 index 0000000000..91eacf6c96 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/thumbsup.json @@ -0,0 +1,10 @@ +{ + "name": "ThumbsUp", + "unique_identifier": "com.devon-technologies.ThumbsUp", + "token": "thumbsup", + "installer_format": "zip", + "slug": "thumbsup/darwin", + "default_categories": [ + "Utilities" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/ticktick.json b/ee/maintained-apps/inputs/homebrew/ticktick.json new file mode 100644 index 0000000000..db721d198f --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/ticktick.json @@ -0,0 +1,10 @@ +{ + "name": "TickTick", + "unique_identifier": "com.TickTick.task.mac", + "token": "ticktick", + "installer_format": "dmg", + "slug": "ticktick/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tidal.json b/ee/maintained-apps/inputs/homebrew/tidal.json new file mode 100644 index 0000000000..17511d64d5 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tidal.json @@ -0,0 +1,10 @@ +{ + "name": "TIDAL", + "unique_identifier": "com.tidal.desktop", + "token": "tidal", + "installer_format": "zip", + "slug": "tidal/darwin", + "default_categories": [ + "Productivity" + ] +} diff --git a/ee/maintained-apps/inputs/homebrew/tiles.json b/ee/maintained-apps/inputs/homebrew/tiles.json new file mode 100644 index 0000000000..a3f4d69dcc --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tiles.json @@ -0,0 +1,10 @@ +{ + "name": "Sempliva Tiles", + "unique_identifier": "com.sempliva.Tiles", + "token": "tiles", + "installer_format": "dmg", + "slug": "tiles/darwin", + "default_categories": [ + "Utilities" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/timescribe.json b/ee/maintained-apps/inputs/homebrew/timescribe.json new file mode 100644 index 0000000000..2cd4857f5f --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/timescribe.json @@ -0,0 +1,10 @@ +{ + "name": "TimeScribe", + "unique_identifier": "de.amplussoftware.timescribe", + "token": "timescribe", + "installer_format": "zip", + "slug": "timescribe/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/timing.json b/ee/maintained-apps/inputs/homebrew/timing.json new file mode 100644 index 0000000000..664f45e421 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/timing.json @@ -0,0 +1,10 @@ +{ + "name": "Timing", + "unique_identifier": "info.eurocomp.Timing2", + "token": "timing", + "installer_format": "dmg", + "slug": "timing/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/topaz-gigapixel-ai.json b/ee/maintained-apps/inputs/homebrew/topaz-gigapixel-ai.json new file mode 100644 index 0000000000..32384a440f --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/topaz-gigapixel-ai.json @@ -0,0 +1,10 @@ +{ + "name": "Topaz Gigapixel AI", + "unique_identifier": "com.topazlabs.TopazGigapixelAI", + "token": "topaz-gigapixel-ai", + "installer_format": "pkg", + "slug": "topaz-gigapixel-ai/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/topaz-photo-ai.json b/ee/maintained-apps/inputs/homebrew/topaz-photo-ai.json new file mode 100644 index 0000000000..3c4dc4974c --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/topaz-photo-ai.json @@ -0,0 +1,10 @@ +{ + "name": "Topaz Photo AI", + "unique_identifier": "com.topazlabs.TopazPhotoAI", + "token": "topaz-photo-ai", + "installer_format": "pkg", + "slug": "topaz-photo-ai/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/topaz-video-ai.json b/ee/maintained-apps/inputs/homebrew/topaz-video-ai.json new file mode 100644 index 0000000000..04027c62a5 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/topaz-video-ai.json @@ -0,0 +1,10 @@ +{ + "name": "Topaz Video AI", + "unique_identifier": "com.topazlabs.Topaz-Video-AI", + "token": "topaz-video-ai", + "installer_format": "pkg", + "slug": "topaz-video-ai/darwin", + "default_categories": [ + "Developer tools" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/topnotch.json b/ee/maintained-apps/inputs/homebrew/topnotch.json new file mode 100644 index 0000000000..19a2ced215 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/topnotch.json @@ -0,0 +1,10 @@ +{ + "name": "TopNotch", + "unique_identifier": "pl.maketheweb.TopNotch", + "token": "topnotch", + "installer_format": "dmg", + "slug": "topnotch/darwin", + "default_categories": [ + "Developer tools" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tradingview.json b/ee/maintained-apps/inputs/homebrew/tradingview.json new file mode 100644 index 0000000000..61fe224ac5 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tradingview.json @@ -0,0 +1,10 @@ +{ + "name": "TradingView Desktop", + "unique_identifier": "com.tradingview.tradingviewapp.desktop", + "token": "tradingview", + "installer_format": "dmg", + "slug": "tradingview/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/transfer.json b/ee/maintained-apps/inputs/homebrew/transfer.json new file mode 100644 index 0000000000..59082eb6af --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/transfer.json @@ -0,0 +1,10 @@ +{ + "name": "Transfer", + "unique_identifier": "com.adriangranados.Transfer", + "token": "transfer", + "installer_format": "dmg", + "slug": "transfer/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/transmission.json b/ee/maintained-apps/inputs/homebrew/transmission.json new file mode 100644 index 0000000000..412a2f088d --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/transmission.json @@ -0,0 +1,10 @@ +{ + "name": "Transmission", + "unique_identifier": "org.m0k.transmission", + "token": "transmission", + "installer_format": "dmg", + "slug": "transmission/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/trex.json b/ee/maintained-apps/inputs/homebrew/trex.json new file mode 100644 index 0000000000..1ff0772576 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/trex.json @@ -0,0 +1,10 @@ +{ + "name": "TRex", + "unique_identifier": "com.ameba.TRex", + "token": "trex", + "installer_format": "zip", + "slug": "trex/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/trezor-suite.json b/ee/maintained-apps/inputs/homebrew/trezor-suite.json new file mode 100644 index 0000000000..49e38da11e --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/trezor-suite.json @@ -0,0 +1,10 @@ +{ + "name": "TREZOR Suite", + "unique_identifier": "io.trezor.TrezorSuite", + "token": "trezor-suite", + "installer_format": "dmg", + "slug": "trezor-suite/darwin", + "default_categories": [ + "Security" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tripmode.json b/ee/maintained-apps/inputs/homebrew/tripmode.json new file mode 100644 index 0000000000..e58f830737 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tripmode.json @@ -0,0 +1,10 @@ +{ + "name": "TripMode", + "unique_identifier": "ch.tripmode.TripMode", + "token": "tripmode", + "installer_format": "zip", + "slug": "tripmode/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/tuple.json b/ee/maintained-apps/inputs/homebrew/tuple.json new file mode 100644 index 0000000000..af9bbe59c7 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/tuple.json @@ -0,0 +1,10 @@ +{ + "name": "Tuple", + "unique_identifier": "app.tuple.app", + "token": "tuple", + "installer_format": "zip", + "slug": "tuple/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/twine-app.json b/ee/maintained-apps/inputs/homebrew/twine-app.json new file mode 100644 index 0000000000..d8f7b210b0 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/twine-app.json @@ -0,0 +1,10 @@ +{ + "name": "Twine", + "unique_identifier": "com.electron.twine", + "token": "twine-app", + "installer_format": "dmg", + "slug": "twine-app/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/twobird.json b/ee/maintained-apps/inputs/homebrew/twobird.json new file mode 100644 index 0000000000..d633ea3184 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/twobird.json @@ -0,0 +1,10 @@ +{ + "name": "Twobird", + "unique_identifier": "com.gingerlabs.bagel", + "token": "twobird", + "installer_format": "dmg", + "slug": "twobird/darwin", + "default_categories": [ + "Communication" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/typeface.json b/ee/maintained-apps/inputs/homebrew/typeface.json new file mode 100644 index 0000000000..b58a5361bb --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/typeface.json @@ -0,0 +1,10 @@ +{ + "name": "Typeface", + "unique_identifier": "com.criminalbird.typeface.standalone", + "token": "typeface", + "installer_format": "dmg", + "slug": "typeface/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/typinator.json b/ee/maintained-apps/inputs/homebrew/typinator.json new file mode 100644 index 0000000000..5c6b231b33 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/typinator.json @@ -0,0 +1,10 @@ +{ + "name": "Typinator", + "unique_identifier": "com.macility.typinator2", + "token": "typinator", + "installer_format": "dmg", + "slug": "typinator/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/inputs/homebrew/typora.json b/ee/maintained-apps/inputs/homebrew/typora.json new file mode 100644 index 0000000000..1437e33ea3 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/typora.json @@ -0,0 +1,10 @@ +{ + "name": "Typora", + "unique_identifier": "abnerworks.Typora", + "token": "typora", + "installer_format": "dmg", + "slug": "typora/darwin", + "default_categories": [ + "Productivity" + ] +} \ No newline at end of file diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 4e49520953..f2979a78b0 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -6280,6 +6280,13 @@ "unique_identifier": "org.sbarex.SourceCodeSyntaxHighlight", "description": "Syntax Highlight is a quicklook extension for source files." }, + { + "name": "Tabby", + "slug": "tabby/darwin", + "platform": "darwin", + "unique_identifier": "org.tabby", + "description": "Tabby is a terminal emulator, SSH and serial client." + }, { "name": "Tableau Desktop", "slug": "tableau-desktop/windows", @@ -6287,6 +6294,13 @@ "unique_identifier": "Tableau Desktop", "description": "Tableau Desktop is a powerful data visualization and business intelligence platform for analyzing and presenting data insights." }, + { + "name": "Tableau Prep", + "slug": "tableau-prep/darwin", + "platform": "darwin", + "unique_identifier": "com.tableau.Tableau-Prep-tableau-2026-1", + "description": "Tableau Prep is a combine, shape, and clean your data for analysis." + }, { "name": "Tableau Desktop", "slug": "tableau/darwin", @@ -6308,6 +6322,13 @@ "unique_identifier": "TablePlus", "description": "TablePlus is a native GUI tool for relational databases." }, + { + "name": "TabTab", + "slug": "tabtab/darwin", + "platform": "darwin", + "unique_identifier": "riccqi.TabTab", + "description": "TabTab is a window and tab manager." + }, { "name": "Tailscale", "slug": "tailscale-app/darwin", @@ -6322,6 +6343,27 @@ "unique_identifier": "Tailscale", "description": "Tailscale is mesh VPN based on WireGuard." }, + { + "name": "Taskade", + "slug": "taskade/darwin", + "platform": "darwin", + "unique_identifier": "com.taskade", + "description": "Taskade is a task manager for teams." + }, + { + "name": "Taskbar", + "slug": "taskbar/darwin", + "platform": "darwin", + "unique_identifier": "com.fpfxtknjju.wbgcdolfev", + "description": "Taskbar is a windows-style taskbar as a Dock replacement." + }, + { + "name": "TeaCode", + "slug": "teacode/darwin", + "platform": "darwin", + "unique_identifier": "com.apptorium.TeaCode-dm", + "description": "TeaCode is a text expanding app for developers." + }, { "name": "TeamViewer", "slug": "teamviewer/darwin", @@ -6371,6 +6413,27 @@ "unique_identifier": "com.gravitational.teleport.tsh", "description": "Teleport Suite is a modern SSH server for teams managing distributed infrastructure." }, + { + "name": "Termius", + "slug": "termius/darwin", + "platform": "darwin", + "unique_identifier": "com.termius-dmg.mac", + "description": "Termius is a SSH client." + }, + { + "name": "TeX Live Utility", + "slug": "tex-live-utility/darwin", + "platform": "darwin", + "unique_identifier": "com.googlecode.mactlmgr.tlu", + "description": "TeX Live Utility is a graphical user interface for TeX Live Manager." + }, + { + "name": "TeXShop", + "slug": "texshop/darwin", + "platform": "darwin", + "unique_identifier": "TeXShop", + "description": "TeXShop is a LaTeX and TeX editor and previewer." + }, { "name": "TextExpander", "slug": "textexpander/darwin", @@ -6385,6 +6448,13 @@ "unique_identifier": "TextExpander", "description": "TextExpander is an application that lets you create and insert pre-made snippets of text anywhere." }, + { + "name": "Thaw", + "slug": "thaw/darwin", + "platform": "darwin", + "unique_identifier": "com.stonerl.Thaw", + "description": "Thaw is a menu bar manager." + }, { "name": "The Unarchiver", "slug": "the-unarchiver/darwin", @@ -6392,6 +6462,27 @@ "unique_identifier": "cx.c3.theunarchiver", "description": "The Unarchiver is an archive extraction utility that supports many formats including ZIP, RAR, and 7z." }, + { + "name": "Thorium Reader", + "slug": "thorium/darwin", + "platform": "darwin", + "unique_identifier": "io.github.edrlab.thorium", + "description": "Thorium Reader is an epub reader." + }, + { + "name": "Threema", + "slug": "threema/darwin", + "platform": "darwin", + "unique_identifier": "threema-consumer-web", + "description": "Threema is an end-to-end encrypted instant messaging application." + }, + { + "name": "ThumbsUp", + "slug": "thumbsup/darwin", + "platform": "darwin", + "unique_identifier": "com.devon-technologies.ThumbsUp", + "description": "ThumbsUp is a batch image thumbnail generation utility." + }, { "name": "Thunderbird", "slug": "thunderbird/darwin", @@ -6406,6 +6497,41 @@ "unique_identifier": "Mozilla Thunderbird (x64 en-US)", "description": "Thunderbird is a free and open-source e-mail client." }, + { + "name": "TickTick", + "slug": "ticktick/darwin", + "platform": "darwin", + "unique_identifier": "com.TickTick.task.mac", + "description": "TickTick is a to-do & task list manager." + }, + { + "name": "TIDAL", + "slug": "tidal/darwin", + "platform": "darwin", + "unique_identifier": "com.tidal.desktop", + "description": "TIDAL is a music streaming service with high fidelity sound and hi-def video quality." + }, + { + "name": "Sempliva Tiles", + "slug": "tiles/darwin", + "platform": "darwin", + "unique_identifier": "com.sempliva.Tiles", + "description": "Sempliva Tiles is a window manager." + }, + { + "name": "TimeScribe", + "slug": "timescribe/darwin", + "platform": "darwin", + "unique_identifier": "de.amplussoftware.timescribe", + "description": "TimeScribe is an app for working time tracker." + }, + { + "name": "Timing", + "slug": "timing/darwin", + "platform": "darwin", + "unique_identifier": "info.eurocomp.Timing2", + "description": "Timing is an automatic time and productivity tracking app." + }, { "name": "Todoist", "slug": "todoist-app/darwin", @@ -6420,6 +6546,34 @@ "unique_identifier": "Todoist", "description": "Todoist is a to do list and a planning center for individuals and teams." }, + { + "name": "Topaz Gigapixel AI", + "slug": "topaz-gigapixel-ai/darwin", + "platform": "darwin", + "unique_identifier": "com.topazlabs.TopazGigapixelAI", + "description": "Topaz Gigapixel AI is an AI image upscaler." + }, + { + "name": "Topaz Photo AI", + "slug": "topaz-photo-ai/darwin", + "platform": "darwin", + "unique_identifier": "com.topazlabs.TopazPhotoAI", + "description": "Topaz Photo AI is an AI image enhancer." + }, + { + "name": "Topaz Video AI", + "slug": "topaz-video-ai/darwin", + "platform": "darwin", + "unique_identifier": "com.topazlabs.Topaz-Video-AI", + "description": "Topaz Video AI is a video upscaler and quality enhancer." + }, + { + "name": "TopNotch", + "slug": "topnotch/darwin", + "platform": "darwin", + "unique_identifier": "pl.maketheweb.TopNotch", + "description": "TopNotch is a utility to hide the notch." + }, { "name": "Tor Browser", "slug": "tor-browser/darwin", @@ -6448,6 +6602,27 @@ "unique_identifier": "Tower", "description": "Tower is a git client focusing on power and productivity." }, + { + "name": "TradingView Desktop", + "slug": "tradingview/darwin", + "platform": "darwin", + "unique_identifier": "com.tradingview.tradingviewapp.desktop", + "description": "TradingView Desktop is an app for charting and social-networking for investment traders." + }, + { + "name": "Transfer", + "slug": "transfer/darwin", + "platform": "darwin", + "unique_identifier": "com.adriangranados.Transfer", + "description": "Transfer is a standalone TFTP, FTP, and SFTP server." + }, + { + "name": "Transmission", + "slug": "transmission/darwin", + "platform": "darwin", + "unique_identifier": "org.m0k.transmission.LSSharedFileList", + "description": "Transmission is an open-source BitTorrent client." + }, { "name": "Transmit", "slug": "transmit/darwin", @@ -6455,6 +6630,27 @@ "unique_identifier": "com.panic.Transmit", "description": "Transmit is a file transfer application." }, + { + "name": "TRex", + "slug": "trex/darwin", + "platform": "darwin", + "unique_identifier": "com.ameba.TRex", + "description": "TRex is an easy to use text extraction tool." + }, + { + "name": "TREZOR Suite", + "slug": "trezor-suite/darwin", + "platform": "darwin", + "unique_identifier": "io.trezor.TrezorSuite", + "description": "TREZOR Suite is a companion app for the Trezor hardware wallet." + }, + { + "name": "TripMode", + "slug": "tripmode/darwin", + "platform": "darwin", + "unique_identifier": "ch.tripmode.TripMode", + "description": "TripMode is a tool to control your data usage on slow or expensive networks." + }, { "name": "Tunnelblick", "slug": "tunnelblick/darwin", @@ -6462,6 +6658,20 @@ "unique_identifier": "net.tunnelblick.tunnelblick", "description": "Tunnelblick is a free and open-source OpenVPN client." }, + { + "name": "Tuple", + "slug": "tuple/darwin", + "platform": "darwin", + "unique_identifier": "app.tuple.app", + "description": "Tuple is a remote pair programming app." + }, + { + "name": "Twine", + "slug": "twine-app/darwin", + "platform": "darwin", + "unique_identifier": "com.electron.twine", + "description": "Twine is a tool for telling interactive, nonlinear stories." + }, { "name": "Twingate", "slug": "twingate/darwin", @@ -6476,6 +6686,34 @@ "unique_identifier": "Twingate", "description": "Twingate is a zero trust network access platform." }, + { + "name": "Twobird", + "slug": "twobird/darwin", + "platform": "darwin", + "unique_identifier": "com.gingerlabs.bagel", + "description": "Twobird is an email client with collaborative notes." + }, + { + "name": "Typeface", + "slug": "typeface/darwin", + "platform": "darwin", + "unique_identifier": "com.criminalbird.typeface.standalone", + "description": "Typeface is a font manager application." + }, + { + "name": "Typinator", + "slug": "typinator/darwin", + "platform": "darwin", + "unique_identifier": "com.macility.typinator2", + "description": "Typinator is a tool to automate the insertion of frequently used text and graphics." + }, + { + "name": "Typora", + "slug": "typora/darwin", + "platform": "darwin", + "unique_identifier": "abnerworks.Typora", + "description": "Typora is a configurable document editor that supports Markdown." + }, { "name": "UA Connect", "slug": "ua-connect/darwin", diff --git a/ee/maintained-apps/outputs/tabby/darwin.json b/ee/maintained-apps/outputs/tabby/darwin.json new file mode 100644 index 0000000000..7bb9f1bdda --- /dev/null +++ b/ee/maintained-apps/outputs/tabby/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.0.234", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'org.tabby';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'org.tabby' AND version_compare(bundle_short_version, '1.0.234') < 0);" + }, + "installer_url": "https://github.com/Eugeny/tabby/releases/download/v1.0.234/tabby-1.0.234-macos-arm64.zip", + "install_script_ref": "9b06e89d", + "uninstall_script_ref": "60d71fa6", + "sha256": "e5073aed89680a591dbb0fb34a2d7de031c792d160c5475357547234ebe29af7", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "60d71fa6": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Tabby.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.tabby.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/tabby'\ntrash $LOGGED_IN_USER '~/Library/Caches/org.tabby'\ntrash $LOGGED_IN_USER '~/Library/Caches/org.tabby.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/org.tabby'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ByHost/org.tabby.ShipIt.*.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.tabby.helper.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.tabby.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.tabby.savedState'\ntrash $LOGGED_IN_USER '~/Library/Services/Open Tabby here.workflow'\ntrash $LOGGED_IN_USER '~/Library/Services/Paste path into Tabby.workflow'\n", + "9b06e89d": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'org.tabby'\nif [ -d \"$APPDIR/Tabby.app\" ]; then\n\tsudo mv \"$APPDIR/Tabby.app\" \"$TMPDIR/Tabby.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Tabby.app\" \"$APPDIR\"\nrelaunch_application 'org.tabby'\n" + } +} diff --git a/ee/maintained-apps/outputs/tableau-prep/darwin.json b/ee/maintained-apps/outputs/tableau-prep/darwin.json new file mode 100644 index 0000000000..cb07b79bad --- /dev/null +++ b/ee/maintained-apps/outputs/tableau-prep/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2026.1.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.tableau.Tableau-Prep-tableau-2026-1';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.tableau.Tableau-Prep-tableau-2026-1' AND version_compare(bundle_short_version, '2026.1.2') < 0);" + }, + "installer_url": "https://downloads.tableau.com/esdalt/tableau_prep/2026.1.2/TableauPrep-2026-1-2-arm64.dmg", + "install_script_ref": "42b99ade", + "uninstall_script_ref": "ec459ac1", + "sha256": "4dc01a186883a91749cd825de9a1bd44d321e407dddd0d87a1178cd2b0dcf1da", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "42b99ade": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# install pkg files\nquit_and_track_application 'com.tableau.Tableau-Prep-tableau-2026-1'\nsudo installer -pkg \"$TMPDIR/Tableau Prep Builder.pkg\" -target /\nrelaunch_application 'com.tableau.Tableau-Prep-tableau-2026-1'\n", + "ec459ac1": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_pkg_files 'com.amazon.redshiftodbc'\nforget_pkg 'com.amazon.redshiftodbc'\nremove_pkg_files 'com.simba.sparkodbc'\nforget_pkg 'com.simba.sparkodbc'\nremove_pkg_files 'com.simba.sqlserverodbc'\nforget_pkg 'com.simba.sqlserverodbc'\nremove_pkg_files 'com.tableausoftware.desktopShortcut'\nforget_pkg 'com.tableausoftware.desktopShortcut'\nremove_pkg_files 'com.tableausoftware.FLEXNet.11.*'\nforget_pkg 'com.tableausoftware.FLEXNet.11.*'\nremove_pkg_files 'com.tableausoftware.Maestro.app'\nforget_pkg 'com.tableausoftware.Maestro.app'\nremove_pkg_files 'com.tableausoftware.oracle'\nforget_pkg 'com.tableausoftware.oracle'\nremove_pkg_files 'com.tableausoftware.postgresql'\nforget_pkg 'com.tableausoftware.postgresql'\nremove_pkg_files 'com.tableausoftware.telemetry'\nforget_pkg 'com.tableausoftware.telemetry'\nremove_pkg_files 'simba.sparkodbc'\nforget_pkg 'simba.sparkodbc'\nsudo rm -rf '/Library/Application Support/Tableau Prep Builder'\nsudo rm -rf '/Library/Preferences/FLEXnet Publisher'\ntrash $LOGGED_IN_USER '~/Documents/My Tableau Prep Repository'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Tableau Prep Builder 2026.1.2'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tableau.caching'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tableau.Tableau-Prep-tableau-2026-1.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tableausoftware.tableauprep.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tableausoftware.tabminerva.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.tableausoftware.tableauprep.savedState'\ntrash $LOGGED_IN_USER '~/Library/Tableau'\n" + } +} diff --git a/ee/maintained-apps/outputs/tableau-public/darwin.json b/ee/maintained-apps/outputs/tableau-public/darwin.json new file mode 100644 index 0000000000..1a08cf2af6 --- /dev/null +++ b/ee/maintained-apps/outputs/tableau-public/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2026.1.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.tableausoftware.tableaupublic';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.tableausoftware.tableaupublic' AND version_compare(bundle_short_version, '2026.1.2') < 0);" + }, + "installer_url": "https://downloads.tableau.com/esdalt/2026.1.2/TableauPublic-2026-1-2-arm64.pkg", + "install_script_ref": "cd51213e", + "uninstall_script_ref": "fab952d2", + "sha256": "c3dcadf1467c5296f62e42369c5de65bd7edff62a816d60d3c96feffcb493130", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "cd51213e": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.tableausoftware.tableaupublic'\nsudo installer -pkg \"$TMPDIR/TableauPublic-2026-1-2-arm64.pkg\" -target /\nrelaunch_application 'com.tableausoftware.tableaupublic'\n", + "fab952d2": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_pkg_files 'com.tableausoftware.FLEXNet.*'\nforget_pkg 'com.tableausoftware.FLEXNet.*'\nremove_pkg_files 'com.tableausoftware.Public.app'\nforget_pkg 'com.tableausoftware.Public.app'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tableau.caching'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tableausoftware.MapTiles'\n" + } +} diff --git a/ee/maintained-apps/outputs/tabtab/darwin.json b/ee/maintained-apps/outputs/tabtab/darwin.json new file mode 100644 index 0000000000..c94c462140 --- /dev/null +++ b/ee/maintained-apps/outputs/tabtab/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2.1.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'riccqi.TabTab';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'riccqi.TabTab' AND version_compare(bundle_short_version, '2.1.1') < 0);" + }, + "installer_url": "https://github.com/riccqi/TabTabApp/releases/download/prod/tabtab.dmg", + "install_script_ref": "db1cb8ec", + "uninstall_script_ref": "0be65ed1", + "sha256": "no_check", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "0be65ed1": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TabTab.app\"\ntrash $LOGGED_IN_USER '~/Library/Caches/riccqi.TabTab'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/riccqi.TabTab'\ntrash $LOGGED_IN_USER '~/Library/Preferences/riccqi.TabTab.plist'\n", + "db1cb8ec": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'riccqi.TabTab'\nif [ -d \"$APPDIR/TabTab.app\" ]; then\n\tsudo mv \"$APPDIR/TabTab.app\" \"$TMPDIR/TabTab.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TabTab.app\" \"$APPDIR\"\nrelaunch_application 'riccqi.TabTab'\n" + } +} diff --git a/ee/maintained-apps/outputs/taskade/darwin.json b/ee/maintained-apps/outputs/taskade/darwin.json new file mode 100644 index 0000000000..32c03c09bb --- /dev/null +++ b/ee/maintained-apps/outputs/taskade/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "4.6.14", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.taskade';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.taskade' AND version_compare(bundle_short_version, '4.6.14') < 0);" + }, + "installer_url": "https://apps.taskade.com/updates/Taskade-4.6.14-universal.dmg", + "install_script_ref": "5cdc6a81", + "uninstall_script_ref": "2a7fe7f4", + "sha256": "912d7fe1f71feac48ffd22fc5deed8cfadccd7b995c22246155f3fa8de94d16b", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "2a7fe7f4": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Taskade.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/taskade'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.taskade.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.taskade.savedState'\n", + "5cdc6a81": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.taskade'\nif [ -d \"$APPDIR/Taskade.app\" ]; then\n\tsudo mv \"$APPDIR/Taskade.app\" \"$TMPDIR/Taskade.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Taskade.app\" \"$APPDIR\"\nrelaunch_application 'com.taskade'\n" + } +} diff --git a/ee/maintained-apps/outputs/taskbar/darwin.json b/ee/maintained-apps/outputs/taskbar/darwin.json new file mode 100644 index 0000000000..2700ecb0be --- /dev/null +++ b/ee/maintained-apps/outputs/taskbar/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.6.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.fpfxtknjju.wbgcdolfev';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.fpfxtknjju.wbgcdolfev' AND version_compare(bundle_short_version, '1.6.1') < 0);" + }, + "installer_url": "https://lawand.io/wp-content/uploads/2026/05/taskbar-1.6.1.zip", + "install_script_ref": "aed90141", + "uninstall_script_ref": "6a449e87", + "sha256": "86cd42b1c58063f53cb7b2ab4a73d4256da120ab01b229aef7098af39a9e236b", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "6a449e87": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Taskbar.app\"\ntrash $LOGGED_IN_USER '~/Library/Caches/com.fpfxtknjju.wbgcdolfev'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.fpfxtknjju.wbgcdolfev'\ntrash $LOGGED_IN_USER '~/Library/LaunchAgents/com.fpfxtknjju.wbgcdolfev.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.fpfxtknjju.wbgcdolfev.plist'\ntrash $LOGGED_IN_USER '~/Library/WebKit/com.fpfxtknjju.wbgcdolfev'\n", + "aed90141": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.fpfxtknjju.wbgcdolfev'\nif [ -d \"$APPDIR/Taskbar.app\" ]; then\n\tsudo mv \"$APPDIR/Taskbar.app\" \"$TMPDIR/Taskbar.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Taskbar.app\" \"$APPDIR\"\nrelaunch_application 'com.fpfxtknjju.wbgcdolfev'\n" + } +} diff --git a/ee/maintained-apps/outputs/teacode/darwin.json b/ee/maintained-apps/outputs/teacode/darwin.json new file mode 100644 index 0000000000..09bc7dec71 --- /dev/null +++ b/ee/maintained-apps/outputs/teacode/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.1.3", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.apptorium.TeaCode-dm';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.apptorium.TeaCode-dm' AND version_compare(bundle_short_version, '1.1.3') < 0);" + }, + "installer_url": "https://www.apptorium.com/public/products/teacode/releases/TeaCode-1.1.3.zip", + "install_script_ref": "5639b7d9", + "uninstall_script_ref": "8cbcf890", + "sha256": "2e2545beafe4c77ef52e76ff49edf1d4dbceed2a6bf6c8c1b22424112480478b", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "5639b7d9": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.apptorium.TeaCode-dm'\nif [ -d \"$APPDIR/TeaCode.app\" ]; then\n\tsudo mv \"$APPDIR/TeaCode.app\" \"$TMPDIR/TeaCode.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TeaCode.app\" \"$APPDIR\"\nrelaunch_application 'com.apptorium.TeaCode-dm'\n", + "8cbcf890": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TeaCode.app\"\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.apptorium.TeaCode-dm.plist'\n" + } +} diff --git a/ee/maintained-apps/outputs/termius/darwin.json b/ee/maintained-apps/outputs/termius/darwin.json new file mode 100644 index 0000000000..53fc94baaf --- /dev/null +++ b/ee/maintained-apps/outputs/termius/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "9.39.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.termius-dmg.mac';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.termius-dmg.mac' AND version_compare(bundle_short_version, '9.39.0') < 0);" + }, + "installer_url": "https://autoupdate.termius.com/mac-arm64/Termius.dmg", + "install_script_ref": "41ddb02e", + "uninstall_script_ref": "70a856f6", + "sha256": "no_check", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "41ddb02e": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.termius-dmg.mac'\nif [ -d \"$APPDIR/Termius.app\" ]; then\n\tsudo mv \"$APPDIR/Termius.app\" \"$TMPDIR/Termius.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Termius.app\" \"$APPDIR\"\nrelaunch_application 'com.termius-dmg.mac'\n", + "70a856f6": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf '/Library/Preferences/com.termius-dmg.mac.plist'\nsudo rm -rf \"$APPDIR/Termius.app\"\ntrash $LOGGED_IN_USER '~/.termius'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Termius'\ntrash $LOGGED_IN_USER '~/Library/Logs/Termius'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.termius-dmg.mac.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/tex-live-utility/darwin.json b/ee/maintained-apps/outputs/tex-live-utility/darwin.json new file mode 100644 index 0000000000..d6122e7347 --- /dev/null +++ b/ee/maintained-apps/outputs/tex-live-utility/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.57", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.googlecode.mactlmgr.tlu';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.googlecode.mactlmgr.tlu' AND version_compare(bundle_short_version, '1.57') < 0);" + }, + "installer_url": "https://github.com/amaxwell/tlutility/releases/download/1.57/TeX.Live.Utility.app-1.57.zip", + "install_script_ref": "629b22f1", + "uninstall_script_ref": "2fc25cd2", + "sha256": "e738c49250a1b62568bdf9d8333e6cfbd57b08185659073f2ab7a6103881dce4", + "default_categories": [ + "Utilities" + ] + } + ], + "refs": { + "2fc25cd2": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TeX Live Utility.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/TeX Live Utility'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexFile/TeX Live Utility Help*'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.googlecode.mactlmgr.tlu'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.googlecode.mactlmgr.tlu'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.googlecode.mactlmgr.tlu.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.googlecode.mactlmgr.tlu.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.googlecode.mactlmgr.tlu.savedState'\n", + "629b22f1": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.googlecode.mactlmgr.tlu'\nif [ -d \"$APPDIR/TeX Live Utility.app\" ]; then\n\tsudo mv \"$APPDIR/TeX Live Utility.app\" \"$TMPDIR/TeX Live Utility.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TeX Live Utility.app\" \"$APPDIR\"\nrelaunch_application 'com.googlecode.mactlmgr.tlu'\n" + } +} diff --git a/ee/maintained-apps/outputs/texshop/darwin.json b/ee/maintained-apps/outputs/texshop/darwin.json new file mode 100644 index 0000000000..a24b11579f --- /dev/null +++ b/ee/maintained-apps/outputs/texshop/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "5.57", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'TeXShop';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'TeXShop' AND version_compare(bundle_short_version, '5.57') < 0);" + }, + "installer_url": "https://pages.uoregon.edu/koch/texshop/texshop-64/texshop557.zip", + "install_script_ref": "9bf7aba0", + "uninstall_script_ref": "88d3d3ad", + "sha256": "08aa26a5dfacfa67bacedbc73d57fe07b64dcfe49e9fab34a3be1dc5372d20d4", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "88d3d3ad": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TeXShop.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/texshop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/TeXShop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/Generated/TeXShop Help*'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexFile/TeXShop Help*'\ntrash $LOGGED_IN_USER '~/Library/Caches/TeXShop'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/TeXShop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/TeXShop.plist'\ntrash $LOGGED_IN_USER '~/Library/TeXShop'\ntrash $LOGGED_IN_USER '~/Library/WebKit/TeXShop'\n", + "9bf7aba0": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'TeXShop'\nif [ -d \"$APPDIR/TeXShop.app\" ]; then\n\tsudo mv \"$APPDIR/TeXShop.app\" \"$TMPDIR/TeXShop.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TeXShop.app\" \"$APPDIR\"\nrelaunch_application 'TeXShop'\n" + } +} diff --git a/ee/maintained-apps/outputs/thaw/darwin.json b/ee/maintained-apps/outputs/thaw/darwin.json new file mode 100644 index 0000000000..018062e99b --- /dev/null +++ b/ee/maintained-apps/outputs/thaw/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.2.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.stonerl.Thaw';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.stonerl.Thaw' AND version_compare(bundle_short_version, '1.2.0') < 0);" + }, + "installer_url": "https://github.com/stonerl/Thaw/releases/download/1.2.0/Thaw_1.2.0.zip", + "install_script_ref": "d8e6eec2", + "uninstall_script_ref": "d4d962b1", + "sha256": "d67f4d31ef9fa057849a98540b810cfa42e0bc66019d3605abd08e45c69aa06f", + "default_categories": [ + "Utilities" + ] + } + ], + "refs": { + "d4d962b1": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Thaw.app\"\ntrash $LOGGED_IN_USER '~/Library/Caches/com.stonerl.Thaw'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.stonerl.Thaw'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.stonerl.Thaw.plist'\ntrash $LOGGED_IN_USER '~/Library/WebKit/com.stonerl.Thaw'\n", + "d8e6eec2": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.stonerl.Thaw'\nif [ -d \"$APPDIR/Thaw.app\" ]; then\n\tsudo mv \"$APPDIR/Thaw.app\" \"$TMPDIR/Thaw.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Thaw.app\" \"$APPDIR\"\nrelaunch_application 'com.stonerl.Thaw'\n" + } +} diff --git a/ee/maintained-apps/outputs/thorium/darwin.json b/ee/maintained-apps/outputs/thorium/darwin.json new file mode 100644 index 0000000000..e672a78d40 --- /dev/null +++ b/ee/maintained-apps/outputs/thorium/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "3.4.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'io.github.edrlab.thorium';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'io.github.edrlab.thorium' AND version_compare(bundle_short_version, '3.4.0') < 0);" + }, + "installer_url": "https://github.com/edrlab/thorium-reader/releases/download/v3.4.0/Thorium-3.4.0-arm64.dmg", + "install_script_ref": "4c5717aa", + "uninstall_script_ref": "2e25a391", + "sha256": "2f19dcaf4b717330626ebce7148653da399945467699bef7f0843d7b5f512030", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "2e25a391": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Thorium.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/EDRLab.ThoriumReader'\ntrash $LOGGED_IN_USER '~/Library/Preferences/io.github.edrlab.thorium.plist'\n", + "4c5717aa": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'io.github.edrlab.thorium'\nif [ -d \"$APPDIR/Thorium.app\" ]; then\n\tsudo mv \"$APPDIR/Thorium.app\" \"$TMPDIR/Thorium.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Thorium.app\" \"$APPDIR\"\nrelaunch_application 'io.github.edrlab.thorium'\n" + } +} diff --git a/ee/maintained-apps/outputs/threema/darwin.json b/ee/maintained-apps/outputs/threema/darwin.json new file mode 100644 index 0000000000..70e769256b --- /dev/null +++ b/ee/maintained-apps/outputs/threema/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.2.50", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'threema-consumer-web';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'threema-consumer-web' AND version_compare(bundle_short_version, '1.2.50') < 0);" + }, + "installer_url": "https://releases.threema.ch/web-electron/v1/release/Threema-Latest.dmg", + "install_script_ref": "495d8899", + "uninstall_script_ref": "18fedfe7", + "sha256": "no_check", + "default_categories": [ + "Communication" + ] + } + ], + "refs": { + "18fedfe7": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Threema.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/threema-consumer-web'\ntrash $LOGGED_IN_USER '~/Library/Logs/threema-consumer-web'\ntrash $LOGGED_IN_USER '~/Library/Preferences/threema-consumer-web.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/threema-consumer-web.savedState'\n", + "495d8899": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'threema-consumer-web'\nif [ -d \"$APPDIR/Threema.app\" ]; then\n\tsudo mv \"$APPDIR/Threema.app\" \"$TMPDIR/Threema.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Threema.app\" \"$APPDIR\"\nrelaunch_application 'threema-consumer-web'\n" + } +} diff --git a/ee/maintained-apps/outputs/thumbsup/darwin.json b/ee/maintained-apps/outputs/thumbsup/darwin.json new file mode 100644 index 0000000000..5bcefbeee3 --- /dev/null +++ b/ee/maintained-apps/outputs/thumbsup/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "4.5.3", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.devon-technologies.ThumbsUp';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.devon-technologies.ThumbsUp' AND version_compare(bundle_short_version, '4.5.3') < 0);" + }, + "installer_url": "https://download.devontechnologies.com/download/freeware/thumbsup/4.5.3/ThumbsUp.app.zip", + "install_script_ref": "fd841bed", + "uninstall_script_ref": "065c2da8", + "sha256": "05e1bbefd09e098eeb7faec29ea7556f76cf17b49be719af93e443d993beeb8c", + "default_categories": [ + "Utilities" + ] + } + ], + "refs": { + "065c2da8": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/ThumbsUp.app\"\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/Generated/com.devontechnologies.thumbsup.help*'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.devon-technologies.ThumbsUp'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.devon-technologies.ThumbsUp'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.devon-technologies.ThumbsUp.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.devon-technologies.ThumbsUp.savedState'\n", + "fd841bed": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.devon-technologies.ThumbsUp'\nif [ -d \"$APPDIR/ThumbsUp.app\" ]; then\n\tsudo mv \"$APPDIR/ThumbsUp.app\" \"$TMPDIR/ThumbsUp.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/ThumbsUp.app\" \"$APPDIR\"\nrelaunch_application 'com.devon-technologies.ThumbsUp'\n" + } +} diff --git a/ee/maintained-apps/outputs/ticktick/darwin.json b/ee/maintained-apps/outputs/ticktick/darwin.json new file mode 100644 index 0000000000..09b382308e --- /dev/null +++ b/ee/maintained-apps/outputs/ticktick/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "8.0.70", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.TickTick.task.mac';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.TickTick.task.mac' AND version_compare(bundle_short_version, '8.0.70') < 0);" + }, + "installer_url": "https://download.ticktick.app/download/mac/TickTick_8.0.70_471.dmg", + "install_script_ref": "758384e1", + "uninstall_script_ref": "25a76e52", + "sha256": "bde79cb46837db5b08fc0c675f05f2e0b4384135135f9450ee30c9564a803c6e", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "25a76e52": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TickTick.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.TickTick.task.mac.*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.TickTick.task.mac'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.TickTick.task.mac'\ntrash $LOGGED_IN_USER '~/Library/Caches/TickTick'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.TickTick.task.mac.*'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/75TY9UT8AY.com.TickTick.task.mac'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.TickTick.task.mac.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.TickTick.task.mac.savedState'\n", + "758384e1": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.TickTick.task.mac'\nif [ -d \"$APPDIR/TickTick.app\" ]; then\n\tsudo mv \"$APPDIR/TickTick.app\" \"$TMPDIR/TickTick.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TickTick.app\" \"$APPDIR\"\nrelaunch_application 'com.TickTick.task.mac'\n" + } +} diff --git a/ee/maintained-apps/outputs/tidal/darwin.json b/ee/maintained-apps/outputs/tidal/darwin.json new file mode 100644 index 0000000000..ce8f6e7e2d --- /dev/null +++ b/ee/maintained-apps/outputs/tidal/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2.41.3", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.tidal.desktop';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.tidal.desktop' AND version_compare(bundle_short_version, '2.41.3') < 0);" + }, + "installer_url": "https://download.tidal.com/desktop/mac/TIDAL.arm64.2.41.3.zip", + "install_script_ref": "8c502559", + "uninstall_script_ref": "fabbd281", + "sha256": "74ed472ddc243d9c784f6066150a5e6e5d68172a1cf4633fd0b7c3f7784ee373", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "8c502559": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.tidal.desktop'\nif [ -d \"$APPDIR/TIDAL.app\" ]; then\n\tsudo mv \"$APPDIR/TIDAL.app\" \"$TMPDIR/TIDAL.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TIDAL.app\" \"$APPDIR\"\nrelaunch_application 'com.tidal.desktop'\n", + "fabbd281": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TIDAL.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/TIDAL'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tidal.desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.tidal.desktop.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/Logs/TIDAL'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tidal.*'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.tidal.desktop.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/tiles/darwin.json b/ee/maintained-apps/outputs/tiles/darwin.json new file mode 100644 index 0000000000..5f3435413f --- /dev/null +++ b/ee/maintained-apps/outputs/tiles/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.3.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.sempliva.Tiles';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.sempliva.Tiles' AND version_compare(bundle_short_version, '1.3.2') < 0);" + }, + "installer_url": "https://updates.sempliva.com/tiles/Tiles-03b500a8.dmg", + "install_script_ref": "cedcb4d7", + "uninstall_script_ref": "0eda6f5d", + "sha256": "b051ea7e5048bac0f7a72b6dd893bb1a02cf47ecde6def9f103d2be8e122f01e", + "default_categories": [ + "Utilities" + ] + } + ], + "refs": { + "0eda6f5d": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.sempliva.TilesHelper'\nquit_application 'com.sempliva.Tiles'\nsudo rm -rf \"$APPDIR/Tiles.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.sempliva.Tiles'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.sempliva.Tiles'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.semplive.Tiles.plist'\n", + "cedcb4d7": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.sempliva.Tiles'\nif [ -d \"$APPDIR/Tiles.app\" ]; then\n\tsudo mv \"$APPDIR/Tiles.app\" \"$TMPDIR/Tiles.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Tiles.app\" \"$APPDIR\"\nrelaunch_application 'com.sempliva.Tiles'\n" + } +} diff --git a/ee/maintained-apps/outputs/timescribe/darwin.json b/ee/maintained-apps/outputs/timescribe/darwin.json new file mode 100644 index 0000000000..e814f03d20 --- /dev/null +++ b/ee/maintained-apps/outputs/timescribe/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.15.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'de.amplussoftware.timescribe';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'de.amplussoftware.timescribe' AND version_compare(bundle_short_version, '1.15.0') < 0);" + }, + "installer_url": "https://github.com/WINBIGFOX/TimeScribe/releases/download/v1.15.0/TimeScribe-1.15.0-arm64.zip", + "install_script_ref": "c0646da6", + "uninstall_script_ref": "d9e61a45", + "sha256": "8ba626d208abf9b104bd6f64c8ece3ffba5ae2d8b59844834834a423b8f745ce", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "c0646da6": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'de.amplussoftware.timescribe'\nif [ -d \"$APPDIR/TimeScribe.app\" ]; then\n\tsudo mv \"$APPDIR/TimeScribe.app\" \"$TMPDIR/TimeScribe.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TimeScribe.app\" \"$APPDIR\"\nrelaunch_application 'de.amplussoftware.timescribe'\n", + "d9e61a45": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TimeScribe.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/timescribe'\n" + } +} diff --git a/ee/maintained-apps/outputs/timing/darwin.json b/ee/maintained-apps/outputs/timing/darwin.json new file mode 100644 index 0000000000..746558d321 --- /dev/null +++ b/ee/maintained-apps/outputs/timing/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2026.3.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'info.eurocomp.Timing2';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'info.eurocomp.Timing2' AND version_compare(bundle_short_version, '2026.3.1') < 0);" + }, + "installer_url": "https://updates.timingapp.com/download/Timing-2026.3.1.dmg", + "install_script_ref": "a3717392", + "uninstall_script_ref": "c2ba8bc0", + "sha256": "ce8f19fcff2aef3d7a1544ea84a74c1abd4c30e494864948f2afc829098fd944", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "a3717392": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'info.eurocomp.Timing2'\nif [ -d \"$APPDIR/Timing.app\" ]; then\n\tsudo mv \"$APPDIR/Timing.app\" \"$TMPDIR/Timing.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Timing.app\" \"$APPDIR\"\nrelaunch_application 'info.eurocomp.Timing2'\n", + "c2ba8bc0": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Timing.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/info.eurocomp.Timing2'\ntrash $LOGGED_IN_USER '~/Library/Application Support/info.eurocomp.TimingHelper'\ntrash $LOGGED_IN_USER '~/Library/Application Support/info.eurocomp.TimingHelper.InfoExtractorService'\ntrash $LOGGED_IN_USER '~/Library/Caches/info.eurocomp.Timing2'\ntrash $LOGGED_IN_USER '~/Library/Caches/info.eurocomp.TimingHelper'\ntrash $LOGGED_IN_USER '~/Library/Caches/info.eurocomp.TimingHelper.InfoExtractorService'\ntrash $LOGGED_IN_USER '~/Library/Preferences/info.eurocomp.Timing2.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/info.eurocomp.TimingHelper.InfoExtractorService.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/info.eurocomp.TimingHelper.plist'\n" + } +} diff --git a/ee/maintained-apps/outputs/topaz-gigapixel-ai/darwin.json b/ee/maintained-apps/outputs/topaz-gigapixel-ai/darwin.json new file mode 100644 index 0000000000..3738e88bda --- /dev/null +++ b/ee/maintained-apps/outputs/topaz-gigapixel-ai/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "8.4.4", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.TopazGigapixelAI';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.TopazGigapixelAI' AND version_compare(bundle_short_version, '8.4.4') < 0);" + }, + "installer_url": "https://downloads.topazlabs.com/deploy/TopazGigapixelAI/8.4.4/TopazGigapixelAI-8.4.4.pkg", + "install_script_ref": "471c999f", + "uninstall_script_ref": "7835397d", + "sha256": "9b3acfa9f98bf52fa494043c4f6e9176ce6385fce07273aa559cf9ff86492aed", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "471c999f": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.topazlabs.TopazGigapixelAI'\nsudo installer -pkg \"$TMPDIR/TopazGigapixelAI-8.4.4.pkg\" -target /\nrelaunch_application 'com.topazlabs.TopazGigapixelAI'\n", + "7835397d": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_pkg_files 'com.topazlabs.TopazGigapixelAI'\nforget_pkg 'com.topazlabs.TopazGigapixelAI'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazGigapixelAI.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazGigapixelAIApply.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazGigapixelAIAutomate.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazGigapixelAIGather.plugin'\nsudo rm -rf '~/Library/Application Support/Adobe/Lightroom/External Editor Presets/TopazGigapixelAI.lrtemplate'\nsudo rm -rf '~/Library/Application Support/Affinity Photo 2/Plugins/TopazGigapixelAI.plugin'\nsudo rm -rf '~/Library/Application Support/Capture One/Plug-ins/TopazGigapixelAI.coplugin'\nsudo rm -rf '~/Library/Application Support/Topaz Labs LLC/Topaz Gigapixel AI'\ntrash $LOGGED_IN_USER '~/Library/Caches/Topaz Labs LLC/Topaz Gigapixel AI'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topaz-labs-llc.Topaz Gigapixel AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.Topaz Gigapixel AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.TopazGigapixelAI.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.topazlabs.TopazGigapixelAI.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/topaz-photo-ai/darwin.json b/ee/maintained-apps/outputs/topaz-photo-ai/darwin.json new file mode 100644 index 0000000000..f157fa2f4e --- /dev/null +++ b/ee/maintained-apps/outputs/topaz-photo-ai/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "4.0.4", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.TopazPhotoAI';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.TopazPhotoAI' AND version_compare(bundle_short_version, '4.0.4') < 0);" + }, + "installer_url": "https://downloads.topazlabs.com/deploy/TopazPhotoAI/4.0.4/TopazPhotoAI-4.0.4.pkg", + "install_script_ref": "eaea3493", + "uninstall_script_ref": "dc017871", + "sha256": "b69dc080940a53b7b3e1b7965d955c6f2c83b5b512a2082fae0ab1e27da828d0", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "dc017871": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_pkg_files 'com.topazlabs.TopazPhotoAI'\nforget_pkg 'com.topazlabs.TopazPhotoAI'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazPhotoAI.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazPhotoAIApply.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazPhotoAIAutomate.plugin'\nsudo rm -rf '/Library/Application Support/Adobe/Plug-Ins/CC/TopazPhotoAIGather.plugin'\nsudo rm -rf '~/Library/Application Support/Adobe/Lightroom/External Editor Presets/TopazPhotoAI.lrtemplate'\nsudo rm -rf '~/Library/Application Support/Adobe/Lightroom/Modules/Topaz Photo AI.lrplugin'\nsudo rm -rf '~/Library/Application Support/Affinity Photo 2/Plugins/TopazPhotoAI.plugin'\nsudo rm -rf '~/Library/Application Support/Capture One/Plug-ins/TopazPhotoAI.coplugin'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.topazlabs.TopazPhotoAIplugin'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Topaz Labs LLC/Topaz Photo AI'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.topazlabs.TopazPhotoAI'\ntrash $LOGGED_IN_USER '~/Library/Caches/Topaz Labs LLC/Topaz Photo AI'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.topazlabs.TopazPhotoAIplugin'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topaz-labs-llc.Topaz Photo AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.Topaz Photo AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.TopazPhotoAI.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.topazlabs.TopazPhotoAI.savedState'\n", + "eaea3493": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.topazlabs.TopazPhotoAI'\nsudo installer -pkg \"$TMPDIR/TopazPhotoAI-4.0.4.pkg\" -target /\nrelaunch_application 'com.topazlabs.TopazPhotoAI'\n" + } +} diff --git a/ee/maintained-apps/outputs/topaz-video-ai/darwin.json b/ee/maintained-apps/outputs/topaz-video-ai/darwin.json new file mode 100644 index 0000000000..cf9296b766 --- /dev/null +++ b/ee/maintained-apps/outputs/topaz-video-ai/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "7.1.5", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.Topaz-Video-AI';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.topazlabs.Topaz-Video-AI' AND version_compare(bundle_short_version, '7.1.5') < 0);" + }, + "installer_url": "https://downloads.topazlabs.com/deploy/TopazVideoAI/7.1.5/TopazVideoAI-7.1.5.pkg", + "install_script_ref": "cd1799f5", + "uninstall_script_ref": "6f416d1b", + "sha256": "4e3721d5605c36cbf872573471a5bbc5eb63860404c939f889251311135090ba", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "6f416d1b": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/volume<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/install-location<\\/key>/ {getline; gsub(/.*|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_pkg_files 'com.topazlabs.aeplugin'\nforget_pkg 'com.topazlabs.aeplugin'\nremove_pkg_files 'com.topazlabs.ofxplugin'\nforget_pkg 'com.topazlabs.ofxplugin'\nremove_pkg_files 'com.topazlabs.VAIPackage'\nforget_pkg 'com.topazlabs.VAIPackage'\nsudo rm -rf '/Applications/Adobe After Effects 2020/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2020/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2021/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2021/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2022/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2022/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2023/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2023/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2024/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2024/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2025/Plug-ins/Topaz Video AI Frame Interpolation.plugin'\nsudo rm -rf '/Applications/Adobe After Effects 2025/Plug-ins/Topaz Video AI.plugin'\nsudo rm -rf '/Library/OFX/Plugins/Topaz Video AI.ofx.bundle'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Topaz Labs LLC/Topaz Video AI'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.topazlabs.Topaz-Video-AI'\ntrash $LOGGED_IN_USER '~/Library/Caches/Topaz Labs LLC/Topaz Video AI'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.Topaz Video AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.topazlabs.Topaz-Video-AI.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.topazlabs.Topaz-Video-AI.savedState'\n", + "cd1799f5": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# install pkg files\nquit_and_track_application 'com.topazlabs.Topaz-Video-AI'\nsudo installer -pkg \"$TMPDIR/TopazVideoAI-7.1.5.pkg\" -target /\nrelaunch_application 'com.topazlabs.Topaz-Video-AI'\n" + } +} diff --git a/ee/maintained-apps/outputs/topnotch/darwin.json b/ee/maintained-apps/outputs/topnotch/darwin.json new file mode 100644 index 0000000000..e7f5921fee --- /dev/null +++ b/ee/maintained-apps/outputs/topnotch/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.3.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'pl.maketheweb.TopNotch';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'pl.maketheweb.TopNotch' AND version_compare(bundle_short_version, '1.3.2') < 0);" + }, + "installer_url": "https://updates.topnotch.app/TopNotch-1.3.2.dmg", + "install_script_ref": "4a34ca78", + "uninstall_script_ref": "6893aaf8", + "sha256": "bedf07c46884e7c6bf43482fd48061beaf2f032a1e8bb23b422d55b85963e3d7", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "4a34ca78": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'pl.maketheweb.TopNotch'\nif [ -d \"$APPDIR/TopNotch.app\" ]; then\n\tsudo mv \"$APPDIR/TopNotch.app\" \"$TMPDIR/TopNotch.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TopNotch.app\" \"$APPDIR\"\nrelaunch_application 'pl.maketheweb.TopNotch'\n", + "6893aaf8": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TopNotch.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/pl.maketheweb.TopNotch-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/Application Support/TopNotch'\ntrash $LOGGED_IN_USER '~/Library/Caches/pl.maketheweb.TopNotch'\ntrash $LOGGED_IN_USER '~/Library/Containers/pl.maketheweb.TopNotch-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/pl.maketheweb.TopNotch'\ntrash $LOGGED_IN_USER '~/Library/Preferences/pl.maketheweb.TopNotch.plist'\ntrash $LOGGED_IN_USER '~/Library/WebKit/pl.maketheweb.TopNotch'\n" + } +} diff --git a/ee/maintained-apps/outputs/tradingview/darwin.json b/ee/maintained-apps/outputs/tradingview/darwin.json new file mode 100644 index 0000000000..a0cc812b2d --- /dev/null +++ b/ee/maintained-apps/outputs/tradingview/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "3.2.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.tradingview.tradingviewapp.desktop';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.tradingview.tradingviewapp.desktop' AND version_compare(bundle_short_version, '3.2.0') < 0);" + }, + "installer_url": "https://tvd-packages.tradingview.com/stable/3.2.0/darwin/TradingView.dmg", + "install_script_ref": "85b28e80", + "uninstall_script_ref": "c17d0530", + "sha256": "972b3a52bc2d50451a29e2a21ed5dced8db674c8b2dd8eae41e280732cb7ff47", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "85b28e80": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.tradingview.tradingviewapp.desktop'\nif [ -d \"$APPDIR/TradingView.app\" ]; then\n\tsudo mv \"$APPDIR/TradingView.app\" \"$TMPDIR/TradingView.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TradingView.app\" \"$APPDIR\"\nrelaunch_application 'com.tradingview.tradingviewapp.desktop'\n", + "c17d0530": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TradingView.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/TradingView'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tradingview.tradingviewapp.desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.tradingview.tradingviewapp.desktop.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/transfer/darwin.json b/ee/maintained-apps/outputs/transfer/darwin.json new file mode 100644 index 0000000000..f805b63745 --- /dev/null +++ b/ee/maintained-apps/outputs/transfer/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2.4.3", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.adriangranados.Transfer';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.adriangranados.Transfer' AND version_compare(bundle_short_version, '2.4.3') < 0);" + }, + "installer_url": "https://www.intuitibits.com/downloads/Transfer_2.4.3.dmg", + "install_script_ref": "c76b3ff6", + "uninstall_script_ref": "4a868851", + "sha256": "f97bd2d3ef07ec54a607926eef6b6a605a72f87eb66cb07ae2e9a1e2e42b5613", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "4a868851": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Transfer.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Transfer'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.adriangranados.Transfer'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/Generated/com.intuitibits.transfer.help*'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.adriangranados.Transfer'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.adriangranados.Transfer.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.adriangranados.Transfer.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.adriangranados.Transfer.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/com.adriangranados.Transfer'\ntrash $LOGGED_IN_USER '~/Transfer'\n", + "c76b3ff6": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.adriangranados.Transfer'\nif [ -d \"$APPDIR/Transfer.app\" ]; then\n\tsudo mv \"$APPDIR/Transfer.app\" \"$TMPDIR/Transfer.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Transfer.app\" \"$APPDIR\"\nrelaunch_application 'com.adriangranados.Transfer'\n" + } +} diff --git a/ee/maintained-apps/outputs/transmission/darwin.json b/ee/maintained-apps/outputs/transmission/darwin.json new file mode 100644 index 0000000000..75960d0efd --- /dev/null +++ b/ee/maintained-apps/outputs/transmission/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "4.1.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'org.m0k.transmission.LSSharedFileList';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'org.m0k.transmission' AND version_compare(bundle_short_version, '4.1.2') < 0);" + }, + "installer_url": "https://github.com/transmission/transmission/releases/download/4.1.2/Transmission-4.1.2.dmg", + "install_script_ref": "34d38a93", + "uninstall_script_ref": "a7abcff2", + "sha256": "0532e8c36732fb37c3db2628b04f9408b38d253e90a3a56b0399ea0151a3340b", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "34d38a93": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'org.m0k.transmission.LSSharedFileList'\nif [ -d \"$APPDIR/Transmission.app\" ]; then\n\tsudo mv \"$APPDIR/Transmission.app\" \"$TMPDIR/Transmission.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Transmission.app\" \"$APPDIR\"\nrelaunch_application 'org.m0k.transmission.LSSharedFileList'\n", + "a7abcff2": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Transmission.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.m0k.transmission.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Transmission'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexFile/org.m0k.transmission.help'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/SDMHelpData/Other/English/HelpSDMIndexFile/Transmission Help*'\ntrash $LOGGED_IN_USER '~/Library/Caches/org.m0k.transmission'\ntrash $LOGGED_IN_USER '~/Library/Cookies/org.m0k.transmission.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.m0k.transmission.LSSharedFileList.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.m0k.transmission.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.m0k.transmission.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/tresorit/darwin.json b/ee/maintained-apps/outputs/tresorit/darwin.json new file mode 100644 index 0000000000..855a9b3f6e --- /dev/null +++ b/ee/maintained-apps/outputs/tresorit/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "3.5.3430.4780", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.tresorit.mac';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.tresorit.mac' AND version_compare(bundle_short_version, '3.5.3430.4780') < 0);" + }, + "installer_url": "https://installer.tresorit.com/Tresorit.dmg", + "install_script_ref": "38395b2e", + "uninstall_script_ref": "62c78b20", + "sha256": "no_check", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "38395b2e": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.tresorit.mac'\nif [ -d \"$APPDIR/Tresorit.app\" ]; then\n\tsudo mv \"$APPDIR/Tresorit.app\" \"$TMPDIR/Tresorit.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Tresorit.app\" \"$APPDIR\"\nrelaunch_application 'com.tresorit.mac'\n", + "62c78b20": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Tresorit.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Tresorit'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.tresorit.mac.plist'\n" + } +} diff --git a/ee/maintained-apps/outputs/trex/darwin.json b/ee/maintained-apps/outputs/trex/darwin.json new file mode 100644 index 0000000000..fe089f4809 --- /dev/null +++ b/ee/maintained-apps/outputs/trex/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2.0.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.ameba.TRex';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.ameba.TRex' AND version_compare(bundle_short_version, '2.0.0') < 0);" + }, + "installer_url": "https://github.com/amebalabs/TRex/releases/download/v2.0.0/TRex-2.0.0.zip", + "install_script_ref": "afaf0df7", + "uninstall_script_ref": "4d0017ff", + "sha256": "4e8defc680daa6e09cb2daba576aa243683c775b93a9510ce5f12544d222de4d", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "4d0017ff": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/TRex.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.ameba.TRex-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.ameba.TRex'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.ameba.TRex-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.ameba.TRex.plist'\n", + "afaf0df7": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.ameba.TRex'\nif [ -d \"$APPDIR/TRex.app\" ]; then\n\tsudo mv \"$APPDIR/TRex.app\" \"$TMPDIR/TRex.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TRex.app\" \"$APPDIR\"\nrelaunch_application 'com.ameba.TRex'\n" + } +} diff --git a/ee/maintained-apps/outputs/trezor-suite/darwin.json b/ee/maintained-apps/outputs/trezor-suite/darwin.json new file mode 100644 index 0000000000..d5d9135c8f --- /dev/null +++ b/ee/maintained-apps/outputs/trezor-suite/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "26.5.2", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'io.trezor.TrezorSuite';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'io.trezor.TrezorSuite' AND version_compare(bundle_short_version, '26.5.2') < 0);" + }, + "installer_url": "https://data.trezor.io/suite/releases/desktop/latest/Trezor-Suite-26.5.2-mac-arm64.dmg", + "install_script_ref": "a95207a7", + "uninstall_script_ref": "9026a399", + "sha256": "59e52c7bff578acc2fecce8463326980c02fa08c6293943408bdf1ecee92a3e4", + "default_categories": [ + "Security" + ] + } + ], + "refs": { + "9026a399": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Trezor Suite.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/@trezor/suite-desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/io.trezor.TrezorSuite.plist'\n", + "a95207a7": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'io.trezor.TrezorSuite'\nif [ -d \"$APPDIR/Trezor Suite.app\" ]; then\n\tsudo mv \"$APPDIR/Trezor Suite.app\" \"$TMPDIR/Trezor Suite.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Trezor Suite.app\" \"$APPDIR\"\nrelaunch_application 'io.trezor.TrezorSuite'\n" + } +} diff --git a/ee/maintained-apps/outputs/tripmode/darwin.json b/ee/maintained-apps/outputs/tripmode/darwin.json new file mode 100644 index 0000000000..eb728bbabd --- /dev/null +++ b/ee/maintained-apps/outputs/tripmode/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "3.2.4", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'ch.tripmode.TripMode';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'ch.tripmode.TripMode' AND version_compare(bundle_short_version, '3.2.4') < 0);" + }, + "installer_url": "https://tripmode-updates.ch/app/TripMode-3.2.4-1385.zip", + "install_script_ref": "2da32712", + "uninstall_script_ref": "d80d1376", + "sha256": "2a5a21ac4c13b5a1a5d43e6aeb2b7588ea9af0116e41829fca19cf9752265410", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "2da32712": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'ch.tripmode.TripMode'\nif [ -d \"$APPDIR/TripMode.app\" ]; then\n\tsudo mv \"$APPDIR/TripMode.app\" \"$TMPDIR/TripMode.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/TripMode.app\" \"$APPDIR\"\nrelaunch_application 'ch.tripmode.TripMode'\n", + "d80d1376": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n}\n\nsend_signal() {\n local signal=\"$1\"\n local bundle_id=\"$2\"\n local logged_in_user=\"$3\"\n local logged_in_uid pids\n\n if [ -z \"$signal\" ] || [ -z \"$bundle_id\" ] || [ -z \"$logged_in_user\" ]; then\n echo \"Usage: uninstall_signal \"\n return 1\n fi\n\n logged_in_uid=$(id -u \"$logged_in_user\")\n if [ -z \"$logged_in_uid\" ]; then\n echo \"Could not find UID for user '$logged_in_user'.\"\n return 1\n fi\n\n echo \"Signalling '$signal' to application ID '$bundle_id' for user '$logged_in_user'\"\n\n pids=$(/bin/launchctl asuser \"$logged_in_uid\" sudo -iu \"$logged_in_user\" /bin/launchctl list | awk -v bundle_id=\"$bundle_id\" '\n $3 ~ bundle_id { print $1 }')\n\n if [ -z \"$pids\" ]; then\n echo \"No processes found for bundle ID '$bundle_id'.\"\n return 0\n fi\n\n echo \"Unix PIDs are $pids for processes with bundle identifier $bundle_id\"\n for pid in $pids; do\n if kill -s \"$signal\" \"$pid\" 2>/dev/null; then\n echo \"Successfully signaled PID $pid with signal $signal.\"\n else\n echo \"Failed to kill PID $pid with signal $signal. Check permissions.\"\n fi\n done\n\n sleep 3\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'ch.tripmode.nke.TripMode'\nremove_launchctl_service 'ch.tripmode.TripMode.HelperTool'\nsend_signal 'TERM' 'ch.tripmode.TripMode' \"$LOGGED_IN_USER\"\nsudo rm -rf '/Library/PrivilegedHelperTools/ch.tripmode.TripMode.HelperTool'\nsudo rm -rf \"$APPDIR/TripMode.app\"\ntrash $LOGGED_IN_USER '/Library/Application Support/Tripmode'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.alix-sarl.TripMode'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/P39EL2R8C4.com.alix-sarl.TripMode'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Tripmode'\ntrash $LOGGED_IN_USER '~/Library/Caches/ch.tripmode.TripMode'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.apple.helpd/Generated/ch.tripmode.TripMode.help*'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/P39EL2R8C4.com.alix-sarl.TripMode'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ch.tripmode.TripMode.plist'\n" + } +} diff --git a/ee/maintained-apps/outputs/tuple/darwin.json b/ee/maintained-apps/outputs/tuple/darwin.json new file mode 100644 index 0000000000..126ac61a69 --- /dev/null +++ b/ee/maintained-apps/outputs/tuple/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "3.0.5", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'app.tuple.app';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'app.tuple.app' AND version_compare(bundle_short_version, '3.0.5') < 0);" + }, + "installer_url": "https://d32ifkf9k9ezcg.cloudfront.net/production/sparkle/tuple-3.0.5-2026-06-05-9277d388e.zip", + "install_script_ref": "ff9821fc", + "uninstall_script_ref": "03815558", + "sha256": "5e53ed5f8e92f70c9d473a904f4b89c9de2cc940e76bab5b45794bfa58a448c6", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "03815558": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'app.tuple.app-LaunchAtLoginHelper'\nquit_application 'app.tuple.app'\nsudo rm -rf \"$APPDIR/Tuple.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/app.tuple.app-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/Application Support/app.tuple.app'\ntrash $LOGGED_IN_USER '~/Library/Caches/app.tuple.app'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.crashlytics.data/app.tuple.app'\ntrash $LOGGED_IN_USER '~/Library/Caches/io.fabric.sdk.mac.data/app.tuple.app'\ntrash $LOGGED_IN_USER '~/Library/Containers/app.tuple.app-LaunchAtLoginHelper'\ntrash $LOGGED_IN_USER '~/Library/Preferences/app.tuple.app.plist'\ntrash $LOGGED_IN_USER '~/Library/WebKit/app.tuple.app'\n", + "ff9821fc": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'app.tuple.app'\nif [ -d \"$APPDIR/Tuple.app\" ]; then\n\tsudo mv \"$APPDIR/Tuple.app\" \"$TMPDIR/Tuple.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Tuple.app\" \"$APPDIR\"\nrelaunch_application 'app.tuple.app'\n" + } +} diff --git a/ee/maintained-apps/outputs/twine-app/darwin.json b/ee/maintained-apps/outputs/twine-app/darwin.json new file mode 100644 index 0000000000..2bfed16fae --- /dev/null +++ b/ee/maintained-apps/outputs/twine-app/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "2.12.0", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.electron.twine';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.electron.twine' AND version_compare(bundle_short_version, '2.12.0') < 0);" + }, + "installer_url": "https://github.com/klembot/twinejs/releases/download/2.12.0/Twine-2.12.0-macOS.dmg", + "install_script_ref": "4bac722d", + "uninstall_script_ref": "35c96d50", + "sha256": "918c55e1ccb4131db6f64f7586d024875075331211c2a1d03c73d2f3ed77bddc", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "35c96d50": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Twine.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Twine'\ntrash $LOGGED_IN_USER '~/Library/Logs/Twine'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.twine.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.twine.savedState'\n", + "4bac722d": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.electron.twine'\nif [ -d \"$APPDIR/Twine.app\" ]; then\n\tsudo mv \"$APPDIR/Twine.app\" \"$TMPDIR/Twine.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Twine.app\" \"$APPDIR\"\nrelaunch_application 'com.electron.twine'\n" + } +} diff --git a/ee/maintained-apps/outputs/twobird/darwin.json b/ee/maintained-apps/outputs/twobird/darwin.json new file mode 100644 index 0000000000..a97ba84c84 --- /dev/null +++ b/ee/maintained-apps/outputs/twobird/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.0.52", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.gingerlabs.bagel';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.gingerlabs.bagel' AND version_compare(bundle_short_version, '1.0.52') < 0);" + }, + "installer_url": "https://www.twobird.com/download/mac-arm64", + "install_script_ref": "2adc3907", + "uninstall_script_ref": "b2eaec73", + "sha256": "no_check", + "default_categories": [ + "Communication" + ] + } + ], + "refs": { + "2adc3907": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.gingerlabs.bagel'\nif [ -d \"$APPDIR/Twobird.app\" ]; then\n\tsudo mv \"$APPDIR/Twobird.app\" \"$TMPDIR/Twobird.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Twobird.app\" \"$APPDIR\"\nrelaunch_application 'com.gingerlabs.bagel'\n", + "b2eaec73": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Twobird.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Twobird'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.gingerlabs.bagel.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.gingerlabs.bagel.savedState'\n" + } +} diff --git a/ee/maintained-apps/outputs/typeface/darwin.json b/ee/maintained-apps/outputs/typeface/darwin.json new file mode 100644 index 0000000000..f5a8ab497c --- /dev/null +++ b/ee/maintained-apps/outputs/typeface/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "4.3.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.criminalbird.typeface.standalone';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.criminalbird.typeface.standalone' AND version_compare(bundle_short_version, '4.3.1') < 0);" + }, + "installer_url": "https://dcdn.typefaceapp.com/Typeface-4.3.1-5064/Typeface-4.3.1-5064.dmg", + "install_script_ref": "a15420fd", + "uninstall_script_ref": "707f4675", + "sha256": "b0aadeef317c1b466c048834d0c0342771bd13b64b5f9dd457cf625af5a7d4c2", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "707f4675": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nquit_application 'com.criminalbird.typeface.standalone'\nsudo rm -rf \"$APPDIR/Typeface.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.criminalbird.typeface.standalone'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.criminalbird.typeface.standalone'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.criminalbird.typeface.standalone.plist'\n", + "a15420fd": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.criminalbird.typeface.standalone'\nif [ -d \"$APPDIR/Typeface.app\" ]; then\n\tsudo mv \"$APPDIR/Typeface.app\" \"$TMPDIR/Typeface.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Typeface.app\" \"$APPDIR\"\nrelaunch_application 'com.criminalbird.typeface.standalone'\n" + } +} diff --git a/ee/maintained-apps/outputs/typinator/darwin.json b/ee/maintained-apps/outputs/typinator/darwin.json new file mode 100644 index 0000000000..72b0a5f23c --- /dev/null +++ b/ee/maintained-apps/outputs/typinator/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "10.1", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.macility.typinator2';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'com.macility.typinator2' AND version_compare(bundle_short_version, '10.1') < 0);" + }, + "installer_url": "https://storage.ergonis.com/apps/production/typinator/archive/Typinator_101.dmg", + "install_script_ref": "dec26639", + "uninstall_script_ref": "282f639a", + "sha256": "223b0ef7d877274ba0133aaf1bf836ff06a3122e0683c82f790446a6d038fd77", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "282f639a": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Typinator.app\"\ntrash $LOGGED_IN_USER '~/Desktop/Typinator Tutorial.rtfd'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Typinator'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.macility.typinator2.plist'\n", + "dec26639": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.macility.typinator2'\nif [ -d \"$APPDIR/Typinator.app\" ]; then\n\tsudo mv \"$APPDIR/Typinator.app\" \"$TMPDIR/Typinator.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Typinator.app\" \"$APPDIR\"\nrelaunch_application 'com.macility.typinator2'\n" + } +} diff --git a/ee/maintained-apps/outputs/typora/darwin.json b/ee/maintained-apps/outputs/typora/darwin.json new file mode 100644 index 0000000000..c7ff5a1347 --- /dev/null +++ b/ee/maintained-apps/outputs/typora/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "1.13.6", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'abnerworks.Typora';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'abnerworks.Typora' AND version_compare(bundle_short_version, '1.13.6') < 0);" + }, + "installer_url": "https://download.typora.io/mac/Typora-1.13.6.dmg", + "install_script_ref": "46cc7e99", + "uninstall_script_ref": "a8ba94c9", + "sha256": "9179f386ebb722d17d995d31fafefe85b60d08ea350c07c8cd8307c002fe2c73", + "default_categories": [ + "Productivity" + ] + } + ], + "refs": { + "46cc7e99": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'abnerworks.Typora'\nif [ -d \"$APPDIR/Typora.app\" ]; then\n\tsudo mv \"$APPDIR/Typora.app\" \"$TMPDIR/Typora.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Typora.app\" \"$APPDIR\"\nrelaunch_application 'abnerworks.Typora'\n", + "a8ba94c9": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Typora.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/abnerworks.Typora'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/abnerworks.typora.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Typora'\ntrash $LOGGED_IN_USER '~/Library/Caches/abnerworks.Typora'\ntrash $LOGGED_IN_USER '~/Library/Cookies/abnerworks.Typora.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/abnerworks.Typora'\ntrash $LOGGED_IN_USER '~/Library/Preferences/abnerworks.Typora.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/abnerworks.Typora.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/abnerworks.Typora'\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Tabby.tsx b/frontend/pages/SoftwarePage/components/icons/Tabby.tsx new file mode 100644 index 0000000000..d406afd35d --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tabby.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tabby = (props: SVGProps) => ( + + + +); +export default Tabby; diff --git a/frontend/pages/SoftwarePage/components/icons/TableauPrep.tsx b/frontend/pages/SoftwarePage/components/icons/TableauPrep.tsx new file mode 100644 index 0000000000..b4139cc10c --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TableauPrep.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TableauPrep = (props: SVGProps) => ( + + + +); +export default TableauPrep; diff --git a/frontend/pages/SoftwarePage/components/icons/Tabtab.tsx b/frontend/pages/SoftwarePage/components/icons/Tabtab.tsx new file mode 100644 index 0000000000..7b36eb14a5 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tabtab.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tabtab = (props: SVGProps) => ( + + + +); +export default Tabtab; diff --git a/frontend/pages/SoftwarePage/components/icons/Taskade.tsx b/frontend/pages/SoftwarePage/components/icons/Taskade.tsx new file mode 100644 index 0000000000..c0fb2042e5 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Taskade.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Taskade = (props: SVGProps) => ( + + + +); +export default Taskade; diff --git a/frontend/pages/SoftwarePage/components/icons/Taskbar.tsx b/frontend/pages/SoftwarePage/components/icons/Taskbar.tsx new file mode 100644 index 0000000000..c9c9d1305d --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Taskbar.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Taskbar = (props: SVGProps) => ( + + + +); +export default Taskbar; diff --git a/frontend/pages/SoftwarePage/components/icons/Teacode.tsx b/frontend/pages/SoftwarePage/components/icons/Teacode.tsx new file mode 100644 index 0000000000..5f0fc2d762 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Teacode.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Teacode = (props: SVGProps) => ( + + + +); +export default Teacode; diff --git a/frontend/pages/SoftwarePage/components/icons/Termius.tsx b/frontend/pages/SoftwarePage/components/icons/Termius.tsx new file mode 100644 index 0000000000..ac97e96a65 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Termius.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Termius = (props: SVGProps) => ( + + + +); +export default Termius; diff --git a/frontend/pages/SoftwarePage/components/icons/TexLiveUtility.tsx b/frontend/pages/SoftwarePage/components/icons/TexLiveUtility.tsx new file mode 100644 index 0000000000..7c8234640a --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TexLiveUtility.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TexLiveUtility = (props: SVGProps) => ( + + + +); +export default TexLiveUtility; diff --git a/frontend/pages/SoftwarePage/components/icons/Texshop.tsx b/frontend/pages/SoftwarePage/components/icons/Texshop.tsx new file mode 100644 index 0000000000..4ce505ddfb --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Texshop.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Texshop = (props: SVGProps) => ( + + + +); +export default Texshop; diff --git a/frontend/pages/SoftwarePage/components/icons/Thaw.tsx b/frontend/pages/SoftwarePage/components/icons/Thaw.tsx new file mode 100644 index 0000000000..e0a42bd694 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Thaw.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Thaw = (props: SVGProps) => ( + + + +); +export default Thaw; diff --git a/frontend/pages/SoftwarePage/components/icons/Thorium.tsx b/frontend/pages/SoftwarePage/components/icons/Thorium.tsx new file mode 100644 index 0000000000..2a4be773d7 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Thorium.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Thorium = (props: SVGProps) => ( + + + +); +export default Thorium; diff --git a/frontend/pages/SoftwarePage/components/icons/Threema.tsx b/frontend/pages/SoftwarePage/components/icons/Threema.tsx new file mode 100644 index 0000000000..6d93f425ad --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Threema.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Threema = (props: SVGProps) => ( + + + +); +export default Threema; diff --git a/frontend/pages/SoftwarePage/components/icons/Thumbsup.tsx b/frontend/pages/SoftwarePage/components/icons/Thumbsup.tsx new file mode 100644 index 0000000000..27ae20fd0b --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Thumbsup.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Thumbsup = (props: SVGProps) => ( + + + +); +export default Thumbsup; diff --git a/frontend/pages/SoftwarePage/components/icons/Ticktick.tsx b/frontend/pages/SoftwarePage/components/icons/Ticktick.tsx new file mode 100644 index 0000000000..b809d60da2 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Ticktick.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Ticktick = (props: SVGProps) => ( + + + +); +export default Ticktick; diff --git a/frontend/pages/SoftwarePage/components/icons/Tidal.tsx b/frontend/pages/SoftwarePage/components/icons/Tidal.tsx new file mode 100644 index 0000000000..ab820fcd06 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tidal.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tidal = (props: SVGProps) => ( + + + +); +export default Tidal; diff --git a/frontend/pages/SoftwarePage/components/icons/Tiles.tsx b/frontend/pages/SoftwarePage/components/icons/Tiles.tsx new file mode 100644 index 0000000000..c99a938d40 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tiles.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tiles = (props: SVGProps) => ( + + + +); +export default Tiles; diff --git a/frontend/pages/SoftwarePage/components/icons/Timescribe.tsx b/frontend/pages/SoftwarePage/components/icons/Timescribe.tsx new file mode 100644 index 0000000000..eb9238fe10 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Timescribe.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Timescribe = (props: SVGProps) => ( + + + +); +export default Timescribe; diff --git a/frontend/pages/SoftwarePage/components/icons/Timing.tsx b/frontend/pages/SoftwarePage/components/icons/Timing.tsx new file mode 100644 index 0000000000..3719f7277d --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Timing.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Timing = (props: SVGProps) => ( + + + +); +export default Timing; diff --git a/frontend/pages/SoftwarePage/components/icons/TopazGigapixelAi.tsx b/frontend/pages/SoftwarePage/components/icons/TopazGigapixelAi.tsx new file mode 100644 index 0000000000..05d0e0607c --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TopazGigapixelAi.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TopazGigapixelAi = (props: SVGProps) => ( + + + +); +export default TopazGigapixelAi; diff --git a/frontend/pages/SoftwarePage/components/icons/TopazPhotoAi.tsx b/frontend/pages/SoftwarePage/components/icons/TopazPhotoAi.tsx new file mode 100644 index 0000000000..c72fad70e6 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TopazPhotoAi.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TopazPhotoAi = (props: SVGProps) => ( + + + +); +export default TopazPhotoAi; diff --git a/frontend/pages/SoftwarePage/components/icons/TopazVideoAi.tsx b/frontend/pages/SoftwarePage/components/icons/TopazVideoAi.tsx new file mode 100644 index 0000000000..d667441659 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TopazVideoAi.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TopazVideoAi = (props: SVGProps) => ( + + + +); +export default TopazVideoAi; diff --git a/frontend/pages/SoftwarePage/components/icons/Topnotch.tsx b/frontend/pages/SoftwarePage/components/icons/Topnotch.tsx new file mode 100644 index 0000000000..de5c85608e --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Topnotch.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Topnotch = (props: SVGProps) => ( + + + +); +export default Topnotch; diff --git a/frontend/pages/SoftwarePage/components/icons/Tradingview.tsx b/frontend/pages/SoftwarePage/components/icons/Tradingview.tsx new file mode 100644 index 0000000000..c0432b7291 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tradingview.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tradingview = (props: SVGProps) => ( + + + +); +export default Tradingview; diff --git a/frontend/pages/SoftwarePage/components/icons/Transfer.tsx b/frontend/pages/SoftwarePage/components/icons/Transfer.tsx new file mode 100644 index 0000000000..823c20e2ac --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Transfer.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Transfer = (props: SVGProps) => ( + + + +); +export default Transfer; diff --git a/frontend/pages/SoftwarePage/components/icons/Transmission.tsx b/frontend/pages/SoftwarePage/components/icons/Transmission.tsx new file mode 100644 index 0000000000..902723ce13 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Transmission.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Transmission = (props: SVGProps) => ( + + + +); +export default Transmission; diff --git a/frontend/pages/SoftwarePage/components/icons/Trex.tsx b/frontend/pages/SoftwarePage/components/icons/Trex.tsx new file mode 100644 index 0000000000..cb81099180 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Trex.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Trex = (props: SVGProps) => ( + + + +); +export default Trex; diff --git a/frontend/pages/SoftwarePage/components/icons/TrezorSuite.tsx b/frontend/pages/SoftwarePage/components/icons/TrezorSuite.tsx new file mode 100644 index 0000000000..e3647677cc --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TrezorSuite.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TrezorSuite = (props: SVGProps) => ( + + + +); +export default TrezorSuite; diff --git a/frontend/pages/SoftwarePage/components/icons/Tripmode.tsx b/frontend/pages/SoftwarePage/components/icons/Tripmode.tsx new file mode 100644 index 0000000000..201437cd6f --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tripmode.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tripmode = (props: SVGProps) => ( + + + +); +export default Tripmode; diff --git a/frontend/pages/SoftwarePage/components/icons/Tuple.tsx b/frontend/pages/SoftwarePage/components/icons/Tuple.tsx new file mode 100644 index 0000000000..34071bf212 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Tuple.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Tuple = (props: SVGProps) => ( + + + +); +export default Tuple; diff --git a/frontend/pages/SoftwarePage/components/icons/TwineApp.tsx b/frontend/pages/SoftwarePage/components/icons/TwineApp.tsx new file mode 100644 index 0000000000..350695b7fa --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/TwineApp.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const TwineApp = (props: SVGProps) => ( + + + +); +export default TwineApp; diff --git a/frontend/pages/SoftwarePage/components/icons/Twobird.tsx b/frontend/pages/SoftwarePage/components/icons/Twobird.tsx new file mode 100644 index 0000000000..c70d39f4b0 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Twobird.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Twobird = (props: SVGProps) => ( + + + +); +export default Twobird; diff --git a/frontend/pages/SoftwarePage/components/icons/Typeface.tsx b/frontend/pages/SoftwarePage/components/icons/Typeface.tsx new file mode 100644 index 0000000000..5df434ec61 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Typeface.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Typeface = (props: SVGProps) => ( + + + +); +export default Typeface; diff --git a/frontend/pages/SoftwarePage/components/icons/Typinator.tsx b/frontend/pages/SoftwarePage/components/icons/Typinator.tsx new file mode 100644 index 0000000000..ced85d7d7d --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Typinator.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Typinator = (props: SVGProps) => ( + + + +); +export default Typinator; diff --git a/frontend/pages/SoftwarePage/components/icons/Typora.tsx b/frontend/pages/SoftwarePage/components/icons/Typora.tsx new file mode 100644 index 0000000000..ae32d81ad4 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Typora.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Typora = (props: SVGProps) => ( + + + +); +export default Typora; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 30e9fe99b9..72db71430e 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -776,24 +776,58 @@ import Syncmate from "./Syncmate"; import Syncovery from "./Syncovery"; import SyncthingApp from "./SyncthingApp"; import SyntaxHighlight from "./SyntaxHighlight"; +import Tabby from "./Tabby"; import TableauDesktop from "./TableauDesktop"; +import TableauPrep from "./TableauPrep"; import TablePlus from "./TablePlus"; +import Tabtab from "./Tabtab"; import Tailscale from "./Tailscale"; +import Taskade from "./Taskade"; +import Taskbar from "./Taskbar"; +import Teacode from "./Teacode"; import Teams from "./Teams"; import TeamViewer from "./TeamViewer"; import Telegram from "./Telegram"; import TeleportConnect from "./TeleportConnect"; import Terminal from "./Terminal"; +import Termius from "./Termius"; +import TexLiveUtility from "./TexLiveUtility"; +import Texshop from "./Texshop"; import TextExpander from "./TextExpander"; +import Thaw from "./Thaw"; import TheUnarchiver from "./TheUnarchiver"; +import Thorium from "./Thorium"; +import Threema from "./Threema"; +import Thumbsup from "./Thumbsup"; import Thunderbird from "./Thunderbird"; +import Ticktick from "./Ticktick"; +import Tidal from "./Tidal"; +import Tiles from "./Tiles"; +import Timescribe from "./Timescribe"; +import Timing from "./Timing"; import Todoist from "./Todoist"; +import TopazGigapixelAi from "./TopazGigapixelAi"; +import TopazPhotoAi from "./TopazPhotoAi"; +import TopazVideoAi from "./TopazVideoAi"; +import Topnotch from "./Topnotch"; import TorBrowser from "./TorBrowser"; import Tortoisegit from "./Tortoisegit"; import Tower from "./Tower"; +import Tradingview from "./Tradingview"; +import Transfer from "./Transfer"; +import Transmission from "./Transmission"; import Transmit from "./Transmit"; +import Trex from "./Trex"; +import TrezorSuite from "./TrezorSuite"; +import Tripmode from "./Tripmode"; import Tunnelblick from "./Tunnelblick"; +import Tuple from "./Tuple"; +import TwineApp from "./TwineApp"; import Twingate from "./Twingate"; +import Twobird from "./Twobird"; +import Typeface from "./Typeface"; +import Typinator from "./Typinator"; +import Typora from "./Typora"; import UaConnect from "./UaConnect"; import Ukelele from "./Ukelele"; import UltimakerCura from "./UltimakerCura"; @@ -1597,6 +1631,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { secretive: Secretive, securesafe: Securesafe, selfcontrol: Selfcontrol, + "sempliva tiles": Tiles, sensei: Sensei, "sequel ace": SequelAce, session: Session, @@ -1680,9 +1715,15 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { syncovery: Syncovery, syncthing: SyncthingApp, "syntax highlight": SyntaxHighlight, + tabby: Tabby, tableau: TableauDesktop, + "tableau prep": TableauPrep, tableplus: TablePlus, + tabtab: Tabtab, tailscale: Tailscale, + taskade: Taskade, + taskbar: Taskbar, + teacode: Teacode, teamviewer: TeamViewer, telegram: Telegram, teleport: TeleportConnect, @@ -1690,16 +1731,43 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { "teleport suite": TeleportConnect, "teradici pcoip software client for macos": Pcoipclient, terminal: Terminal, + termius: Termius, + "tex live utility": TexLiveUtility, + texshop: Texshop, textexpander: TextExpander, + thaw: Thaw, "the unarchiver": TheUnarchiver, + "thorium reader": Thorium, + threema: Threema, + thumbsup: Thumbsup, thunderbird: Thunderbird, + ticktick: Ticktick, + tidal: Tidal, + timescribe: Timescribe, + timing: Timing, todoist: Todoist, + "topaz gigapixel ai": TopazGigapixelAi, + "topaz photo ai": TopazPhotoAi, + "topaz video ai": TopazVideoAi, + topnotch: Topnotch, "tor browser": TorBrowser, tortoisegit: Tortoisegit, tower: Tower, + "tradingview desktop": Tradingview, + transfer: Transfer, + transmission: Transmission, transmit: Transmit, + trex: Trex, + "trezor suite": TrezorSuite, + tripmode: Tripmode, tunnelblick: Tunnelblick, + tuple: Tuple, + twine: TwineApp, twingate: Twingate, + twobird: Twobird, + typeface: Typeface, + typinator: Typinator, + typora: Typora, "ua connect": UaConnect, ukelele: Ukelele, "ultimaker cura": UltimakerCura, diff --git a/website/assets/images/app-icon-tabby-60x60@2x.png b/website/assets/images/app-icon-tabby-60x60@2x.png new file mode 100644 index 0000000000..c389538cc4 Binary files /dev/null and b/website/assets/images/app-icon-tabby-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tableau-prep-60x60@2x.png b/website/assets/images/app-icon-tableau-prep-60x60@2x.png new file mode 100644 index 0000000000..8a45449b3b Binary files /dev/null and b/website/assets/images/app-icon-tableau-prep-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tableau-public-60x60@2x.png b/website/assets/images/app-icon-tableau-public-60x60@2x.png new file mode 100644 index 0000000000..768ad8b0f3 Binary files /dev/null and b/website/assets/images/app-icon-tableau-public-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tabtab-60x60@2x.png b/website/assets/images/app-icon-tabtab-60x60@2x.png new file mode 100644 index 0000000000..dcf05ac79d Binary files /dev/null and b/website/assets/images/app-icon-tabtab-60x60@2x.png differ diff --git a/website/assets/images/app-icon-taskade-60x60@2x.png b/website/assets/images/app-icon-taskade-60x60@2x.png new file mode 100644 index 0000000000..1a8f2f1bed Binary files /dev/null and b/website/assets/images/app-icon-taskade-60x60@2x.png differ diff --git a/website/assets/images/app-icon-taskbar-60x60@2x.png b/website/assets/images/app-icon-taskbar-60x60@2x.png new file mode 100644 index 0000000000..6122c28509 Binary files /dev/null and b/website/assets/images/app-icon-taskbar-60x60@2x.png differ diff --git a/website/assets/images/app-icon-teacode-60x60@2x.png b/website/assets/images/app-icon-teacode-60x60@2x.png new file mode 100644 index 0000000000..b2903c27ed Binary files /dev/null and b/website/assets/images/app-icon-teacode-60x60@2x.png differ diff --git a/website/assets/images/app-icon-termius-60x60@2x.png b/website/assets/images/app-icon-termius-60x60@2x.png new file mode 100644 index 0000000000..5506bcead3 Binary files /dev/null and b/website/assets/images/app-icon-termius-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tex-live-utility-60x60@2x.png b/website/assets/images/app-icon-tex-live-utility-60x60@2x.png new file mode 100644 index 0000000000..1d08b760ad Binary files /dev/null and b/website/assets/images/app-icon-tex-live-utility-60x60@2x.png differ diff --git a/website/assets/images/app-icon-texshop-60x60@2x.png b/website/assets/images/app-icon-texshop-60x60@2x.png new file mode 100644 index 0000000000..8238b29954 Binary files /dev/null and b/website/assets/images/app-icon-texshop-60x60@2x.png differ diff --git a/website/assets/images/app-icon-thaw-60x60@2x.png b/website/assets/images/app-icon-thaw-60x60@2x.png new file mode 100644 index 0000000000..bbcd329660 Binary files /dev/null and b/website/assets/images/app-icon-thaw-60x60@2x.png differ diff --git a/website/assets/images/app-icon-thorium-60x60@2x.png b/website/assets/images/app-icon-thorium-60x60@2x.png new file mode 100644 index 0000000000..e3ccce627e Binary files /dev/null and b/website/assets/images/app-icon-thorium-60x60@2x.png differ diff --git a/website/assets/images/app-icon-threema-60x60@2x.png b/website/assets/images/app-icon-threema-60x60@2x.png new file mode 100644 index 0000000000..0a8fba66d4 Binary files /dev/null and b/website/assets/images/app-icon-threema-60x60@2x.png differ diff --git a/website/assets/images/app-icon-thumbsup-60x60@2x.png b/website/assets/images/app-icon-thumbsup-60x60@2x.png new file mode 100644 index 0000000000..7b7ae0cc56 Binary files /dev/null and b/website/assets/images/app-icon-thumbsup-60x60@2x.png differ diff --git a/website/assets/images/app-icon-ticktick-60x60@2x.png b/website/assets/images/app-icon-ticktick-60x60@2x.png new file mode 100644 index 0000000000..b3ec355268 Binary files /dev/null and b/website/assets/images/app-icon-ticktick-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tidal-60x60@2x.png b/website/assets/images/app-icon-tidal-60x60@2x.png new file mode 100644 index 0000000000..a43a186c6f Binary files /dev/null and b/website/assets/images/app-icon-tidal-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tiles-60x60@2x.png b/website/assets/images/app-icon-tiles-60x60@2x.png new file mode 100644 index 0000000000..c7d47849fd Binary files /dev/null and b/website/assets/images/app-icon-tiles-60x60@2x.png differ diff --git a/website/assets/images/app-icon-timescribe-60x60@2x.png b/website/assets/images/app-icon-timescribe-60x60@2x.png new file mode 100644 index 0000000000..42f7bcd3e8 Binary files /dev/null and b/website/assets/images/app-icon-timescribe-60x60@2x.png differ diff --git a/website/assets/images/app-icon-timing-60x60@2x.png b/website/assets/images/app-icon-timing-60x60@2x.png new file mode 100644 index 0000000000..47f0604f74 Binary files /dev/null and b/website/assets/images/app-icon-timing-60x60@2x.png differ diff --git a/website/assets/images/app-icon-topaz-gigapixel-ai-60x60@2x.png b/website/assets/images/app-icon-topaz-gigapixel-ai-60x60@2x.png new file mode 100644 index 0000000000..1daa8caf6c Binary files /dev/null and b/website/assets/images/app-icon-topaz-gigapixel-ai-60x60@2x.png differ diff --git a/website/assets/images/app-icon-topaz-photo-ai-60x60@2x.png b/website/assets/images/app-icon-topaz-photo-ai-60x60@2x.png new file mode 100644 index 0000000000..ec6df5c4d1 Binary files /dev/null and b/website/assets/images/app-icon-topaz-photo-ai-60x60@2x.png differ diff --git a/website/assets/images/app-icon-topaz-video-ai-60x60@2x.png b/website/assets/images/app-icon-topaz-video-ai-60x60@2x.png new file mode 100644 index 0000000000..c273ae11ee Binary files /dev/null and b/website/assets/images/app-icon-topaz-video-ai-60x60@2x.png differ diff --git a/website/assets/images/app-icon-topnotch-60x60@2x.png b/website/assets/images/app-icon-topnotch-60x60@2x.png new file mode 100644 index 0000000000..1cf0bfda69 Binary files /dev/null and b/website/assets/images/app-icon-topnotch-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tradingview-60x60@2x.png b/website/assets/images/app-icon-tradingview-60x60@2x.png new file mode 100644 index 0000000000..034474c2d4 Binary files /dev/null and b/website/assets/images/app-icon-tradingview-60x60@2x.png differ diff --git a/website/assets/images/app-icon-transfer-60x60@2x.png b/website/assets/images/app-icon-transfer-60x60@2x.png new file mode 100644 index 0000000000..237f86a40e Binary files /dev/null and b/website/assets/images/app-icon-transfer-60x60@2x.png differ diff --git a/website/assets/images/app-icon-transmission-60x60@2x.png b/website/assets/images/app-icon-transmission-60x60@2x.png new file mode 100644 index 0000000000..c782ef6b68 Binary files /dev/null and b/website/assets/images/app-icon-transmission-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tresorit-60x60@2x.png b/website/assets/images/app-icon-tresorit-60x60@2x.png new file mode 100644 index 0000000000..e64904f685 Binary files /dev/null and b/website/assets/images/app-icon-tresorit-60x60@2x.png differ diff --git a/website/assets/images/app-icon-trex-60x60@2x.png b/website/assets/images/app-icon-trex-60x60@2x.png new file mode 100644 index 0000000000..b591bb0f53 Binary files /dev/null and b/website/assets/images/app-icon-trex-60x60@2x.png differ diff --git a/website/assets/images/app-icon-trezor-suite-60x60@2x.png b/website/assets/images/app-icon-trezor-suite-60x60@2x.png new file mode 100644 index 0000000000..6a8aa6d1e6 Binary files /dev/null and b/website/assets/images/app-icon-trezor-suite-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tripmode-60x60@2x.png b/website/assets/images/app-icon-tripmode-60x60@2x.png new file mode 100644 index 0000000000..4731fe8204 Binary files /dev/null and b/website/assets/images/app-icon-tripmode-60x60@2x.png differ diff --git a/website/assets/images/app-icon-tuple-60x60@2x.png b/website/assets/images/app-icon-tuple-60x60@2x.png new file mode 100644 index 0000000000..15473dacf2 Binary files /dev/null and b/website/assets/images/app-icon-tuple-60x60@2x.png differ diff --git a/website/assets/images/app-icon-twine-app-60x60@2x.png b/website/assets/images/app-icon-twine-app-60x60@2x.png new file mode 100644 index 0000000000..81c1f582f0 Binary files /dev/null and b/website/assets/images/app-icon-twine-app-60x60@2x.png differ diff --git a/website/assets/images/app-icon-twobird-60x60@2x.png b/website/assets/images/app-icon-twobird-60x60@2x.png new file mode 100644 index 0000000000..f710029388 Binary files /dev/null and b/website/assets/images/app-icon-twobird-60x60@2x.png differ diff --git a/website/assets/images/app-icon-typeface-60x60@2x.png b/website/assets/images/app-icon-typeface-60x60@2x.png new file mode 100644 index 0000000000..07e0e2c56b Binary files /dev/null and b/website/assets/images/app-icon-typeface-60x60@2x.png differ diff --git a/website/assets/images/app-icon-typinator-60x60@2x.png b/website/assets/images/app-icon-typinator-60x60@2x.png new file mode 100644 index 0000000000..3e45c18fdf Binary files /dev/null and b/website/assets/images/app-icon-typinator-60x60@2x.png differ diff --git a/website/assets/images/app-icon-typora-60x60@2x.png b/website/assets/images/app-icon-typora-60x60@2x.png new file mode 100644 index 0000000000..47cf8b1803 Binary files /dev/null and b/website/assets/images/app-icon-typora-60x60@2x.png differ