@@ -37,6 +37,12 @@ export FORCE_COLOR=1
3737# Version-specific paths
3838version_path=" $AZTEC_HOME /versions/$VERSION "
3939version_bin_path=" $version_path /bin"
40+ # Native binaries (forge/nargo/anvil/...) live here and are NOT on the user's PATH.
41+ # The aztec wrapper prepends this directory to its child PATH so subprocesses
42+ # spawned from the aztec workflow (which call sibling tools by basename) resolve
43+ # to the bundled binaries. User-facing access is only via the aztec-* symlinks
44+ # in version_bin_path.
45+ version_internal_bin_path=" $version_path /internal-bin"
4046
4147os=" $( uname -s) "
4248
@@ -137,7 +143,15 @@ function install_noir {
137143 set -euo pipefail
138144
139145 if [[ -n ${NARGO:- } ]]; then
140- cp " $NARGO " " $version_bin_path /nargo"
146+ cp " $NARGO " " $version_internal_bin_path /nargo"
147+ # noir's release build co-locates `noir-profiler` next to `nargo`
148+ # (see noir/bootstrap.sh::build_native). Copy it too so the
149+ # `aztec-noir-profiler` symlink in install_native_symlinks resolves.
150+ local nargo_dir
151+ nargo_dir=$( dirname " $NARGO " )
152+ if [ -f " $nargo_dir /noir-profiler" ]; then
153+ cp " $nargo_dir /noir-profiler" " $version_internal_bin_path /noir-profiler"
154+ fi
141155 else
142156 local noir_version
143157 noir_version=$( get_version " noir" )
@@ -150,13 +164,12 @@ function install_noir {
150164 # Always install/update noirup
151165 curl -Ls https://raw.githubusercontent.com/noir-lang/noirup/refs/heads/main/install | bash
152166
153- # Install noir to temp location and move to version directory
167+ # Install noir to temp location and move into internal-bin (off PATH).
154168 NARGO_HOME=" $temp_nargo_home " " $HOME /.nargo/bin/noirup" -v " $noir_version "
155169
156- # Move the nargo binary to our version bin directory
157- mv " $temp_nargo_home /bin/nargo" " $version_bin_path /nargo"
170+ mv " $temp_nargo_home /bin/nargo" " $version_internal_bin_path /nargo"
158171 # Also move noir-profiler, needed by `aztec profile flamegraph`
159- mv " $temp_nargo_home /bin/noir-profiler" " $version_bin_path /noir-profiler"
172+ mv " $temp_nargo_home /bin/noir-profiler" " $version_internal_bin_path /noir-profiler"
160173
161174 # Cleanup temp directory
162175 rm -rf " $temp_nargo_home "
@@ -182,10 +195,11 @@ function install_foundry {
182195 # Install foundry to temp location and move to version directory
183196 FOUNDRY_DIR=" $temp_foundry_dir " timeout 30 " $foundry_home /bin/foundryup" -i " $foundry_version "
184197
185- # Move the foundry binaries to our version bin directory
198+ # Move the foundry binaries into internal-bin (off PATH); aztec-forge etc.
199+ # symlinks in version_bin_path expose them under aztec-prefixed names.
186200 for binary in forge cast anvil chisel; do
187201 if [ -f " $temp_foundry_dir /bin/$binary " ]; then
188- mv " $temp_foundry_dir /bin/$binary " " $version_bin_path /$binary "
202+ mv " $temp_foundry_dir /bin/$binary " " $version_internal_bin_path /$binary "
189203 fi
190204 done
191205
@@ -200,32 +214,88 @@ function install_aztec_packages {
200214 npm install @aztec/aztec@$VERSION @aztec/cli-wallet@$VERSION @aztec/bb.js@$VERSION --prefix " $version_path "
201215}
202216
203- function symlink_aztec_bins {
217+ # Expose every native tool in internal-bin under an aztec-<tool> symlink in bin.
218+ # Bare `forge`/`nargo`/etc. are intentionally NOT on PATH so they cannot shadow
219+ # user-installed tools.
220+ function install_native_symlinks {
221+ set -euo pipefail
222+ local tool
223+ for tool in forge cast anvil chisel nargo noir-profiler; do
224+ if [ ! -e " $version_internal_bin_path /$tool " ]; then
225+ echo " Error: expected bundled binary '$tool ' missing from $version_internal_bin_path " >&2
226+ exit 1
227+ fi
228+ ln -sfn " ../internal-bin/$tool " " $version_bin_path /aztec-$tool "
229+ done
230+ }
231+
232+ # Npm bins are NOT mirrored into internal-bin. The contract for any TS tool
233+ # that needs to spawn a sibling binary is to resolve an absolute bundled
234+ # path itself (e.g. via @aztec/bb.js findBbBinary(), or a BB-style env
235+ # var) -- never by basename + PATH lookup. If you find yourself wanting to
236+ # add an npm bin to internal-bin so a child process can find it on PATH,
237+ # fix the caller instead of broadening this list.
238+ function install_npm_bin_symlinks {
204239 set -euo pipefail
205- # Populate version_bin_path with symlinks to @aztec-owned bins only. Adding
206- # node_modules/.bin wholesale to PATH would shadow user-installed tools
207- # (jest, tsc, semver, ...) with Aztec's transitive dependencies.
208240 local npm_bin_dir=" $version_path /node_modules/.bin"
209241 [ -d " $npm_bin_dir " ] || return 0
210242
211- local bin_link bin_name target
243+ local bin_link bin_name target link_name
212244 for bin_link in " $npm_bin_dir " /* ; do
213245 [ -L " $bin_link " ] || continue
214246 target=$( readlink " $bin_link " )
215247 # npm writes relative symlinks like ../@aztec/aztec/... for scoped packages.
216248 [[ " $target " == ../@aztec/* ]] || continue
217249 bin_name=$( basename " $bin_link " )
218- if [ -e " $version_bin_path /$bin_name " ] && [ ! -L " $version_bin_path /$bin_name " ]; then
219- echo_yellow " refusing to overwrite non-symlink $bin_name ; @aztec package bin collides with a hand-installed toolchain binary" >&2
250+
251+ # `aztec` is a wrapper, written by install_aztec_wrapper.
252+ [[ " $bin_name " == " aztec" ]] && continue
253+
254+ # Already prefixed (e.g. aztec-wallet) keeps its name; everything else gets
255+ # renamed to aztec-<orig> so it cannot shadow a user-installed binary.
256+ if [[ " $bin_name " == aztec-* ]]; then
257+ link_name=" $bin_name "
258+ else
259+ link_name=" aztec-$bin_name "
260+ fi
261+
262+ if [ -e " $version_bin_path /$link_name " ] && [ ! -L " $version_bin_path /$link_name " ]; then
263+ echo_yellow " refusing to overwrite non-symlink $link_name ; @aztec package bin collides with a hand-installed toolchain binary" >&2
220264 exit 1
221265 fi
222- ln -sfn " ../node_modules/.bin/$bin_name " " $version_bin_path /$bin_name "
266+ ln -sfn " ../node_modules/.bin/$bin_name " " $version_bin_path /$link_name "
223267 done
224268}
225269
270+ # Wrapper for `aztec`: prepends internal-bin to PATH so the aztec workflow
271+ # resolves bundled native tools by basename. yarn-project/aztec/scripts/aztec.sh
272+ # (the npm bin entry of @aztec/aztec) calls bare `nargo` (line 36, in `aztec
273+ # test`) and bare `anvil` (line 55-56, in `aztec start --local-network`); the
274+ # TS commands it spawns also fall back to bare `forge` / `nargo` /
275+ # `noir-profiler` when their respective env vars are unset. The wrapper is
276+ # kept minimal -- it is the only place we maintain a PATH-based execution
277+ # context, by design (see install_npm_bin_symlinks for the rationale).
278+ # BASH_SOURCE[0] (not $0) so PATH-name invocation still resolves internal-bin
279+ # from the wrapper's actual location.
280+ function install_aztec_wrapper {
281+ set -euo pipefail
282+ local wrapper=" $version_bin_path /aztec"
283+ cat > " $wrapper " << 'EOF '
284+ #!/usr/bin/env bash
285+ # Auto-generated by aztec-up. Do not edit.
286+ set -euo pipefail
287+ self_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
288+ internal_bin="$self_dir/../internal-bin"
289+ export PATH="$internal_bin:$PATH"
290+ exec "$self_dir/../node_modules/.bin/aztec" "$@"
291+ EOF
292+ chmod +x " $wrapper "
293+ }
294+
226295function main {
227- # Create version directory
296+ # Create version directories. bin/ is exposed on PATH; internal-bin/ is not.
228297 mkdir -p " $version_bin_path "
298+ mkdir -p " $version_internal_bin_path "
229299
230300 # Download versions manifest
231301 echo -n " Installing version manifest... "
@@ -250,14 +320,23 @@ function main {
250320 dump_fail retry install_foundry
251321 echo_green " done."
252322
323+ # Expose native tools as aztec-forge / aztec-nargo / etc.
324+ echo -n " Linking aztec native tools... "
325+ dump_fail install_native_symlinks
326+ echo_green " done."
327+
253328 # Install aztec npm packages
254- echo -n " Installing aztec packages... "
329+ echo -n " Installing aztec npm packages... "
255330 dump_fail retry install_aztec_packages
256331 echo_green " done."
257332
258- # Expose only @aztec-owned bins on PATH (drops transitive npm deps).
333+ # Expose @aztec-owned npm bins under aztec-prefixed symlinks. Bare names
334+ # (bb, pxe, txe, ...) are intentionally NOT exposed as they would shadow
335+ # user-installed tools.
259336 echo -n " Making aztec commands available... "
260- dump_fail retry symlink_aztec_bins
337+ dump_fail install_npm_bin_symlinks
338+ # Wrap `aztec` so its subprocesses see internal-bin on PATH.
339+ dump_fail install_aztec_wrapper
261340 echo_green " done."
262341}
263342
0 commit comments