agent-dev-env 0.1.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.
- package/LICENSE +21 -0
- package/dist/assets/bridge/bridge.js +202 -0
- package/dist/assets/guest/guest-agent-mac.js +586 -0
- package/dist/assets/guest/guest-agent-ubuntu.js +481 -0
- package/dist/assets/guest/guest-agent-windows.js +466 -0
- package/dist/assets/images/mac/CHANGELOG.md +265 -0
- package/dist/assets/images/mac/README.md +63 -0
- package/dist/assets/images/mac/sandbox.pkr.hcl +468 -0
- package/dist/assets/images/mac/vars/sandbox-macos-tahoe.pkrvars.hcl +39 -0
- package/dist/assets/images/ubuntu-arm64-vmware/CHANGELOG.md +239 -0
- package/dist/assets/images/ubuntu-arm64-vmware/README.md +177 -0
- package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/meta-data +2 -0
- package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/user-data +34 -0
- package/dist/assets/images/ubuntu-arm64-vmware/sandbox.pkr.hcl +776 -0
- package/dist/assets/images/ubuntu-arm64-vmware/vars/sandbox-ubuntu-24-04-arm64-vmware.pkrvars.hcl +71 -0
- package/dist/assets/images/windows-arm64-qemu/CHANGELOG.md +209 -0
- package/dist/assets/images/windows-arm64-qemu/README.md +142 -0
- package/dist/assets/images/windows-arm64-qemu/autounattend.xml +325 -0
- package/dist/assets/images/windows-arm64-qemu/qemu-with-tpm.sh +170 -0
- package/dist/assets/images/windows-arm64-qemu/sandbox.pkr.hcl +1012 -0
- package/dist/assets/images/windows-arm64-qemu/vars/sandbox-windows-11-arm64-qemu.pkrvars.hcl +83 -0
- package/dist/assets/images/windows-arm64-vmware/CHANGELOG.md +270 -0
- package/dist/assets/images/windows-arm64-vmware/README.md +171 -0
- package/dist/assets/images/windows-arm64-vmware/autounattend.xml +311 -0
- package/dist/assets/images/windows-arm64-vmware/sandbox.pkr.hcl +1036 -0
- package/dist/assets/images/windows-arm64-vmware/vars/sandbox-windows-11-arm64-vmware.pkrvars.hcl +83 -0
- package/dist/assets/rules/agent-rules-linux.md +68 -0
- package/dist/assets/rules/agent-rules.md +71 -0
- package/dist/assets/watchdog/watch-build-ocr.swift +40 -0
- package/dist/assets/watchdog/watch-build.py +275 -0
- package/dist/cli.js +52 -0
- package/dist/commands/delete.js +179 -0
- package/dist/commands/doctor.js +165 -0
- package/dist/commands/list.js +38 -0
- package/dist/commands/not-yet.js +15 -0
- package/dist/commands/register.js +150 -0
- package/dist/commands/run.js +65 -0
- package/dist/commands/status.js +142 -0
- package/dist/commands/stop.js +186 -0
- package/dist/commands/sync.js +98 -0
- package/dist/lib/exec.js +250 -0
- package/dist/lib/ghcr.js +82 -0
- package/dist/lib/git.js +100 -0
- package/dist/lib/logger.js +87 -0
- package/dist/lib/network.js +63 -0
- package/dist/lib/paths.js +116 -0
- package/dist/lib/platform.js +87 -0
- package/dist/lib/prompt.js +66 -0
- package/dist/lib/qemu.js +373 -0
- package/dist/lib/regex.js +9 -0
- package/dist/lib/ssh.js +230 -0
- package/dist/lib/tart.js +210 -0
- package/dist/lib/template.js +35 -0
- package/dist/lib/vars.js +99 -0
- package/dist/lib/vmrun.js +334 -0
- package/dist/lifecycle/build-macos.js +23 -0
- package/dist/lifecycle/build-qemu.js +204 -0
- package/dist/lifecycle/build-shared.js +355 -0
- package/dist/lifecycle/build-ubuntu.js +184 -0
- package/dist/lifecycle/build-watchdog.js +146 -0
- package/dist/lifecycle/build-windows-vmware.js +112 -0
- package/dist/lifecycle/build.js +55 -0
- package/dist/lifecycle/catalog.js +165 -0
- package/dist/lifecycle/deploy.js +161 -0
- package/dist/lifecycle/tag.js +77 -0
- package/dist/lifecycle/watch-build.js +64 -0
- package/dist/runners/bridges.js +153 -0
- package/dist/runners/framework.js +66 -0
- package/dist/runners/macos-bridges.js +143 -0
- package/dist/runners/macos-guest.js +76 -0
- package/dist/runners/macos-rules.js +77 -0
- package/dist/runners/macos-summary.js +145 -0
- package/dist/runners/macos.js +258 -0
- package/dist/runners/openchamber.js +60 -0
- package/dist/runners/options.js +56 -0
- package/dist/runners/qemu-image.js +183 -0
- package/dist/runners/rules.js +49 -0
- package/dist/runners/ubuntu-bridges.js +154 -0
- package/dist/runners/ubuntu-guest.js +136 -0
- package/dist/runners/ubuntu-image.js +26 -0
- package/dist/runners/ubuntu-rules.js +86 -0
- package/dist/runners/ubuntu-shared.js +65 -0
- package/dist/runners/ubuntu-summary.js +141 -0
- package/dist/runners/ubuntu.js +117 -0
- package/dist/runners/vmware-common.js +158 -0
- package/dist/runners/vmware-image.js +242 -0
- package/dist/runners/windows-autologon.js +119 -0
- package/dist/runners/windows-bridges.js +136 -0
- package/dist/runners/windows-guest.js +213 -0
- package/dist/runners/windows-image.js +23 -0
- package/dist/runners/windows-qemu-summary.js +85 -0
- package/dist/runners/windows-qemu.js +189 -0
- package/dist/runners/windows-shared.js +68 -0
- package/dist/runners/windows-summary.js +104 -0
- package/dist/runners/windows.js +96 -0
- package/dist/settings/common.js +107 -0
- package/dist/settings/macos-copy.js +223 -0
- package/dist/settings/macos.js +41 -0
- package/dist/settings/ubuntu-copy.js +223 -0
- package/dist/settings/ubuntu.js +68 -0
- package/package.json +52 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
packer {
|
|
2
|
+
required_plugins {
|
|
3
|
+
tart = {
|
|
4
|
+
version = ">= 1.20.0"
|
|
5
|
+
source = "github.com/cirruslabs/tart"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
# ===== Variables =====
|
|
11
|
+
#
|
|
12
|
+
# Each sandbox image is a single macOS version, described by a variables file
|
|
13
|
+
# in vars/ named after the image (`sandbox-macos-<macos-version>`). See
|
|
14
|
+
# DEVELOPMENT.md for how to add a new macOS version.
|
|
15
|
+
|
|
16
|
+
variable "macos_version" {
|
|
17
|
+
type = string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
variable "xcode_version" {
|
|
21
|
+
type = string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
variable "disk_size" {
|
|
25
|
+
type = number
|
|
26
|
+
default = 160
|
|
27
|
+
# VM disk size in GB. Must be >= the Cirrus base image disk (140 GB): tart
|
|
28
|
+
# can only grow a disk, never shrink it.
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
variable "cpu_count" {
|
|
32
|
+
type = number
|
|
33
|
+
default = 4
|
|
34
|
+
# CPU count of the VM.
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
variable "memory_gb" {
|
|
38
|
+
type = number
|
|
39
|
+
default = 8
|
|
40
|
+
# RAM of the VM in GB.
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
variable "ssh_username" {
|
|
44
|
+
type = string
|
|
45
|
+
default = "admin"
|
|
46
|
+
# SSH user used for provisioning (fixed in the Cirrus Labs base images).
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
variable "ssh_password" {
|
|
50
|
+
type = string
|
|
51
|
+
default = "admin"
|
|
52
|
+
# SSH password used for provisioning (fixed in the Cirrus Labs base images).
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
variable "openchamber_ui_password" {
|
|
56
|
+
type = string
|
|
57
|
+
default = "sandbox"
|
|
58
|
+
# Password protecting the OpenChamber web UI. OpenChamber refuses to bind
|
|
59
|
+
# the server to a network interface without a UI password; the sandbox
|
|
60
|
+
# listens on 0.0.0.0:<openchamber_port> so the host can reach it (see
|
|
61
|
+
# docs/macos.md).
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
variable "openchamber_port" {
|
|
65
|
+
type = number
|
|
66
|
+
default = 4000
|
|
67
|
+
# TCP port the OpenChamber web UI listens on inside the guest. Not 3000 —
|
|
68
|
+
# that is the default Vite dev-server port and would collide with frontend
|
|
69
|
+
# dev servers in the guest. The CLI's SANDBOX_OPENCHAMBER_PORT default
|
|
70
|
+
# (lib/platform.ts) must stay in sync with this.
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
variable "image_version" {
|
|
74
|
+
type = string
|
|
75
|
+
# Semantic version this image is published under; bump it and add a
|
|
76
|
+
# CHANGELOG.md entry for every release.
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
variable "node_version" {
|
|
80
|
+
type = string
|
|
81
|
+
# Node.js version installed via nvm and set as the default (see the
|
|
82
|
+
# "Node.js via nvm" provisioner below).
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
variable "python_version" {
|
|
86
|
+
type = string
|
|
87
|
+
# Homebrew Python version, e.g. "3.14"; also used for the unversioned
|
|
88
|
+
# python/python3/pip/pip3 aliases.
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
variable "brew_formulas" {
|
|
92
|
+
type = list(string)
|
|
93
|
+
default = [
|
|
94
|
+
# Core CLI tools
|
|
95
|
+
"bash", "git", "gh", "jq", "ripgrep", "coreutils", "curl", "wget",
|
|
96
|
+
# SSH agent bridging (docs/ssh-agent.md)
|
|
97
|
+
"socat",
|
|
98
|
+
# Node.js version manager (Keg-only; the Node runtime itself is installed
|
|
99
|
+
# via nvm — see the "Node.js via nvm" provisioner below)
|
|
100
|
+
"nvm",
|
|
101
|
+
# The required programming languages (Python is installed separately by
|
|
102
|
+
# the toolchain provisioner, pinned via python_version)
|
|
103
|
+
"ruby",
|
|
104
|
+
# Docker CLI + plugins (client only — the sandbox is a macOS VM and cannot
|
|
105
|
+
# run a local container engine, see docs/macos.md "Docker (remote engine)";
|
|
106
|
+
# the compose/buildx plugins are wired up in the provisioner below)
|
|
107
|
+
"docker", "docker-compose", "docker-buildx",
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
variable "extra_brew_formulas" {
|
|
112
|
+
type = list(string)
|
|
113
|
+
default = []
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# ===== Builder =====
|
|
117
|
+
#
|
|
118
|
+
# Derives the sandbox VM from Cirrus Labs' pre-built macOS image with Xcode.
|
|
119
|
+
# The base images are published to GHCR, see:
|
|
120
|
+
# https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos-
|
|
121
|
+
#
|
|
122
|
+
# The resulting VM boots to a desktop with auto-login enabled and can be used
|
|
123
|
+
# both with graphics (tart run) and headless (tart run --no-graphics).
|
|
124
|
+
#
|
|
125
|
+
# Audio pass-through to the host (guest sound to host speakers, host
|
|
126
|
+
# microphone to the guest) is a per-run Tart flag, not a persisted VM
|
|
127
|
+
# setting — the sandbox stays audio-isolated from the host by running with
|
|
128
|
+
# `tart run --no-audio` (see docs/macos.md). The build honors the same
|
|
129
|
+
# policy via run_extra_args.
|
|
130
|
+
|
|
131
|
+
source "tart-cli" "tart" {
|
|
132
|
+
vm_base_name = "ghcr.io/cirruslabs/macos-${var.macos_version}-xcode:${var.xcode_version}"
|
|
133
|
+
# The image name is fixed per macOS version: sandbox-macos-<macos-version>.
|
|
134
|
+
# The Xcode version selects the base image only and is not part of the name.
|
|
135
|
+
vm_name = "sandbox-macos-${var.macos_version}"
|
|
136
|
+
cpu_count = var.cpu_count
|
|
137
|
+
memory_gb = var.memory_gb
|
|
138
|
+
disk_size_gb = var.disk_size
|
|
139
|
+
headless = true
|
|
140
|
+
ssh_password = var.ssh_password
|
|
141
|
+
ssh_username = var.ssh_username
|
|
142
|
+
ssh_timeout = "120s"
|
|
143
|
+
# No audio pass-through with the host during the build either (Tart attaches
|
|
144
|
+
# the VirtIO sound device even when running headless).
|
|
145
|
+
run_extra_args = ["--no-audio"]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# ===== Provisioners =====
|
|
149
|
+
|
|
150
|
+
build {
|
|
151
|
+
sources = ["source.tart-cli.tart"]
|
|
152
|
+
|
|
153
|
+
# Base system setup: Xcode license, SSH + Screen Sharing (for tart run --vnc),
|
|
154
|
+
# auto-login as admin (boots straight into the desktop and creates an
|
|
155
|
+
# unlocked login.keychain, which is required for headless VMs on macOS 15+).
|
|
156
|
+
provisioner "shell" {
|
|
157
|
+
inline = [<<-END
|
|
158
|
+
set -e -x
|
|
159
|
+
# Xcode (already pre-installed in the Cirrus Labs base image)
|
|
160
|
+
sudo xcodebuild -license accept || true
|
|
161
|
+
sudo xcode-select -p || true
|
|
162
|
+
|
|
163
|
+
# Remote Login (SSH) and Screen Sharing (VNC) — used by `tart run --vnc`
|
|
164
|
+
# and by `tart ip`-based SSH from the host.
|
|
165
|
+
sudo systemsetup -setremotelogin on || true
|
|
166
|
+
sudo launchctl enable system/com.apple.screensharing || true
|
|
167
|
+
sudo launchctl kickstart -k system/com.apple.screensharing || true
|
|
168
|
+
|
|
169
|
+
# Auto-login as admin: boot lands straight on the desktop.
|
|
170
|
+
sudo sysadminctl -autologin set -userName admin -password admin || true
|
|
171
|
+
|
|
172
|
+
# Friendly hostname for the VM
|
|
173
|
+
sudo scutil --set ComputerName "Agent Sandbox" || true
|
|
174
|
+
sudo scutil --set HostName "agent-sandbox" || true
|
|
175
|
+
sudo scutil --set LocalHostName "agent-sandbox" || true
|
|
176
|
+
|
|
177
|
+
# Tart Guest Agent (pre-installed in Cirrus base images) powers clipboard
|
|
178
|
+
# sharing in GUI mode and `tart exec`. Check that it is present.
|
|
179
|
+
if pgrep -x tart-guest-agent >/dev/null; then
|
|
180
|
+
echo "tart-guest-agent: OK"
|
|
181
|
+
else
|
|
182
|
+
echo "tart-guest-agent: MISSING" >&2
|
|
183
|
+
fi
|
|
184
|
+
END
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Homebrew toolchain: nvm (Node version manager), python, ruby and CLI
|
|
189
|
+
# utilities. Node.js itself is installed via nvm in the provisioner below.
|
|
190
|
+
provisioner "shell" {
|
|
191
|
+
inline = [<<-END
|
|
192
|
+
set -e -x
|
|
193
|
+
touch ~/.zprofile
|
|
194
|
+
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
195
|
+
|
|
196
|
+
brew update
|
|
197
|
+
brew install python@${var.python_version}
|
|
198
|
+
brew install ${join(" ", concat(var.brew_formulas, var.extra_brew_formulas))}
|
|
199
|
+
|
|
200
|
+
# Make Homebrew available to non-interactive shells
|
|
201
|
+
grep -qxF 'eval "$(/opt/homebrew/bin/brew shellenv)"' ~/.zprofile || \
|
|
202
|
+
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
|
|
203
|
+
|
|
204
|
+
# Unversioned python/pip aliases pointing at brew's python@${var.python_version}
|
|
205
|
+
sudo ln -sf /opt/homebrew/bin/python${var.python_version} /opt/homebrew/bin/python3
|
|
206
|
+
sudo ln -sf /opt/homebrew/bin/python${var.python_version} /opt/homebrew/bin/python
|
|
207
|
+
sudo ln -sf /opt/homebrew/bin/pip${var.python_version} /opt/homebrew/bin/pip3
|
|
208
|
+
sudo ln -sf /opt/homebrew/bin/pip${var.python_version} /opt/homebrew/bin/pip
|
|
209
|
+
|
|
210
|
+
source ~/.zprofile
|
|
211
|
+
python3 --version && pip3 --version
|
|
212
|
+
ruby --version
|
|
213
|
+
END
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Node.js via nvm — brew's nvm formula is keg-only, so we wire it into
|
|
218
|
+
# ~/.zprofile and install the node_version from the vars file as the
|
|
219
|
+
# default version for both interactive and non-interactive shells.
|
|
220
|
+
provisioner "shell" {
|
|
221
|
+
inline = [<<-END
|
|
222
|
+
set -e -x
|
|
223
|
+
# Load nvm in every shell (brew's nvm is keg-only). nvm use default picks the
|
|
224
|
+
# alias created below; the || true keeps non-interactive shells happy before
|
|
225
|
+
# the default alias exists.
|
|
226
|
+
grep -qxF 'export NVM_DIR="$HOME/.nvm"' ~/.zprofile || \
|
|
227
|
+
cat >> ~/.zprofile <<'NVM'
|
|
228
|
+
export NVM_DIR="$HOME/.nvm"
|
|
229
|
+
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
|
|
230
|
+
nvm use default >/dev/null 2>&1 || true
|
|
231
|
+
NVM
|
|
232
|
+
|
|
233
|
+
source ~/.zprofile
|
|
234
|
+
nvm install ${var.node_version}
|
|
235
|
+
nvm alias default ${var.node_version}
|
|
236
|
+
|
|
237
|
+
node --version && npm --version
|
|
238
|
+
nvm --version
|
|
239
|
+
END
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
# Visual Studio Code
|
|
244
|
+
provisioner "shell" {
|
|
245
|
+
inline = [<<-END
|
|
246
|
+
set -e -x
|
|
247
|
+
source ~/.zprofile
|
|
248
|
+
curl -fsSL -o /tmp/vscode.zip "https://update.code.visualstudio.com/latest/darwin-universal/stable"
|
|
249
|
+
unzip -q /tmp/vscode.zip -d /tmp/vscode
|
|
250
|
+
sudo rm -rf "/Applications/Visual Studio Code.app"
|
|
251
|
+
sudo mv "/tmp/vscode/Visual Studio Code.app" /Applications/
|
|
252
|
+
rm -rf /tmp/vscode /tmp/vscode.zip
|
|
253
|
+
|
|
254
|
+
# Drop the quarantine attribute so the app launches without Gatekeeper prompts
|
|
255
|
+
sudo xattr -dr com.apple.quarantine "/Applications/Visual Studio Code.app" || true
|
|
256
|
+
|
|
257
|
+
# `code` CLI on PATH
|
|
258
|
+
sudo ln -sf "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" /opt/homebrew/bin/code
|
|
259
|
+
|
|
260
|
+
code --version
|
|
261
|
+
END
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Browsers — Google Chrome and Mozilla Firefox (latest stable universal
|
|
266
|
+
# macOS builds, via Homebrew casks). Quarantine is stripped explicitly so
|
|
267
|
+
# they launch without Gatekeeper prompts (the VM boots straight to the
|
|
268
|
+
# desktop and may run headless; same choice as the xattr call for VS Code
|
|
269
|
+
# above — brew's own --no-quarantine flag was removed in newer Homebrew).
|
|
270
|
+
provisioner "shell" {
|
|
271
|
+
inline = [<<-END
|
|
272
|
+
set -e -x
|
|
273
|
+
source ~/.zprofile
|
|
274
|
+
brew install --cask google-chrome firefox
|
|
275
|
+
|
|
276
|
+
# Drop the quarantine attribute so the apps launch without Gatekeeper prompts
|
|
277
|
+
sudo xattr -dr com.apple.quarantine "/Applications/Google Chrome.app" || true
|
|
278
|
+
sudo xattr -dr com.apple.quarantine "/Applications/Firefox.app" || true
|
|
279
|
+
|
|
280
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --version
|
|
281
|
+
"/Applications/Firefox.app/Contents/MacOS/firefox" --version
|
|
282
|
+
END
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# Sublime Text — the text editor (Homebrew cask, current stable build).
|
|
287
|
+
# The cask also links the `subl` CLI into the Homebrew bin dir.
|
|
288
|
+
provisioner "shell" {
|
|
289
|
+
inline = [<<-END
|
|
290
|
+
set -e -x
|
|
291
|
+
source ~/.zprofile
|
|
292
|
+
brew install --cask sublime-text
|
|
293
|
+
|
|
294
|
+
# Drop the quarantine attribute so the app launches without Gatekeeper prompts
|
|
295
|
+
sudo xattr -dr com.apple.quarantine "/Applications/Sublime Text.app" || true
|
|
296
|
+
|
|
297
|
+
"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" --version
|
|
298
|
+
END
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# OpenCode — the AI coding agent
|
|
303
|
+
provisioner "shell" {
|
|
304
|
+
inline = [<<-END
|
|
305
|
+
set -e -x
|
|
306
|
+
source ~/.zprofile
|
|
307
|
+
# The recommended Homebrew tap, see https://opencode.ai/docs/
|
|
308
|
+
brew install anomalyco/tap/opencode
|
|
309
|
+
opencode --version
|
|
310
|
+
END
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# OpenCodeReview — the AI-powered code review CLI
|
|
315
|
+
# (https://github.com/alibaba/open-code-review). Installed via npm (the
|
|
316
|
+
# image ships Node.js via nvm), provides the `ocr` command; its global
|
|
317
|
+
# config (~/.opencodereview/config.json) is synced from the host by the
|
|
318
|
+
# user-settings copy (settings/macos.ts).
|
|
319
|
+
provisioner "shell" {
|
|
320
|
+
inline = [<<-END
|
|
321
|
+
set -e -x
|
|
322
|
+
source ~/.zprofile
|
|
323
|
+
npm install -g @alibaba-group/open-code-review
|
|
324
|
+
ocr --version
|
|
325
|
+
END
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
# OpenChamber — the native macOS desktop app (https://openchamber.dev),
|
|
330
|
+
# installed alongside the web UI below. Distributed as the `openchamber`
|
|
331
|
+
# Homebrew cask (the arm64 build on Apple Silicon); the cask pins the DMG
|
|
332
|
+
# checksum and stays in sync with the GitHub releases. The app bundles its
|
|
333
|
+
# own OpenCode CLI and manages its own server by default — the sandbox's
|
|
334
|
+
# web UI service on port 4000 below remains the main server; docs/macos.md
|
|
335
|
+
# explains how to pair the app with it so both share sessions.
|
|
336
|
+
provisioner "shell" {
|
|
337
|
+
inline = [<<-END
|
|
338
|
+
set -e -x
|
|
339
|
+
source ~/.zprofile
|
|
340
|
+
brew install --cask openchamber
|
|
341
|
+
|
|
342
|
+
# Drop the quarantine attribute so the app launches without Gatekeeper
|
|
343
|
+
# prompts (same choice as the browsers above)
|
|
344
|
+
sudo xattr -dr com.apple.quarantine "/Applications/OpenChamber.app" || true
|
|
345
|
+
|
|
346
|
+
test -d "/Applications/OpenChamber.app"
|
|
347
|
+
defaults read "/Applications/OpenChamber.app/Contents/Info.plist" CFBundleShortVersionString
|
|
348
|
+
END
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# OpenChamber — web UI for OpenCode (https://openchamber.dev). Installed via
|
|
353
|
+
# npm (requires Node.js 22+, the image ships 26 via nvm, and the opencode
|
|
354
|
+
# CLI on PATH). Registered as a login service (LaunchAgent
|
|
355
|
+
# dev.openchamber.web) that listens on 0.0.0.0:${var.openchamber_port}, so
|
|
356
|
+
# the host can open the UI at http://$(tart ip <vm>):${var.openchamber_port}
|
|
357
|
+
# — see docs/macos.md.
|
|
358
|
+
provisioner "shell" {
|
|
359
|
+
inline = [<<-END
|
|
360
|
+
set -e -x
|
|
361
|
+
source ~/.zprofile
|
|
362
|
+
npm install -g @openchamber/web
|
|
363
|
+
openchamber --version
|
|
364
|
+
|
|
365
|
+
# Pin the opencode binary the service will run: `startup enable` snapshots
|
|
366
|
+
# the environment into the LaunchAgent, so resolving the absolute path here
|
|
367
|
+
# (instead of relying on PATH lookup inside the login session) guarantees
|
|
368
|
+
# OpenChamber uses exactly the opencode this image ships.
|
|
369
|
+
opencode_bin="$(command -v opencode)"
|
|
370
|
+
test -x "$opencode_bin"
|
|
371
|
+
export OPENCODE_BINARY="$opencode_bin"
|
|
372
|
+
echo "OpenChamber will run opencode at: $OPENCODE_BINARY"
|
|
373
|
+
|
|
374
|
+
# Auto-start at login, bind to 0.0.0.0 for host access. --lan refuses to
|
|
375
|
+
# start without a UI password, hence openchamber_ui_password.
|
|
376
|
+
# During image builds the admin user may not have a GUI login session yet
|
|
377
|
+
# (auto-login applies on the next boot), so a failed immediate start is OK:
|
|
378
|
+
# the plist is installed and RunAtLoad starts the service at first login.
|
|
379
|
+
openchamber startup enable --port ${var.openchamber_port} --lan --ui-password "${var.openchamber_ui_password}" \
|
|
380
|
+
|| echo "WARNING: OpenChamber service installed but not started yet (expected during image builds); it will start at first login"
|
|
381
|
+
|
|
382
|
+
openchamber startup status
|
|
383
|
+
|
|
384
|
+
# Health check if the service already came up during the build.
|
|
385
|
+
if curl -fsS --max-time 5 http://127.0.0.1:${var.openchamber_port}/health >/dev/null 2>&1; then
|
|
386
|
+
echo "OpenChamber: OK (http://127.0.0.1:${var.openchamber_port}/health)"
|
|
387
|
+
else
|
|
388
|
+
echo "WARNING: OpenChamber not reachable yet; it will start at first login"
|
|
389
|
+
fi
|
|
390
|
+
END
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
# Docker CLI — client only. The sandbox is a macOS VM, and Apple's
|
|
395
|
+
# Virtualization.framework does not support nested virtualization for macOS
|
|
396
|
+
# guests (only Linux guests on M3+ with macOS 15+), so no container engine
|
|
397
|
+
# (Docker Desktop, Colima, ...) can run inside it. The CLI is meant to be
|
|
398
|
+
# pointed at a remote engine — e.g. the host's Docker Desktop over SSH; see
|
|
399
|
+
# docs/macos.md "Docker (remote engine)". The brew docker-compose and
|
|
400
|
+
# docker-buildx formulas install the compose/buildx plugins into
|
|
401
|
+
# $HOMEBREW_PREFIX/lib/docker/cli-plugins; the CLI only discovers them via
|
|
402
|
+
# cliPluginsExtraDirs in ~/.docker/config.json.
|
|
403
|
+
provisioner "shell" {
|
|
404
|
+
inline = [<<-END
|
|
405
|
+
set -e -x
|
|
406
|
+
source ~/.zprofile
|
|
407
|
+
|
|
408
|
+
# Wire Homebrew's cli-plugins dir into the docker CLI config so `docker
|
|
409
|
+
# compose` and `docker buildx` are found. docker preserves this key when the
|
|
410
|
+
# user later runs `docker context use ...` (the file never pre-exists in a
|
|
411
|
+
# fresh image; the jq branch is only defensive).
|
|
412
|
+
mkdir -p ~/.docker
|
|
413
|
+
if [ -f ~/.docker/config.json ]; then
|
|
414
|
+
jq '.cliPluginsExtraDirs += ["/opt/homebrew/lib/docker/cli-plugins"] | .cliPluginsExtraDirs |= unique' \
|
|
415
|
+
~/.docker/config.json > /tmp/docker-config.json
|
|
416
|
+
mv /tmp/docker-config.json ~/.docker/config.json
|
|
417
|
+
else
|
|
418
|
+
cat > ~/.docker/config.json <<'DOCKER'
|
|
419
|
+
{
|
|
420
|
+
"cliPluginsExtraDirs": [
|
|
421
|
+
"/opt/homebrew/lib/docker/cli-plugins"
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
DOCKER
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
docker --version
|
|
428
|
+
docker compose version
|
|
429
|
+
docker buildx version
|
|
430
|
+
END
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
# Final verification and cleanup
|
|
435
|
+
provisioner "shell" {
|
|
436
|
+
inline = [<<-END
|
|
437
|
+
set -e -x
|
|
438
|
+
source ~/.zprofile
|
|
439
|
+
brew cleanup
|
|
440
|
+
|
|
441
|
+
echo "===== Agent Sandbox image contents ====="
|
|
442
|
+
sw_vers
|
|
443
|
+
xcodebuild -version
|
|
444
|
+
brew --version | head -1
|
|
445
|
+
node --version
|
|
446
|
+
npm --version
|
|
447
|
+
nvm --version
|
|
448
|
+
python3 --version
|
|
449
|
+
pip3 --version
|
|
450
|
+
ruby --version
|
|
451
|
+
git --version
|
|
452
|
+
gh --version | head -1
|
|
453
|
+
code --version | head -1
|
|
454
|
+
subl --version
|
|
455
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --version
|
|
456
|
+
"/Applications/Firefox.app/Contents/MacOS/firefox" --version
|
|
457
|
+
opencode --version
|
|
458
|
+
ocr --version | head -1
|
|
459
|
+
openchamber --version
|
|
460
|
+
defaults read "/Applications/OpenChamber.app/Contents/Info.plist" CFBundleShortVersionString
|
|
461
|
+
docker --version
|
|
462
|
+
docker compose version
|
|
463
|
+
docker buildx version
|
|
464
|
+
echo "========================================"
|
|
465
|
+
END
|
|
466
|
+
]
|
|
467
|
+
}
|
|
468
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# macOS 26 (Tahoe) + Xcode 26.4.1
|
|
2
|
+
#
|
|
3
|
+
# The default sandbox image. macos_version + xcode_version must point at a
|
|
4
|
+
# tag that exists in the Cirrus Labs base images on GHCR:
|
|
5
|
+
# https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos-
|
|
6
|
+
macos_version = "tahoe"
|
|
7
|
+
xcode_version = "26.4.1"
|
|
8
|
+
|
|
9
|
+
# Node.js version installed via nvm and set as the default.
|
|
10
|
+
node_version = "26"
|
|
11
|
+
|
|
12
|
+
# Homebrew Python version (also used for the unversioned python/pip aliases).
|
|
13
|
+
python_version = "3.14"
|
|
14
|
+
|
|
15
|
+
# VM resources
|
|
16
|
+
# disk_size must be >= the Cirrus base image disk (140 GB): tart can only
|
|
17
|
+
# grow a disk, never shrink it.
|
|
18
|
+
disk_size = 160
|
|
19
|
+
cpu_count = 4
|
|
20
|
+
memory_gb = 8
|
|
21
|
+
|
|
22
|
+
# SSH credentials for provisioning (fixed in the Cirrus Labs base images).
|
|
23
|
+
ssh_username = "admin"
|
|
24
|
+
ssh_password = "admin"
|
|
25
|
+
|
|
26
|
+
# OpenChamber web UI password (host access: http://<vm-ip>:4000, see
|
|
27
|
+
# docs/macos.md). OpenChamber refuses to serve on the network without it.
|
|
28
|
+
openchamber_ui_password = "sandbox"
|
|
29
|
+
|
|
30
|
+
# TCP port the OpenChamber web UI listens on inside the guest (host access:
|
|
31
|
+
# http://<vm-ip>:4000). 4000 — not the Vite dev-server default 3000 — so
|
|
32
|
+
# frontend dev servers don't collide with it. Keep
|
|
33
|
+
# the CLI's SANDBOX_OPENCHAMBER_PORT default (lib/platform.ts) in sync.
|
|
34
|
+
openchamber_port = 4000
|
|
35
|
+
|
|
36
|
+
# Semantic version this image is published under (also the GHCR push tag,
|
|
37
|
+
# besides :latest). For every release: bump it, add a CHANGELOG.md entry,
|
|
38
|
+
# and create the mac-v<version> git tag (agent-dev-env tag <image>).
|
|
39
|
+
image_version = "1.6.0"
|