Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions home-manager/services/code-syncer/default.nix
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
{ pkgs, ... }:
let
inherit (pkgs) lib;
in
{
launchd.agents.code-syncer = pkgs.lib.mkIf pkgs.stdenv.isDarwin {
launchd.agents.code-syncer = lib.mkIf pkgs.stdenv.isDarwin {
enable = true;
config = {
ProgramArguments = [
"${pkgs.bash}/bin/bash"
"${./sync.sh}"
];
Environment = {
PATH = "${pkgs.lib.makeBinPath [
PATH = "${lib.makeBinPath [
pkgs.fswatch
]}";
};
Expand All @@ -18,4 +21,26 @@
StandardErrorPath = "/tmp/code-syncer.error.log";
};
};

systemd.user.services.code-syncer = lib.mkIf pkgs.stdenv.isLinux {
Unit = {
Description = "VS Code settings syncer";
};
Service = {
Type = "simple";
Environment = "PATH=${
lib.makeBinPath [

@cubic-dev-ai cubic-dev-ai Bot Dec 14, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The systemd service PATH is missing gnugrep and gnused packages. The sync.sh script uses grep (for filtering extensions) and sed (for in-place edits), which are separate packages in Nix, not part of coreutils.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/services/code-syncer/default.nix, line 32:

<comment>The systemd service PATH is missing `gnugrep` and `gnused` packages. The sync.sh script uses `grep` (for filtering extensions) and `sed` (for in-place edits), which are separate packages in Nix, not part of `coreutils`.</comment>

<file context>
@@ -18,4 +21,26 @@
+    Service = {
+      Type = &quot;simple&quot;;
+      Environment = &quot;PATH=${
+        lib.makeBinPath [
+          pkgs.bash
+          pkgs.coreutils
</file context>
Fix with Cubic

pkgs.bash
pkgs.coreutils
pkgs.inotify-tools

Copilot AI Dec 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The systemd service PATH is missing several required packages that the script uses. The sync.sh script requires 'sed' (for extension filtering), 'grep' (for extension checking), and 'cp' (for file copying), but only bash, coreutils, and inotify-tools are included in the PATH. While coreutils provides cp, you should also add gnused and gnugrep to ensure the script has access to all required utilities on Linux systems.

Suggested change
pkgs.inotify-tools
pkgs.inotify-tools
pkgs.gnused
pkgs.gnugrep

Copilot uses AI. Check for mistakes.
]
}";
ExecStart = "${pkgs.bash}/bin/bash ${./sync.sh}";
Restart = "always";
RestartSec = 10;
};
Install = {
WantedBy = [ "default.target" ];
};
};
}
68 changes: 51 additions & 17 deletions home-manager/services/code-syncer/sync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@

# --- CONFIGURATION ---

# Base directories
VSCODE_USER_DIR="$HOME/Library/Application Support/Code/User"
VSCODE_INSIDERS_USER_DIR="$HOME/Library/Application Support/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$HOME/Library/Application Support/Antigravity/User"
CURSOR_USER_DIR="$HOME/Library/Application Support/Cursor/User"
WINDSURF_USER_DIR="$HOME/Library/Application Support/Windsurf/User"
# Detect OS
OS_TYPE="$(uname -s)"

# Base directories (OS-specific)
if [ "$OS_TYPE" = "Darwin" ]; then
VSCODE_USER_DIR="$HOME/Library/Application Support/Code/User"
VSCODE_INSIDERS_USER_DIR="$HOME/Library/Application Support/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$HOME/Library/Application Support/Antigravity/User"
CURSOR_USER_DIR="$HOME/Library/Application Support/Cursor/User"
WINDSURF_USER_DIR="$HOME/Library/Application Support/Windsurf/User"
else
# Linux/Other
VSCODE_USER_DIR="$HOME/.config/Code/User"
VSCODE_INSIDERS_USER_DIR="$HOME/.config/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$HOME/.config/Antigravity/User"
CURSOR_USER_DIR="$HOME/.config/Cursor/User"
WINDSURF_USER_DIR="$HOME/.config/Windsurf/User"
fi
Comment on lines +10 to +23

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a lot of repetition in defining the base directories for different operating systems. You can reduce this by defining a single base path variable depending on the OS and then constructing the full paths from it. This will make the script easier to maintain if you need to add more application paths in the future.

Suggested change
if [ "$OS_TYPE" = "Darwin" ]; then
VSCODE_USER_DIR="$HOME/Library/Application Support/Code/User"
VSCODE_INSIDERS_USER_DIR="$HOME/Library/Application Support/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$HOME/Library/Application Support/Antigravity/User"
CURSOR_USER_DIR="$HOME/Library/Application Support/Cursor/User"
WINDSURF_USER_DIR="$HOME/Library/Application Support/Windsurf/User"
else
# Linux/Other
VSCODE_USER_DIR="$HOME/.config/Code/User"
VSCODE_INSIDERS_USER_DIR="$HOME/.config/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$HOME/.config/Antigravity/User"
CURSOR_USER_DIR="$HOME/.config/Cursor/User"
WINDSURF_USER_DIR="$HOME/.config/Windsurf/User"
fi
if [ "$OS_TYPE" = "Darwin" ]; then
CONFIG_BASE_DIR="$HOME/Library/Application Support"
else
# Linux/Other
CONFIG_BASE_DIR="$HOME/.config"
fi
VSCODE_USER_DIR="$CONFIG_BASE_DIR/Code/User"
VSCODE_INSIDERS_USER_DIR="$CONFIG_BASE_DIR/Code - Insiders/User"
ANTIGRAVITY_USER_DIR="$CONFIG_BASE_DIR/Antigravity/User"
CURSOR_USER_DIR="$CONFIG_BASE_DIR/Cursor/User"
WINDSURF_USER_DIR="$CONFIG_BASE_DIR/Windsurf/User"


# Files
SETTINGS_FILE="settings.json"
Expand Down Expand Up @@ -94,14 +106,21 @@ clean_extension_list() {
cp "$input_source" "$clean_file"
fi

# Use appropriate sed syntax for OS
if [ "$OS_TYPE" = "Darwin" ]; then
SED_INPLACE="sed -i ''"

@cubic-dev-ai cubic-dev-ai Bot Dec 14, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Storing sed -i '' in a string variable and expanding it with $SED_INPLACE won't work correctly. The '' becomes literal quote characters, not an empty string argument. Use a bash array instead:

if [ "$OS_TYPE" = "Darwin" ]; then
  SED_INPLACE=(sed -i '')
else
  SED_INPLACE=(sed -i)
fi

Then invoke with "${SED_INPLACE[@]}" to preserve argument boundaries.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/services/code-syncer/sync.sh, line 111:

<comment>Storing `sed -i &#39;&#39;` in a string variable and expanding it with `$SED_INPLACE` won&#39;t work correctly. The `&#39;&#39;` becomes literal quote characters, not an empty string argument. Use a bash array instead:

```bash
if [ &quot;$OS_TYPE&quot; = &quot;Darwin&quot; ]; then
  SED_INPLACE=(sed -i &#39;&#39;)
else
  SED_INPLACE=(sed -i)
fi

Then invoke with &quot;${SED_INPLACE[@]}&quot; to preserve argument boundaries.

@@ -94,14 +106,21 @@ clean_extension_list() {
  • Use appropriate sed syntax for OS

  • if [ "$OS_TYPE" = "Darwin" ]; then
  • SED_INPLACE="sed -i ''"
  • else
  • SED_INPLACE="sed -i"
    </file context>

</details>

<a href="https://www.cubic.dev/action/fix/violation/0e062d72-4e68-40be-bd63-cd9a5881b1d7" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://cubic.dev/buttons/fix-with-cubic-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://cubic.dev/buttons/fix-with-cubic-light.svg">
    <img alt="Fix with Cubic" src="https://cubic.dev/buttons/fix-with-cubic-dark.svg">
  </picture>
</a>

Copilot AI Dec 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SED_INPLACE variable is incorrectly set for macOS. The syntax "sed -i ''" needs to be split into separate arguments when used with variable expansion. The current approach will result in sed receiving a single argument "sed -i ''" instead of "sed", "-i", and an empty string. This should be changed to use an array or invoke sed directly in each branch to handle the platform-specific syntax correctly.

Copilot uses AI. Check for mistakes.
else
SED_INPLACE="sed -i"
fi
Comment on lines +110 to +114

Copilot AI Dec 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SED_INPLACE variable contains the command name "sed" itself, which will cause command execution to fail. When $SED_INPLACE is expanded on lines 118 and 123, it will result in commands like "sed -i '' /$bad_ext/d", which treats "sed" as a command to find rather than executing sed. The variable should only contain the flag arguments (-i '' for macOS, -i for Linux), and sed should be invoked directly.

Copilot uses AI. Check for mistakes.

for bad_ext in "${PROPRIETARY_EXTENSIONS[@]}"; do
# Remove the line containing the bad extension
sed -i '' "/$bad_ext/d" "$clean_file"
$SED_INPLACE "/$bad_ext/d" "$clean_file"
done

for ai_ext in "${AI_EXTENSIONS[@]}"; do
# Remove the line containing the AI extension
sed -i '' "/$ai_ext/d" "$clean_file"
$SED_INPLACE "/$ai_ext/d" "$clean_file"
done
Comment on lines 116 to 124

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These two loops can be combined into one by first merging the two arrays of extensions. This improves readability and reduces code duplication. While the performance impact of multiple sed calls may be small, a single loop is cleaner. A further optimization would be to generate a single sed command to perform all deletions in one pass.

Suggested change
for bad_ext in "${PROPRIETARY_EXTENSIONS[@]}"; do
# Remove the line containing the bad extension
sed -i '' "/$bad_ext/d" "$clean_file"
$SED_INPLACE "/$bad_ext/d" "$clean_file"
done
for ai_ext in "${AI_EXTENSIONS[@]}"; do
# Remove the line containing the AI extension
sed -i '' "/$ai_ext/d" "$clean_file"
$SED_INPLACE "/$ai_ext/d" "$clean_file"
done
local extensions_to_remove=("${PROPRIETARY_EXTENSIONS[@]}" "${AI_EXTENSIONS[@]}")
for ext in "${extensions_to_remove[@]}"; do
# Remove the line containing the extension
$SED_INPLACE "/$ext/d" "$clean_file"
done

}

Expand Down Expand Up @@ -394,14 +413,29 @@ install_extensions "windsurf"

echo "Initial Sync Complete."

# 4. Watcher (Mac only)
if command -v fswatch >/dev/null; then
echo "Watching for changes in VS Code settings..."
fswatch -o "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" | while read num; do
sync_config_file "$SETTINGS_FILE"
sync_config_file "$KEYBINDINGS_FILE"
echo "Updated at $(date)"
done
# 4. Watcher (OS-specific)
if [ "$OS_TYPE" = "Darwin" ]; then
# macOS: use fswatch
if command -v fswatch >/dev/null; then
echo "Watching for changes in VS Code settings (macOS)..."
fswatch -o "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" | while read num; do
sync_config_file "$SETTINGS_FILE"
sync_config_file "$KEYBINDINGS_FILE"
echo "Updated at $(date)"
done
else
echo "fswatch not found. Auto-sync disabled."
fi
else
echo "fswatch not found. Auto-sync disabled."
# Linux: use inotifywait
if command -v inotifywait >/dev/null; then
echo "Watching for changes in VS Code settings (Linux)..."
inotifywait -m -e modify,create "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" 2>/dev/null | while read -r directory events filename; do
sync_config_file "$SETTINGS_FILE"
sync_config_file "$KEYBINDINGS_FILE"
echo "Updated at $(date)"
Comment on lines +433 to +436

Copilot AI Dec 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inotifywait command will exit with a non-zero status code if the watched files don't exist at startup. If the SETTINGS_FILE or KEYBINDINGS_FILE don't exist when the service starts, inotifywait will fail and the script will exit. Consider adding existence checks for these files before starting the watcher, or use the --quiet flag with inotifywait and handle the case where files might be created after the watcher starts.

Suggested change
inotifywait -m -e modify,create "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" 2>/dev/null | while read -r directory events filename; do
sync_config_file "$SETTINGS_FILE"
sync_config_file "$KEYBINDINGS_FILE"
echo "Updated at $(date)"
inotifywait -m -e modify,create "$VSCODE_USER_DIR" 2>/dev/null | while read -r directory events filename; do
if [ "$filename" = "$SETTINGS_FILE" ]; then
sync_config_file "$SETTINGS_FILE"
fi
if [ "$filename" = "$KEYBINDINGS_FILE" ]; then
sync_config_file "$KEYBINDINGS_FILE"
fi
if [ "$filename" = "$SETTINGS_FILE" ] || [ "$filename" = "$KEYBINDINGS_FILE" ]; then
echo "Updated at $(date)"
fi

Copilot uses AI. Check for mistakes.
done
else
echo "inotifywait not found. Auto-sync disabled."
fi
fi
Comment on lines +417 to 441

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The watcher logic currently re-syncs both settings.json and keybindings.json regardless of which one actually changed. Both fswatch and inotifywait can report the specific file that triggered the event. By using this information, you can make the sync more efficient by only processing the file that was modified.

For fswatch, you can remove the -o flag to get file paths. For inotifywait, the filename is already available in the while loop.

if [ "$OS_TYPE" = "Darwin" ]; then
  # macOS: use fswatch
  if command -v fswatch >/dev/null; then
    echo "Watching for changes in VS Code settings (macOS)..."
    fswatch "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" | while read -r path; do
      filename=$(basename "$path")
      sync_config_file "$filename"
      echo "Updated at $(date)"
    done
  else
    echo "fswatch not found. Auto-sync disabled."
  fi
else
  # Linux: use inotifywait
  if command -v inotifywait >/dev/null; then
    echo "Watching for changes in VS Code settings (Linux)..."
    inotifywait -m -e modify,create "$VSCODE_USER_DIR/$SETTINGS_FILE" "$VSCODE_USER_DIR/$KEYBINDINGS_FILE" 2>/dev/null | while read -r directory events filename; do
      if [ -n "$filename" ]; then
        sync_config_file "$filename"
        echo "Updated at $(date)"
      fi
    done
  else
    echo "inotifywait not found. Auto-sync disabled."
  fi
fi

8 changes: 6 additions & 2 deletions home-manager/services/dotfiles-updater/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ in
Type = "oneshot";
Environment = "PATH=${
lib.makeBinPath [
pkgs.git
pkgs.bash
pkgs.coreutils
pkgs.gnumake
pkgs.curl
pkgs.gawk
pkgs.git
pkgs.gnumake
pkgs.gnused
pkgs.nix
pkgs.sudo
pkgs.which
]
}";
Comment on lines 39 to 52

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -type f -name "update.sh" home-manager/services/dotfiles-updater/

Repository: shunkakinoki/dotfiles

Length of output: 235


🏁 Script executed:

fd --type f "update.sh" home-manager/services/dotfiles-updater/

Repository: shunkakinoki/dotfiles

Length of output: 113


🏁 Script executed:

cat -n home-manager/services/dotfiles-updater/update.sh

Repository: shunkakinoki/dotfiles

Length of output: 536


🏁 Script executed:

fd --type f "install.sh" home-manager/services/dotfiles-updater/

Repository: shunkakinoki/dotfiles

Length of output: 47


🏁 Script executed:

fd --type f "install.sh"

Repository: shunkakinoki/dotfiles

Length of output: 75


🏁 Script executed:

wc -l install.sh && head -100 install.sh

Repository: shunkakinoki/dotfiles

Length of output: 3808


🏁 Script executed:

tail -60 install.sh && echo "---" && rg -n "sudo" install.sh

Repository: shunkakinoki/dotfiles

Length of output: 2186


🏁 Script executed:

cat -n home-manager/services/dotfiles-updater/default.nix | head -60

Repository: shunkakinoki/dotfiles

Length of output: 1827


Remove sudo from the service PATH or document why it's necessary.

The sudo package is included in the systemd user service PATH, but examination of install.sh shows it's only used conditionally (line 136) to install make via apt-get if it's not already present. For a periodic update service, make should already be installed, making sudo unnecessary. Additionally, the macOS equivalent launchd.agents configuration omits sudo, suggesting it's not essential. Including sudo in a user service PATH presents a potential security consideration—if the update script is ever compromised, it could perform privileged operations. Either remove sudo from the PATH or document the security rationale for its inclusion.

ExecStart = "${./update.sh}";
Expand Down
4 changes: 2 additions & 2 deletions named-hosts/kyber/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ home-manager.lib.homeManagerConfiguration {
enable = true;
enableSshSupport = false;
pinentry.package = pkgs.pinentry-tty;
defaultCacheTtl = 1800;
maxCacheTtl = 7200;
defaultCacheTtl = 94608000; # 3 years
maxCacheTtl = 94608000; # 3 years
Comment on lines +137 to +138

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Setting the GPG agent cache TTL to 3 years (94608000 seconds) is a significant security risk. If this machine were compromised, an attacker would have access to your unlocked GPG key for an extremely long period. It is strongly recommended to use a much shorter TTL. The previous values (30 minutes and 2 hours) were much safer. If you need a longer duration for convenience, consider a value like one day (86400) instead.

          defaultCacheTtl = 1800;
          maxCacheTtl = 7200;

Comment on lines +137 to +138

Copilot AI Dec 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

services.gpg-agent is configured with defaultCacheTtl and maxCacheTtl set to 94,608,000 seconds (~3 years), which effectively keeps your GPG key passphrase cached and usable for an extremely long period once it has been entered. If an attacker gains access to this user account at any point while the agent is still running, they can sign or decrypt data with your GPG key without ever knowing the passphrase. Consider reducing these TTL values to a short duration (e.g., minutes or hours) so that long-lived server sessions do not leave the GPG key effectively unlocked for years.

Suggested change
defaultCacheTtl = 94608000; # 3 years
maxCacheTtl = 94608000; # 3 years
defaultCacheTtl = 600; # 10 minutes
maxCacheTtl = 7200; # 2 hours

Copilot uses AI. Check for mistakes.
};

# GPG_TTY is set in fish shell init instead of sessionVariables
Expand Down
67 changes: 50 additions & 17 deletions spec/code_syncer_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@ SCRIPT="$PWD/home-manager/services/code-syncer/sync.sh"
Describe 'VS Code CLI detection'
setup() {
TEMP_HOME=$(mktemp -d)
mkdir -p "$TEMP_HOME/Library/Application Support/Code/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User"
OS_TYPE="$(uname -s)"
if [ "$OS_TYPE" = "Darwin" ]; then
mkdir -p "$TEMP_HOME/Library/Application Support/Code/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User"
else
mkdir -p "$TEMP_HOME/.config/Code/User"
mkdir -p "$TEMP_HOME/.config/Cursor/User"
mkdir -p "$TEMP_HOME/.config/Windsurf/User"
mkdir -p "$TEMP_HOME/.config/Antigravity/User"
mkdir -p "$TEMP_HOME/.config/Code - Insiders/User"
fi
}
Comment on lines 8 to 24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The directory creation logic inside this setup function is repeated in other setup functions within this test file (e.g., lines 41-59 and 108-126). To improve maintainability and reduce code duplication, you could extract this logic into a shared helper function.

For example, you could define a function like _setup_test_dirs() at the top of the file and call it from each setup function.


cleanup() {
Expand All @@ -30,15 +39,24 @@ End

Describe 'extension filtering'
setup() {
mock_bin_setup code fswatch
mock_bin_setup code fswatch inotifywait
TEMP_HOME=$(mktemp -d)

# Create required directories
mkdir -p "$TEMP_HOME/Library/Application Support/Code/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User"
OS_TYPE="$(uname -s)"
if [ "$OS_TYPE" = "Darwin" ]; then
mkdir -p "$TEMP_HOME/Library/Application Support/Code/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User"
else
mkdir -p "$TEMP_HOME/.config/Code/User"
mkdir -p "$TEMP_HOME/.config/Cursor/User"
mkdir -p "$TEMP_HOME/.config/Windsurf/User"
mkdir -p "$TEMP_HOME/.config/Antigravity/User"
mkdir -p "$TEMP_HOME/.config/Code - Insiders/User"
fi

# Create mock VS Code CLI that lists extensions
cat >"$MOCK_BIN/code" <<'EOF'
Expand Down Expand Up @@ -88,20 +106,35 @@ End

Describe 'config file syncing'
setup() {
mock_bin_setup code fswatch cp
mock_bin_setup code fswatch cp inotifywait
TEMP_HOME=$(mktemp -d)

# Detect OS and create appropriate directories
OS_TYPE="$(uname -s)"
if [ "$OS_TYPE" = "Darwin" ]; then
VSCODE_DIR="$TEMP_HOME/Library/Application Support/Code/User"
VSCODE_INSIDERS_DIR="$TEMP_HOME/Library/Application Support/Code - Insiders/User"
CURSOR_DIR="$TEMP_HOME/Library/Application Support/Cursor/User"
WINDSURF_DIR="$TEMP_HOME/Library/Application Support/Windsurf/User"
ANTIGRAVITY_DIR="$TEMP_HOME/Library/Application Support/Antigravity/User"
else
VSCODE_DIR="$TEMP_HOME/.config/Code/User"
VSCODE_INSIDERS_DIR="$TEMP_HOME/.config/Code - Insiders/User"
CURSOR_DIR="$TEMP_HOME/.config/Cursor/User"
WINDSURF_DIR="$TEMP_HOME/.config/Windsurf/User"
ANTIGRAVITY_DIR="$TEMP_HOME/.config/Antigravity/User"
fi

# Create VS Code user directory with config files
VSCODE_DIR="$TEMP_HOME/Library/Application Support/Code/User"
mkdir -p "$VSCODE_DIR"
echo '{"editor.fontSize": 14}' >"$VSCODE_DIR/settings.json"
echo '[]' >"$VSCODE_DIR/keybindings.json"

# Create target directories
mkdir -p "$TEMP_HOME/Library/Application Support/Cursor/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Windsurf/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Antigravity/User"
mkdir -p "$TEMP_HOME/Library/Application Support/Code - Insiders/User"
mkdir -p "$CURSOR_DIR"
mkdir -p "$WINDSURF_DIR"
mkdir -p "$ANTIGRAVITY_DIR"
mkdir -p "$VSCODE_INSIDERS_DIR"

# Create code mock
cat >"$MOCK_BIN/code" <<'EOF'
Expand Down
Loading