agent-dev-env 0.1.0-canary.2.fbbd044

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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/assets/bridge/bridge.js +202 -0
  4. package/dist/assets/guest/guest-agent-mac.js +586 -0
  5. package/dist/assets/guest/guest-agent-ubuntu.js +481 -0
  6. package/dist/assets/guest/guest-agent-windows.js +466 -0
  7. package/dist/assets/images/mac/CHANGELOG.md +265 -0
  8. package/dist/assets/images/mac/README.md +63 -0
  9. package/dist/assets/images/mac/sandbox.pkr.hcl +468 -0
  10. package/dist/assets/images/mac/vars/sandbox-macos-tahoe.pkrvars.hcl +39 -0
  11. package/dist/assets/images/ubuntu-arm64-vmware/CHANGELOG.md +239 -0
  12. package/dist/assets/images/ubuntu-arm64-vmware/README.md +177 -0
  13. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/meta-data +2 -0
  14. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/user-data +34 -0
  15. package/dist/assets/images/ubuntu-arm64-vmware/sandbox.pkr.hcl +776 -0
  16. package/dist/assets/images/ubuntu-arm64-vmware/vars/sandbox-ubuntu-24-04-arm64-vmware.pkrvars.hcl +71 -0
  17. package/dist/assets/images/windows-arm64-qemu/CHANGELOG.md +209 -0
  18. package/dist/assets/images/windows-arm64-qemu/README.md +142 -0
  19. package/dist/assets/images/windows-arm64-qemu/autounattend.xml +325 -0
  20. package/dist/assets/images/windows-arm64-qemu/qemu-with-tpm.sh +170 -0
  21. package/dist/assets/images/windows-arm64-qemu/sandbox.pkr.hcl +1012 -0
  22. package/dist/assets/images/windows-arm64-qemu/vars/sandbox-windows-11-arm64-qemu.pkrvars.hcl +83 -0
  23. package/dist/assets/images/windows-arm64-vmware/CHANGELOG.md +270 -0
  24. package/dist/assets/images/windows-arm64-vmware/README.md +171 -0
  25. package/dist/assets/images/windows-arm64-vmware/autounattend.xml +311 -0
  26. package/dist/assets/images/windows-arm64-vmware/sandbox.pkr.hcl +1036 -0
  27. package/dist/assets/images/windows-arm64-vmware/vars/sandbox-windows-11-arm64-vmware.pkrvars.hcl +83 -0
  28. package/dist/assets/rules/agent-rules-linux.md +68 -0
  29. package/dist/assets/rules/agent-rules.md +71 -0
  30. package/dist/assets/watchdog/watch-build-ocr.swift +40 -0
  31. package/dist/assets/watchdog/watch-build.py +275 -0
  32. package/dist/cli.js +52 -0
  33. package/dist/commands/delete.js +179 -0
  34. package/dist/commands/doctor.js +165 -0
  35. package/dist/commands/list.js +38 -0
  36. package/dist/commands/not-yet.js +15 -0
  37. package/dist/commands/register.js +150 -0
  38. package/dist/commands/run.js +65 -0
  39. package/dist/commands/status.js +142 -0
  40. package/dist/commands/stop.js +186 -0
  41. package/dist/commands/sync.js +98 -0
  42. package/dist/lib/exec.js +250 -0
  43. package/dist/lib/ghcr.js +82 -0
  44. package/dist/lib/git.js +100 -0
  45. package/dist/lib/logger.js +87 -0
  46. package/dist/lib/network.js +63 -0
  47. package/dist/lib/paths.js +116 -0
  48. package/dist/lib/platform.js +87 -0
  49. package/dist/lib/prompt.js +66 -0
  50. package/dist/lib/qemu.js +373 -0
  51. package/dist/lib/regex.js +9 -0
  52. package/dist/lib/ssh.js +230 -0
  53. package/dist/lib/tart.js +210 -0
  54. package/dist/lib/template.js +35 -0
  55. package/dist/lib/vars.js +99 -0
  56. package/dist/lib/vmrun.js +334 -0
  57. package/dist/lifecycle/build-macos.js +23 -0
  58. package/dist/lifecycle/build-qemu.js +204 -0
  59. package/dist/lifecycle/build-shared.js +355 -0
  60. package/dist/lifecycle/build-ubuntu.js +184 -0
  61. package/dist/lifecycle/build-watchdog.js +146 -0
  62. package/dist/lifecycle/build-windows-vmware.js +112 -0
  63. package/dist/lifecycle/build.js +55 -0
  64. package/dist/lifecycle/catalog.js +165 -0
  65. package/dist/lifecycle/deploy.js +161 -0
  66. package/dist/lifecycle/tag.js +77 -0
  67. package/dist/lifecycle/watch-build.js +64 -0
  68. package/dist/runners/bridges.js +156 -0
  69. package/dist/runners/framework.js +66 -0
  70. package/dist/runners/macos-bridges.js +143 -0
  71. package/dist/runners/macos-guest.js +76 -0
  72. package/dist/runners/macos-rules.js +77 -0
  73. package/dist/runners/macos-summary.js +145 -0
  74. package/dist/runners/macos.js +258 -0
  75. package/dist/runners/openchamber.js +60 -0
  76. package/dist/runners/options.js +56 -0
  77. package/dist/runners/qemu-image.js +183 -0
  78. package/dist/runners/rules.js +49 -0
  79. package/dist/runners/ubuntu-bridges.js +154 -0
  80. package/dist/runners/ubuntu-guest.js +136 -0
  81. package/dist/runners/ubuntu-image.js +26 -0
  82. package/dist/runners/ubuntu-rules.js +86 -0
  83. package/dist/runners/ubuntu-shared.js +65 -0
  84. package/dist/runners/ubuntu-summary.js +141 -0
  85. package/dist/runners/ubuntu.js +117 -0
  86. package/dist/runners/vmware-common.js +158 -0
  87. package/dist/runners/vmware-image.js +242 -0
  88. package/dist/runners/windows-autologon.js +119 -0
  89. package/dist/runners/windows-bridges.js +136 -0
  90. package/dist/runners/windows-guest.js +213 -0
  91. package/dist/runners/windows-image.js +23 -0
  92. package/dist/runners/windows-qemu-summary.js +85 -0
  93. package/dist/runners/windows-qemu.js +189 -0
  94. package/dist/runners/windows-shared.js +68 -0
  95. package/dist/runners/windows-summary.js +104 -0
  96. package/dist/runners/windows.js +96 -0
  97. package/dist/settings/common.js +107 -0
  98. package/dist/settings/macos-copy.js +223 -0
  99. package/dist/settings/macos.js +41 -0
  100. package/dist/settings/ubuntu-copy.js +223 -0
  101. package/dist/settings/ubuntu.js +68 -0
  102. package/package.json +52 -0
