vagrant-claude-sandbox 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +117 -22
- data/lib/docker/Dockerfile +33 -0
- data/lib/vagrant-claude-sandbox/command.rb +41 -0
- data/lib/vagrant-claude-sandbox/config.rb +97 -38
- data/lib/vagrant-claude-sandbox/path_fixer.rb +73 -0
- data/lib/vagrant-claude-sandbox/plugin.rb +10 -0
- data/lib/vagrant-claude-sandbox/version.rb +1 -1
- metadata +11 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a0c3f6d76bc6a8854641197815ae4e7a1b5685a322576d72969d8e00b82b39d7
|
|
4
|
+
data.tar.gz: 67eb291fdbefa65b04a48d684e89658955c7819d9f49df469a27d1b8b035cd38
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0da4554053ffc441c32e1f97e0be973aead1bc98b8a77d62956987b4f4f9413709e935c48731bea51740f52f20ef78f44331ca422ad86c3c082173776af26d68
|
|
7
|
+
data.tar.gz: bf1b40b5839f36a84180436c120af389eb7b3d92aadacf3172520e2f5b8ec01a4396230f7c237fb1450a79f0400ed171becf14716914fdc0be18d492d816641b
|
data/README.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Vagrant Claude Sandbox
|
|
2
2
|
|
|
3
|
-
A Vagrant plugin for running Claude Code in an isolated
|
|
3
|
+
A Vagrant plugin for running Claude Code in an isolated sandbox environment.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- Fast container-based sandbox using Docker
|
|
8
|
+
- Ubuntu 24.04 LTS with Node.js and git pre-installed
|
|
8
9
|
- Automatic Claude Code CLI installation
|
|
9
|
-
- Synced workspace folder and Claude config
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- Customizable VM resources
|
|
10
|
+
- Synced workspace folder and Claude config (plugins and skills work automatically)
|
|
11
|
+
- Customizable resources (memory, CPUs)
|
|
12
|
+
- Optional VirtualBox provider for full VM isolation
|
|
13
13
|
|
|
14
14
|
## Prerequisites
|
|
15
15
|
|
|
16
16
|
- [Vagrant](https://www.vagrantup.com/downloads) >= 2.2.0
|
|
17
|
-
- [
|
|
17
|
+
- [Docker](https://docs.docker.com/get-docker/) (default provider)
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
@@ -32,12 +32,17 @@ Vagrant.configure("2") do |config|
|
|
|
32
32
|
end
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Start the
|
|
35
|
+
Start the sandbox:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
vagrant up
|
|
39
|
-
vagrant
|
|
40
|
-
|
|
39
|
+
vagrant claude # Launch Claude CLI with Chrome integration
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Access a normal shell:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
vagrant ssh # Regular shell session
|
|
41
46
|
```
|
|
42
47
|
|
|
43
48
|
### Custom Configuration
|
|
@@ -52,31 +57,121 @@ Vagrant.configure("2") do |config|
|
|
|
52
57
|
end
|
|
53
58
|
```
|
|
54
59
|
|
|
60
|
+
### Mounting Additional Directories
|
|
61
|
+
|
|
62
|
+
Mount additional directories using Vagrant's `synced_folder` directive:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
Vagrant.configure("2") do |config|
|
|
66
|
+
config.claude_sandbox.apply_to!(config) do |sandbox|
|
|
67
|
+
sandbox.memory = 8192
|
|
68
|
+
sandbox.cpus = 4
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
config.vm.synced_folder "~/Projects/my-project", "/my-project"
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Note:** The workspace (`/agent-workspace`) and Claude config (`~/.claude/`) are mounted automatically.
|
|
76
|
+
|
|
55
77
|
### Options
|
|
56
78
|
|
|
57
79
|
| Option | Default | Description |
|
|
58
80
|
|--------|---------|-------------|
|
|
81
|
+
| `provider` | `"docker"` | Provider: `"docker"` or `"virtualbox"` |
|
|
59
82
|
| `memory` | `4096` | RAM in MB |
|
|
60
83
|
| `cpus` | `2` | Number of CPUs |
|
|
61
|
-
| `
|
|
62
|
-
| `workspace_path` | `"/agent-workspace"` | Workspace path in VM |
|
|
84
|
+
| `workspace_path` | `"/agent-workspace"` | Workspace path in container/VM |
|
|
63
85
|
| `claude_config_path` | `"~/.claude/"` | Host Claude config path |
|
|
64
|
-
| `skip_claude_cli_install` | `false` | Skip Claude CLI installation |
|
|
65
86
|
| `additional_packages` | `[]` | Extra apt packages |
|
|
87
|
+
| `skip_claude_cli_install` | `false` | Skip Claude CLI installation |
|
|
88
|
+
| `ubuntu_mirror` | `nil` | Ubuntu package mirror URL (uses official mirror by default) |
|
|
89
|
+
|
|
90
|
+
## VirtualBox Provider
|
|
91
|
+
|
|
92
|
+
For full VM isolation or Docker-in-Docker capabilities:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
Vagrant.configure("2") do |config|
|
|
96
|
+
config.claude_sandbox.provider = "virtualbox"
|
|
97
|
+
config.claude_sandbox.apply_to!(config)
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**When to use VirtualBox:**
|
|
102
|
+
- You need Docker available inside the sandbox
|
|
103
|
+
- You need full VM isolation (kernel-level)
|
|
104
|
+
- You're running on a system without Docker
|
|
66
105
|
|
|
67
|
-
|
|
106
|
+
**Prerequisites:**
|
|
107
|
+
- [VirtualBox](https://www.virtualbox.org/wiki/Downloads) >= 6.1
|
|
108
|
+
|
|
109
|
+
### Ubuntu Mirror Configuration
|
|
68
110
|
|
|
69
|
-
|
|
111
|
+
By default, the plugin uses Ubuntu's official mirror (`http://ports.ubuntu.com/ubuntu-ports`). If package updates are slow in your region, you can configure a faster mirror:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
Vagrant.configure("2") do |config|
|
|
115
|
+
# Choose a mirror close to your location for faster updates
|
|
116
|
+
config.claude_sandbox.ubuntu_mirror = "http://ftp.jaist.ac.jp/pub/Linux/ubuntu-ports" # Japan
|
|
117
|
+
config.claude_sandbox.apply_to!(config)
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Trusted mirrors for ARM (ubuntu-ports):**
|
|
122
|
+
- Official Ubuntu: `http://ports.ubuntu.com/ubuntu-ports` (default, safest)
|
|
123
|
+
- JAIST (Japan): `http://ftp.jaist.ac.jp/pub/Linux/ubuntu-ports` (university mirror)
|
|
124
|
+
- Kakao (Korea): `http://mirror.kakao.com/ubuntu-ports` (major tech company)
|
|
125
|
+
|
|
126
|
+
**Security note:** Only use mirrors from trusted sources. The official Ubuntu mirror is always the safest option.
|
|
127
|
+
|
|
128
|
+
## Development and Testing
|
|
129
|
+
|
|
130
|
+
### Running Tests
|
|
131
|
+
|
|
132
|
+
The project includes comprehensive unit and integration tests:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Install development dependencies
|
|
136
|
+
bundle install
|
|
70
137
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- Plugin paths are automatically updated from host paths to VM paths
|
|
138
|
+
# Run unit tests
|
|
139
|
+
bundle exec rake spec
|
|
74
140
|
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
- `~/.claude/plugins/known_marketplaces.json`
|
|
141
|
+
# Run integration tests
|
|
142
|
+
./test-plugin.sh docker --skip-extended # Quick test
|
|
78
143
|
|
|
79
|
-
|
|
144
|
+
# Run all tests
|
|
145
|
+
bundle exec rake test
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
See [TESTING.md](TESTING.md) for detailed testing instructions.
|
|
149
|
+
|
|
150
|
+
### Contributing
|
|
151
|
+
|
|
152
|
+
1. Fork the repository
|
|
153
|
+
2. Create a feature branch
|
|
154
|
+
3. Add tests for your changes
|
|
155
|
+
4. Ensure all tests pass: `bundle exec rake test`
|
|
156
|
+
5. Submit a pull request
|
|
157
|
+
|
|
158
|
+
## Troubleshooting
|
|
159
|
+
|
|
160
|
+
### Docker "Permission denied" Error
|
|
161
|
+
|
|
162
|
+
**This is now handled automatically by the plugin!**
|
|
163
|
+
|
|
164
|
+
The plugin automatically detects and fixes PATH conflicts that could cause "Permission denied" errors with the Docker provider. If you have a directory named `docker` in your PATH before the actual Docker executable, the plugin will reorder your PATH to prioritize common Docker binary locations.
|
|
165
|
+
|
|
166
|
+
You should see a message during `vagrant up` if a conflict was detected and fixed:
|
|
167
|
+
```
|
|
168
|
+
Detected Docker PATH conflict - automatically reordered PATH
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If you're still experiencing issues, you can manually fix the PATH as a fallback:
|
|
172
|
+
```bash
|
|
173
|
+
PATH=/usr/local/bin:$PATH vagrant up
|
|
174
|
+
```
|
|
80
175
|
|
|
81
176
|
## Credits
|
|
82
177
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
FROM ubuntu:24.04
|
|
2
|
+
|
|
3
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
4
|
+
|
|
5
|
+
# Install SSH and basic packages
|
|
6
|
+
RUN apt-get update && apt-get install -y \
|
|
7
|
+
openssh-server \
|
|
8
|
+
sudo \
|
|
9
|
+
curl \
|
|
10
|
+
git \
|
|
11
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
12
|
+
|
|
13
|
+
# Configure SSH
|
|
14
|
+
RUN mkdir /var/run/sshd
|
|
15
|
+
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
|
|
16
|
+
RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config
|
|
17
|
+
|
|
18
|
+
# Create vagrant user (Vagrant expects this)
|
|
19
|
+
RUN useradd -m -s /bin/bash vagrant && \
|
|
20
|
+
echo "vagrant:vagrant" | chpasswd && \
|
|
21
|
+
echo "vagrant ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
|
22
|
+
|
|
23
|
+
# Set up SSH key directory and install Vagrant insecure key
|
|
24
|
+
RUN mkdir -p /home/vagrant/.ssh && \
|
|
25
|
+
chmod 700 /home/vagrant/.ssh && \
|
|
26
|
+
curl -fsSL https://raw.githubusercontent.com/hashicorp/vagrant/main/keys/vagrant.pub \
|
|
27
|
+
-o /home/vagrant/.ssh/authorized_keys && \
|
|
28
|
+
chmod 600 /home/vagrant/.ssh/authorized_keys && \
|
|
29
|
+
chown -R vagrant:vagrant /home/vagrant/.ssh
|
|
30
|
+
|
|
31
|
+
EXPOSE 22
|
|
32
|
+
|
|
33
|
+
CMD ["/usr/sbin/sshd", "-D"]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module VagrantPlugins
|
|
2
|
+
module ClaudeSandbox
|
|
3
|
+
class Command < Vagrant.plugin("2", :command)
|
|
4
|
+
def self.synopsis
|
|
5
|
+
"SSH into the VM and launch Claude CLI"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def execute
|
|
9
|
+
options = {}
|
|
10
|
+
opts = OptionParser.new do |o|
|
|
11
|
+
o.banner = "Usage: vagrant claude [-- extra ssh args]"
|
|
12
|
+
o.separator ""
|
|
13
|
+
o.separator self.class.synopsis
|
|
14
|
+
o.separator ""
|
|
15
|
+
o.separator "This will SSH into the VM, cd to the workspace, and launch Claude CLI"
|
|
16
|
+
o.separator "with Chrome integration enabled."
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Parse the options
|
|
20
|
+
argv = parse_options(opts)
|
|
21
|
+
return if !argv
|
|
22
|
+
|
|
23
|
+
# Get the machine
|
|
24
|
+
with_target_vms(argv, single_target: true) do |machine|
|
|
25
|
+
# Get workspace path from config
|
|
26
|
+
config = machine.config.claude_sandbox
|
|
27
|
+
workspace_path = config.workspace_path || "/agent-workspace"
|
|
28
|
+
|
|
29
|
+
# Build the command to run
|
|
30
|
+
command = "cd #{workspace_path}; . ~/.nvm/nvm.sh && exec claude --dangerously-skip-permissions --chrome"
|
|
31
|
+
|
|
32
|
+
# Execute SSH with the command
|
|
33
|
+
machine.action(:ssh_run, ssh_run_command: command, ssh_opts: { extra_args: ["-t"] })
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Success
|
|
37
|
+
0
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -8,6 +8,9 @@ module VagrantPlugins
|
|
|
8
8
|
attr_accessor :claude_config_path
|
|
9
9
|
attr_accessor :skip_claude_cli_install
|
|
10
10
|
attr_accessor :additional_packages
|
|
11
|
+
attr_accessor :provider # "virtualbox" or "docker"
|
|
12
|
+
attr_accessor :docker_image # Docker image (default: build from Dockerfile)
|
|
13
|
+
attr_accessor :ubuntu_mirror # Ubuntu mirror URL (default: nil, uses official mirror)
|
|
11
14
|
|
|
12
15
|
def initialize
|
|
13
16
|
@memory = UNSET_VALUE
|
|
@@ -17,6 +20,9 @@ module VagrantPlugins
|
|
|
17
20
|
@claude_config_path = UNSET_VALUE
|
|
18
21
|
@skip_claude_cli_install = UNSET_VALUE
|
|
19
22
|
@additional_packages = UNSET_VALUE
|
|
23
|
+
@provider = UNSET_VALUE
|
|
24
|
+
@docker_image = UNSET_VALUE
|
|
25
|
+
@ubuntu_mirror = UNSET_VALUE
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def finalize!
|
|
@@ -27,6 +33,9 @@ module VagrantPlugins
|
|
|
27
33
|
@claude_config_path = File.expand_path("~/.claude/") if @claude_config_path == UNSET_VALUE
|
|
28
34
|
@skip_claude_cli_install = false if @skip_claude_cli_install == UNSET_VALUE
|
|
29
35
|
@additional_packages = [] if @additional_packages == UNSET_VALUE
|
|
36
|
+
@provider = "virtualbox" if @provider == UNSET_VALUE
|
|
37
|
+
@docker_image = nil if @docker_image == UNSET_VALUE
|
|
38
|
+
@ubuntu_mirror = nil if @ubuntu_mirror == UNSET_VALUE
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
def validate(machine)
|
|
@@ -44,6 +53,10 @@ module VagrantPlugins
|
|
|
44
53
|
errors << "additional_packages must be an array"
|
|
45
54
|
end
|
|
46
55
|
|
|
56
|
+
if @provider != UNSET_VALUE && !["virtualbox", "docker"].include?(@provider)
|
|
57
|
+
errors << "provider must be 'virtualbox' or 'docker'"
|
|
58
|
+
end
|
|
59
|
+
|
|
47
60
|
{ "Claude Sandbox" => errors }
|
|
48
61
|
end
|
|
49
62
|
|
|
@@ -52,9 +65,24 @@ module VagrantPlugins
|
|
|
52
65
|
# Ensure values are finalized before use
|
|
53
66
|
finalize!
|
|
54
67
|
|
|
55
|
-
#
|
|
56
|
-
root_config
|
|
68
|
+
# Common configuration
|
|
69
|
+
apply_common_config!(root_config)
|
|
70
|
+
|
|
71
|
+
# Always configure both providers
|
|
72
|
+
# Vagrant will choose the appropriate one based on:
|
|
73
|
+
# 1. --provider flag from command line
|
|
74
|
+
# 2. Existing .vagrant directory state
|
|
75
|
+
# 3. Default provider (VirtualBox)
|
|
76
|
+
apply_virtualbox_config!(root_config)
|
|
77
|
+
apply_docker_config!(root_config)
|
|
57
78
|
|
|
79
|
+
# Provisioning (with provider awareness)
|
|
80
|
+
apply_provisioning!(root_config)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def apply_common_config!(root_config)
|
|
58
86
|
# Configure synced folder for workspace
|
|
59
87
|
root_config.vm.synced_folder ".", @workspace_path,
|
|
60
88
|
create: true,
|
|
@@ -68,33 +96,70 @@ module VagrantPlugins
|
|
|
68
96
|
destination: "/tmp/claude-config"
|
|
69
97
|
end
|
|
70
98
|
|
|
71
|
-
# Configure
|
|
72
|
-
root_config.vm.
|
|
99
|
+
# Configure SSH port with auto-correction for conflicts
|
|
100
|
+
root_config.vm.network :forwarded_port, guest: 22, host: 2200, id: "ssh", auto_correct: true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def apply_virtualbox_config!(root_config)
|
|
104
|
+
root_config.vm.provider "virtualbox" do |vb, override|
|
|
105
|
+
# Set box only for VirtualBox provider
|
|
106
|
+
override.vm.box = @box
|
|
73
107
|
vb.memory = @memory
|
|
74
108
|
vb.cpus = @cpus
|
|
75
109
|
vb.customize ["modifyvm", :id, "--audio", "none"]
|
|
76
110
|
vb.customize ["modifyvm", :id, "--usb", "off"]
|
|
77
111
|
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def apply_docker_config!(root_config)
|
|
115
|
+
root_config.vm.provider "docker" do |d|
|
|
116
|
+
if @docker_image
|
|
117
|
+
d.image = @docker_image
|
|
118
|
+
else
|
|
119
|
+
d.build_dir = File.expand_path("../../docker", __FILE__)
|
|
120
|
+
end
|
|
121
|
+
d.has_ssh = true
|
|
122
|
+
d.remains_running = true
|
|
123
|
+
d.create_args = ["--memory=#{@memory}m", "--cpus=#{@cpus}"]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
78
126
|
|
|
79
|
-
|
|
127
|
+
def apply_provisioning!(root_config)
|
|
80
128
|
unless @skip_claude_cli_install
|
|
81
129
|
root_config.vm.provision "shell",
|
|
82
130
|
inline: generate_provision_script,
|
|
83
131
|
env: {"HOST_CLAUDE_PATH" => @claude_config_path}
|
|
84
132
|
end
|
|
85
|
-
|
|
86
|
-
# Configure SSH to auto-cd to workspace
|
|
87
|
-
root_config.ssh.extra_args = ["-t", "cd #{@workspace_path}; bash --login"]
|
|
88
133
|
end
|
|
89
134
|
|
|
90
|
-
private
|
|
91
|
-
|
|
92
135
|
def generate_provision_script
|
|
93
136
|
additional_packages = @additional_packages.join(" ")
|
|
137
|
+
skip_docker = @provider == "docker"
|
|
138
|
+
|
|
139
|
+
docker_install_script = skip_docker ? "" : <<-DOCKER
|
|
140
|
+
# Install Docker
|
|
141
|
+
if ! command -v docker &> /dev/null; then
|
|
142
|
+
echo "Installing Docker..."
|
|
143
|
+
curl -fsSL https://get.docker.com -o get-docker.sh
|
|
144
|
+
sh get-docker.sh
|
|
145
|
+
usermod -aG docker vagrant
|
|
146
|
+
rm get-docker.sh
|
|
147
|
+
else
|
|
148
|
+
echo "Docker already installed"
|
|
149
|
+
fi
|
|
150
|
+
DOCKER
|
|
151
|
+
|
|
152
|
+
mirror_config = @ubuntu_mirror ? <<-MIRROR
|
|
153
|
+
# Switch to faster Ubuntu mirror
|
|
154
|
+
echo "Configuring Ubuntu mirror: #{@ubuntu_mirror}"
|
|
155
|
+
sed -i 's|http://ports.ubuntu.com/ubuntu-ports|#{@ubuntu_mirror}|g' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true
|
|
156
|
+
sed -i 's|http://ports.ubuntu.com/ubuntu-ports|#{@ubuntu_mirror}|g' /etc/apt/sources.list 2>/dev/null || true
|
|
157
|
+
MIRROR
|
|
158
|
+
: ""
|
|
94
159
|
|
|
95
160
|
script = <<-SHELL
|
|
96
161
|
set -e
|
|
97
|
-
|
|
162
|
+
#{mirror_config}
|
|
98
163
|
echo "Updating package lists..."
|
|
99
164
|
apt-get update
|
|
100
165
|
|
|
@@ -109,30 +174,33 @@ module VagrantPlugins
|
|
|
109
174
|
unzip \
|
|
110
175
|
#{additional_packages}
|
|
111
176
|
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
177
|
+
#{docker_install_script}
|
|
178
|
+
|
|
179
|
+
# Install nvm for the vagrant user
|
|
180
|
+
if [ ! -d "/home/vagrant/.nvm" ]; then
|
|
181
|
+
echo "Installing nvm..."
|
|
182
|
+
# Install nvm as vagrant user
|
|
183
|
+
sudo -u vagrant bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash'
|
|
184
|
+
|
|
185
|
+
# Load nvm in this script
|
|
186
|
+
export NVM_DIR="/home/vagrant/.nvm"
|
|
187
|
+
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
|
122
188
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
127
|
-
apt-get install -y nodejs
|
|
189
|
+
# Install Node.js LTS version
|
|
190
|
+
echo "Installing Node.js LTS via nvm..."
|
|
191
|
+
sudo -u vagrant bash -c '. /home/vagrant/.nvm/nvm.sh && nvm install --lts && nvm use --lts'
|
|
128
192
|
else
|
|
129
|
-
echo "
|
|
193
|
+
echo "nvm already installed"
|
|
130
194
|
fi
|
|
131
195
|
|
|
196
|
+
# Ensure nvm is loaded for subsequent commands
|
|
197
|
+
export NVM_DIR="/home/vagrant/.nvm"
|
|
198
|
+
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
|
199
|
+
|
|
132
200
|
# Install Claude Code CLI
|
|
133
|
-
if ! command -v claude &> /dev/null; then
|
|
201
|
+
if ! sudo -u vagrant bash -c '. /home/vagrant/.nvm/nvm.sh && command -v claude' &> /dev/null; then
|
|
134
202
|
echo "Installing Claude Code CLI..."
|
|
135
|
-
npm install -g @anthropic-ai/claude-code --no-audit
|
|
203
|
+
sudo -u vagrant bash -c '. /home/vagrant/.nvm/nvm.sh && npm install -g @anthropic-ai/claude-code --no-audit'
|
|
136
204
|
else
|
|
137
205
|
echo "Claude Code CLI already installed"
|
|
138
206
|
fi
|
|
@@ -155,16 +223,7 @@ module VagrantPlugins
|
|
|
155
223
|
echo "Claude plugins and skills loaded successfully!"
|
|
156
224
|
fi
|
|
157
225
|
|
|
158
|
-
# Create claude-yolo wrapper
|
|
159
|
-
echo "Creating claude-yolo command..."
|
|
160
|
-
cat > /usr/local/bin/claude-yolo << 'EOF'
|
|
161
|
-
#!/bin/bash
|
|
162
|
-
claude --dangerously-skip-permissions "$@"
|
|
163
|
-
EOF
|
|
164
|
-
chmod +x /usr/local/bin/claude-yolo
|
|
165
|
-
|
|
166
226
|
echo "Claude sandbox environment setup complete!"
|
|
167
|
-
echo "You can now run 'claude-yolo' to start Claude Code with permissions disabled"
|
|
168
227
|
SHELL
|
|
169
228
|
|
|
170
229
|
script
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module VagrantPlugins
|
|
2
|
+
module ClaudeSandbox
|
|
3
|
+
class PathFixer
|
|
4
|
+
def self.fix_docker_path!
|
|
5
|
+
# Always check for PATH conflicts and fix them
|
|
6
|
+
# This is necessary because commands like 'vagrant destroy' don't have --provider flag
|
|
7
|
+
# but still need the correct PATH to interact with Docker containers
|
|
8
|
+
|
|
9
|
+
# Check if there's a PATH conflict
|
|
10
|
+
path_dirs = ENV['PATH'].split(':')
|
|
11
|
+
docker_binary_path = find_docker_binary
|
|
12
|
+
|
|
13
|
+
return unless docker_binary_path
|
|
14
|
+
|
|
15
|
+
docker_dir = File.dirname(docker_binary_path)
|
|
16
|
+
|
|
17
|
+
# Check if there's a directory named 'docker' appearing before the real docker binary
|
|
18
|
+
conflict_detected = false
|
|
19
|
+
path_dirs.each_with_index do |dir, index|
|
|
20
|
+
# If we find the real docker directory, stop checking
|
|
21
|
+
break if dir == docker_dir
|
|
22
|
+
|
|
23
|
+
# Check if this directory has a 'docker' subdirectory or file that would conflict
|
|
24
|
+
potential_conflict = File.join(dir, 'docker')
|
|
25
|
+
if File.exist?(potential_conflict) && File.directory?(potential_conflict)
|
|
26
|
+
conflict_detected = true
|
|
27
|
+
break
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if conflict_detected
|
|
32
|
+
# Reorder PATH to put common Docker binary locations first
|
|
33
|
+
prioritized_paths = ['/usr/local/bin', '/usr/bin', docker_dir].uniq
|
|
34
|
+
other_paths = path_dirs - prioritized_paths
|
|
35
|
+
new_path = (prioritized_paths + other_paths).join(':')
|
|
36
|
+
|
|
37
|
+
ENV['PATH'] = new_path
|
|
38
|
+
# Only show message for commands that actually use Docker
|
|
39
|
+
if using_docker_related_command?
|
|
40
|
+
puts "Detected Docker PATH conflict - automatically reordered PATH"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def self.using_docker_related_command?
|
|
48
|
+
# Check if this is a Docker-related command
|
|
49
|
+
ARGV.include?('--provider=docker') ||
|
|
50
|
+
ARGV.include?('--provider docker') ||
|
|
51
|
+
ENV['VAGRANT_DEFAULT_PROVIDER'] == 'docker' ||
|
|
52
|
+
ARGV.include?('up') ||
|
|
53
|
+
ARGV.include?('destroy') ||
|
|
54
|
+
ARGV.include?('halt') ||
|
|
55
|
+
ARGV.include?('reload') ||
|
|
56
|
+
ARGV.include?('ssh')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.find_docker_binary
|
|
60
|
+
# Try common Docker installation paths
|
|
61
|
+
['/usr/local/bin/docker', '/usr/bin/docker', '/opt/homebrew/bin/docker'].each do |path|
|
|
62
|
+
return path if File.executable?(path)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Fall back to using 'which' if available
|
|
66
|
+
result = `which docker 2>/dev/null`.strip
|
|
67
|
+
result.empty? ? nil : result
|
|
68
|
+
rescue
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
require_relative "path_fixer"
|
|
2
|
+
|
|
3
|
+
# Fix Docker PATH issues immediately when plugin loads (before Vagrant initialization)
|
|
4
|
+
VagrantPlugins::ClaudeSandbox::PathFixer.fix_docker_path!
|
|
5
|
+
|
|
1
6
|
module VagrantPlugins
|
|
2
7
|
module ClaudeSandbox
|
|
3
8
|
class Plugin < Vagrant.plugin("2")
|
|
@@ -8,6 +13,11 @@ module VagrantPlugins
|
|
|
8
13
|
require_relative "config"
|
|
9
14
|
Config
|
|
10
15
|
end
|
|
16
|
+
|
|
17
|
+
command "claude" do
|
|
18
|
+
require_relative "command"
|
|
19
|
+
Command
|
|
20
|
+
end
|
|
11
21
|
end
|
|
12
22
|
end
|
|
13
23
|
end
|
metadata
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vagrant-claude-sandbox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bero
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: rake
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '13.0'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '13.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: rspec
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '3.12'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '3.12'
|
|
41
41
|
description: Provides a pre-configured sandbox environment for running Claude Code
|
|
42
42
|
in an isolated VM with full plugin and skills support
|
|
43
43
|
email:
|
|
@@ -47,8 +47,11 @@ extra_rdoc_files: []
|
|
|
47
47
|
files:
|
|
48
48
|
- LICENSE
|
|
49
49
|
- README.md
|
|
50
|
+
- lib/docker/Dockerfile
|
|
50
51
|
- lib/vagrant-claude-sandbox.rb
|
|
52
|
+
- lib/vagrant-claude-sandbox/command.rb
|
|
51
53
|
- lib/vagrant-claude-sandbox/config.rb
|
|
54
|
+
- lib/vagrant-claude-sandbox/path_fixer.rb
|
|
52
55
|
- lib/vagrant-claude-sandbox/plugin.rb
|
|
53
56
|
- lib/vagrant-claude-sandbox/version.rb
|
|
54
57
|
homepage: https://github.com/bgrgicak/vagrant-claude-sandbox
|