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
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:
+104
@@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Extract metadata for Visual Studio Code
|
||||
# This script dynamically extracts and outputs JSON metadata from installed artifacts
|
||||
|
||||
# Find the code binary
|
||||
BINARY_PATH=$(which code)
|
||||
BINARY_NAME=$(basename "$BINARY_PATH")
|
||||
|
||||
# Get version using dpkg-query for reliability
|
||||
VERSION=$(dpkg-query -W -f='${Version}' code 2>/dev/null | cut -d- -f1 || echo "unknown")
|
||||
|
||||
# Find the main desktop file (prefer code.desktop over code-url-handler.desktop)
|
||||
DESKTOP_ENTRY=""
|
||||
if [ -f "/usr/share/applications/code.desktop" ]; then
|
||||
DESKTOP_ENTRY="/usr/share/applications/code.desktop"
|
||||
else
|
||||
# Search for any code desktop file, excluding url-handler
|
||||
for desktop_file in /usr/share/applications/code*.desktop; do
|
||||
if [ -f "$desktop_file" ] && [[ "$desktop_file" != *"url-handler"* ]]; then
|
||||
DESKTOP_ENTRY="$desktop_file"
|
||||
break
|
||||
fi
|
||||
done
|
||||
# If still not found, use the first one
|
||||
if [ -z "$DESKTOP_ENTRY" ]; then
|
||||
for desktop_file in /usr/share/applications/code*.desktop; do
|
||||
if [ -f "$desktop_file" ]; then
|
||||
DESKTOP_ENTRY="$desktop_file"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Extract display name from desktop file (primary source)
|
||||
DISPLAY_NAME=""
|
||||
if [ -f "$DESKTOP_ENTRY" ]; then
|
||||
# Extract Name field from desktop file
|
||||
DISPLAY_NAME=$(grep "^Name=" "$DESKTOP_ENTRY" | head -1 | cut -d= -f2-)
|
||||
# Trim whitespace
|
||||
DISPLAY_NAME=$(echo "$DISPLAY_NAME" | xargs)
|
||||
fi
|
||||
|
||||
# If display name is still empty, try to get from dpkg
|
||||
if [ -z "$DISPLAY_NAME" ]; then
|
||||
DISPLAY_NAME=$(dpkg-query -W -f='${Summary}' code 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
# Fallback to package description if still empty
|
||||
if [ -z "$DISPLAY_NAME" ]; then
|
||||
DISPLAY_NAME=$(apt-cache show code 2>/dev/null | grep -i "^Description:" | cut -d: -f2- | head -1 | xargs)
|
||||
fi
|
||||
|
||||
# Extract icon name from desktop file
|
||||
ICON_NAME=""
|
||||
if [ -f "$DESKTOP_ENTRY" ]; then
|
||||
ICON_NAME=$(grep "^Icon=" "$DESKTOP_ENTRY" | head -1 | cut -d= -f2)
|
||||
# Trim whitespace
|
||||
ICON_NAME=$(echo "$ICON_NAME" | xargs)
|
||||
fi
|
||||
|
||||
# Find actual icon files dynamically based on discovered icon name
|
||||
ICON_PATHS=()
|
||||
|
||||
# If we have an icon name, search for it in standard icon directories
|
||||
if [ -n "$ICON_NAME" ]; then
|
||||
while IFS= read -r icon_file; do
|
||||
if [ -f "$icon_file" ]; then
|
||||
ICON_PATHS+=("$icon_file")
|
||||
fi
|
||||
done < <(find /usr/share/icons /usr/share/pixmaps -name "${ICON_NAME}" -o -name "${ICON_NAME}.*" 2>/dev/null)
|
||||
fi
|
||||
|
||||
# Build JSON output
|
||||
build_json() {
|
||||
local binary_path="$1"
|
||||
local binary_name="$2"
|
||||
local display_name="$3"
|
||||
local desktop_entry="$4"
|
||||
local version="$5"
|
||||
shift 5
|
||||
local icon_paths=("$@")
|
||||
|
||||
# Build icon array JSON
|
||||
local icon_json="["
|
||||
local first=true
|
||||
for icon in "${icon_paths[@]}"; do
|
||||
if [ "$first" = true ]; then
|
||||
icon_json+="\"$icon\""
|
||||
first=false
|
||||
else
|
||||
icon_json+=",\"$icon\""
|
||||
fi
|
||||
done
|
||||
icon_json+="]"
|
||||
|
||||
# Output compact JSON
|
||||
cat <<EOF
|
||||
{"binary_path":"$binary_path","binary_name":"$binary_name","display_name":"$display_name","desktop_entry":"$desktop_entry","icon_paths":$icon_json,"version":"$version"}
|
||||
EOF
|
||||
}
|
||||
|
||||
build_json "$BINARY_PATH" "$BINARY_NAME" "$DISPLAY_NAME" "$DESKTOP_ENTRY" "$VERSION" "${ICON_PATHS[@]}"
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Install Visual Studio Code on Linux (Ubuntu/Debian)
|
||||
# This script is idempotent and handles existing installations
|
||||
|
||||
echo "Installing Visual Studio Code on Linux..."
|
||||
|
||||
# Update package lists
|
||||
sudo apt-get update -y
|
||||
|
||||
# Install curl (needed for downloading the key) if not present
|
||||
sudo apt-get install -y curl gpg
|
||||
|
||||
# Add Microsoft's GPG key (or update if it already exists)
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /usr/share/keyrings/microsoft.gpg > /dev/null
|
||||
|
||||
# Add or update the VS Code repository
|
||||
echo 'deb [arch=amd64,arm64,armhf signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/code stable main' | sudo tee /etc/apt/sources.list.d/vscode.list > /dev/null
|
||||
|
||||
# Update package lists again to include the repository
|
||||
sudo apt-get update -y
|
||||
|
||||
# Install VS Code (or update if already installed)
|
||||
sudo apt-get install -y code
|
||||
|
||||
echo "✅ Visual Studio Code installed successfully!"
|
||||
echo "Binary path: $(which code)"
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Launch Visual Studio Code
|
||||
# This script starts VS Code with a fresh window
|
||||
|
||||
echo "Launching Visual Studio Code..."
|
||||
|
||||
# Set environment variable to disable WSL detection prompt
|
||||
export DONT_PROMPT_WSL_INSTALL=1
|
||||
|
||||
# Launch VS Code in the background
|
||||
# Use /tmp as the initial workspace directory
|
||||
code /tmp &
|
||||
|
||||
# Give it time to start and initialize
|
||||
sleep 5
|
||||
|
||||
echo "✅ Visual Studio Code launched!"
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"app_id": "visual-studio-code",
|
||||
"os": "linux",
|
||||
"install_exit_code": 0,
|
||||
"install_script": "#!/bin/bash\nset -e\n\n# Install Visual Studio Code on Linux (Ubuntu/Debian)\n# This script is idempotent and handles existing installations\n\necho \"Installing Visual Studio Code on Linux...\"\n\n# Update package lists\nsudo apt-get update -y\n\n# Install curl (needed for downloading the key) if not present\nsudo apt-get install -y curl gpg\n\n# Add Microsoft's GPG key (or update if it already exists)\ncurl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /usr/share/keyrings/microsoft.gpg > /dev/null\n\n# Add or update the VS Code repository\necho 'deb [arch=amd64,arm64,armhf signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/code stable main' | sudo tee /etc/apt/sources.list.d/vscode.list > /dev/null\n\n# Update package lists again to include the repository\nsudo apt-get update -y\n\n# Install VS Code (or update if already installed)\nsudo apt-get install -y code\n\necho \"\u2705 Visual Studio Code installed successfully!\"\necho \"Binary path: $(which code)\"",
|
||||
"install_stdout": "Installing Visual Studio Code on Linux...\ncode is already the newest version (1.115.0-1775600353).\n\u2705 Visual Studio Code installed successfully!\nBinary path: /usr/bin/code",
|
||||
"launch_script": "#!/bin/bash\n\n# Launch Visual Studio Code\n# This script starts VS Code with a fresh window\n\necho \"Launching Visual Studio Code...\"\n\n# Set environment variable to disable WSL detection prompt\nexport DONT_PROMPT_WSL_INSTALL=1\n\n# Launch VS Code in the background\n# Use /tmp as the initial workspace directory\ncode /tmp &\n\n# Give it time to start and initialize\nsleep 5\n\necho \"\u2705 Visual Studio Code launched!\"",
|
||||
"extract_metadata_script": "#!/bin/bash\n\n# Extract metadata for Visual Studio Code\n# This script dynamically extracts and outputs JSON metadata from installed artifacts\n\n# Find the code binary\nBINARY_PATH=$(which code)\nBINARY_NAME=$(basename \"$BINARY_PATH\")\n\n# Get version using dpkg-query for reliability\nVERSION=$(dpkg-query -W -f='${Version}' code 2>/dev/null | cut -d- -f1 || echo \"unknown\")\n\n# Find the main desktop file (prefer code.desktop over code-url-handler.desktop)\nDESKTOP_ENTRY=\"\"\nif [ -f \"/usr/share/applications/code.desktop\" ]; then\n DESKTOP_ENTRY=\"/usr/share/applications/code.desktop\"\nelse\n # Search for any code desktop file, excluding url-handler\n for desktop_file in /usr/share/applications/code*.desktop; do\n if [ -f \"$desktop_file\" ] && [[ \"$desktop_file\" != *\"url-handler\"* ]]; then\n DESKTOP_ENTRY=\"$desktop_file\"\n break\n fi\n done\n # If still not found, use the first one\n if [ -z \"$DESKTOP_ENTRY\" ]; then\n for desktop_file in /usr/share/applications/code*.desktop; do\n if [ -f \"$desktop_file\" ]; then\n DESKTOP_ENTRY=\"$desktop_file\"\n break\n fi\n done\n fi\nfi\n\n# Extract display name from desktop file (primary source)\nDISPLAY_NAME=\"\"\nif [ -f \"$DESKTOP_ENTRY\" ]; then\n # Extract Name field from desktop file\n DISPLAY_NAME=$(grep \"^Name=\" \"$DESKTOP_ENTRY\" | head -1 | cut -d= -f2-)\n # Trim whitespace\n DISPLAY_NAME=$(echo \"$DISPLAY_NAME\" | xargs)\nfi\n\n# If display name is still empty, try to get from dpkg\nif [ -z \"$DISPLAY_NAME\" ]; then\n DISPLAY_NAME=$(dpkg-query -W -f='${Summary}' code 2>/dev/null || echo \"\")\nfi\n\n# Fallback to package description if still empty\nif [ -z \"$DISPLAY_NAME\" ]; then\n DISPLAY_NAME=$(apt-cache show code 2>/dev/null | grep -i \"^Description:\" | cut -d: -f2- | head -1 | xargs)\nfi\n\n# Extract icon name from desktop file\nICON_NAME=\"\"\nif [ -f \"$DESKTOP_ENTRY\" ]; then\n ICON_NAME=$(grep \"^Icon=\" \"$DESKTOP_ENTRY\" | head -1 | cut -d= -f2)\n # Trim whitespace\n ICON_NAME=$(echo \"$ICON_NAME\" | xargs)\nfi\n\n# Find actual icon files dynamically based on discovered icon name\nICON_PATHS=()\n\n# If we have an icon name, search for it in standard icon directories\nif [ -n \"$ICON_NAME\" ]; 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 /usr/share/icons /usr/share/pixmaps -name \"${ICON_NAME}\" -o -name \"${ICON_NAME}.*\" 2>/dev/null)\nfi\n\n# Build JSON output\nbuild_json() {\n local binary_path=\"$1\"\n local binary_name=\"$2\"\n local display_name=\"$3\"\n local desktop_entry=\"$4\"\n local version=\"$5\"\n shift 5\n local icon_paths=(\"$@\")\n \n # Build icon array JSON\n local icon_json=\"[\"\n local first=true\n for icon in \"${icon_paths[@]}\"; do\n if [ \"$first\" = true ]; then\n icon_json+=\"\\\"$icon\\\"\"\n first=false\n else\n icon_json+=\",\\\"$icon\\\"\"\n fi\n done\n icon_json+=\"]\"\n \n # Output compact JSON\n cat <<EOF\n{\"binary_path\":\"$binary_path\",\"binary_name\":\"$binary_name\",\"display_name\":\"$display_name\",\"desktop_entry\":\"$desktop_entry\",\"icon_paths\":$icon_json,\"version\":\"$version\"}\nEOF\n}\n\nbuild_json \"$BINARY_PATH\" \"$BINARY_NAME\" \"$DISPLAY_NAME\" \"$DESKTOP_ENTRY\" \"$VERSION\" \"${ICON_PATHS[@]}\"",
|
||||
"sandbox_name": "linux-0c31c819",
|
||||
"metadata": {
|
||||
"binary_path": "/usr/bin/code",
|
||||
"binary_name": "code",
|
||||
"display_name": "Visual Studio Code",
|
||||
"desktop_entry": "/usr/share/applications/code.desktop",
|
||||
"icon_paths": [
|
||||
"/usr/share/pixmaps/vscode.png"
|
||||
],
|
||||
"version": "1.115.0"
|
||||
},
|
||||
"is_cli": false,
|
||||
"notes": "Visual Studio Code successfully installed from Microsoft's official APT repository and launched on Ubuntu/Debian Linux. The install script is idempotent and adds the Microsoft repository with GPG key verification. The launch script sets DONT_PROMPT_WSL_INSTALL to suppress WSL detection warnings. The metadata extraction script dynamically discovers all values from installed artifacts: binary via which, version via dpkg-query, desktop file by searching /usr/share/applications, display name from desktop file with dpkg/apt-cache fallbacks, and icon files by searching standard directories based on the Icon= field.",
|
||||
"screenshot_verification": "PASS: Visual Studio Code is visibly open with the Welcome tab displayed and a trust dialog box asking about folder authors.",
|
||||
"verification_passed": true,
|
||||
"extracted_icons": [
|
||||
"cua_sandbox_apps\\apps\\visual-studio-code\\linux\\logs\\icon-1024x1024.png"
|
||||
]
|
||||
}
|
||||
+219
File diff suppressed because one or more lines are too long
+547
@@ -0,0 +1,547 @@
|
||||
<!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">← Prev</span>
|
||||
<a href="page-001.html">1</a>
|
||||
<a href="page-001.html">Next →</a>
|
||||
</div>
|
||||
|
||||
<p style="color: var(--text-muted); margin-bottom: 24px;">1 prompts · 203 messages · 63 tool calls · 0 commits · 1 pages</p>
|
||||
|
||||
<div class="index-item"><a href="page-001.html#msg-2026-04-12T23-16-33-191Z"><div class="index-item-header"><span class="index-item-number">#1</span><time datetime="2026-04-12T23:16:33.191Z" data-timestamp="2026-04-12T23:16:33.191Z">2026-04-12T23:16:33.191Z</time></div><div class="index-item-content"><p>Create install and launch scripts for: Visual Studio Code
|
||||
Target OS: linux
|
||||
App metadata: {"id": "visual-studio-code", "name": "Visual Studio Code", "description": "A lightweight but powerful source code editor that runs on your desktop and is available for Windows, macOS and Linux. It comes with built-in support for JavaScript, TypeScript and Node.js, and has a rich ecosystem of extensions for other languages and runtimes. Enhanced with AI capabilities for agentic development workflows.", "website": "https://code.visualstudio.com", "icon_url": "https://code.visualstudio.com/favicon.ico", "categories": ["IDE", "Code Editor", "Developer Tools"], "tags": ["open-source", "cross-platform", "syntax-highlighting", "debugging", "git-integration", "extensions", "AI-powered", "typescript", "javascript", "python"], "os_support": ["linux", "macos", "windows"], "requires_payment": false, "foss": true, "gh_repo": "https://github.com/microsoft/vscode", "self_hostable": true, "requires_hardware": false, "package_managers": {"apt": "code", "snap": "code", "flatpak": "com.visualstudio.code", "brew": "visual-studio-code", "choco": "vscode", "winget": "Microsoft.VisualStudioCode"}, "download_url": "https://code.visualstudio.com/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>37 mcp__sandbox__sandbox_run · 12 mcp__sandbox__sandbox_write · 4 mcp__sandbox__sandbox_read · 3 mcp__sandbox__submit_result · 2 mcp__sandbox__sandbox_screenshot · 2 read · 1 fetch · 1 mcp__sandbox__create_sandbox · 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>Perfect! ✅ I have successfully completed the task for Visual Studio Code on Linux. Here's a summary of what was delivered:</p>
|
||||
<h2>Summary</h2>
|
||||
<p><strong>Application:</strong> Visual Studio Code v1.115.0
|
||||
<strong>Target OS:</strong> Linux (Ubuntu/Debian)
|
||||
<strong>Status:</strong> ✅ Successfully installed, launched, and verified</p>
|
||||
<h3>Deliverables:</h3>
|
||||
<ol>
|
||||
<li><strong>Install Script</strong> (<code>install.sh</code>)</li>
|
||||
<li>Adds Microsoft's official APT repository with GPG key verification</li>
|
||||
<li>Updates package lists and installs the <code>code</code> package</li>
|
||||
<li>Idempotent - safe to run multiple times</li>
|
||||
<li>
|
||||
<p>Handles dependency installation (curl, gpg)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Launch Script</strong> (<code>launch.sh</code>)</p>
|
||||
</li>
|
||||
<li>Sets <code>DONT_PROMPT_WSL_INSTALL</code> environment variable to suppress WSL warnings</li>
|
||||
<li>Launches VS Code in the background with <code>/tmp</code> as workspace</li>
|
||||
<li>
|
||||
<p>Allows sufficient startup time (5 seconds)</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Metadata Extraction Script</strong> (<code>extract_metadata.sh</code>)</p>
|
||||
</li>
|
||||
<li><strong>Binary Path:</strong> <code>/usr/bin/code</code></li>
|
||||
<li><strong>Display Name:</strong> "Visual Studio Code" (extracted from desktop file)</li>
|
||||
<li><strong>Version:</strong> 1.115.0 (via dpkg-query)</li>
|
||||
<li><strong>Desktop Entry:</strong> <code>/usr/share/applications/code.desktop</code></li>
|
||||
<li><strong>Icon Paths:</strong> <code>/usr/share/pixmaps/vscode.png</code></li>
|
||||
<li>Fully dynamic - extracts all values from installed artifacts and system metadata</li>
|
||||
</ol>
|
||||
<h3>Verification:</h3>
|
||||
<ul>
|
||||
<li>Screenshot confirmed VS Code was successfully launched and visible on the desktop</li>
|
||||
<li>Application showed the Welcome tab with a trust folder dialog</li>
|
||||
<li>All metadata was correctly extracted and validated</li>
|
||||
</ul></div></div><button class="expand-btn">Show more</button></div></div>
|
||||
</div></div>
|
||||
|
||||
|
||||
<div class="pagination">
|
||||
<span class="current">Index</span>
|
||||
<span class="disabled">← Prev</span>
|
||||
<a href="page-001.html">1</a>
|
||||
<a href="page-001.html">Next →</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>
|
||||
+1580
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"binary_path": "/usr/bin/code",
|
||||
"binary_name": "code",
|
||||
"display_name": "Visual Studio Code",
|
||||
"desktop_entry": "/usr/share/applications/code.desktop",
|
||||
"icon_paths": [
|
||||
"/usr/share/pixmaps/vscode.png"
|
||||
],
|
||||
"version": "1.115.0"
|
||||
}
|
||||
Reference in New Issue
Block a user