From fbabd079d14f4cf759db95dc74e68ba2a8e59bf0 Mon Sep 17 00:00:00 2001 From: Allen Houchins <32207388+allenhouchins@users.noreply.github.com> Date: Sat, 6 Jun 2026 23:34:28 -0500 Subject: [PATCH] Add Comet as a macOS & Windows FMA (#47027) This pull request adds support for the Comet browser (an AI-integrated browser from Perplexity) to the maintained apps catalog for both macOS and Windows. It introduces metadata, installation, and uninstallation scripts, as well as versioned definitions for both platforms. **New application support: Comet browser** *Metadata and catalog integration:* - Added `comet.json` metadata files for Homebrew (macOS) and Winget (Windows) in the `inputs` directory, defining identifiers, installer types, and categories. [[1]](diffhunk://#diff-60e2346d602b7538ba08314f7adfdde98ca8e802dd3706c65bb75273fe7bbbd4R1-R8) [[2]](diffhunk://#diff-ecdccc5ed1a1f1e6f2b66439941fcd74419b2706c1df155cb4bc1940abd6bfa7R1-R13) - Updated `apps.json` to include Comet for both `darwin` (macOS) and `windows` platforms with descriptive text. *macOS support:* - Added `outputs/comet/darwin.json` with versioned app definition, install/uninstall queries, download URL, and references to install/uninstall scripts. *Windows support:* - Added `outputs/comet/windows.json` with versioned app definition, install/uninstall queries, download URL, SHA256, and references to install/uninstall scripts. - Added PowerShell scripts for silent installation (`comet_install.ps1`) and uninstallation (`comet_uninstall.ps1`) of Comet, handling machine-wide deployment and proper exit codes. [[1]](diffhunk://#diff-5b9c60857fd2a49958f05124e8744394683297127503578e9b4eaf227470f1f7R1-R31) [[2]](diffhunk://#diff-3433e05da3c0601490c7d90084264d4a793d0feef4211569b4aff884f85116dbR1-R101) --- ee/maintained-apps/inputs/homebrew/comet.json | 8 ++ ee/maintained-apps/inputs/winget/comet.json | 13 +++ .../inputs/winget/scripts/comet_install.ps1 | 31 ++++++ .../inputs/winget/scripts/comet_uninstall.ps1 | 101 ++++++++++++++++++ ee/maintained-apps/outputs/apps.json | 14 +++ ee/maintained-apps/outputs/comet/darwin.json | 22 ++++ ee/maintained-apps/outputs/comet/windows.json | 22 ++++ .../SoftwarePage/components/icons/Comet.tsx | 14 +++ .../SoftwarePage/components/icons/index.ts | 2 + .../assets/images/app-icon-comet-60x60@2x.png | Bin 0 -> 16805 bytes 10 files changed, 227 insertions(+) create mode 100644 ee/maintained-apps/inputs/homebrew/comet.json create mode 100644 ee/maintained-apps/inputs/winget/comet.json create mode 100644 ee/maintained-apps/inputs/winget/scripts/comet_install.ps1 create mode 100644 ee/maintained-apps/inputs/winget/scripts/comet_uninstall.ps1 create mode 100644 ee/maintained-apps/outputs/comet/darwin.json create mode 100644 ee/maintained-apps/outputs/comet/windows.json create mode 100644 frontend/pages/SoftwarePage/components/icons/Comet.tsx create mode 100644 website/assets/images/app-icon-comet-60x60@2x.png diff --git a/ee/maintained-apps/inputs/homebrew/comet.json b/ee/maintained-apps/inputs/homebrew/comet.json new file mode 100644 index 0000000000..e26ad8a878 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/comet.json @@ -0,0 +1,8 @@ +{ + "name": "Comet", + "slug": "comet/darwin", + "unique_identifier": "ai.perplexity.comet", + "token": "comet", + "installer_format": "dmg", + "default_categories": ["Browsers"] +} diff --git a/ee/maintained-apps/inputs/winget/comet.json b/ee/maintained-apps/inputs/winget/comet.json new file mode 100644 index 0000000000..acb0b06997 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/comet.json @@ -0,0 +1,13 @@ +{ + "name": "Comet", + "slug": "comet/windows", + "package_identifier": "Perplexity.Comet", + "unique_identifier": "Comet", + "program_publisher": "PERPLEXITY AI, INC.", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/comet_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/comet_uninstall.ps1", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "default_categories": ["Browsers"] +} diff --git a/ee/maintained-apps/inputs/winget/scripts/comet_install.ps1 b/ee/maintained-apps/inputs/winget/scripts/comet_install.ps1 new file mode 100644 index 0000000000..7de7516d67 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/comet_install.ps1 @@ -0,0 +1,31 @@ +# Learn more about .exe install scripts: +# http://fleetdm.com/learn-more-about/exe-install-scripts +# +# Comet ships a Chromium/Omaha-based machine-scope installer +# (comet_*_system.exe). Fleet runs as SYSTEM, so it installs machine-wide. + +$exeFilePath = "${env:INSTALLER_PATH}" + +try { + +# Add arguments to install silently machine-wide. +# --install --silent -> silent machine-scope install +$processOptions = @{ + FilePath = "$exeFilePath" + ArgumentList = "--install --silent" + PassThru = $true + Wait = $true +} + +# Start process and track exit code +$process = Start-Process @processOptions +$exitCode = $process.ExitCode + +# Prints the exit code +Write-Host "Install exit code: $exitCode" +Exit $exitCode + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/comet_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/comet_uninstall.ps1 new file mode 100644 index 0000000000..23b1b4104c --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/comet_uninstall.ps1 @@ -0,0 +1,101 @@ +# Fleet extracts name from installer (EXE) and saves it to PACKAGE_ID +# variable +$softwareName = "Comet" + +# It is recommended to use exact software name here if possible to avoid +# uninstalling unintended software. +$softwareNameLike = "*$softwareName*" + +# Comet uses a Chromium/Omaha uninstaller. Its UninstallString already +# contains "--uninstall --system-level"; "--force-uninstall" runs it silently +# without a confirmation prompt. +$uninstallArgs = "--force-uninstall" + +# Comet installs machine-wide, so look in the per-machine uninstall keys. +$machineKey = ` + 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' +$machineKey32on64 = ` + 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + +# Define acceptable/expected exit codes (19 = uninstall requires reboot) +$ExpectedExitCodes = @(0, 19) + +$exitCode = 0 + +try { + +[array]$uninstallKeys = Get-ChildItem ` + -Path @($machineKey, $machineKey32on64) ` + -ErrorAction SilentlyContinue | + ForEach-Object { Get-ItemProperty $_.PSPath } + +$foundUninstaller = $false +foreach ($key in $uninstallKeys) { + # If needed, add -notlike to the comparison to exclude certain similar + # software + if ($key.DisplayName -like $softwareNameLike) { + $foundUninstaller = $true + # Get the uninstall command. Some uninstallers do not include + # 'QuietUninstallString' and require a flag to run silently. + $uninstallCommand = if ($key.QuietUninstallString) { + $key.QuietUninstallString + } else { + $key.UninstallString + } + + # The uninstall command may contain command and args, like: + # "C:\Program Files\Software\uninstall.exe" --uninstall --silent + # Split the command and args + $splitArgs = $uninstallCommand.Split('"') + if ($splitArgs.Length -gt 1) { + if ($splitArgs.Length -eq 3) { + $uninstallArgs = "$( $splitArgs[2] ) $uninstallArgs".Trim() + } elseif ($splitArgs.Length -gt 3) { + Throw ` + "Uninstall command contains multiple quoted strings. " + + "Please update the uninstall script.`n" + + "Uninstall command: $uninstallCommand" + } + $uninstallCommand = $splitArgs[1] + } + Write-Host "Uninstall command: $uninstallCommand" + Write-Host "Uninstall args: $uninstallArgs" + + $processOptions = @{ + FilePath = $uninstallCommand + PassThru = $true + Wait = $true + } + if ($uninstallArgs -ne '') { + $processOptions.ArgumentList = "$uninstallArgs" + } + + # Start process and track exit code + $process = Start-Process @processOptions + $exitCode = $process.ExitCode + + # Prints the exit code + Write-Host "Uninstall exit code: $exitCode" + # Exit the loop once the software is found and uninstalled. + break + } +} + +if (-not $foundUninstaller) { + Write-Host "Uninstaller for '$softwareName' not found." + # Change exit code to 0 if you don't want to fail if uninstaller is not + # found. This could happen if program was already uninstalled. + $exitCode = 1 +} + +} catch { + Write-Host "Error: $_" + $exitCode = 1 +} + +# Treat acceptable exit codes as success +if ($ExpectedExitCodes -contains $exitCode) { + Exit 0 +} else { + Exit $exitCode +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 28123b7536..7c52336dce 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -673,6 +673,20 @@ "unique_identifier": "Cloudflare WARP", "description": "Cloudflare WARP enhances internet safety and performance by encrypting your data and optimizing connections for privacy." }, + { + "name": "Comet", + "slug": "comet/darwin", + "platform": "darwin", + "unique_identifier": "ai.perplexity.comet", + "description": "Comet is a web browser with an integrated AI assistant from Perplexity." + }, + { + "name": "Comet", + "slug": "comet/windows", + "platform": "windows", + "unique_identifier": "Comet", + "description": "Comet is a web browser with an integrated AI assistant from Perplexity." + }, { "name": "Connect Fonts", "slug": "connect-fonts/darwin", diff --git a/ee/maintained-apps/outputs/comet/darwin.json b/ee/maintained-apps/outputs/comet/darwin.json new file mode 100644 index 0000000000..dd323ab4ea --- /dev/null +++ b/ee/maintained-apps/outputs/comet/darwin.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "148.0.7778.1016", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'ai.perplexity.comet';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM apps WHERE bundle_identifier = 'ai.perplexity.comet' AND version_compare(bundle_short_version, '148.0.7778.1016') < 0);" + }, + "installer_url": "https://www.perplexity.ai/rest/browser/download?channel=stable&platform=mac_arm64", + "install_script_ref": "af8d196c", + "uninstall_script_ref": "e2a92aa5", + "sha256": "no_check", + "default_categories": [ + "Browsers" + ] + } + ], + "refs": { + "af8d196c": "#!/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 'ai.perplexity.comet'\nif [ -d \"$APPDIR/Comet.app\" ]; then\n\tsudo mv \"$APPDIR/Comet.app\" \"$TMPDIR/Comet.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Comet.app\" \"$APPDIR\"\nrelaunch_application 'ai.perplexity.comet'\n", + "e2a92aa5": "#!/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/Comet.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/ai.perplexity.comet'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Comet'\ntrash $LOGGED_IN_USER '~/Library/Caches/ai.perplexity.comet'\ntrash $LOGGED_IN_USER '~/Library/Caches/Comet'\ntrash $LOGGED_IN_USER '~/Library/Preferences/ai.perplexity.comet.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/ai.perplexity.comet.savedState'\ntrash $LOGGED_IN_USER '~/Library/WebKit/ai.perplexity.comet'\n" + } +} diff --git a/ee/maintained-apps/outputs/comet/windows.json b/ee/maintained-apps/outputs/comet/windows.json new file mode 100644 index 0000000000..4428ebbece --- /dev/null +++ b/ee/maintained-apps/outputs/comet/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "148.0.7778.1018", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name = 'Comet' AND publisher = 'PERPLEXITY AI, INC.';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name = 'Comet' AND publisher = 'PERPLEXITY AI, INC.' AND version_compare(version, '148.0.7778.1018') < 0);" + }, + "installer_url": "https://www.perplexity.ai/rest/browser/download?platform=win_x64&channel=stable", + "install_script_ref": "9f163ee3", + "uninstall_script_ref": "faa38912", + "sha256": "3d85ad9e2be15a1258d88e0b280a27131a2f2ca7b01e2f24e40bda5bc600d537", + "default_categories": [ + "Browsers" + ] + } + ], + "refs": { + "9f163ee3": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# Comet ships a Chromium/Omaha-based machine-scope installer\n# (comet_*_system.exe). Fleet runs as SYSTEM, so it installs machine-wide.\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n\n# Add arguments to install silently machine-wide.\n# --install --silent -> silent machine-scope install\n$processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"--install --silent\"\n PassThru = $true\n Wait = $true\n}\n\n# Start process and track exit code\n$process = Start-Process @processOptions\n$exitCode = $process.ExitCode\n\n# Prints the exit code\nWrite-Host \"Install exit code: $exitCode\"\nExit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "faa38912": "# Fleet extracts name from installer (EXE) and saves it to PACKAGE_ID\n# variable\n$softwareName = \"Comet\"\n\n# It is recommended to use exact software name here if possible to avoid\n# uninstalling unintended software.\n$softwareNameLike = \"*$softwareName*\"\n\n# Comet uses a Chromium/Omaha uninstaller. Its UninstallString already\n# contains \"--uninstall --system-level\"; \"--force-uninstall\" runs it silently\n# without a confirmation prompt.\n$uninstallArgs = \"--force-uninstall\"\n\n# Comet installs machine-wide, so look in the per-machine uninstall keys.\n$machineKey = `\n 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = `\n 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\n# Define acceptable/expected exit codes (19 = uninstall requires reboot)\n$ExpectedExitCodes = @(0, 19)\n\n$exitCode = 0\n\ntry {\n\n[array]$uninstallKeys = Get-ChildItem `\n -Path @($machineKey, $machineKey32on64) `\n -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath }\n\n$foundUninstaller = $false\nforeach ($key in $uninstallKeys) {\n # If needed, add -notlike to the comparison to exclude certain similar\n # software\n if ($key.DisplayName -like $softwareNameLike) {\n $foundUninstaller = $true\n # Get the uninstall command. Some uninstallers do not include\n # 'QuietUninstallString' and require a flag to run silently.\n $uninstallCommand = if ($key.QuietUninstallString) {\n $key.QuietUninstallString\n } else {\n $key.UninstallString\n }\n\n # The uninstall command may contain command and args, like:\n # \"C:\\Program Files\\Software\\uninstall.exe\" --uninstall --silent\n # Split the command and args\n $splitArgs = $uninstallCommand.Split('\"')\n if ($splitArgs.Length -gt 1) {\n if ($splitArgs.Length -eq 3) {\n $uninstallArgs = \"$( $splitArgs[2] ) $uninstallArgs\".Trim()\n } elseif ($splitArgs.Length -gt 3) {\n Throw `\n \"Uninstall command contains multiple quoted strings. \" +\n \"Please update the uninstall script.`n\" +\n \"Uninstall command: $uninstallCommand\"\n }\n $uninstallCommand = $splitArgs[1]\n }\n Write-Host \"Uninstall command: $uninstallCommand\"\n Write-Host \"Uninstall args: $uninstallArgs\"\n\n $processOptions = @{\n FilePath = $uninstallCommand\n PassThru = $true\n Wait = $true\n }\n if ($uninstallArgs -ne '') {\n $processOptions.ArgumentList = \"$uninstallArgs\"\n }\n\n # Start process and track exit code\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode\n\n # Prints the exit code\n Write-Host \"Uninstall exit code: $exitCode\"\n # Exit the loop once the software is found and uninstalled.\n break\n }\n}\n\nif (-not $foundUninstaller) {\n Write-Host \"Uninstaller for '$softwareName' not found.\"\n # Change exit code to 0 if you don't want to fail if uninstaller is not\n # found. This could happen if program was already uninstalled.\n $exitCode = 1\n}\n\n} catch {\n Write-Host \"Error: $_\"\n $exitCode = 1\n}\n\n# Treat acceptable exit codes as success\nif ($ExpectedExitCodes -contains $exitCode) {\n Exit 0\n} else {\n Exit $exitCode\n}\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Comet.tsx b/frontend/pages/SoftwarePage/components/icons/Comet.tsx new file mode 100644 index 0000000000..88955bbf3b --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Comet.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Comet = (props: SVGProps) => ( + + + +); +export default Comet; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index 2c8599fc50..aaf381bdbd 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -22,6 +22,7 @@ import Charles from "./Charles"; import ChromeRemoteDesktop from "./ChromeRemoteDesktop"; import Cinc from "./Cinc"; import ClickShare from "./ClickShare"; +import Comet from "./Comet"; import ConnectFonts from "./ConnectFonts"; import CrashPlan from "./CrashPlan"; import Cryptomator from "./Cryptomator"; @@ -384,6 +385,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { "clockify desktop": ClockifyDesktop, cloudflare: Cloudflare, code: VisualStudioCode, + comet: Comet, "company portal": IntuneCompanyPortal, "connect fonts": ConnectFonts, crashplan: CrashPlan, diff --git a/website/assets/images/app-icon-comet-60x60@2x.png b/website/assets/images/app-icon-comet-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2534a0e37acbf54dde5e64fda3597acb82c5ed76 GIT binary patch literal 16805 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