diff --git a/cursor/.gitignore b/cursor/.gitignore new file mode 100644 index 0000000..6e50e12 --- /dev/null +++ b/cursor/.gitignore @@ -0,0 +1 @@ +./cache/ diff --git a/cursor/extensions.lock b/cursor/extensions.lock new file mode 100644 index 0000000..398fddb --- /dev/null +++ b/cursor/extensions.lock @@ -0,0 +1,61 @@ +# Cursor Extensions +# Generated on Fri Feb 21 18:59:21 GMT 2025 + +alefragnani.project-manager@12.8.0 +antiantisepticeye.vscode-color-picker@0.0.4 +antyos.openscad@1.3.2 +arahata.linter-actionlint@0.1.0 +bibhasdn.unique-lines@1.0.0 +bodil.file-browser@0.2.11 +bufbuild.vscode-buf@0.7.0 +carlos-algms.make-task-provider@2.5.1 +christian-kohler.path-intellisense@2.10.0 +connorshea.vscode-ruby-test-adapter@0.9.2 +connorshea.vscode-test-explorer-status-bar@1.2.0 +ctf0.macros@1.1.1 +dnut.rewrap-revived@1.16.3 +exiasr.hadolint@1.1.2 +fnando.linter@0.0.19 +foxundermoon.shell-format@7.2.5 +github.remotehub@0.64.0 +github.vscode-github-actions@0.27.1 +github.vscode-pull-request-github@0.102.0 +gofenix.go-lines@0.0.10 +golang.go@0.44.0 +gruntfuggly.todo-tree@0.0.226 +hashicorp.terraform@2.34.3 +hbenl.vscode-test-explorer@2.22.1 +humao.rest-client@0.25.1 +kahole.magit@0.6.66 +karunamurti.haml@1.4.1 +m4ns0ur.base64@1.0.0 +mhutchie.git-graph@1.30.0 +ms-azuretools.vscode-docker@1.29.4 +ms-vscode-remote.remote-containers@0.394.0 +ms-vscode-remote.remote-ssh@0.113.1 +ms-vscode-remote.remote-ssh-edit@0.87.0 +ms-vscode.hexeditor@1.11.1 +ms-vscode.remote-explorer@0.4.3 +ms-vscode.remote-repositories@0.42.0 +ms-vscode.remote-server@1.5.2 +ms-vscode.test-adapter-converter@0.2.1 +ms-vscode.vscode-speech@0.12.1 +ms-vsliveshare.vsliveshare@1.0.5948 +ninoseki.vscode-gem-lens@0.4.3 +pflannery.vscode-versionlens@1.16.2 +pkief.material-icon-theme@5.19.0 +redhat.vscode-xml@0.27.2 +redhat.vscode-yaml@1.16.0 +rrudi.vscode-dired@0.0.9 +rust-lang.rust-analyzer@0.3.2308 +shopify.ruby-extensions-pack@0.1.12 +shopify.ruby-lsp@0.9.6 +sorbet.sorbet-vscode-extension@0.3.37 +sumneko.lua@3.13.6 +swellaby.vscode-rust-test-adapter@0.11.0 +tamasfe.even-better-toml@0.21.2 +tuttieee.emacs-mcx@0.65.1 +viktorzetterstrom.non-breaking-space-highlighter@0.0.3 +wenhoujx.swiper@2.1.2 +zhuangtongfa.material-theme@3.19.0 +zxh404.vscode-proto3@0.5.5 diff --git a/cursor/extensions.txt b/cursor/extensions.txt deleted file mode 100644 index 1de095f..0000000 --- a/cursor/extensions.txt +++ /dev/null @@ -1,43 +0,0 @@ -# Cursor Extensions -# Generated on Wed Feb 19 19:29:16 GMT 2025 - -alefragnani.project-manager -antiantisepticeye.vscode-color-picker -arahata.linter-actionlint -bibhasdn.unique-lines -bodil.file-browser -carlos-algms.make-task-provider -connorshea.vscode-ruby-test-adapter -ctf0.macros -dnut.rewrap-revived -efbenson.scad -fnando.linter -foxundermoon.shell-format -github.remotehub -github.vscode-github-actions -github.vscode-pull-request-github -gofenix.go-lines -golang.go -gruntfuggly.todo-tree -hbenl.vscode-test-explorer -kahole.magit -karunamurti.haml -ms-azuretools.vscode-docker -ms-kubernetes-tools.vscode-kubernetes-tools -ms-vscode-remote.remote-containers -ms-vscode.remote-repositories -ms-vscode.test-adapter-converter -redhat.vscode-yaml -rrudi.vscode-dired -rust-lang.rust-analyzer -shan.code-settings-sync -shopify.ruby-extensions-pack -shopify.ruby-lsp -sorbet.sorbet-vscode-extension -sumneko.lua -swellaby.vscode-rust-test-adapter -tamasfe.even-better-toml -tuttieee.emacs-mcx -viktorzetterstrom.non-breaking-space-highlighter -wenhoujx.swiper -zhuangtongfa.material-theme diff --git a/cursor/setup.sh b/cursor/setup.sh index 1cb164f..15b8b6f 100755 --- a/cursor/setup.sh +++ b/cursor/setup.sh @@ -14,6 +14,9 @@ CONFIG_SOURCES=( # Detect current script directory. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Extensions lockfile path +EXTENSIONS_LOCK="${SCRIPT_DIR}/extensions.lock" + # ============================================================================== # Help # ============================================================================== @@ -116,11 +119,10 @@ find_cursor_cmd() { echo "${cursor_cmd}" } -# Dump installed extensions to extensions.txt +# Dump installed extensions to extensions.lock do_dump_extensions() { local cursor_cmd cursor_cmd="$(find_cursor_cmd)" - local extensions_file="${SCRIPT_DIR}/extensions.txt" local current_date current_date="$(date)" @@ -128,31 +130,102 @@ do_dump_extensions() { echo "# Cursor Extensions" echo "# Generated on ${current_date}" echo - "${cursor_cmd}" --list-extensions - } >"${extensions_file}" + "${cursor_cmd}" --list-extensions --show-versions + } >"${EXTENSIONS_LOCK}" - echo "Extensions list dumped to ${extensions_file}" + echo "Extensions list dumped to ${EXTENSIONS_LOCK}" } -# Install extensions from extensions.txt +# Global variable to cache installed extensions +_INSTALLED_EXTENSIONS="" + +# Check if extension is already installed with exact version +is_extension_installed() { + local cursor_cmd="$1" + local extension="$2" + local version="$3" + + # Build cache if not already built + if [[ -z "${_INSTALLED_EXTENSIONS}" ]]; then + _INSTALLED_EXTENSIONS="$("${cursor_cmd}" --list-extensions --show-versions)" + fi + + # Check if extension@version exists in cached list + echo "${_INSTALLED_EXTENSIONS}" | grep -q "^${extension}@${version}$" +} + +# Download and install a single extension. +# +# This is needed for cursor right now as installing an extension based on its +# ID yields a signature error. But installing from a .vsix file works fine. +download_and_install_extension() { + local cursor_cmd="$1" + local extension="$2" + local version="$3" + local extensions_dir="$4" + + # Check if already installed with correct version + if is_extension_installed "${cursor_cmd}" "${extension}" "${version}"; then + echo "Extension ${extension}@${version} is already installed, skipping" + return 0 + fi + + local vsix_path="${extensions_dir}/${extension}@${version}.vsix" + + # Create extensions directory if it doesn't exist + mkdir -p "${extensions_dir}" + + # If .vsix doesn't exist, download it + if [[ ! -f "${vsix_path}" ]]; then + local publisher_id="${extension%%.*}" + local extension_id="${extension#*.}" + local vsix_url="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher_id}/vsextensions/${extension_id}/${version}/vspackage" + + echo "Downloading ${extension}@${version}.vsix..." + echo " - URL: ${vsix_url}" + if ! curl --compressed -L -o "${vsix_path}" "${vsix_url}"; then + echo "Failed to download ${extension}@${version}.vsix" + return 1 + fi + fi + + # Install the extension from .vsix file + echo "Installing extension from ${vsix_path}" + if ! "${cursor_cmd}" --install-extension "${vsix_path}"; then + echo "Failed to install ${extension}@${version}" + return 1 + fi + + # Clean up the .vsix file after successful installation + rm "${vsix_path}" + return 0 +} + +# Install extensions from extensions.lock do_install_extensions() { local cursor_cmd cursor_cmd="$(find_cursor_cmd)" - local extensions_file="${SCRIPT_DIR}/extensions.txt" + local extensions_dir="${SCRIPT_DIR}/cache/extensions" - if [[ ! -f "${extensions_file}" ]]; then - echo "Error: ${extensions_file} not found" + if [[ ! -f "${EXTENSIONS_LOCK}" ]]; then + echo "Error: ${EXTENSIONS_LOCK} not found" exit 1 fi - # Read extensions file, skip comments and empty lines + # Process each extension while IFS= read -r line; do if [[ -n "${line}" && ! "${line}" =~ ^[[:space:]]*# ]]; then - echo "Installing extension: ${line}" - "${cursor_cmd}" --install-extension "${line}" - fi - done <"${extensions_file}" + extension="${line%@*}" + version="${line#*@}" + if ! download_and_install_extension "${cursor_cmd}" "${extension}" "${version}" "${extensions_dir}"; then + echo "Warning: Failed to install ${extension}@${version}" + fi + fi + done <"${EXTENSIONS_LOCK}" + + # Clean up extensions directory if empty + rmdir "${extensions_dir}" 2>/dev/null || true echo "Extensions installation complete!" }