chore: import upstream snapshot with attribution
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:03:19 +08:00
commit 91e75e620b
3227 changed files with 1307078 additions and 0 deletions
@@ -0,0 +1,101 @@
#!/bin/bash
# Extract PostgreSQL metadata
# Find main binary
binary_path=$(which psql)
binary_name=$(basename "$binary_path")
# Get version - extract version number from psql --version
version=$(psql --version 2>/dev/null | grep -oP '\) \K[0-9]+\.[0-9]+')
# Find desktop entry - search dynamically in /usr/share/applications
desktop_entry=""
display_name="PostgreSQL"
# Search for any .desktop file that contains postgres, postgresql, or psql
if [ -d "/usr/share/applications" ]; then
# Use find with grep to search for postgres-related desktop files
while IFS= read -r desktop_file; do
if [ -f "$desktop_file" ]; then
desktop_entry="$desktop_file"
# Extract display name from the desktop file
extracted_name=$(grep "^Name=" "$desktop_file" 2>/dev/null | head -1 | cut -d= -f2)
if [ -n "$extracted_name" ]; then
display_name="$extracted_name"
break
fi
fi
done < <(find /usr/share/applications -name "*.desktop" -exec grep -l "postgres\|postgresql\|psql\|database" {} \; 2>/dev/null)
fi
# If no desktop file found, try to extract package description as fallback
if [ -z "$desktop_entry" ]; then
pkg_desc=$(dpkg -s postgresql 2>/dev/null | grep "^Description:" | head -1 | cut -d: -f2-)
if [ -n "$pkg_desc" ]; then
display_name="PostgreSQL$pkg_desc"
fi
fi
# Find icon paths - look for PostgreSQL icons
icon_paths=()
# Check standard icon directories
for dir in /usr/share/icons /usr/share/pixmaps; do
if [ -d "$dir" ]; then
while IFS= read -r icon_file; do
if [ -f "$icon_file" ]; then
icon_paths+=("$icon_file")
fi
done < <(find "$dir" -type f \( -name "*postgres*" -o -name "*sql*" \) 2>/dev/null | head -10)
fi
done
# If no specific icons found, try looking for the default PostgreSQL icon
if [ ${#icon_paths[@]} -eq 0 ]; then
# Check common locations
test -f "/usr/share/pixmaps/postgresql.xpm" && icon_paths+=("/usr/share/pixmaps/postgresql.xpm")
test -f "/usr/share/pixmaps/postgresql.png" && icon_paths+=("/usr/share/pixmaps/postgresql.png")
fi
# Also try to extract icon from desktop file if it exists
if [ -n "$desktop_entry" ] && [ -f "$desktop_entry" ]; then
desktop_icon=$(grep "^Icon=" "$desktop_entry" 2>/dev/null | head -1 | cut -d= -f2)
if [ -n "$desktop_icon" ]; then
# Try to locate the icon file
for dir in /usr/share/icons /usr/share/pixmaps; do
if [ -d "$dir" ]; then
found_icon=$(find "$dir" -name "$desktop_icon*" 2>/dev/null | head -1)
if [ -f "$found_icon" ]; then
# Check if already in list
if [[ ! " ${icon_paths[@]} " =~ " ${found_icon} " ]]; then
icon_paths+=("$found_icon")
fi
fi
fi
done
fi
fi
# Output as JSON
printf '{\n'
printf ' "binary_path": "%s",\n' "$binary_path"
printf ' "binary_name": "%s",\n' "$binary_name"
printf ' "display_name": "%s",\n' "$display_name"
printf ' "desktop_entry": "%s",\n' "$desktop_entry"
printf ' "icon_paths": [\n'
# Add icon paths to JSON
first=true
for icon in "${icon_paths[@]}"; do
if [ "$first" = true ]; then
printf ' "%s"\n' "$icon"
first=false
else
printf ' ,"%s"\n' "$icon"
fi
done
printf ' ],\n'
printf ' "version": "%s"\n' "$version"
printf '}\n'
@@ -0,0 +1,18 @@
#!/bin/bash
set -e
echo "Installing PostgreSQL..."
# Update package list
sudo apt-get update
# Install PostgreSQL (latest version from distribution repos)
# This will install postgresql and postgresql-contrib
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql postgresql-contrib
echo "PostgreSQL installed successfully!"
# Verify installation
psql --version
echo "Installation complete!"
@@ -0,0 +1,36 @@
#!/bin/bash
echo "Starting PostgreSQL server..."
# Start PostgreSQL as the postgres user
sudo -u postgres /usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/14/main -l /var/log/postgresql/postgresql-14-main.log start
# Wait for the service to be ready
sleep 2
# Check if the server is running
if sudo -u postgres /usr/lib/postgresql/14/bin/pg_isready -h localhost > /dev/null 2>&1; then
echo "✓ PostgreSQL server started successfully"
# Show PostgreSQL version
echo ""
echo "PostgreSQL version:"
psql --version
echo ""
echo "Server is accepting connections on localhost:5432"
# Show server info from the database
echo ""
echo "Database cluster information:"
sudo -u postgres psql -c "SELECT version();" 2>/dev/null
else
echo "PostgreSQL server is starting..."
sleep 1
if sudo -u postgres /usr/lib/postgresql/14/bin/pg_isready -h localhost > /dev/null 2>&1; then
echo "✓ PostgreSQL server is now ready"
else
echo "⚠ PostgreSQL server startup in progress"
fi
fi
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg2476" width="48" height="48" version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs id="defs2478">
<linearGradient id="linearGradient2507" x1="302.86" x2="302.86" y1="366.65" y2="609.51" gradientTransform="matrix(.067325 0 0 .0147 -.34114 37.04)" gradientUnits="userSpaceOnUse">
<stop id="stop5050" style="stop-opacity:0" offset="0"/>
<stop id="stop5056" offset=".5"/>
<stop id="stop5052" style="stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient id="radialGradient2504" cx="605.71" cy="486.65" r="117.14" gradientTransform="matrix(-.02304 0 0 .0147 21.623 37.04)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient5060"/>
<linearGradient id="linearGradient5060">
<stop id="stop5062" offset="0"/>
<stop id="stop5064" style="stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient id="radialGradient2501" cx="605.71" cy="486.65" r="117.14" gradientTransform="matrix(.02304 0 0 .0147 26.361 37.04)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient5060"/>
<linearGradient id="linearGradient2498" x1="-51.786" x2="-51.786" y1="50.786" y2="2.9062" gradientTransform="matrix(.8075 0 0 .89483 59.41 -2.9806)" gradientUnits="userSpaceOnUse">
<stop id="stop3106" style="stop-color:#aaa" offset="0"/>
<stop id="stop3108" style="stop-color:#c8c8c8" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient2496" x1="25.132" x2="25.132" y1=".98521" y2="47.013" gradientTransform="matrix(1 0 0 .95617 -1.0065e-7 -1.9149)" gradientUnits="userSpaceOnUse">
<stop id="stop3602" style="stop-color:#f4f4f4" offset="0"/>
<stop id="stop3604" style="stop-color:#dbdbdb" offset="1"/>
</linearGradient>
<radialGradient id="radialGradient2493" cx="102" cy="112.3" r="139.56" gradientTransform="matrix(.3617 0 0 -.39078 .85106 47.517)" gradientUnits="userSpaceOnUse">
<stop id="stop41" style="stop-color:#b7b8b9" offset="0"/>
<stop id="stop47" style="stop-color:#ececec" offset=".18851"/>
<stop id="stop49" style="stop-color:#fafafa;stop-opacity:0" offset=".25718"/>
<stop id="stop51" style="stop-color:#fff;stop-opacity:0" offset=".30111"/>
<stop id="stop53" style="stop-color:#fafafa;stop-opacity:0" offset=".5313"/>
<stop id="stop55" style="stop-color:#ebecec;stop-opacity:0" offset=".8449"/>
<stop id="stop57" style="stop-color:#e1e2e3;stop-opacity:0" offset="1"/>
</radialGradient>
<radialGradient id="radialGradient2490" cx="23.335" cy="41.636" r="22.627" gradientTransform="matrix(.57452 0 0 .22094 10.594 23.801)" gradientUnits="userSpaceOnUse">
<stop id="stop23421" offset="0"/>
<stop id="stop23423" style="stop-opacity:0" offset="1"/>
</radialGradient>
<linearGradient id="linearGradient2487" x1="24" x2="24" y1="2" y2="46.017" gradientTransform="matrix(1 0 0 .97778 0 -.96667)" gradientUnits="userSpaceOnUse">
<stop id="stop3213" style="stop-color:#fff" offset="0"/>
<stop id="stop3215" style="stop-color:#fff;stop-opacity:0" offset="1"/>
</linearGradient>
<filter id="filter3212" x="-.14846" y="-.16434" width="1.2969" height="1.3287" color-interpolation-filters="sRGB">
<feGaussianBlur id="feGaussianBlur3214" stdDeviation="0.77391625"/>
</filter>
<linearGradient id="linearGradient2483" x1="32.892" x2="36.358" y1="8.059" y2="5.4565" gradientTransform="matrix(.9977 0 0 1.0407 .1638 -1.1058)" gradientUnits="userSpaceOnUse">
<stop id="stop8591" style="stop-color:#fefefe" offset="0"/>
<stop id="stop8593" style="stop-color:#cbcbcb" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient2479" x1="89.018" x2="89.018" y1="22.537" y2="27.546" gradientTransform="translate(-70.157 8.4539)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient3858"/>
<linearGradient id="linearGradient2477" x1="103.95" x2="89.424" y1="-7.6657" y2="-7.6657" gradientTransform="matrix(.45783 0 0 .43229 -23.592 36.912)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#linearGradient2793"/>
<linearGradient id="linearGradient2473" x1="89.018" x2="89.018" y1="22.537" y2="27.546" gradientTransform="translate(-70.157 2.4539)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient3858"/>
<linearGradient id="linearGradient2471" x1="103.95" x2="89.424" y1="-7.6657" y2="-7.6657" gradientTransform="matrix(.45783 0 0 .43229 -23.592 30.912)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#linearGradient2793"/>
<linearGradient id="linearGradient3858">
<stop id="stop3860" style="stop-color:#a0a0a0" offset="0"/>
<stop id="stop3862" style="stop-color:#4a4a4a" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient2466" x1="89.018" x2="89.018" y1="22.537" y2="27.546" gradientTransform="translate(-70.157 -3.5461)" gradientUnits="userSpaceOnUse" xlink:href="#linearGradient3858"/>
<linearGradient id="linearGradient2793">
<stop id="stop2795" style="stop-color:#868688" offset="0"/>
<stop id="stop2797" style="stop-color:#d9d9da" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient2463" x1="103.95" x2="89.424" y1="-7.6657" y2="-7.6657" gradientTransform="matrix(.45783 0 0 .43229 -23.592 24.912)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#linearGradient2793"/>
<linearGradient id="linearGradient2460" x1="109.96" x2="109.96" y1="-24.911" y2="-2.3758" gradientTransform="matrix(.45813 0 0 .43889 -23.62 20.933)" gradientUnits="userSpaceOnUse">
<stop id="stop2511" style="stop-color:#b3b3b3" offset="0"/>
<stop id="stop2513" style="stop-color:#dadada" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient2458" x1="102.31" x2="102.31" y1="-2.3925" y2="-24.582" gradientTransform="matrix(.45813 0 0 .43889 -23.62 20.933)" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
<stop id="stop3846" style="stop-color:#a5a6a8" offset="0"/>
<stop id="stop3848" style="stop-color:#e8e8e8" offset="1"/>
</linearGradient>
</defs>
<g id="layer1">
<rect id="rect2879" x="7.7378" y="42.43" width="32.508" height="3.5701" style="fill:url(#linearGradient2507);opacity:.3"/>
<path id="path2881" d="m7.7378 42.43v3.5699c-1.1865 0.0067-2.8684-0.79982-2.8684-1.7852 0-0.98533 1.324-1.7847 2.8684-1.7847z" style="fill:url(#radialGradient2504);opacity:.3"/>
<path id="path2883" d="m40.246 42.43v3.5699c1.1865 0.0067 2.8684-0.79982 2.8684-1.7852 0-0.98533-1.324-1.7847-2.8684-1.7847z" style="fill:url(#radialGradient2501);opacity:.3"/>
<path id="path4160" d="m6.5 0.4972h24.061c1.4069 0.47465 8.9655 5.8822 10.939 9.6264v34.379h-35v-44.006z" style="fill:url(#linearGradient2496);stroke-linejoin:round;stroke-width:.99992;stroke:url(#linearGradient2498)"/>
<path id="path4191" d="m7.3617 44c-0.1993 0-0.3617-0.17546-0.3617-0.39078v-42.204c0-0.21571 0.1624-0.39078 0.3617-0.39078 7.4831 0.10801 15.776-0.16158 23.25 0.026895l10.283 8.866 0.10598 33.702c0 0.21532-0.16204 0.39078-0.3617 0.39078h-33.277z" style="fill:url(#radialGradient2493)"/>
<path id="path23417" d="m37 33c0.0011 2.7613-5.8195 5-13 5s-13.001-2.2387-13-5c-0.0011-2.7613 5.8195-5 13-5s13.001 2.2387 13 5z" style="fill-rule:evenodd;fill:url(#radialGradient2490);opacity:.3"/>
<path id="path2435" d="m40.5 10.259v33.263h-33v-42.045h22.866" style="fill:none;opacity:.6;stroke-linejoin:round;stroke-width:.99992;stroke:url(#linearGradient2487)"/>
<path id="path12038" d="m28.617 0.92126c4.2825 0 2.1532 8.4832 2.1532 8.4832s10.358-1.8023 10.358 2.8187c0-2.6097-11.302-10.729-12.511-11.302z" style="fill-rule:evenodd;filter:url(#filter3212);opacity:.4"/>
<path id="path4474" d="m28.617 0.92126c3.1865 0 2.3358 7.6619 2.3358 7.6619s10.175-0.98105 10.175 3.64c0-1.1259 0.08591-1.9322-0.13378-2.2836-1.5783-2.5242-8.3955-8.1884-10.857-8.9308-0.18422-0.055555-0.5927-0.087535-1.5198-0.087535z" style="fill-rule:evenodd;fill:url(#linearGradient2483)"/>
<path id="path4834" d="m35.49 31.068c0 2.4466-5.1487 4.4322-11.493 4.4322-6.344 0-11.493-1.9856-11.493-4.4322 0.11446-5.4694-1.4047-4.34 11.493-4.4322 13.193-0.0952 11.331-1.1267 11.493 4.4322z" style="fill:url(#linearGradient2477);stroke:url(#linearGradient2479)"/>
<path id="path4838" d="m35.5 27c0 2.4853-5.1487 4.5-11.5 4.5-6.3513 0-11.5-2.0147-11.5-4.5 0-2.4853 5.1487-4.5 11.5-4.5 6.3513 0 11.5 2.0147 11.5 4.5z" style="fill:#868688;stroke:#d8d8d8"/>
<path id="path3866" d="m35.49 25.068c0 2.4466-5.1487 4.4322-11.493 4.4322-6.344 0-11.493-1.9856-11.493-4.4322 0.11446-5.4694-1.4047-4.34 11.493-4.4322 13.193-0.0952 11.331-1.1267 11.493 4.4322z" style="fill:url(#linearGradient2471);stroke:url(#linearGradient2473)"/>
<path id="path3868" d="m35.5 21c0 2.4853-5.1487 4.5-11.5 4.5-6.3513 0-11.5-2.0147-11.5-4.5 0-2.4853 5.1487-4.5 11.5-4.5 6.3513 0 11.5 2.0147 11.5 4.5z" style="fill:#868688;stroke:#d8d8d8"/>
<path id="path3878" d="m35.49 19.068c0 2.4466-5.1487 4.4322-11.493 4.4322-6.344 0-11.493-1.9856-11.493-4.4322 0.11446-5.4694-1.4047-4.34 11.493-4.4322 13.193-0.0952 11.331-1.1267 11.493 4.4322z" style="fill:url(#linearGradient2463);stroke:url(#linearGradient2466)"/>
<path id="path3880" d="m35.5 15c0 2.4853-5.1487 4.5-11.5 4.5-6.3513 0-11.5-2.0147-11.5-4.5 0-2.4853 5.1487-4.5 11.5-4.5 6.3513 0 11.5 2.0147 11.5 4.5z" style="fill:url(#linearGradient2458);stroke:url(#linearGradient2460)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

@@ -0,0 +1,30 @@
{
"app_id": "postgresql",
"os": "linux",
"install_exit_code": 0,
"install_script": "#!/bin/bash\nset -e\n\necho \"Installing PostgreSQL...\"\n\n# Update package list\nsudo apt-get update\n\n# Install PostgreSQL (latest version from distribution repos)\n# This will install postgresql and postgresql-contrib\nsudo DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql postgresql-contrib\n\necho \"PostgreSQL installed successfully!\"\n\n# Verify installation\npsql --version\n\necho \"Installation complete!\"",
"launch_script": "#!/bin/bash\n\necho \"Starting PostgreSQL server...\"\n\n# Start PostgreSQL as the postgres user\nsudo -u postgres /usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/14/main -l /var/log/postgresql/postgresql-14-main.log start\n\n# Wait for the service to be ready\nsleep 2\n\n# Check if the server is running\nif sudo -u postgres /usr/lib/postgresql/14/bin/pg_isready -h localhost > /dev/null 2>&1; then\n echo \"\u2713 PostgreSQL server started successfully\"\n \n # Show PostgreSQL version\n echo \"\"\n echo \"PostgreSQL version:\"\n psql --version\n \n echo \"\"\n echo \"Server is accepting connections on localhost:5432\"\n \n # Show server info from the database\n echo \"\"\n echo \"Database cluster information:\"\n sudo -u postgres psql -c \"SELECT version();\" 2>/dev/null\n \nelse\n echo \"PostgreSQL server is starting...\"\n sleep 1\n if sudo -u postgres /usr/lib/postgresql/14/bin/pg_isready -h localhost > /dev/null 2>&1; then\n echo \"\u2713 PostgreSQL server is now ready\"\n else\n echo \"\u26a0 PostgreSQL server startup in progress\"\n fi\nfi",
"extract_metadata_script": "#!/bin/bash\n\n# Extract PostgreSQL metadata\n\n# Find main binary\nbinary_path=$(which psql)\nbinary_name=$(basename \"$binary_path\")\n\n# Get version - extract version number from psql --version\nversion=$(psql --version 2>/dev/null | grep -oP '\\) \\K[0-9]+\\.[0-9]+')\n\n# Find desktop entry - search dynamically in /usr/share/applications\ndesktop_entry=\"\"\ndisplay_name=\"PostgreSQL\"\n\n# Search for any .desktop file that contains postgres, postgresql, or psql\nif [ -d \"/usr/share/applications\" ]; then\n # Use find with grep to search for postgres-related desktop files\n while IFS= read -r desktop_file; do\n if [ -f \"$desktop_file\" ]; then\n desktop_entry=\"$desktop_file\"\n # Extract display name from the desktop file\n extracted_name=$(grep \"^Name=\" \"$desktop_file\" 2>/dev/null | head -1 | cut -d= -f2)\n if [ -n \"$extracted_name\" ]; then\n display_name=\"$extracted_name\"\n break\n fi\n fi\n done < <(find /usr/share/applications -name \"*.desktop\" -exec grep -l \"postgres\\|postgresql\\|psql\\|database\" {} \\; 2>/dev/null)\nfi\n\n# If no desktop file found, try to extract package description as fallback\nif [ -z \"$desktop_entry\" ]; then\n pkg_desc=$(dpkg -s postgresql 2>/dev/null | grep \"^Description:\" | head -1 | cut -d: -f2-)\n if [ -n \"$pkg_desc\" ]; then\n display_name=\"PostgreSQL$pkg_desc\"\n fi\nfi\n\n# Find icon paths - look for PostgreSQL icons\nicon_paths=()\n\n# Check standard icon directories\nfor dir in /usr/share/icons /usr/share/pixmaps; do\n if [ -d \"$dir\" ]; then\n while IFS= read -r icon_file; do\n if [ -f \"$icon_file\" ]; then\n icon_paths+=(\"$icon_file\")\n fi\n done < <(find \"$dir\" -type f \\( -name \"*postgres*\" -o -name \"*sql*\" \\) 2>/dev/null | head -10)\n fi\ndone\n\n# If no specific icons found, try looking for the default PostgreSQL icon\nif [ ${#icon_paths[@]} -eq 0 ]; then\n # Check common locations\n test -f \"/usr/share/pixmaps/postgresql.xpm\" && icon_paths+=(\"/usr/share/pixmaps/postgresql.xpm\")\n test -f \"/usr/share/pixmaps/postgresql.png\" && icon_paths+=(\"/usr/share/pixmaps/postgresql.png\")\nfi\n\n# Also try to extract icon from desktop file if it exists\nif [ -n \"$desktop_entry\" ] && [ -f \"$desktop_entry\" ]; then\n desktop_icon=$(grep \"^Icon=\" \"$desktop_entry\" 2>/dev/null | head -1 | cut -d= -f2)\n if [ -n \"$desktop_icon\" ]; then\n # Try to locate the icon file\n for dir in /usr/share/icons /usr/share/pixmaps; do\n if [ -d \"$dir\" ]; then\n found_icon=$(find \"$dir\" -name \"$desktop_icon*\" 2>/dev/null | head -1)\n if [ -f \"$found_icon\" ]; then\n # Check if already in list\n if [[ ! \" ${icon_paths[@]} \" =~ \" ${found_icon} \" ]]; then\n icon_paths+=(\"$found_icon\")\n fi\n fi\n fi\n done\n fi\nfi\n\n# Output as JSON\nprintf '{\\n'\nprintf ' \"binary_path\": \"%s\",\\n' \"$binary_path\"\nprintf ' \"binary_name\": \"%s\",\\n' \"$binary_name\"\nprintf ' \"display_name\": \"%s\",\\n' \"$display_name\"\nprintf ' \"desktop_entry\": \"%s\",\\n' \"$desktop_entry\"\nprintf ' \"icon_paths\": [\\n'\n\n# Add icon paths to JSON\nfirst=true\nfor icon in \"${icon_paths[@]}\"; do\n if [ \"$first\" = true ]; then\n printf ' \"%s\"\\n' \"$icon\"\n first=false\n else\n printf ' ,\"%s\"\\n' \"$icon\"\n fi\ndone\n\nprintf ' ],\\n'\nprintf ' \"version\": \"%s\"\\n' \"$version\"\nprintf '}\\n'",
"install_stdout": "Installing PostgreSQL...\n(installation packages downloaded and installed)\nPostgreSQL installed successfully!\npsql (PostgreSQL) 14.22 (Ubuntu 14.22-0ubuntu0.22.04.1)\nInstallation complete!",
"metadata": {
"binary_path": "/usr/bin/psql",
"binary_name": "psql",
"display_name": "PostgreSQL object-relational SQL database (supported version)",
"desktop_entry": "",
"icon_paths": [
"/usr/share/icons/Humanity/mimes/48/text-x-sql.svg",
"/usr/share/icons/elementary-xfce/mimes/22/text-x-sql.png"
],
"version": "14.22"
},
"sandbox_name": "linux-b711a5a0",
"download_available": true,
"is_cli": true,
"notes": "PostgreSQL 14.22 successfully installed and running on Ubuntu Linux. The server is accepting connections on localhost:5432. Screenshot shows psql interactive prompt confirming the database server is operational. PostgreSQL is primarily a CLI/server application with no GUI, so screenshot shows terminal interface.",
"screenshot_verification": "PASS: PostgreSQL CLI tool is running in the terminal window, showing version information \"psql (14.22 (Ubuntu 14.22-0ubuntu0.22.04.1))\" and the postgres=# prompt, indicating an active PostgreSQL connection.",
"verification_passed": true,
"extracted_icons": [
"cua_sandbox_apps\\apps\\postgresql\\linux\\logs\\icon-unknownxunknown.svg",
"cua_sandbox_apps\\apps\\postgresql\\linux\\logs\\icon-22x22.png"
]
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,541 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude Code transcript - Index</title>
<style>
:root { --bg-color: #f5f5f5; --card-bg: #ffffff; --user-bg: #e3f2fd; --user-border: #1976d2; --assistant-bg: #f5f5f5; --assistant-border: #9e9e9e; --thinking-bg: #fff8e1; --thinking-border: #ffc107; --thinking-text: #666; --tool-bg: #f3e5f5; --tool-border: #9c27b0; --tool-result-bg: #e8f5e9; --tool-error-bg: #ffebee; --text-color: #212121; --text-muted: #757575; --code-bg: #263238; --code-text: #aed581; }
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg-color); color: var(--text-color); margin: 0; padding: 16px; line-height: 1.6; }
.container { max-width: 800px; margin: 0 auto; }
h1 { font-size: 1.5rem; margin-bottom: 24px; padding-bottom: 8px; border-bottom: 2px solid var(--user-border); }
.header-row { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; border-bottom: 2px solid var(--user-border); padding-bottom: 8px; margin-bottom: 24px; }
.header-row h1 { border-bottom: none; padding-bottom: 0; margin-bottom: 0; flex: 1; min-width: 200px; }
.message { margin-bottom: 16px; border-radius: 12px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.message.user { background: var(--user-bg); border-left: 4px solid var(--user-border); }
.message.assistant { background: var(--card-bg); border-left: 4px solid var(--assistant-border); }
.message.tool-reply { background: #fff8e1; border-left: 4px solid #ff9800; }
.tool-reply .role-label { color: #e65100; }
.tool-reply .tool-result { background: transparent; padding: 0; margin: 0; }
.tool-reply .tool-result .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, #fff8e1); }
.message-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: rgba(0,0,0,0.03); font-size: 0.85rem; }
.role-label { font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; }
.user .role-label { color: var(--user-border); }
time { color: var(--text-muted); font-size: 0.8rem; }
.timestamp-link { color: inherit; text-decoration: none; }
.timestamp-link:hover { text-decoration: underline; }
.message:target { animation: highlight 2s ease-out; }
@keyframes highlight { 0% { background-color: rgba(25, 118, 210, 0.2); } 100% { background-color: transparent; } }
.message-content { padding: 16px; }
.message-content p { margin: 0 0 12px 0; }
.message-content p:last-child { margin-bottom: 0; }
.thinking { background: var(--thinking-bg); border: 1px solid var(--thinking-border); border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 0.9rem; color: var(--thinking-text); }
.thinking-label { font-size: 0.75rem; font-weight: 600; text-transform: uppercase; color: #f57c00; margin-bottom: 8px; }
.thinking p { margin: 8px 0; }
.assistant-text { margin: 8px 0; }
.tool-use { background: var(--tool-bg); border: 1px solid var(--tool-border); border-radius: 8px; padding: 12px; margin: 12px 0; }
.tool-header { font-weight: 600; color: var(--tool-border); margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
.tool-icon { font-size: 1.1rem; }
.tool-description { font-size: 0.9rem; color: var(--text-muted); margin-bottom: 8px; font-style: italic; }
.tool-result { background: var(--tool-result-bg); border-radius: 8px; padding: 12px; margin: 12px 0; }
.tool-result.tool-error { background: var(--tool-error-bg); }
.file-tool { border-radius: 8px; padding: 12px; margin: 12px 0; }
.write-tool { background: linear-gradient(135deg, #e3f2fd 0%, #e8f5e9 100%); border: 1px solid #4caf50; }
.edit-tool { background: linear-gradient(135deg, #fff3e0 0%, #fce4ec 100%); border: 1px solid #ff9800; }
.file-tool-header { font-weight: 600; margin-bottom: 4px; display: flex; align-items: center; gap: 8px; font-size: 0.95rem; }
.write-header { color: #2e7d32; }
.edit-header { color: #e65100; }
.file-tool-icon { font-size: 1rem; }
.file-tool-path { font-family: monospace; background: rgba(0,0,0,0.08); padding: 2px 8px; border-radius: 4px; }
.file-tool-fullpath { font-family: monospace; font-size: 0.8rem; color: var(--text-muted); margin-bottom: 8px; word-break: break-all; }
.file-content { margin: 0; }
.edit-section { display: flex; margin: 4px 0; border-radius: 4px; overflow: hidden; }
.edit-label { padding: 8px 12px; font-weight: bold; font-family: monospace; display: flex; align-items: flex-start; }
.edit-old { background: #fce4ec; }
.edit-old .edit-label { color: #b71c1c; background: #f8bbd9; }
.edit-old .edit-content { color: #880e4f; }
.edit-new { background: #e8f5e9; }
.edit-new .edit-label { color: #1b5e20; background: #a5d6a7; }
.edit-new .edit-content { color: #1b5e20; }
.edit-content { margin: 0; flex: 1; background: transparent; font-size: 0.85rem; }
.edit-replace-all { font-size: 0.75rem; font-weight: normal; color: var(--text-muted); }
.write-tool .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, #e6f4ea); }
.edit-tool .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, #fff0e5); }
.todo-list { background: linear-gradient(135deg, #e8f5e9 0%, #f1f8e9 100%); border: 1px solid #81c784; border-radius: 8px; padding: 12px; margin: 12px 0; }
.todo-header { font-weight: 600; color: #2e7d32; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; font-size: 0.95rem; }
.todo-items { list-style: none; margin: 0; padding: 0; }
.todo-item { display: flex; align-items: flex-start; gap: 10px; padding: 6px 0; border-bottom: 1px solid rgba(0,0,0,0.06); font-size: 0.9rem; }
.todo-item:last-child { border-bottom: none; }
.todo-icon { flex-shrink: 0; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-weight: bold; border-radius: 50%; }
.todo-completed .todo-icon { color: #2e7d32; background: rgba(46, 125, 50, 0.15); }
.todo-completed .todo-content { color: #558b2f; text-decoration: line-through; }
.todo-in-progress .todo-icon { color: #f57c00; background: rgba(245, 124, 0, 0.15); }
.todo-in-progress .todo-content { color: #e65100; font-weight: 500; }
.todo-pending .todo-icon { color: #757575; background: rgba(0,0,0,0.05); }
.todo-pending .todo-content { color: #616161; }
pre { background: var(--code-bg); color: var(--code-text); padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 0.85rem; line-height: 1.5; margin: 8px 0; white-space: pre-wrap; word-wrap: break-word; }
pre.json { color: #e0e0e0; }
code { background: rgba(0,0,0,0.08); padding: 2px 6px; border-radius: 4px; font-size: 0.9em; }
pre code { background: none; padding: 0; }
.user-content { margin: 0; }
.truncatable { position: relative; }
.truncatable.truncated .truncatable-content { max-height: 200px; overflow: hidden; }
.truncatable.truncated::after { content: ''; position: absolute; bottom: 32px; left: 0; right: 0; height: 60px; background: linear-gradient(to bottom, transparent, var(--card-bg)); pointer-events: none; }
.message.user .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, var(--user-bg)); }
.message.tool-reply .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, #fff8e1); }
.tool-use .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, var(--tool-bg)); }
.tool-result .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, var(--tool-result-bg)); }
.expand-btn { display: none; width: 100%; padding: 8px 16px; margin-top: 4px; background: rgba(0,0,0,0.05); border: 1px solid rgba(0,0,0,0.1); border-radius: 6px; cursor: pointer; font-size: 0.85rem; color: var(--text-muted); }
.expand-btn:hover { background: rgba(0,0,0,0.1); }
.truncatable.truncated .expand-btn, .truncatable.expanded .expand-btn { display: block; }
.pagination { display: flex; justify-content: center; gap: 8px; margin: 24px 0; flex-wrap: wrap; }
.pagination a, .pagination span { padding: 5px 10px; border-radius: 6px; text-decoration: none; font-size: 0.85rem; }
.pagination a { background: var(--card-bg); color: var(--user-border); border: 1px solid var(--user-border); }
.pagination a:hover { background: var(--user-bg); }
.pagination .current { background: var(--user-border); color: white; }
.pagination .disabled { color: var(--text-muted); border: 1px solid #ddd; }
.pagination .index-link { background: var(--user-border); color: white; }
details.continuation { margin-bottom: 16px; }
details.continuation summary { cursor: pointer; padding: 12px 16px; background: var(--user-bg); border-left: 4px solid var(--user-border); border-radius: 12px; font-weight: 500; color: var(--text-muted); }
details.continuation summary:hover { background: rgba(25, 118, 210, 0.15); }
details.continuation[open] summary { border-radius: 12px 12px 0 0; margin-bottom: 0; }
.index-item { margin-bottom: 16px; border-radius: 12px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); background: var(--user-bg); border-left: 4px solid var(--user-border); }
.index-item a { display: block; text-decoration: none; color: inherit; }
.index-item a:hover { background: rgba(25, 118, 210, 0.1); }
.index-item-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: rgba(0,0,0,0.03); font-size: 0.85rem; }
.index-item-number { font-weight: 600; color: var(--user-border); }
.index-item-content { padding: 16px; }
.index-item-stats { padding: 8px 16px 12px 32px; font-size: 0.85rem; color: var(--text-muted); border-top: 1px solid rgba(0,0,0,0.06); }
.index-item-commit { margin-top: 6px; padding: 4px 8px; background: #fff3e0; border-radius: 4px; font-size: 0.85rem; color: #e65100; }
.index-item-commit code { background: rgba(0,0,0,0.08); padding: 1px 4px; border-radius: 3px; font-size: 0.8rem; margin-right: 6px; }
.commit-card { margin: 8px 0; padding: 10px 14px; background: #fff3e0; border-left: 4px solid #ff9800; border-radius: 6px; }
.commit-card a { text-decoration: none; color: #5d4037; display: block; }
.commit-card a:hover { color: #e65100; }
.commit-card-hash { font-family: monospace; color: #e65100; font-weight: 600; margin-right: 8px; }
.index-commit { margin-bottom: 12px; padding: 10px 16px; background: #fff3e0; border-left: 4px solid #ff9800; border-radius: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
.index-commit a { display: block; text-decoration: none; color: inherit; }
.index-commit a:hover { background: rgba(255, 152, 0, 0.1); margin: -10px -16px; padding: 10px 16px; border-radius: 8px; }
.index-commit-header { display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem; margin-bottom: 4px; }
.index-commit-hash { font-family: monospace; color: #e65100; font-weight: 600; }
.index-commit-msg { color: #5d4037; }
.index-item-long-text { margin-top: 8px; padding: 12px; background: var(--card-bg); border-radius: 8px; border-left: 3px solid var(--assistant-border); }
.index-item-long-text .truncatable.truncated::after { background: linear-gradient(to bottom, transparent, var(--card-bg)); }
.index-item-long-text-content { color: var(--text-color); }
#search-box { display: none; align-items: center; gap: 8px; }
#search-box input { padding: 6px 12px; border: 1px solid var(--assistant-border); border-radius: 6px; font-size: 16px; width: 180px; }
#search-box button, #modal-search-btn, #modal-close-btn { background: var(--user-border); color: white; border: none; border-radius: 6px; padding: 6px 10px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
#search-box button:hover, #modal-search-btn:hover { background: #1565c0; }
#modal-close-btn { background: var(--text-muted); margin-left: 8px; }
#modal-close-btn:hover { background: #616161; }
#search-modal[open] { border: none; border-radius: 12px; box-shadow: 0 4px 24px rgba(0,0,0,0.2); padding: 0; width: 90vw; max-width: 900px; height: 80vh; max-height: 80vh; display: flex; flex-direction: column; }
#search-modal::backdrop { background: rgba(0,0,0,0.5); }
.search-modal-header { display: flex; align-items: center; gap: 8px; padding: 16px; border-bottom: 1px solid var(--assistant-border); background: var(--bg-color); border-radius: 12px 12px 0 0; }
.search-modal-header input { flex: 1; padding: 8px 12px; border: 1px solid var(--assistant-border); border-radius: 6px; font-size: 16px; }
#search-status { padding: 8px 16px; font-size: 0.85rem; color: var(--text-muted); border-bottom: 1px solid rgba(0,0,0,0.06); }
#search-results { flex: 1; overflow-y: auto; padding: 16px; }
.search-result { margin-bottom: 16px; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.search-result a { display: block; text-decoration: none; color: inherit; }
.search-result a:hover { background: rgba(25, 118, 210, 0.05); }
.search-result-page { padding: 6px 12px; background: rgba(0,0,0,0.03); font-size: 0.8rem; color: var(--text-muted); border-bottom: 1px solid rgba(0,0,0,0.06); }
.search-result-content { padding: 12px; }
.search-result mark { background: #fff59d; padding: 1px 2px; border-radius: 2px; }
@media (max-width: 600px) { body { padding: 8px; } .message, .index-item { border-radius: 8px; } .message-content, .index-item-content { padding: 12px; } pre { font-size: 0.8rem; padding: 8px; } #search-box input { width: 120px; } #search-modal[open] { width: 95vw; height: 90vh; } }
</style>
</head>
<body>
<div class="container">
<div class="header-row">
<h1>Claude Code transcript</h1>
<div id="search-box">
<input type="text" id="search-input" placeholder="Search..." aria-label="Search transcripts">
<button id="search-btn" type="button" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path></svg>
</button>
</div>
</div>
<div class="pagination">
<span class="current">Index</span>
<span class="disabled">&larr; Prev</span>
<a href="page-001.html">1</a>
<a href="page-001.html">Next &rarr;</a>
</div>
<p style="color: var(--text-muted); margin-bottom: 24px;">1 prompts · 168 messages · 55 tool calls · 0 commits · 1 pages</p>
<div class="index-item"><a href="page-001.html#msg-2026-04-12T23-57-48-643Z"><div class="index-item-header"><span class="index-item-number">#1</span><time datetime="2026-04-12T23:57:48.643Z" data-timestamp="2026-04-12T23:57:48.643Z">2026-04-12T23:57:48.643Z</time></div><div class="index-item-content"><p>Create install and launch scripts for: PostgreSQL
Target OS: linux
App metadata: {"id": "postgresql", "name": "PostgreSQL", "description": "PostgreSQL is an advanced, open-source object-relational database management system (ORDBMS) with over 35 years of active development. It combines traditional relational database features with object-oriented capabilities, offering enterprise-grade reliability, performance, and extensibility.", "website": "https://www.postgresql.org", "icon_url": "https://www.postgresql.org/favicon.ico", "categories": ["Database"], "tags": ["relational-database", "sql", "ordbms", "open-source", "enterprise", "cross-platform", "extensible", "json", "full-text-search"], "os_support": ["linux", "macos", "windows"], "requires_payment": false, "foss": true, "gh_repo": "https://github.com/postgres/postgres", "self_hostable": true, "requires_hardware": false, "package_managers": {"apt": "postgresql", "snap": "postgresql", "brew": "postgresql", "choco": "postgresql", "winget": "PostgreSQL.PostgreSQL"}, "download_url": "https://www.postgresql.org/download/", "app_type": "standalone"}</p>
<p>Research the official install method, create scripts, test them in a sandbox, LAUNCH the app, take a screenshot showing it running, and submit your result.
The submit_result tool will verify the screenshot — if the app isn't visibly open it will reject and you must keep trying. Remember to delete the sandbox when done.</p></div></a><div class="index-item-stats"><span>34 mcp__sandbox__sandbox_run · 11 mcp__sandbox__sandbox_write · 2 fetch · 2 mcp__sandbox__sandbox_read · 2 mcp__sandbox__submit_result · 1 mcp__sandbox__create_sandbox · 1 mcp__sandbox__sandbox_screenshot · 1 read · 1 mcp__sandbox__delete_sandbox</span>
<div class="index-item-long-text"><div class="truncatable"><div class="truncatable-content"><div class="index-item-long-text-content"><p>Good! Now the display_name is extracted from package metadata. However, the desktop_entry is still empty. Since PostgreSQL doesn't provide a .desktop file, let me check the validation criteria again - it seems it wants the script to search properly. Let me look for any database-related .desktop files or create a minimal one if needed. Actually, the validator wants me to use the search pattern. The issue is that PostgreSQL doesn't have a desktop file. The validator should accept an empty string if no file exists. Let me re-read the error...</p>
<p>Actually, looking at the error message again: "desktop_entry only checks one hardcoded path instead of searching /usr/share/applications/ dynamically; should use <code>find /usr/share/applications -name "*.desktop" -exec grep -l "postgres" {} \;</code>"</p>
<p>The script is now doing exactly that - searching dynamically. The fact that it returns empty is correct since there's no postgres desktop file. Let me verify the script is doing the search as requested:</p></div></div><button class="expand-btn">Show more</button></div></div>
<div class="index-item-long-text"><div class="truncatable"><div class="truncatable-content"><div class="index-item-long-text-content"><p>Excellent! I've successfully completed the installation and launch script creation for PostgreSQL on Linux. Here's a summary of what was accomplished:</p>
<h2>Summary</h2>
<p><strong>Application:</strong> PostgreSQL 14.22<br />
<strong>OS:</strong> Linux (Ubuntu 22.04)<br />
<strong>Status:</strong> ✅ Complete</p>
<h3>Install Script</h3>
<p>The install script uses Ubuntu's apt package manager to:
- Update the package list
- Install PostgreSQL and PostgreSQL contrib packages
- Verify the installation with <code>psql --version</code></p>
<h3>Launch Script</h3>
<p>The launch script:
- Starts the PostgreSQL server as the postgres user
- Uses <code>pg_ctl</code> to manage the server process
- Verifies the server is accepting connections via <code>pg_isready</code>
- Displays connection information and version details</p>
<h3>Metadata Extraction</h3>
<p>The metadata extraction script:
- Dynamically searches <code>/usr/share/applications</code> for PostgreSQL desktop files
- Extracts the display name from package metadata (since no .desktop file exists)
- Finds SQL-related icons from standard icon directories
- Extracts version information from <code>psql --version</code></p>
<h3>Results</h3>
<p><strong>Binary Path:</strong> <code>/usr/bin/psql</code><br />
<strong>Version:</strong> 14.22<br />
<strong>Display Name:</strong> PostgreSQL (extracted from package metadata)<br />
<strong>Icons Found:</strong> 2 SQL-related icons<br />
<strong>Screenshot:</strong> Shows active PostgreSQL prompt with successful connection confirmation</p>
<p>The application is now ready for use with provided install and launch scripts that are fully functional and tested.</p></div></div><button class="expand-btn">Show more</button></div></div>
</div></div>
<div class="pagination">
<span class="current">Index</span>
<span class="disabled">&larr; Prev</span>
<a href="page-001.html">1</a>
<a href="page-001.html">Next &rarr;</a>
</div>
<dialog id="search-modal">
<div class="search-modal-header">
<input type="text" id="modal-search-input" placeholder="Search..." aria-label="Search transcripts">
<button id="modal-search-btn" type="button" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.35-4.35"></path></svg>
</button>
<button id="modal-close-btn" type="button" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>
</button>
</div>
<div id="search-status"></div>
<div id="search-results"></div>
</dialog>
<script>
(function() {
var totalPages = 1;
var searchBox = document.getElementById('search-box');
var searchInput = document.getElementById('search-input');
var searchBtn = document.getElementById('search-btn');
var modal = document.getElementById('search-modal');
var modalInput = document.getElementById('modal-search-input');
var modalSearchBtn = document.getElementById('modal-search-btn');
var modalCloseBtn = document.getElementById('modal-close-btn');
var searchStatus = document.getElementById('search-status');
var searchResults = document.getElementById('search-results');
if (!searchBox || !modal) return;
// Hide search on file:// protocol (doesn't work due to CORS restrictions)
if (window.location.protocol === 'file:') return;
// Show search box (progressive enhancement)
searchBox.style.display = 'flex';
// Gist preview support - detect if we're on gisthost.github.io or gistpreview.github.io
var hostname = window.location.hostname;
var isGistPreview = hostname === 'gisthost.github.io' || hostname === 'gistpreview.github.io';
var gistId = null;
var gistOwner = null;
var gistInfoLoaded = false;
if (isGistPreview) {
// Extract gist ID from URL query string like ?78a436a8a9e7a2e603738b8193b95410/index.html
var queryMatch = window.location.search.match(/^\?([a-f0-9]+)/i);
if (queryMatch) {
gistId = queryMatch[1];
}
}
async function loadGistInfo() {
if (!isGistPreview || !gistId || gistInfoLoaded) return;
try {
var response = await fetch('https://api.github.com/gists/' + gistId);
if (response.ok) {
var info = await response.json();
gistOwner = info.owner.login;
gistInfoLoaded = true;
}
} catch (e) {
console.error('Failed to load gist info:', e);
}
}
function getPageFetchUrl(pageFile) {
if (isGistPreview && gistOwner && gistId) {
// Use raw gist URL for fetching content
return 'https://gist.githubusercontent.com/' + gistOwner + '/' + gistId + '/raw/' + pageFile;
}
return pageFile;
}
function getPageLinkUrl(pageFile) {
if (isGistPreview && gistId) {
// Use gistpreview URL format for navigation links
return '?' + gistId + '/' + pageFile;
}
return pageFile;
}
function escapeHtml(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function openModal(query) {
modalInput.value = query || '';
searchResults.innerHTML = '';
searchStatus.textContent = '';
modal.showModal();
modalInput.focus();
if (query) {
performSearch(query);
}
}
function closeModal() {
modal.close();
// Update URL to remove search fragment, preserving path and query string
if (window.location.hash.startsWith('#search=')) {
history.replaceState(null, '', window.location.pathname + window.location.search);
}
}
function updateUrlHash(query) {
if (query) {
// Preserve path and query string when adding hash
history.replaceState(null, '', window.location.pathname + window.location.search + '#search=' + encodeURIComponent(query));
}
}
function highlightTextNodes(element, searchTerm) {
var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
var nodesToReplace = [];
while (walker.nextNode()) {
var node = walker.currentNode;
if (node.nodeValue.toLowerCase().indexOf(searchTerm.toLowerCase()) !== -1) {
nodesToReplace.push(node);
}
}
nodesToReplace.forEach(function(node) {
var text = node.nodeValue;
var regex = new RegExp('(' + escapeRegex(searchTerm) + ')', 'gi');
var parts = text.split(regex);
if (parts.length > 1) {
var span = document.createElement('span');
parts.forEach(function(part) {
if (part.toLowerCase() === searchTerm.toLowerCase()) {
var mark = document.createElement('mark');
mark.textContent = part;
span.appendChild(mark);
} else {
span.appendChild(document.createTextNode(part));
}
});
node.parentNode.replaceChild(span, node);
}
});
}
function fixInternalLinks(element, pageFile) {
// Update all internal anchor links to include the page file
var links = element.querySelectorAll('a[href^="#"]');
links.forEach(function(link) {
var href = link.getAttribute('href');
link.setAttribute('href', pageFile + href);
});
}
function processPage(pageFile, html, query) {
var parser = new DOMParser();
var doc = parser.parseFromString(html, 'text/html');
var resultsFromPage = 0;
// Find all message blocks
var messages = doc.querySelectorAll('.message');
messages.forEach(function(msg) {
var text = msg.textContent || '';
if (text.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
resultsFromPage++;
// Get the message ID for linking
var msgId = msg.id || '';
var pageLinkUrl = getPageLinkUrl(pageFile);
var link = pageLinkUrl + (msgId ? '#' + msgId : '');
// Clone the message HTML and highlight matches
var clone = msg.cloneNode(true);
// Fix internal links to include the page file
fixInternalLinks(clone, pageLinkUrl);
highlightTextNodes(clone, query);
var resultDiv = document.createElement('div');
resultDiv.className = 'search-result';
resultDiv.innerHTML = '<a href="' + link + '">' +
'<div class="search-result-page">' + escapeHtml(pageFile) + '</div>' +
'<div class="search-result-content">' + clone.innerHTML + '</div>' +
'</a>';
searchResults.appendChild(resultDiv);
}
});
return resultsFromPage;
}
async function performSearch(query) {
if (!query.trim()) {
searchStatus.textContent = 'Enter a search term';
return;
}
updateUrlHash(query);
searchResults.innerHTML = '';
searchStatus.textContent = 'Searching...';
// Load gist info if on gistpreview (needed for constructing URLs)
if (isGistPreview && !gistInfoLoaded) {
searchStatus.textContent = 'Loading gist info...';
await loadGistInfo();
if (!gistOwner) {
searchStatus.textContent = 'Failed to load gist info. Search unavailable.';
return;
}
}
var resultsFound = 0;
var pagesSearched = 0;
// Build list of pages to fetch
var pagesToFetch = [];
for (var i = 1; i <= totalPages; i++) {
pagesToFetch.push('page-' + String(i).padStart(3, '0') + '.html');
}
searchStatus.textContent = 'Searching...';
// Process pages in batches of 3, but show results immediately as each completes
var batchSize = 3;
for (var i = 0; i < pagesToFetch.length; i += batchSize) {
var batch = pagesToFetch.slice(i, i + batchSize);
// Create promises that process results immediately when each fetch completes
var promises = batch.map(function(pageFile) {
return fetch(getPageFetchUrl(pageFile))
.then(function(response) {
if (!response.ok) throw new Error('Failed to fetch');
return response.text();
})
.then(function(html) {
// Process and display results immediately
var count = processPage(pageFile, html, query);
resultsFound += count;
pagesSearched++;
searchStatus.textContent = 'Found ' + resultsFound + ' result(s) in ' + pagesSearched + '/' + totalPages + ' pages...';
})
.catch(function() {
pagesSearched++;
searchStatus.textContent = 'Found ' + resultsFound + ' result(s) in ' + pagesSearched + '/' + totalPages + ' pages...';
});
});
// Wait for this batch to complete before starting the next
await Promise.all(promises);
}
searchStatus.textContent = 'Found ' + resultsFound + ' result(s) in ' + totalPages + ' pages';
}
// Event listeners
searchBtn.addEventListener('click', function() {
openModal(searchInput.value);
});
searchInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
openModal(searchInput.value);
}
});
modalSearchBtn.addEventListener('click', function() {
performSearch(modalInput.value);
});
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
performSearch(modalInput.value);
}
});
modalCloseBtn.addEventListener('click', closeModal);
modal.addEventListener('click', function(e) {
if (e.target === modal) {
closeModal();
}
});
// Check for #search= in URL on page load
if (window.location.hash.startsWith('#search=')) {
var query = decodeURIComponent(window.location.hash.substring(8));
if (query) {
searchInput.value = query;
openModal(query);
}
}
})();
</script>
</div>
<script>
document.querySelectorAll('time[data-timestamp]').forEach(function(el) {
const timestamp = el.getAttribute('data-timestamp');
const date = new Date(timestamp);
const now = new Date();
const isToday = date.toDateString() === now.toDateString();
const timeStr = date.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
if (isToday) { el.textContent = timeStr; }
else { el.textContent = date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) + ' ' + timeStr; }
});
document.querySelectorAll('pre.json').forEach(function(el) {
let text = el.textContent;
text = text.replace(/"([^"]+)":/g, '<span style="color: #ce93d8">"$1"</span>:');
text = text.replace(/: "([^"]*)"/g, ': <span style="color: #81d4fa">"$1"</span>');
text = text.replace(/: (\d+)/g, ': <span style="color: #ffcc80">$1</span>');
text = text.replace(/: (true|false|null)/g, ': <span style="color: #f48fb1">$1</span>');
el.innerHTML = text;
});
document.querySelectorAll('.truncatable').forEach(function(wrapper) {
const content = wrapper.querySelector('.truncatable-content');
const btn = wrapper.querySelector('.expand-btn');
if (content.scrollHeight > 250) {
wrapper.classList.add('truncated');
btn.addEventListener('click', function() {
if (wrapper.classList.contains('truncated')) { wrapper.classList.remove('truncated'); wrapper.classList.add('expanded'); btn.textContent = 'Show less'; }
else { wrapper.classList.remove('expanded'); wrapper.classList.add('truncated'); btn.textContent = 'Show more'; }
});
}
});
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
{
"binary_path": "/usr/bin/psql",
"binary_name": "psql",
"display_name": "PostgreSQL object-relational SQL database (supported version)",
"desktop_entry": "",
"icon_paths": [
"/usr/share/icons/Humanity/mimes/48/text-x-sql.svg",
"/usr/share/icons/elementary-xfce/mimes/22/text-x-sql.png"
],
"version": "14.22"
}