@@ -0,0 +1,71 @@
1
+ # Ubuntu 24.04 LTS (ARM64) sandbox image — VMware (Fusion) build.
2
+ #
3
+ # Built with the Packer vmware-iso plugin on Apple Silicon (the vmware-iso
4
+ # builder drives VMware Fusion, which virtualizes ARM64 guests natively):
5
+ # Ubuntu Server ARM64 ISO + Subiquity autoinstall (seed served over HTTP).
6
+ # See images/ubuntu-arm64-vmware/README.md for the full build flow — the
7
+ # Ubuntu ISO is bring-your-own (not redistributable via Packer), so it is
8
+ # not part of this repo.
9
+
10
+ ubuntu_version = "24-04"
11
+
12
+ # SHA256 of the Ubuntu Server 24.04 ARM64 ISO. Canonical publishes the hash
13
+ # in the release SHA256SUMS (https://cdimage.ubuntu.com/releases/24.04/release/);
14
+ # paste it here to enable integrity verification. Set UBUNTU_ISO_PATH to the
15
+ # local ISO path when building. Empty = skip verification.
16
+ iso_sha256 = "9a6ce6d7e66c8abed24d24944570a495caca80b3b0007df02818e13829f27f32"
17
+
18
+ # Toolchain versions. Direct downloads are pinned by version + SHA256 here
19
+ # (the hashes come from the vendor's published checksums); nvm (Node) and
20
+ # rustup (Rust) pin the major/minor and resolve the latest patch. apt
21
+ # packages (gcc, git, python3, ...) come from the Ubuntu archive.
22
+ node_version = "26"
23
+ python_version = "3.12"
24
+ github_cli_version = "2.98.0"
25
+ github_cli_sha256 = "bbc4ac7964c2a091fd555cd1758d10a7cfcfdc472e405f0b0fb958f05d535cb6"
26
+ open_code_review_version = "1.9.5"
27
+ go_version = "1.27.0"
28
+ go_sha256 = "51798d2c42d0e1c6ed7fd9f48728b4193abac9e8aad6dbac2fe96a81f5909bda"
29
+ rust_version = "1.95"
30
+ vscode_version = "1.134.0"
31
+ vscode_sha256 = "b30f5bda4855231681cc7fe22d4a59e7dbee2be170b0e4fb04c7e83b9f9affe5"
32
+
33
+ # Mozilla Firefox: official linux-aarch64 release tarball (en-US), pinned
34
+ # by version + SHA256 (SHA256SUMS from the same FTP directory). No Google
35
+ # Chrome: CfT publishes no linux-arm64 build (only x86_64 linux64) and
36
+ # Ubuntu's chromium is snap-only.
37
+ firefox_version = "154.0"
38
+ firefox_sha256 = "0391a8d072431286fbed8f9ff497a126ff0c9e81c455d4ef04f9fb878fd4bf1f"
39
+
40
+ # Docker CLI + plugins (client only — the engine is bridged from the host
41
+ # by the sandbox runner). Static aarch64 binaries, hash-pinned.
42
+ docker_version = "29.7.2"
43
+ docker_sha256 = "43d143448adf2c2787704e7d7704fd6d62d367a54c5edaef0a3f75509cb0938d"
44
+ docker_compose_version = "5.5.0"
45
+ docker_compose_sha256 = "ff42489f5a9b879d5d117c5ffea6defc27390b3286da8ad52cbc9c6ab5df590e"
46
+ docker_buildx_version = "0.36.1"
47
+ docker_buildx_sha256 = "5d0cafd9d16afe1a0f0d9529885344ace2cc99efdd531b6c783c5455a6001569"
48
+
49
+ # VM resources
50
+ disk_size = 100
51
+ cpu_count = 4
52
+ memory_gb = 8
53
+
54
+ # SSH credentials used for provisioning. They are baked into
55
+ # images/ubuntu-arm64-vmware/autoinstall/user-data (identity: user +
56
+ # password hash) and become the sandbox's login — keep the two files in
57
+ # sync.
58
+ ssh_username = "admin"
59
+ ssh_password = "sandbox1"
60
+
61
+ # OpenChamber web UI password + port. The runner advertises the UI at
62
+ # http://<guest-ip>:4000 (password "sandbox" by default). OpenChamber
63
+ # refuses to serve on the network without a password.
64
+ openchamber_ui_password = "sandbox"
65
+ openchamber_port = 4000
66
+
67
+ # Semantic version this image is published under (also the GHCR push tag,
68
+ # besides :latest). For every release: bump it, add a CHANGELOG.md entry,
69
+ # and create the ubuntu-arm64-vmware-v<version> git tag
70
+ # (npx agent-dev-env tag <image>).
71
+ image_version = "1.1.0"
@@ -0,0 +1,209 @@
1
+ # Changelog
2
+
3
+ All notable changes to the Windows sandbox images.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ The image version lives in the image's vars file (`image_version`); every
9
+ release bumps it, adds an entry below, and tags the release commit
10
+ `<platform>-v<version>` (e.g. `windows-arm64-qemu-v1.0.0`). The
11
+ `[Unreleased]` section on top is never removed — changes land there until
12
+ the next release.
13
+
14
+ ## [Unreleased]
15
+
16
+ ### Added
17
+
18
+ - `agent-dev-env stop` (windows-qemu) — stops the sandbox: qemu (via the
19
+ runner's `qemu.pid`) and swtpm, plus the host SSH agent / Docker bridge
20
+ listeners the runner leaves up. Honors the runner's
21
+ `SANDBOX_AGENT_PORT` / `SANDBOX_DOCKER_PORT` overrides.
22
+ - `agent-dev-env delete` (windows-qemu) — deletes the sandbox: stops it
23
+ first (delegating to the stop step), then removes the state dir (working
24
+ disk overlay + TPM/EFI NVRAM + pulled image cache). Asks before deleting
25
+ unless `--yes`.
26
+ - The virtual display is now a virtio-gpu-pci (virtio-gpu) instead of
27
+ ramfb at runtime: the image stages the ARM64 `viogpudo` (virtio-gpu
28
+ display-only) driver onto the unattend CD, so first logon lands it in
29
+ the driver store and the runtime VM's virtio-gpu-pci binds it.
30
+ Resizing the QEMU window now changes the guest's resolution
31
+ (`VIRTIO_GPU_EVENT_DISPLAY`) instead of only scaling the framebuffer.
32
+ The image build itself keeps ramfb (WinPE has no display driver).
33
+
34
+ ### Changed
35
+
36
+ - Node.js is bumped from 22 to 26 (`nodejs_version = "26.8.1"` in the
37
+ vars file, choco package `nodejs`).
38
+ - The image was renamed from `sandbox-windows-11` to
39
+ `sandbox-windows-11-arm64-qemu` (vars file, template `vm_name` —
40
+ `sandbox-windows-<windows_version>-arm64-qemu.qcow2` — the GHCR package
41
+ name and the runner's `image_name`): the platform is now part of the
42
+ image name, matching the state-dir naming
43
+ (`~/Library/Application Support/agent-dev-env/windows-qemu/`).
44
+ Older releases stay published under the old name.
45
+ - The QEMU runner (`agent-dev-env run`, windows-qemu) boots the guest
46
+ in a resizable window: it passes `-display cocoa,zoom-to-fit=on` (the
47
+ cocoa window is fixed-size otherwise) and replaced `-device ramfb` with
48
+ `-device virtio-gpu-pci`. Full screen is available from the QEMU
49
+ window's View menu → Enter Fullscreen.
50
+ - The build flow (`agent-dev-env build`) — the EXIT trap no longer prints
51
+ `stop_watchdog: command not found` when the build aborts before the
52
+ watchdog function is defined (it now checks before calling it).
53
+ - `agent-dev-env run` (windows-qemu) — the working VM is recreated
54
+ when the pristine image *changes*, not just when its path changes: the
55
+ backing marker now records path + size + mtime, and the stale overlay /
56
+ EFI NVRAM / TPM state are discarded (previously a rebuild that replaced
57
+ the file at the same path stacked the old overlay on the new base — a
58
+ corrupt disk that dropped Windows to the UEFI shell). The EFI NVRAM is
59
+ also seeded from the build output's `efivars.fd` when one exists, so
60
+ Windows' own Boot0000 is used instead of the empty edk2 template.
61
+ - `agent-dev-env run` (windows-qemu) — the default working-VM state
62
+ dir now lives under the CLI's data root
63
+ (`~/Library/Application Support/agent-dev-env/windows-qemu/<image>/`):
64
+ the platform and image are part of the path, so state from different
65
+ platforms and images never collides. Override the data root with
66
+ `AGENT_DEV_ENV_DATA_HOME` (or `XDG_DATA_HOME`) as before.
67
+ - `agent-dev-env run` (windows-qemu) — the summary's stop hints now
68
+ point at `agent-dev-env stop` instead of a bare
69
+ `kill $(cat …/qemu.pid)` and a hand-written `lsof | xargs kill` for the
70
+ bridge listeners.
71
+
72
+ ### Fixed
73
+
74
+ - The runner's guest bridge setup no longer takes ~5 min per SSH command
75
+ on a guest whose bridges are already installed: the sshd channel does
76
+ not close when a PowerShell payload finishes (the guest-side relays
77
+ hold the console handles and keep trickling output, which resets
78
+ expect's idle timeout), so every `guest_ps` call used to end only at
79
+ an alarm (or never, before the hard alarm was added). Each remote
80
+ command now ends with a unique sentinel echoed by the guest's shell
81
+ after the payload exits, and expect kills the ssh client on it — step
82
+ 5 finishes in seconds.
83
+ - The image no longer depends on the Chocolatey bootstrapper persisting
84
+ the machine PATH: the Chocolatey provisioner adds
85
+ `C:\ProgramData\chocolatey\bin` to the Machine PATH itself and the
86
+ toolchain + VS provisioners call `choco.exe` by its full path — the
87
+ bootstrapper's compiled `Install-ChocolateyPath` can silently fail to
88
+ persist in the elevated WinRM context, so after the reboot the
89
+ re-read PATH still lacked the choco bin dir ('choco' not recognized).
90
+ `choco cleanup` in the final verification now redirects inside `cmd`
91
+ too, so PowerShell 5.1 never turns choco's stderr into a terminating
92
+ error under `$ErrorActionPreference='Stop'`.
93
+ - The RemoteSigned bake-in no longer aborts the build (observed at the
94
+ OpenChamber provisioner): the build passes `-ExecutionPolicy Bypass`
95
+ at Process scope, so `Set-ExecutionPolicy -Scope LocalMachine`
96
+ emitted its "overridden by a more specific scope" notice, which
97
+ Windows PowerShell 5.1 under WinRM turned into a terminating error
98
+ even though the machine policy was updated. The provisioner now sets
99
+ the Process scope first (no override, no notice) and tolerates a
100
+ failed machine-policy set.
101
+ - The image now bakes in machine-wide PowerShell `RemoteSigned` instead
102
+ of shipping Windows' default `Restricted` policy: `opencode` (an npm
103
+ shim — `opencode.ps1` in `%APPDATA%\npm`) refused to start in a
104
+ PowerShell session with "running scripts is disabled on this system".
105
+ The runners' runtime `Set-ExecutionPolicy` stays as a fallback for
106
+ images built before this change.
107
+
108
+ ## [windows-arm64-qemu-v1.1.0] - 2026-08-24
109
+
110
+ ### Changed
111
+
112
+ - Build artifacts moved out of the image directory into a top-level
113
+ `build/windows-arm64-<platform>/` directory: `output/` for
114
+ the built qcow2, `packer_cache/` for virtio-win.iso/swtpm/watchdog
115
+ scratch and `drivers/staging/` for the unattend CD driver subset. The
116
+ template's `output_directory` and the staged `cd_files` path are now
117
+ variables set by the platform `build.sh` wrapper; the macOS/tart images
118
+ build no files and have no such directory.
119
+
120
+ ### Added
121
+
122
+ - The toolchain and VS provisioners re-read PATH from the registry at
123
+ the start of their scripts: after the tools reboot a fresh WinRM
124
+ process can inherit a stale PATH (observed once: 'choco' not
125
+ recognized), and the choco bootstrapper's PATH update must be picked
126
+ up explicitly.
127
+ - The final verification checks the new toolchains with a check-and-warn
128
+ loop instead of hard version dumps: a missing helper (e.g.
129
+ `llvm-config`, not shipped by every LLVM Windows build) no longer
130
+ fails the build.
131
+ - The build reboots the guest once after the virtio-win guest-tools MSI
132
+ install (new `windows-restart` provisioner): the MSI leaves a pending
133
+ reboot, which makes `choco install` return 3010 and makes the .NET
134
+ Framework 4.8 Developer Pack installer fail with exit code 1 (it
135
+ refuses to run while a reboot is pending). Choco exit-code checks in
136
+ the VS phase accept 3010 (success, reboot required).
137
+ - Toolchains from AdGuard's `build-agent-images` Windows image
138
+ (`windows2022-vs2022` / `windows2022-go`) that were missing: Go, Rust
139
+ (via rustup — arm64 host toolchain + MSVC targets for
140
+ x86_64/i686/aarch64), Visual Studio 2022 Build Tools (choco package +
141
+ `setup.exe` finalizer: .NET 4.8/.NET Core SDKs, VC++ workload
142
+ x86/x64/ARM/ARM64, CMake, Windows 11 SDK 22621), WiX Toolset, protoc,
143
+ NASM, LLVM, Vim, NuGet CLI, MinGW-w64 and GNU make. All versions are
144
+ pinned in the vars file (`go_version`, `rust_version`,
145
+ `vs_buildtools_version`, `wixtoolset_version`, `protoc_version`,
146
+ `nasm_version`, `llvm_version`, `vim_version`, `nuget_version`,
147
+ `mingw_version`, `make_version`); the toolchain provisioner and the
148
+ final verification dump their versions.
149
+ - Build watchdog: `scripts/watch-build.sh` (+ `watch-build.py` supervisor
150
+ and `watch-build-ocr.swift` OCR helper). The headless build's
151
+ boot-command Enter-spam can hit "Cancel" on Windows Setup's "Installing
152
+ Windows 11" screen, and boot races can land in the UEFI shell — either
153
+ way the build stalls until something answers. The watchdog polls the
154
+ VNC framebuffer the Packer plugin exposes (pinned to port 5901 in the
155
+ template), OCRs each frame with Apple Vision, and auto-dismisses the
156
+ quit dialog (clicking "No" at the OCR'd button position), answers the
157
+ "Press any key to boot from CD or DVD" prompt, and boots the ISO from
158
+ the UEFI shell. `build.sh` starts it around `packer build` and stops it
159
+ in the cleanup trap; skipped with a warning when `vncdotool` or the
160
+ Xcode command line tools are missing. Observed during the v1.0.0 build:
161
+ one cancel dialog dismissed, one EFI-shell boot rescued.
162
+
163
+ ## [windows-arm64-qemu-v1.0.0] - 2026-08-23
164
+
165
+ ### Added
166
+
167
+ - Windows 11 (ARM64) sandbox image (`sandbox-windows-11`), built with the
168
+ Packer QEMU plugin on Apple Silicon (HVF accelerator). Windows 11 Pro
169
+ ARM64 from the official Microsoft ISO (bring-your-own), installed
170
+ unattended via `autounattend.xml` with swtpm-provided TPM 2.0 and edk2
171
+ AAVMF UEFI firmware; the ARM64 virtio drivers (viostor/vioscsi/NetKVM)
172
+ are staged into the unattend CD by `images/windows-arm64-qemu/build.sh`,
173
+ which
174
+ wraps `packer build` and also compresses the resulting qcow2 with zstd.
175
+ `scripts/build.sh` now delegates to a platform's `build.sh` wrapper when
176
+ one exists.
177
+ - The image ships: Chocolatey + toolchain (Node.js, Python, Git, GitHub
178
+ CLI, ripgrep, jq, curl — versions pinned in the vars file), Visual
179
+ Studio Code (native arm64), Chrome (Chrome for Testing snapshot,
180
+ hash-pinned), Firefox, OpenCode, OpenCodeReview (`ocr`), the OpenChamber
181
+ web UI as a native service on port 4000, OpenSSH Server + RDP, a Docker
182
+ CLI client (remote engine via the host bridge), and the bridge tooling
183
+ (`socat` + `npiperelay`) as utilities.
184
+ - `scripts/run-windows-qemu-sandbox.sh` — the user-facing Windows sandbox
185
+ runner, landing together with the user guide `docs/windows-qemu.md`: boots
186
+ the qcow2 under `qemu-system-aarch64` + swtpm (working VM = COW overlay
187
+ with persistent TPM/NVRAM under `~/Library/Application Support/
188
+ agent-dev-env/windows-11`), forwards SSH/RDP/WinRM/OpenChamber ports,
189
+ re-enables Windows auto-logon (the image's `LogonCount=1` disables it
190
+ after the OOBE boot) so the OpenChamber task fires at boot, and bridges
191
+ the host's SSH agent and Docker engine into the guest: host-side socat
192
+ on TCP 4200/4201 (loopback only) + guest-side Node relays serving the
193
+ `\\.\pipe\openssh-ssh-agent` and `\\.\pipe\docker_engine` named pipes
194
+ (started detached via a SYSTEM scheduled task — sshd's session job would
195
+ kill in-session children). Docker context `host` is created and made the
196
+ default.
197
+ - `images/windows-arm64-qemu/deploy.sh` — platform deploy wrapper that
198
+ pushes the qcow2 to GHCR as an OCI artifact with `oras`
199
+ (`ghcr.io/<owner>/sandbox-windows-11:<version>` + `:latest`);
200
+ `scripts/deploy.sh` delegates to it like `build.sh` does (the macOS
201
+ `tart push` flow cannot push a qcow2).
202
+ - Known limitations at this stage: no host-folder mount (the virtio-fs
203
+ driver has no ARM64 Windows build) and Windows runs unactivated with a
204
+ watermark. The sandbox agent rules (`scripts/agent-rules.md`) are
205
+ macOS-flavored and not installed into Windows guests yet.
206
+
207
+ [unreleased]: https://github.com/ameshkov/agent-dev-env/compare/windows-arm64-qemu-v1.1.0...HEAD
208
+ [windows-arm64-qemu-v1.1.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/windows-arm64-qemu-v1.1.0
209
+ [windows-arm64-qemu-v1.0.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/windows-arm64-qemu-v1.0.0
@@ -0,0 +1,142 @@
1
+ # Windows Sandbox Images
2
+
3
+ Windows 11 (ARM64) sandbox VM images built with [Packer](https://www.packer.io/)
4
+ and the [QEMU plugin](https://developer.hashicorp.com/packer/integrations/hashicorp/qemu)
5
+ on an Apple Silicon Mac. The output is a qcow2 disk image; the macOS host
6
+ runs it under `qemu-system-aarch64` with the HVF accelerator (near-native
7
+ performance — HVF can only virtualize ARM64 guests, so this image is
8
+ ARM64-only).
9
+
10
+ See [docs/macos.md](../../docs/macos.md) for the macOS images and
11
+ [docs/windows-qemu.md](../../docs/windows-qemu.md) for the Windows sandbox
12
+ user guide (boot it with `npx agent-dev-env run windows-qemu`).
13
+
14
+ ## Prerequisites
15
+
16
+ - Apple Silicon Mac (M-series).
17
+ - [QEMU](https://www.qemu.org/): `brew install qemu` (provides
18
+ `qemu-system-aarch64`, `qemu-img`, and the edk2 AAVMF firmware).
19
+ - [swtpm](https://github.com/stefanberger/swtpm) for the virtual TPM 2.0
20
+ (Windows 11 system requirement): `brew install swtpm`.
21
+ - [Packer](https://www.packer.io/): `brew install hashicorp/tap/packer`
22
+ (the QEMU plugin is installed automatically by `packer init`).
23
+ - The **Windows 11 ARM64 ISO** — bring your own, Microsoft does not permit
24
+ redistribution:
25
+
26
+ 1. Visit [Download Windows 11 (ARM64)](https://www.microsoft.com/software-download/windows11arm64)
27
+ and generate a download link (no Insider login required).
28
+ 2. Download the ISO (e.g. `Win11_24H2_English_Arm64.iso`, ~5 GB) and
29
+ copy the SHA256 shown on the page into `iso_sha256` in the vars file.
30
+ 3. Set `WINDOWS_ISO_PATH` to its absolute path when building.
31
+
32
+ - **virtio-win.iso** with ARM64 drivers (release 0.1.240 or later). The
33
+ wrapper downloads it automatically from the URL pinned in the vars file,
34
+ or you can point `VIRTIO_WIN_ISO_PATH` at a local copy.
35
+
36
+ ## How to Build
37
+
38
+ ```bash
39
+ # From the repository root
40
+ WINDOWS_ISO_PATH=/path/to/Win11_24H2_English_Arm64.iso \
41
+ npx agent-dev-env build sandbox-windows-11-arm64-qemu
42
+ ```
43
+
44
+ `agent-dev-env` is the CLI shipped by this repo (see
45
+ [docs/cli.md](../../docs/cli.md)). The windows-qemu build flow:
46
+
47
+ 1. Verifies the host (Apple Silicon), the tools, and the Windows ISO
48
+ (SHA256 against `iso_sha256` from the vars file).
49
+ 2. Downloads virtio-win.iso into the build cache unless
50
+ `VIRTIO_WIN_ISO_PATH` is set.
51
+ 3. Mounts virtio-win.iso and stages the ARM64 `viostor` / `vioscsi` /
52
+ `NetKVM` driver subset into `drivers/staging/`, which Packer packs
53
+ into the same CD as `autounattend.xml` (WinPE drive-letter
54
+ enumeration on ARM64 is non-deterministic, so a separate drivers CD
55
+ would be a guessing game).
56
+ 4. Starts `swtpm` (TPM 2.0) and runs `packer init` + `packer build`
57
+ with the vars file; Packer's `qemu_binary` points at
58
+ `qemu-with-tpm.sh`, which appends the TPM/ramfb/USB/CD-ROM wiring the
59
+ plugin's `qemuargs` option cannot express.
60
+ 5. Runs a VNC **build watchdog** (bundled `assets/watchdog/`) alongside
61
+ `packer build`: the headless boot's Enter-spam can hit "Cancel" on
62
+ Windows Setup's "Installing Windows 11" screen, and boot races can land
63
+ in the UEFI shell — the watchdog OCRs the VNC framebuffer (Apple
64
+ Vision, pinned VNC port 5901) and auto-dismisses the dialog, answers
65
+ the "Press any key" prompt, or boots the ISO from the shell. Needs
66
+ `pip3 install vncdotool`; skipped with a warning when missing.
67
+ 6. Compresses the resulting qcow2 with zstd.
68
+
69
+ A build takes roughly 30 minutes on an M-series Mac (Windows Setup itself
70
+ dominates; HVF runs the guest at near-native speed). Everything per image
71
+ lives under the CLI's data root:
72
+ `~/Library/Application Support/agent-dev-env/build/windows-qemu/output/`
73
+ (`sandbox-windows-11-arm64-qemu.qcow2`, compressed with zstd), plus
74
+ `packer_cache/` and `drivers/staging/`. The macOS/tart images build no
75
+ files and have no such directory.
76
+
77
+ ## What's in the image
78
+
79
+ | Component | Detail |
80
+ | --- | --- |
81
+ | Windows 11 Pro (ARM64) | Unactivated (watermark); generic Pro key used for Setup |
82
+ | VirtIO drivers | viostor/vioscsi, NetKVM, viogpudo (virtio-gpu display — drives the runtime VM's virtio-gpu-pci) from the unattend CD; vioserial, balloon + qemu guest agent from virtio-win guest tools |
83
+ | Chocolatey | Community package manager (versions pinned in the vars file) |
84
+ | Node.js, Python, Git, gh, ripgrep, jq, curl | Choco packages (versions from the vars file) |
85
+ | Go, Vim, NuGet, make, MinGW-w64 | Choco packages (versions from the vars file) |
86
+ | Rust | Via rustup (arm64 host toolchain + MSVC targets for x86_64/i686/aarch64), `rust`/`cargo` on PATH |
87
+ | VS2022 Build Tools | Choco + `setup.exe` finalizer: .NET 4.8/.NET Core SDKs, VC++ workload (x86/x64/ARM/ARM64), CMake, Windows 11 SDK |
88
+ | WiX, protoc, NASM, LLVM | Choco packages (versions from the vars file) |
89
+ | Visual Studio Code | Native arm64 build, latest stable, direct download; `code` on PATH |
90
+ | Google Chrome | Chrome for Testing snapshot, hash-pinned (see the vars file); x64, runs under Prism emulation |
91
+ | Firefox | Choco package (x64, runs under Prism emulation) |
92
+ | OpenCode (`opencode-ai`) | npm global |
93
+ | OpenCodeReview (`ocr`) | npm global (`@alibaba-group/open-code-review`) |
94
+ | OpenChamber web UI | npm global (`@openchamber/web`), native service on `0.0.0.0:4000` |
95
+ | OpenSSH Server + RDP | Enabled; Administrator/sandbox1 (see the vars file) |
96
+ | Docker CLI | Client only (`docker` + `docker compose`), remote engine via the host bridge |
97
+ | Bridge tooling | Node relays (in-image `node.exe`, written by the runner) for the SSH-agent/Docker bridges — the host side is the CLI's own forwarder (no socat) |
98
+
99
+ ## Versioning
100
+
101
+ Same convention as the macOS images: the image version lives in
102
+ `image_version` in the vars file; every release bumps it, adds a
103
+ `CHANGELOG.md` entry, and creates a `windows-arm64-qemu-v<version>` git
104
+ tag via `npx agent-dev-env tag <image>`.
105
+
106
+ ## Running and publishing
107
+
108
+ - Run the sandbox: `npx agent-dev-env run windows-qemu` — boots the qcow2
109
+ under QEMU + swtpm in a resizable window, forwards SSH/RDP/OpenChamber
110
+ ports, and bridges the host's Docker engine and SSH agent into the
111
+ guest (see [docs/windows-qemu.md](../../docs/windows-qemu.md)).
112
+ - Publish: `npx agent-dev-env deploy sandbox-windows-11-arm64-qemu` pushes
113
+ the qcow2 to
114
+ `ghcr.io/<owner>/sandbox-windows-11-arm64-qemu:<version>` + `:latest` as
115
+ an OCI artifact via `oras` (the CLI pushes the qcow2 directly — no
116
+ platform wrapper — because `tart push` only works for Tart VMs). Needs
117
+ `brew install oras` and a GHCR token with `write:packages`
118
+ (`oras login ghcr.io`).
119
+
120
+ ## Gotchas
121
+
122
+ - **The Windows ISO is not in the repo.** The build fails fast without
123
+ `WINDOWS_ISO_PATH`; the sha256 in the vars file protects against a
124
+ corrupt download.
125
+ - **ARM64 only.** x86_64 Windows under QEMU on Apple Silicon runs on TCG
126
+ (pure emulation) and is unusably slow; HVF only virtualizes ARM64.
127
+ - **virtio-win ≥ 0.1.240** is required for ARM64 driver builds; older
128
+ releases fail at the driver-staging step.
129
+ - **No shared folder.** The virtio-fs driver has no ARM64 Windows build
130
+ (virtio-win issue #1337), so there is no host-directory mount like the
131
+ macOS image's shared `dev` volume — use git, RDP clipboard, or the
132
+ OpenChamber web UI instead.
133
+ - **Unactivated Windows.** The image runs indefinitely with a desktop
134
+ watermark; personalization (wallpaper) is locked.
135
+ - **`qemuargs` replaces, not appends.** Any change that needs extra qemu
136
+ args belongs in `qemu-with-tpm.sh`, not in the template's `qemuargs`.
137
+ - **USB enumeration order is load-bearing.** The install ISO's
138
+ usb-storage device must precede virtio-win.iso's, or EDK2 drops to the
139
+ EFI Shell instead of booting Setup — keep the argv layout in
140
+ `qemu-with-tpm.sh` intact.
141
+ - **Computer name ≤ 15 chars.** `win11-sandbox` fits; longer names fail
142
+ the specialize pass even though `xmllint`/`packer validate` pass.