[
  {
    "path": ".github/workflows/actions.yml",
    "content": "name: history-sync\nenv:\n  ACCESS_KEY: ${{ secrets.ACCESS_KEY }}\non: [push, workflow_dispatch]\njobs:\n  setup_and_test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - run: docker build . --file test/Dockerfile --build-arg ACCESS_KEY=${ACCESS_KEY} --tag test/history-sync:latest\n      - run: docker run test/history-sync:latest; exit $?\n"
  },
  {
    "path": ".gitignore",
    "content": "zsh_history_test*\n.*.swp\n*.swp\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 James Fraser <wulfgar.pro@gmail.com> (https://www.wulfgar.pro)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![history-sync](https://github.com/wulfgarpro/history-sync/actions/workflows/actions.yml/badge.svg)](https://github.com/wulfgarpro/history-sync/actions/workflows/actions.yml)\n\n# history-sync\n\n> An Oh My Zsh plugin for GPG encrypted, Internet synchronized Zsh history using Git.\n\n## Installation\n\n```bash\nsudo apt install gpg git\ngit clone git@github.com:wulfgarpro/history-sync.git\ncp -r history-sync ~/.oh-my-zsh/plugins\n```\n\nOpen `.zshrc` file and add `history-sync` to the plugins list:\n\n```bash\nplugins=(... history-sync)\n```\n\nThe reaload Zsh:\n\n```bash\nexec zsh\n```\n\n## Usage\n\nBefore using `history-sync`, ensure you have:\n\n1. A hosted Git repository, e.g. GitHub, Bitbucket, with SSH key access.\n2. A configured GPG key pair for encrypting/decrypting your history file, and the public keys of all\n   nodes in your web-of-trust.\n   * See [the GnuPG documentation](https://www.gnupg.org/documentation/) for details.\n\nOnce set up, configure the following environment variables:\n\n* `ZSH_HISTORY_FILE`: your `zsh_history` file location\n* `ZSH_HISTORY_PROJ`: Git project for storing `zsh_history`\n* `ZSH_HISTORY_FILE_ENC`: encrypted history file location\n* `ZSH_HISTORY_COMMIT_MSG`: default commit message when pushing\n* `ZSH_HISTORY_DEFAULT_RECIPIENT`: default recipient for `zhps`\n\nDefaults:\n\n```bash\nZSH_HISTORY_FILE_NAME=\".zsh_history\"\nZSH_HISTORY_FILE=\"${HOME}/${ZSH_HISTORY_FILE_NAME}\"\nZSH_HISTORY_PROJ=\"${HOME}/.zsh_history_proj\"\nZSH_HISTORY_FILE_ENC_NAME=\"zsh_history\"\nZSH_HISTORY_FILE_ENC=\"${ZSH_HISTORY_PROJ}/${ZSH_HISTORY_FILE_ENC_NAME}\"\nZSH_HISTORY_COMMIT_MSG=\"latest $(date)\"\nZSH_HISTORY_DEFAULT_RECIPIENT=\"\"\n```\n\nOptional:\n\n* `ZSH_HISTORY_GIT_REMOTE`: if set, the plugin clones the remote repo on first use\n\n## Commands\n\n```bash\n# Pull history\nzhpl\n\n# Push history\nzhps -r \"John Brown\" -r 876T3F78 -r ...\n\n# Or set a default recipient to omit -r:\n# ZSH_HISTORY_DEFAULT_RECIPIENT=\"John Brown\"\n\n# Pull + push history\nzhsync\n```\n\n## Demo\n\nCheck out the [screen cast](https://asciinema.org/a/43575).\n\n## Licence\n\nMIT @ [James Fraser](https://www.wulfgar.pro)\n"
  },
  {
    "path": "history-sync.plugin.zsh",
    "content": "# ----------------------------------------------------------------\n# Description\n# ----------------------------------------------------------------\n# An Oh My Zsh plugin for GPG encrypted, Internet synchronized Zsh\n# history using Git.\n#\n# ----------------------------------------------------------------\n# James Fraser <wulfgar.pro@gmail.com> - https://www.wulfgar.pro\n# ----------------------------------------------------------------\n\nautoload -U colors && colors\n\nalias zhpl=history_sync_pull\nalias zhps=history_sync_push\nalias zhsync=\"history_sync_pull && history_sync_push\"\n\nCP() { command cp \"$@\"; }\nMV() { command mv \"$@\"; }\nRM() { command rm \"$@\"; }\nTR() { LC_ALL=C command tr \"$@\"; }\nAWK() { command awk \"$@\"; }\nCAT() { command cat \"$@\"; }\nGIT() { command git \"$@\"; }\nGPG() { command gpg \"$@\"; }\nSED() { command sed \"$@\"; }\nDATE() { command date \"$@\"; }\nFOLD() { command fold \"$@\"; }\nGREP() { command grep \"$@\"; }\nHEAD() { command head \"$@\"; }\nPERL() { command perl \"$@\"; }\nSORT() { LC_ALL=C command sort \"$@\"; }\nMKTEMP() { command mktemp \"$@\"; }\n\nZSH_HISTORY_PROJ=\"${ZSH_HISTORY_PROJ:-${HOME}/.zsh_history_proj}\"\nZSH_HISTORY_FILE_NAME=\"${ZSH_HISTORY_FILE_NAME:-.zsh_history}\"\nZSH_HISTORY_FILE=\"${ZSH_HISTORY_FILE:-${HOME}/${ZSH_HISTORY_FILE_NAME}}\"\nZSH_HISTORY_FILE_ENC_NAME=\"${ZSH_HISTORY_FILE_ENC_NAME:-zsh_history}\"\nZSH_HISTORY_FILE_ENC=\"${ZSH_HISTORY_FILE_ENC:-${ZSH_HISTORY_PROJ}/${ZSH_HISTORY_FILE_ENC_NAME}}\"\nZSH_HISTORY_FILE_DECRYPT_NAME=\"${ZSH_HISTORY_FILE_DECRYPT_NAME:-zsh_history_decrypted}\"\nZSH_HISTORY_FILE_MERGED_NAME=\"${ZSH_HISTORY_FILE_MERGED_NAME:-zsh_history_merged}\"\nZSH_HISTORY_COMMIT_MSG=\"${ZSH_HISTORY_COMMIT_MSG:-latest $(DATE)}\"\nZSH_HISTORY_DEFAULT_RECIPIENT=\"${ZSH_HISTORY_DEFAULT_RECIPIENT:-}\"\n\n_print_git_error_msg() {\n    echo \"$bold_color${fg[red]}There's a problem with git repository: ${ZSH_HISTORY_PROJ}.$reset_color\"\n    return\n}\n\n_print_gpg_encrypt_error_msg() {\n    echo \"$bold_color${fg[red]}GPG failed to encrypt history file.$reset_color\"\n    return\n}\n\n_print_gpg_decrypt_error_msg() {\n    echo \"$bold_color${fg[red]}GPG failed to decrypt history file.$reset_color\"\n    return\n}\n\n_usage() {\n    echo \"Usage: [ [-r <string> ...] [-y] ]\" 1>&2\n    echo\n    echo \"Optional args:\"\n    echo\n    echo \"      -r recipients\"\n    echo \"      -s signers\"\n    echo \"      -y force\"\n    return\n}\n\n# \"Squash\" each multi-line command in the passed history files to one line\n_squash_multiline_commands_in_files() {\n    # Create temporary files\n    # Use global variables to use same path's in the restore-multi-line commands\n    # function\n    TMP_FILE_1=$(mktemp)\n    TMP_FILE_2=$(mktemp)\n\n    # Generate random character sequences to replace \\n and anchor the first\n    # line of a command (use global variable for new-line-replacement to use it\n    # in the restore-multi-line commands function)\n    NL_REPLACEMENT=$(TR -dc 'a-zA-Z0-9' < /dev/urandom |\n        FOLD -w 32 | HEAD -n 1)\n    local FIRST_LINE_ANCHOR=$(TR -dc 'a-zA-Z0-9' < /dev/urandom |\n        FOLD -w 32 | HEAD -n 1)\n\n    for i in \"$ZSH_HISTORY_FILE\" \"$ZSH_HISTORY_FILE_DECRYPT_NAME\"; do\n        # Filter out multi-line commands and save them to a separate file\n        GREP -v -B 1 '^: [0-9]\\{1,10\\}:[0-9]\\+;' \"${i}\" |\n            GREP -v -e '^--$' > \"${TMP_FILE_1}\"\n\n        # Filter out multi-line commands and remove them from the original file\n        GREP -v -x -F -f \"${TMP_FILE_1}\" \"${i}\" > \"${TMP_FILE_2}\" \\\n            && MV \"${TMP_FILE_2}\" \"${i}\"\n\n        # Add anchor before the first line of each command\n        SED \"s/\\(^: [0-9]\\{1,10\\}:[0-9]\\+;\\)/${FIRST_LINE_ANCHOR} \\1/\" \\\n            \"${TMP_FILE_1}\" > \"${TMP_FILE_2}\" \\\n            && MV \"${TMP_FILE_2}\" \"${TMP_FILE_1}\"\n\n        # Replace all \\n with a sequence of symbols\n        if [[ \"$(SED --version 2>&1)\"  == *\"GNU\"* ]]; then\n          SED ':a;N;$!ba;s/\\n/'\" ${NL_REPLACEMENT} \"'/g' \\\n              \"${TMP_FILE_1}\" > \"${TMP_FILE_2}\"\n        else\n          # Assume BSD `sed`\n          PERL -0777 -pe 's/\\n/'\" ${NL_REPLACEMENT} \"'/g' \\\n            \"${TMP_FILE_1}\" > \"${TMP_FILE_2}\"\n        fi\n        MV \"${TMP_FILE_2}\" \"${TMP_FILE_1}\"\n\n        # Replace first line anchor by \\n\n        SED \"s/${FIRST_LINE_ANCHOR} \\(: [0-9]\\{1,10\\}:[0-9]\\+;\\)/\\n\\1/g\" \\\n            \"${TMP_FILE_1}\" > \"${TMP_FILE_2}\" \\\n            && MV \"${TMP_FILE_2}\" \"${TMP_FILE_1}\"\n\n        # Merge squashed multiline commands to the history file\n        CAT \"${TMP_FILE_1}\" >> \"${i}\"\n\n        # Sort history file\n        SORT -n < \"${i}\" > \"${TMP_FILE_1}\" && MV \"${TMP_FILE_1}\" \"${i}\"\n    done\n}\n\n# Restore multi-line commands in the history file\n_restore_multiline_commands_in_file() {\n    # Filter unnecessary lines from the history file (Binary file ... matches)\n    # and save them in a separate file\n    GREP -v '^: [0-9]\\{1,10\\}:[0-9]\\+;' \"$ZSH_HISTORY_FILE\" > \"${TMP_FILE_1}\"\n\n    # Filter out unnecessary lines and remove them from the original file\n    GREP -v -x -F -f \"${TMP_FILE_1}\" \"$ZSH_HISTORY_FILE\" > \"${TMP_FILE_2}\" && \\\n        MV \"${TMP_FILE_2}\" \"$ZSH_HISTORY_FILE\"\n\n    # Replace the sequence of symbols by \\n to restore multi-line commands\n    SED \"s/ ${NL_REPLACEMENT} /\\n/g\" \"$ZSH_HISTORY_FILE\" > \"${TMP_FILE_1}\" \\\n        && MV \"${TMP_FILE_1}\" \"$ZSH_HISTORY_FILE\"\n\n    # Unset global variables\n    unset NL_REPLACEMENT TMP_FILE_1 TMP_FILE_2\n}\n\n# Pull current master, decrypt, and merge with .zsh_history\nhistory_sync_pull() {\n    # Get options force\n    local force=false\n    while getopts y opt; do\n        case \"$opt\" in\n            y)\n                force=true\n                ;;\n        esac\n    done\n    DIR=$(pwd)\n\n    # Backup\n    if [[ $force = false ]]; then\n        CP -av \"$ZSH_HISTORY_FILE\" \"$ZSH_HISTORY_FILE.backup\" 1>&2\n    fi\n\n\n    # Clone if not exist\n    if [[ ! -d \"$ZSH_HISTORY_PROJ\" ]]; then\n        if [[ ! -v ZSH_HISTORY_GIT_REMOTE ]]; then\n            _print_git_error_msg\n            return\n        fi\n\n        \"$GIT\" clone \"$ZSH_HISTORY_GIT_REMOTE\" \"$ZSH_HISTORY_PROJ\"\n        if [[ \"$?\" != 0 ]]; then\n            _print_git_error_msg\n            return\n        fi\n    fi\n\n    # Pull\n    cd \"$ZSH_HISTORY_PROJ\" && GIT pull\n    if [[ \"$?\" != 0 ]]; then\n        _print_git_error_msg\n        cd \"$DIR\"\n        return\n    fi\n\n    # Decrypt\n    GPG --output \"$ZSH_HISTORY_FILE_DECRYPT_NAME\" --decrypt \"$ZSH_HISTORY_FILE_ENC\"\n    if [[ \"$?\" != 0 ]]; then\n        _print_gpg_decrypt_error_msg\n        cd \"$DIR\"\n        return\n    fi\n\n    # Check if EXTENDED_HISTORY is enabled, and if so, \"squash\" each multi-line\n    # command in local and decrypted history files to one line\n    [[ -o extendedhistory ]] && _squash_multiline_commands_in_files\n\n    # Merge\n    CAT \"$ZSH_HISTORY_FILE\" \"$ZSH_HISTORY_FILE_DECRYPT_NAME\" | \\\n      AWK '/:[0-9]/ { if(s) { print s } s=$0 } !/:[0-9]/ { s=s\"\\n\"$0 } END { print s }' | \\\n      SORT -u > \"$ZSH_HISTORY_FILE_MERGED_NAME\"\n    MV \"$ZSH_HISTORY_FILE_MERGED_NAME\" \"$ZSH_HISTORY_FILE\"\n    RM  \"$ZSH_HISTORY_FILE_DECRYPT_NAME\"\n    cd  \"$DIR\"\n\n    # Check if EXTENDED_HISTORY is enabled, and if so, restore multi-line\n    # commands in the local history file\n    [[ -o extendedhistory ]] && _restore_multiline_commands_in_file\n    # Strip trailing '\\' if the next line is blank\n    SED -E -i '/\\\\$/ { N; s/\\\\+\\n$/\\n/ }' \"$ZSH_HISTORY_FILE\"\n    # Strip blank lines\n    SED -i '/^$/d' \"$ZSH_HISTORY_FILE\"\n}\n\n# Encrypt and push current history to master\nhistory_sync_push() {\n    # Get options recipients, force\n    local recipients=()\n    local signers=()\n    local force=false\n    while getopts r:s:y opt; do\n        case \"$opt\" in\n            r)\n                recipients+=(\"$OPTARG\")\n                ;;\n            s)\n                signers+=(\"$OPTARG\")\n                ;;\n            y)\n                force=true\n                ;;\n            *)\n                _usage\n                return\n                ;;\n        esac\n    done\n\n    # Encrypt\n    if ! [[ \"${#recipients[@]}\" > 0 ]]; then\n        if [[ -n \"$ZSH_HISTORY_DEFAULT_RECIPIENT\" ]]; then\n            recipients+=(\"$ZSH_HISTORY_DEFAULT_RECIPIENT\")\n        else\n            echo -n \"Please enter GPG recipient name: \"\n            read name\n            recipients+=(\"$name\")\n        fi\n    fi\n\n    GPG_ENCRYPT_CMD_OPT=\"--yes -v \"\n    for r in \"${recipients[@]}\"; do\n        GPG_ENCRYPT_CMD_OPT+=\"-r \\\"$r\\\" \"\n    done\n    if [[ \"${#signers[@]}\" > 0 ]]; then\n        GPG_ENCRYPT_CMD_OPT+=\"--sign \"\n        for s in \"${signers[@]}\"; do\n            GPG_ENCRYPT_CMD_OPT+=\"--default-key \\\"$s\\\" \"\n        done\n    fi\n\n    if [[ \"$GPG_ENCRYPT_CMD_OPT\" != *\"--sign\"* ]]; then\n        if [[ $force = false ]]; then\n            echo -n \"$bold_color${fg[yellow]}Do you want to sign with first key found in secret keyring (y/N)?$reset_color \"\n            read sign\n        else\n            sign='y'\n        fi\n\n        case \"$sign\" in\n            [Yy]* )\n                    GPG_ENCRYPT_CMD_OPT+=\"--sign \"\n                    ;;\n                * )\n                    ;;\n        esac\n    fi\n\n    if [[ \"$GPG_ENCRYPT_CMD_OPT\" =~ '.(-r).+.' ]]; then\n        GPG_ENCRYPT_CMD_OPT+=\"--encrypt --armor --output \\\"$ZSH_HISTORY_FILE_ENC\\\" \\\"$ZSH_HISTORY_FILE\\\"\"\n        eval GPG \"$GPG_ENCRYPT_CMD_OPT\"\n        if [[ \"$?\" != 0 ]]; then\n            _print_gpg_encrypt_error_msg\n            return\n        fi\n\n        # Commit\n        if [[ $force = false ]]; then\n            echo -n \"$bold_color${fg[yellow]}Do you want to commit current local history file (y/N)?$reset_color \"\n            read commit\n        else\n            commit='y'\n        fi\n\n        if [[ -n \"$commit\" ]]; then\n            case \"$commit\" in\n                [Yy]* )\n                    DIR=$(pwd)\n                    cd \"$ZSH_HISTORY_PROJ\" && GIT add * && GIT commit -m \"$ZSH_HISTORY_COMMIT_MSG\"\n                    local local_status=$?\n\n                    if [[ $force = false ]]; then\n                        echo -n \"$bold_color${fg[yellow]}Do you want to push to remote (y/N)?$reset_color \"\n                        read push\n                    else\n                        push='y'\n                    fi\n\n                    if [[ -n \"$push\" ]]; then\n                        case \"$push\" in\n                            [Yy]* )\n                                GIT push\n                                local_status=$?\n                                ;;\n                        esac\n                    fi\n\n                    cd \"$DIR\"\n                    if [[ \"$local_status\" != 0 ]]; then\n                        _print_git_error_msg\n                        return\n                    fi\n                    ;;\n                * )\n                    ;;\n            esac\n        fi\n    fi\n}\n"
  },
  {
    "path": "test/Dockerfile",
    "content": "FROM ubuntu:22.04\n\n# Install system packages\nRUN apt-get update \\\n  && apt-get install -y --no-install-recommends \\\n    ca-certificates \\\n    curl \\\n    git \\\n    zsh \\\n    gpg \\\n    gpg-agent \\\n    ripgrep \\\n  && rm -rf /var/lib/apt/lists/*\n\n# Install oh-my-zsh and history-sync plugin\nRUN bash -c 'set -o pipefail && curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sh -e' \\\n  && mkdir -p /root/.oh-my-zsh/plugins/history-sync\nCOPY history-sync.plugin.zsh /root/.oh-my-zsh/plugins/history-sync/\n# Install a basic `zshrc`\nCOPY test/zshrc /root/.zshrc\n# Install the test script\nCOPY test/test.zsh /root\nRUN chmod +x /root/test.zsh\n\nARG ACCESS_KEY\nENV ACCESS_KEY=${ACCESS_KEY}\nENTRYPOINT [\"/usr/bin/zsh\"]\nCMD [\"-i\", \"-c\", \"source /root/test.zsh ${ACCESS_KEY}\"]\n"
  },
  {
    "path": "test/test.zsh",
    "content": "#!/usr/bin/env zsh\n\nACCESS_KEY=$1\n\nset -e\ngpg -q --quick-gen-key --yes --batch --passphrase '' $UID\ngit config --global user.name \"James Fraser\"\ngit config --global user.email \"wulfgar.pro@gmail.com\"\ngit clone \"https://$ACCESS_KEY@github.com/wulfgarpro/history-sync-test\" ~/.zsh_history_proj\nset +e\n\nfunction success() {\n    echo $fg[green]\"$1\"$reset_color\n}\n\nfunction failure() {\n    echo $fg[red]\"$1\"$reset_color\n    exit 1\n}\n\nfunction info() {\n    echo $fg[yellow]\"$1\"$reset_color\n}\n\nfunction check_fn_exists() {\n    typeset -f \"$1\" >/dev/null\n    [[ $? -eq 0 ]] || {failure \"FAILURE: Function '$1' missing\"}\n}\n\nfunction check_alias_exists() {\n    alias \"$1\" >/dev/null\n    [[ $? -eq 0 ]] || {failure \"FAILURE: Alias '$1' missing\"}\n}\n\nfunction check_env_exists() {\n    [[ -v $1 ]]\n    [[ $? -eq 0 ]] || {failure \"FAILURE: Environment variable '$1' missing\"}\n}\n\nfunction check_history() {\n    cat ~/.zsh_history \n    rg -U \"$1\" ~/.zsh_history >/dev/null\n    [[ $? -eq 0 ]] || {failure \"FAILURE: History did not match '$1'\"}\n}\n\nfunction setup() {\n    set -e\n    [[ -d ~/.zsh_history_proj ]]\n    # Clear existing history file\n    echo -n \"\" > ~/.zsh_history_proj/zsh_history\n    set +e\n}\n\ninfo \"TEST HISTORY-SYNC FUNCTIONS EXIST\"\ncheck_fn_exists _print_git_error_msg\ncheck_fn_exists _print_gpg_encrypt_error_msg\ncheck_fn_exists _print_gpg_decrypt_error_msg\ncheck_fn_exists _usage\ncheck_fn_exists history_sync_pull\ncheck_fn_exists history_sync_push\nsuccess \"SUCCESS\"\n\ninfo \"TEST HISTORY-SYNC ALIASES EXIST\"\ncheck_alias_exists zhps\ncheck_alias_exists zhpl\ncheck_alias_exists zhsync\nsuccess \"SUCCESS\"\n\ninfo \"TEST ENVIRONMENT VARIABLES EXIST\"\ncheck_env_exists ZSH_HISTORY_PROJ\ncheck_env_exists ZSH_HISTORY_FILE_NAME\ncheck_env_exists ZSH_HISTORY_FILE\ncheck_env_exists ZSH_HISTORY_FILE_ENC_NAME\ncheck_env_exists ZSH_HISTORY_FILE_ENC\ncheck_env_exists ZSH_HISTORY_FILE_DECRYPT_NAME\ncheck_env_exists ZSH_HISTORY_COMMIT_MSG\nsuccess \"SUCCESS\"\n\ninfo \"TEST SYNC HISTORY BASIC 0\"\nsetup\nRAND=$RANDOM\necho \"1 echo $RAND\" >> ~/.zsh_history\nzhps -y -r $UID && zhpl -y\ncheck_history \"^1 echo $RAND$\"\nsuccess \"SUCCESS\"\n\ninfo \"TEST SYNC HISTORY BASIC 1\"\nsetup\nRAND0=$RANDOM\nRAND1=$RANDOM\nRAND2=$RANDOM\nRAND3=$RANDOM\nRAND4=$RANDOM\necho \"1 echo $RAND0\" >> ~/.zsh_history\necho \"2 echo $RAND1\" >> ~/.zsh_history\necho \"3 echo $RAND2\" >> ~/.zsh_history\necho \"4 echo $RAND3\" >> ~/.zsh_history\necho \"5 echo $RAND4\" >> ~/.zsh_history\nzhps -y -r $UID -s $UID && zhpl -y\ncheck_history \"^1 echo $RAND0$\"\ncheck_history \"^2 echo $RAND1$\"\ncheck_history \"^3 echo $RAND2$\"\ncheck_history \"^4 echo $RAND3$\"\ncheck_history \"^5 echo $RAND4$\"\nsuccess \"SUCCESS\"\n\ninfo \"TEST SYNC HISTORY MULTI-LINE 0\"\nsetup\necho \"1 for i in {1..3}; do\necho \\$i\ndone\" >> ~/.zsh_history\nzhps -y -r $UID && zhpl -y\ncheck_history \"^1 for i in \\{1..3\\}; do\\necho \\\\\\$i\\ndone$\"\nsuccess \"SUCCESS\"\n\ninfo \"TEST SYNC HISTORY MULTI-LINE PERL\"\nsetup\nalias sed=\"echo\"\necho \"1 for i in {1..3}; do\necho \\$i\ndone\" >> ~/.zsh_history\nzhps -y -r $UID && zhpl -y\ncheck_history \"^1 for i in \\{1..3\\}; do\\necho \\\\\\$i\\ndone$\"\nunalias sed\nsuccess \"SUCCESS\"\n"
  },
  {
    "path": "test/zshrc",
    "content": "# If you come from bash you might have to change your $PATH.\n# export PATH=$HOME/bin:/usr/local/bin:$PATH\n\n# Path to your oh-my-zsh installation.\nexport ZSH=\"/root/.oh-my-zsh\"\n\n# Set name of the theme to load --- if set to \"random\", it will\n# load a random theme each time oh-my-zsh is loaded, in which case,\n# to know which specific one was loaded, run: echo $RANDOM_THEME\n# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes\nZSH_THEME=\"robbyrussell\"\n\n# Set list of themes to pick from when loading at random\n# Setting this variable when ZSH_THEME=random will cause zsh to load\n# a theme from this variable instead of looking in $ZSH/themes/\n# If set to an empty array, this variable will have no effect.\n# ZSH_THEME_RANDOM_CANDIDATES=( \"robbyrussell\" \"agnoster\" )\n\n# Uncomment the following line to use case-sensitive completion.\n# CASE_SENSITIVE=\"true\"\n\n# Uncomment the following line to use hyphen-insensitive completion.\n# Case-sensitive completion must be off. _ and - will be interchangeable.\n# HYPHEN_INSENSITIVE=\"true\"\n\n# Uncomment one of the following lines to change the auto-update behavior\n# zstyle ':omz:update' mode disabled  # disable automatic updates\n# zstyle ':omz:update' mode auto      # update automatically without asking\n# zstyle ':omz:update' mode reminder  # just remind me to update when it's time\n\n# Uncomment the following line to change how often to auto-update (in days).\n# zstyle ':omz:update' frequency 13\n\n# Uncomment the following line if pasting URLs and other text is messed up.\n# DISABLE_MAGIC_FUNCTIONS=\"true\"\n\n# Uncomment the following line to disable colors in ls.\n# DISABLE_LS_COLORS=\"true\"\n\n# Uncomment the following line to disable auto-setting terminal title.\n# DISABLE_AUTO_TITLE=\"true\"\n\n# Uncomment the following line to enable command auto-correction.\n# ENABLE_CORRECTION=\"true\"\n\n# Uncomment the following line to display red dots whilst waiting for completion.\n# You can also set it to another string to have that shown instead of the default red dots.\n# e.g. COMPLETION_WAITING_DOTS=\"%F{yellow}waiting...%f\"\n# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765)\n# COMPLETION_WAITING_DOTS=\"true\"\n\n# Uncomment the following line if you want to disable marking untracked files\n# under VCS as dirty. This makes repository status check for large repositories\n# much, much faster.\n# DISABLE_UNTRACKED_FILES_DIRTY=\"true\"\n\n# Uncomment the following line if you want to change the command execution time\n# stamp shown in the history command output.\n# You can set one of the optional three formats:\n# \"mm/dd/yyyy\"|\"dd.mm.yyyy\"|\"yyyy-mm-dd\"\n# or set a custom format using the strftime function format specifications,\n# see 'man strftime' for details.\n# HIST_STAMPS=\"mm/dd/yyyy\"\n\n# Would you like to use another custom folder than $ZSH/custom?\n# ZSH_CUSTOM=/path/to/new-custom-folder\n\n# Which plugins would you like to load?\n# Standard plugins can be found in $ZSH/plugins/\n# Custom plugins may be added to $ZSH_CUSTOM/plugins/\n# Example format: plugins=(rails git textmate ruby lighthouse)\n# Add wisely, as too many plugins slow down shell startup.\nplugins=(git history-sync)\n\nsource $ZSH/oh-my-zsh.sh\n\n# User configuration\n\n# export MANPATH=\"/usr/local/man:$MANPATH\"\n\n# You may need to manually set your language environment\n# export LANG=en_US.UTF-8\n\n# Preferred editor for local and remote sessions\n# if [[ -n $SSH_CONNECTION ]]; then\n#   export EDITOR='vim'\n# else\n#   export EDITOR='mvim'\n# fi\n\n# Compilation flags\n# export ARCHFLAGS=\"-arch x86_64\"\n\n# Set personal aliases, overriding those provided by oh-my-zsh libs,\n# plugins, and themes. Aliases can be placed here, though oh-my-zsh\n# users are encouraged to define aliases within the ZSH_CUSTOM folder.\n# For a full list of active aliases, run `alias`.\n#\n# Example aliases\n# alias zshconfig=\"mate ~/.zshrc\"\n# alias ohmyzsh=\"mate ~/.oh-my-zsh\"\n"
  }
]