release: 0.39.0 — avocado-vm, desktop JSON output, shell completion#144
Merged
Conversation
The SDK container is built from a stripped image that doesn't ship rsync in every variant — extension build, rootfs/initramfs overlay merge, and runtime build all hit "rsync: command not found" on those SDKs. The flows here only need recursive copy + attr/symlink preservation + a root:root chown, all of which `cp -a … && chown -R root:root …` covers. Drop the rsync invocations and the environment-setup sourcing that existed only to put SDK-provided rsync on PATH. Adjust the test assertions to expect cp -a.
`docker` was hardcoded in copy_volume_path_to_host, VolumeManager construction, and the per-command copy_rpm_to_host helpers. Pass the caller's already-resolved `container_helper.container_tool` through instead so podman / nerdctl / any other docker-compatible runtime users have keeps working consistently across ext/sdk image + package flows. No behavioural change for docker users.
On macOS and Windows, avocado-cli now drives a single user-level QEMU
guest that hosts its own dockerd + 9p source mount, so flows that need
Docker (provision, ext build, sdk run) work without Docker Desktop and
without the dev needing to manage qemu themselves. New surface:
* `avocado vm {start,stop,status,shell,logs,rebuild}` — lifecycle for
the helper VM. State lives in `~/.avocado/vm/` (pidfile, ssh-port,
qmp/qga/control sockets, var.btrfs, ssh-config + key).
* `utils/vm/route` — flips DOCKER_HOST to the SSH-forwarded socket at
`~/.avocado/vm/docker.sock` so subsequent `docker run` calls land
inside the VM. Auto-runs for subcommands that need docker; opt out
with `--no-vm-auto-start` / `AVOCADO_VM_AUTO_START=0` / `--runs-on`.
* `utils/vm/share` — records the workspace root (default `$HOME`) and
exports it to the VM at `/run/workspace` over 9p. `translate_to_vm`
rewrites host paths into the VM's view of the mount.
* `utils/container::translate_bind_for_vm` — every `docker run -v
<host>:<ctr>` bind we generate now passes through this when VM
routing is active, so user-workspace paths resolve inside the guest.
* `utils/container::is_vm_routing_active` + provision.rs — when routing
is on (or `/run/avocado-agent.sock` exists locally), inject
`AVOCADO_AGENT_SOCK=/run/avocado-agent.sock` into the SDK container's
env and bind-mount the socket. Provisioning scripts (notably Jetson
tegraflash's initrd-flash) use this to ask the host to perform a real
USB disconnect/reconnect cycle via the avocado-vm-agent — the Linux
`authorized=0` toggle is a no-op through vhci_hcd.
On macOS the qemu spawn step is delegated to Avocado.app
(com.peridio.avocadodesktop) via a JSON-line IPC socket at
`~/Library/Application Support/Avocado/avocado.sock`. `utils/vm/client`
auto-launches the app via `open -gja` if its socket isn't listening,
then sends `vm.start` / `vm.wait_ready` / `vm.stop` IPC calls. Without
that delegation, qemu's user-net + IOUSBHost claim semantics don't
compose with a non-app process on macOS Sonoma+. Linux keeps spawning
qemu directly.
USB passthrough is intentionally not part of this commit: it's handled
out-of-band by Avocado.app's IOUSBHost → USB/IP → vhci_hcd bridge.
login emits NDJSON events (login_url, info, complete, error) so the desktop app can drive the browser handshake; status and logout emit single objects. Human output is unchanged when --output is omitted.
Mechanical reformat across the VM and ext command paths, plus three clippy fixes the stable toolchain now promotes under -D warnings: - src/utils/vm/client.rs — drop redundant inner #![cfg(target_os = "macos")]; the parent vm/mod.rs already gates the whole module. - src/utils/vm/lifecycle.rs — `!n.is_multiple_of(8)` in place of the manual `n % 8 != 0` for ssh-key padding. No behavior changes.
The connect-auth subcommands had their own OutputFormat enum plus `emit_json_event` / `emit_json_object` helpers. Promote them to a shared `crate::utils::output_format` module so init, config show, install, build, and provision can all import the same type and use the same NDJSON helpers without duplication. The auth module re-exports the type under its old name for existing call sites.
…sion
Phase 2 of the Avocado desktop integration: every command the macOS app
shells out to now supports `--output json` so the desktop UI can consume
structured events instead of regexing prose.
New surface:
- `avocado init --reference X --name myproj --output json` writes into
`<directory>/<myproj>/` (instead of `<directory>/`) and emits NDJSON:
`{event:info,…}` per progress step, terminal `{event:complete,…}` or
`{event:error,…}`. Test fixtures updated for the new `new()` signature.
- `avocado config show --output json` — new subcommand under a new
`Config` group. Returns a stable narrow projection of avocado.yaml
(distro release/channel, default_target, supported_targets as `"*"`
or list, runtimes, provision_profiles, src_dir). Human mode prints
a YAML-ish summary. Lets the app stop parsing YAML in Swift.
- `avocado install / build / provision --output json` skip TUI
rendering and emit NDJSON `step` events for each task lifecycle
transition (`task_registered`, `step` with running/success/failed,
`step_error`, `output`). JSON mode also auto-enables `--force`
semantics so dnf gets `-y` and docker drops `-it`.
Plumbing:
- `utils::output::should_create_renderer()` — new helper. The
install/build dispatch and `create_standalone_tui` now create a
TaskRenderer in JSON mode too (Passthrough mode, doesn't paint;
state-mutators tap a JSON event sink). Previously the renderer was
skipped in JSON mode and sdk/rootfs/initramfs/target-dev steps
were invisible to the desktop app.
- `utils::tui::renderer` — `register_task`, `set_status`,
`append_output`, `replace_last_output`, `set_error` now emit
matching NDJSON events when JSON mode is active. Output lines carry
the task name so the UI can attribute parallel-task logs.
- `utils::output::tui_is_active()` and `should_use_tui()` treat JSON
mode as "TUI on" for prose suppression / docker-flag purposes.
- Dispatch arms in main.rs install/build/provision wrap execution in
`JsonOutputGuard::enable()` + emit `{event:start,…}`; `Install`
and `Provision` derive `force = explicit_force || json_mode`.
In container.rs's docker arg builder, JSON mode skips both `-i` and
`-t` (stdin is a Pipe, not a TTY; dnf would deadlock on prompts).
When `avocado vm start` (terminal) launches the VM, lifecycle::start SSHes in post-boot to mount the 9p `workspace` share at /run/workspace so docker bind mounts under the user's home directory work inside the guest. When Avocado.app launches QEMU directly (via VMSupervisor.swift) the SSH-mount step is skipped — leaving `/run/workspace` as empty tmpfs scaffolding and every subsequent docker bind silently mounting nothing. The symptom was `Compile script rust-compile.sh not found` with an empty `ls -la` of `/opt/src` inside the build container — the host file existed, the 9p share was declared at QEMU, but never mounted in the guest. Fix: call `share::ensure_mounted_in_guest` lazily from `SdkContainer::run_in_container`, gated on `is_vm_routing_active()`. The SSH probe is idempotent (`mountpoint -q` precheck) so calling on every container start costs ~5ms when already mounted, ~80ms cold. Failures are non-fatal — surface a warning and let docker fail loudly if the mount is genuinely broken.
`avocado build` without `-r` already parallelized extension builds via the TaskScheduler at the main path, but `-r <runtime>` took an early-return into `build_single_runtime`, which ran extensions through a plain serial for-loop (and also missed the renderer registration and pre-flight stamp check that the main path picked up later). Remove the early return and let `get_runtimes_to_build` filter to the single requested runtime — it already supports that. The unused `build_single_runtime` / `find_extensions_for_runtime` helpers go with it (~280 lines). The only behavioral lossage is the legacy `packages.<name>.extensions:` discovery path, which had no test coverage and is absent from current projects (modern format uses the top-level `extensions: [...]` array). Verified on rust-vitals: 4 ext builds now fire concurrently for `avocado build -r dev`, 5th queued behind the parallelism cap — same pattern as the no-flag form.
Provisioning profiles aren't statically declared in avocado.yaml —
they live in `$AVOCADO_SDK_PREFIX/stone/stone-<target>.json` inside
the SDK volume, written there during `avocado install`. Add a
`--list` flag to `avocado provision` that short-circuits the run,
reads that manifest, and returns the available profiles plus the
declared default.
Output (JSON):
{ "available": true, "target": "qemux86-64", "default": "img",
"profiles": [{"name": "img", "script": "stone-provision-img.sh"}] }
Implementation: a one-shot `docker run --rm -v <vol>:/opt/_avocado:ro
<sdk-image> /bin/sh -c "cat /opt/_avocado/<target>/sdk/*/stone/..."`
glob handles both x86_64 and aarch64 SDK arches. Gracefully returns
`available:false` with a reason when the SDK isn't installed, when
there's no stone manifest for the resolved target, or when the
config is missing required fields — so the desktop app can
distinguish "no profiles yet" from "command failed" via the JSON
envelope instead of the process exit code.
A long-lived per-project inspector container would amortize the
docker startup across reads; saving that for a follow-up once the
UI has more uses for it.
`.avocado-state` is the only pointer to the docker volume's name. Removing it on `--skip-volumes` invocations (the unlock-/stamps-only paths) orphans the volume — it stays on disk but the next `avocado clean --volumes` can't find it. Pair the two: remove `.avocado-state` together with the docker volume, leave it untouched when `--skip-volumes` is set. Tests are rewritten to cover both arms.
The desktop app needs the new project's ID right after creation to
persist the {org, project} link in its own per-project state (no
avocado.yaml write-back). Single-shot JSON keeps the contract small:
`{org, id, name}`.
`config show --output json` gains a `connect: {org, project}` mirror
so the desktop can render a "Delete project" affordance that knows
which IDs to pass to `connect projects delete`.
Existing human prose output is unchanged.
Prep for distributing avocado-cli through a private Homebrew tap
(`avocado-linux/homebrew-tap`) with a path to homebrew-core later.
- License: MIT -> Apache-2.0. homebrew-core accepts both, but
Apache-2.0 is what the rest of the avocado-linux org publishes
under and what we want to standardise on.
- src/utils/install_method.rs (new): detects Homebrew / Cargo /
Direct installs by inspecting the current exe path. Used by:
* `avocado upgrade` — after a successful self-update under
Homebrew, advises `brew upgrade avocado-cli` so the next
`brew upgrade` doesn't silently reset the binary to the
formula version.
* the `[UPDATE]` notice — adjusts the suggested command for
Homebrew users.
- .github/workflows/release.yml gains three things:
* per-tarball `.sha256` sidecar files, uploaded alongside each
release asset.
* a `sha256sums` job that aggregates them into a single
`SHA256SUMS` file on the release.
* a `bump-homebrew-tap` job that runs on stable tags
(no prerelease suffix), reads the sha256s for each platform,
and dispatches an update to `avocado-linux/homebrew-tap`.
- README gains an Install section pointing at the Homebrew tap and
the GitHub Releases download path.
Stone 2.2.0 lets the last expand=true partition omit `size` and instead take its byte count from `--partition-size NAME=BYTES` at bundle time. Our manifests now drop the hand-picked var size, so the build script must measure the freshly-built btrfs and forward the result. `FINAL_SIZE` is already computed a few lines above (mkfs.btrfs post-creation stat); just thread it into the stone bundle invocation. Stone rounds the raw bytes up to the partition's size_alignment (default 4 MiB) before writing the layout section, so the result is provisioning-friendly.
ext.<name>.post_build and runtimes.<name>.post_build name a src-relative script that runs as the final step of `avocado ext build` and `avocado runtime build` (and through them, `avocado build`). For extensions the hook fires after the sysroot is populated but BEFORE the sysext/confext .raw images are sealed, so the script can mutate $AVOCADO_BUILD_EXT_SYSROOT and have changes baked into the image (e.g. generating /etc/ssl/certs/ca-certificates.crt from the installed ca-certificates package). For runtimes the hook fires after the runtime image is built — the runtime image is the final artifact, so there's no equivalent pre-seal slot. Extension scripts resolve relative to the ext's source dir: /opt/src for local extensions, $AVOCADO_PREFIX/includes/<ext>/ for remote ones, so remote extensions can ship their own scripts. Runtime scripts resolve relative to /opt/src (runtimes are local-only). Hashing the post_build field into the build stamp lets adding/removing/renaming the hook re-trigger a build; the script's contents are NOT hashed, so editing the script in-place still needs --no-stamps to force a re-run.
Plumbing for `avocado vm update` and `avocado vm reset-var`. No behaviour change yet — this commit only adds modules; nothing invokes them. - vm::manifest: extend the existing Manifest/Artifact types with the 0.1.0-contract fields. `version` and `released_at` on the manifest, `size` and `update_policy` on each artifact. All optional via serde defaults so legacy installs that pre-date the contract still parse. - vm::channel (new): types for `stable.json` / `beta.json` plus `is_newer_than()` (semver-aware) and `check_cli_compatibility()` (refuses to advertise a release whose `min_cli_version` exceeds the running CLI). - vm::staging (new): `~/.avocado/vm/staging/<version>/` discipline. Provides slot paths, sha256 verification, atomic-swap-by-rename, and a `.was-running` marker so a crashed update can preserve the restart intent across a retry. - vm_update_check (new): 24h-cached poll of `https://repo.avocadolinux.org/releases/vm/<channel>.json`, parallel to update_check.rs's GitHub Releases poll for the CLI itself. Respects AVOCADO_NO_UPDATE_CHECK and an AVOCADO_VM_CHANNEL_URL_BASE env override for testing. - user_config (new): ~/.avocado/config.yaml loader. Today exposes `[vm].channel`; future hooks for `[vm].dir` and `[vm].auto_update` already declared (dead_code-allowed) so the schema doesn't churn when those land. 13 new unit tests, all green. CLI still compiles + passes its existing 957 tests.
Polls the configured channel for a newer VM release, downloads any artifacts whose update_policy is "replace" and whose sha differs from the installed copy, atomic-swaps them into ~/.avocado/vm/install/. Stops the VM during the swap and restarts it afterward if it was running. `update_policy: "seed_only"` artifacts (i.e. var) are downloaded only on first install — never overwritten on a real update. User state in the persistent var.btrfs survives version bumps. Refresh the var artifact via the upcoming `vm reset-var` command if you actually want a clean slate. CLI surface: avocado vm update --check # availability check, no download avocado vm update -y # skip interactive confirmation avocado vm update --channel beta avocado vm update --output json Behaviour against live https://repo.avocadolinux.org/releases/vm/ verified end-to-end: --check on a fresh host reports v0.1.0 with correct channel/released_at/source. VmPaths grows install_dir() + install_manifest() helpers for the managed install location (separate from a developer-supplied --vm-source which the CLI never modifies).
Wipe the persistent var.btrfs and re-seed from the installed `var` artifact (the one recorded in ~/.avocado/vm/artifact-dir from the last `vm start`/`vm update`/`vm rebuild`). Doesn't touch the VM image version — only state. Interactive confirmation requires typing 'reset' to proceed (not just 'y') because this is genuinely irreversible — Docker volumes, container caches, project work in /data, /etc/machine-id all go away. `-y/--yes` for scripted use. If the VM is running, stop it gracefully, wipe, restart with the same artifact dir. Matches the `vm update` lifecycle pattern. Use cases captured in the doc comment: corrupted /var, testing provision flows from scratch, drop accumulated cruft.
Covers the common cases: check-only, apply, scripted, channel override, ~/.avocado/config.yaml for persistent channel pinning, and the reset flow with its 'type reset' confirmation. Includes a pointer to AVOCADO_NO_UPDATE_CHECK for users who want to disable polling entirely.
- fmt --check fixups across the new modules (reset, update,
user_config, vm/manifest, vm/staging, vm_update_check).
- Drop the redundant closure on default_platform_for_host().
- Collapse nested format! into a single one ({}/{} instead of
format!("{}{}", base, format!("/{}", file))).
- Derive Default on UpdatePolicy via #[default] on Replace instead
of a hand-rolled impl.
pr.yml + test-reusable.yml gate on cargo fmt --check + cargo
clippy -D warnings + cargo test; all four now pass locally
(966 lib + 126 integration tests green).
Generates static completion scripts for bash/zsh/fish/elvish/PowerShell from the existing clap derive macros. Users wire it up via e.g. `avocado completion bash > /etc/bash_completion.d/avocado` (zsh: write to a file named `_avocado` on `$fpath`). Skips the background update-check spawn for this command — like `upgrade`, it has no reason to hit the network.
…s, signing keys Switches `avocado completion <shell>` from emitting a multi-thousand-line static script to emitting a thin registration wrapper. The wrapper calls back into `avocado` on every TAB press, which lets candidate sets stay live with the current `avocado.yaml` and the user's signing-key registry. Wiring is centralized in a `clap::Command` walker (`attach_completers`) that matches by arg id, so every `--extension` / `--runtime` / `--target` flag across all subcommands gets a completer with no per-site `#[arg(add = ...)]` attribute. Signing-key positionals are wired explicitly at the two call sites. The completers read `avocado.yaml` directly (no include resolution, no SDK container) and the local signing-key registry. Each TAB invocation measures at ~7ms in release builds. Missing `avocado.yaml` or absent sections silently yield no candidates rather than erroring. Provision-profile completion is deliberately omitted: the stone manifest lives inside the SDK docker volume and reading it costs seconds per TAB, which would make completion feel broken. Revisit if we add a local manifest cache.
Extends the stone manifest reader to parse `provision.envs` and
`provision.fields`, then resolves each profile's enabled fields by
walking its named env-block references for `${VAR}` placeholders.
The resolved field list (name, type, label, description, required,
default) is emitted under each profile in the JSON output so the
desktop app can render a dynamic provisioning form keyed off the
manifest rather than hardcoding inputs per target.
Inline env blocks are skipped — they carry no field metadata.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bumps avocado-cli to 0.39.0. 24 commits since the 0.38.0 tag.
Three big themes:
avocado vmsubcommand — first-class managed QEMU helper so Docker-dependent flows (provision, ext build, sdk run) work on macOS / Windows without Docker Desktop. Includes its own update + reset lifecycle.--output jsonacross the command surface — every command the macOS desktop app shells out to now emits structured NDJSON, enabling the desktop UI to consume events instead of regexing prose.homebrew-coreeventually.Plus shell tab completion, parallel extension builds under
-r, and a post-build hook for extensions/runtimes.avocado vm(macOS / Windows)avocado vm {start,stop,status,shell,logs,rebuild}(4d6b797) — managed QEMU guest with built-in dockerd + 9p source mount. State under~/.avocado/vm/.DOCKER_HOSTauto-flips to the SSH-forwarded socket for subcommands that need docker; opt out with--no-vm-auto-start/AVOCADO_VM_AUTO_START=0/--runs-on. macOS delegates qemu spawn toAvocado.appover a JSON-line IPC socket (qemu's user-net + IOUSBHost don't compose with a non-app process on Sonoma+). Linux still spawns qemu directly.avocado vm update(077d37f,d34110e) — polls the configured channel athttps://repo.avocadolinux.org/releases/vm/, atomic-swapsreplace-policy artifacts whose sha changed, and preserves the persistentvar.btrfs(which isseed_only). Supports--check,-y,--channel beta,--output json. Pinning available via~/.avocado/config.yaml[vm].channel.avocado vm reset(9554f79) — wipe the persistent var and re-seed from the last installedvarartifact. Interactive confirmation requires typingreset;-yfor scripted use.68545a5) — when Avocado.app launches QEMU directly (vs.avocado vm startin a terminal), the SSH-driven 9p mount step would be skipped, leaving every docker bind mount silently empty. Now triggered lazily fromSdkContainer::run_in_containergated onis_vm_routing_active().4e44151).--output json(desktop integration)init / config show / install / build / provision(efd77a5) — every command emits NDJSON{event, …}records.inithonours--nameand writes into<directory>/<name>/.config showis a new subcommand returning a narrow projection ofavocado.yaml.install/build/provisionJSON mode also auto-enables--forceso dnf gets-yand docker drops-i/-t.connect auth {login,status,logout}(f66af80) — login emits{login_url, info, complete, error}NDJSON so the desktop can drive the browser handshake.connect projects create+config show'sconnectblock (606686d) — desktop needs the new project's ID immediately after creation;config show --output jsonmirrorsconnect: {org, project}so a "Delete project" affordance knows which IDs to pass.avocado provision --list(1484062) — short-circuits the provision run to enumerate available profiles fromstone-<target>.jsoninside the SDK volume. Returns{available, target, default, profiles}so the desktop can render a profile picker, with a distinctavailable:falsereason when the SDK isn't installed yet.--listJSON (af3f7bf) — extends the stone manifest reader to parseprovision.envs/provision.fields; resolves each profile's enabled fields by walking its env-block references. Desktop renders a dynamic provisioning form keyed off the manifest.utils::output_formatrefactor (47db766) — sharedOutputFormatenum +emit_json_event/emit_json_objecthelpers, hoisted out of the auth module.Shell completion
avocado completion <shell>(9812399) — bash/zsh/fish/elvish/PowerShell. Skips the update-check spawn likeupgradedoes.434e652) — wrapper calls back intoavocadoon every TAB.--extension/--runtime/--targetand signing-key positionals get candidates from the liveavocado.yamland signing-key registry. ~7ms per TAB in release. Provision-profile completion deliberately deferred (manifest lives inside SDK volume, too slow).Build / extension improvements
post_buildhook on extensions and runtimes (02a7ebf) — script runs as the final step ofext build/runtime build. For extensions, fires before the sysext/confext.rawimages are sealed so the script can mutate$AVOCADO_BUILD_EXT_SYSROOT. Hashed into the build stamp so adding/removing the hook re-triggers a build (script contents aren't hashed — edit in place still needs--no-stamps).-r <runtime>(af70b73) —avocado build -r devpreviously took an early-return into a serial path. Removed;get_runtimes_to_buildalready supports the filter, and theTaskSchedulerpath handles parallelism. Verified 4 concurrent ext builds on rust-vitals. Drops ~280 lines of dead code.cp -ainstead ofrsyncin overlay merges (671939a) — stripped SDK variants don't ship rsync.cp -acovers recursive copy + attrs + symlinks; a follow-upchown -R root:rootcovers ownership.container_toolplumbed through volume + image copy paths (0fdb5aa) —dockerwas hardcoded incopy_volume_path_to_host,VolumeManager, and per-commandcopy_rpm_to_host. Now uses the caller's already-resolved tool so podman / nerdctl keep working.d7bd22c) — Stone 2.2.0 lets the lastexpand=truepartition omitsizeand take its byte count via--partition-size NAME=BYTESat bundle time.Cleanup
cleanno longer orphans the docker volume (f5c1d48) —.avocado-stateis the only pointer to the docker volume's name; removing it on--skip-volumesinvocations made the volume unreachable. Paired the two: remove together, leave untouched when--skip-volumesis set.Distribution
e2eacd8):utils::install_methoddetects Homebrew / Cargo / Direct installs and adjusts theupgradeadvisory +[UPDATE]notice accordingly..github/workflows/release.ymlgains per-tarball.sha256sidecars, aSHA256SUMSaggregate, and abump-homebrew-tapjob that dispatches toavocado-linux/homebrew-tapon stable tags.Maintenance
923d5bc— cargo fmt sweep + clippy fixes for the newer stable toolchain (across vm/ + ext paths).0edc1a7— additional fmt + clippy fixups across the new VM modules;pr.ymlalready gates onfmt --check+clippy -D warnings+cargo test.Test plan
cargo fmt --all -- --checkcleancargo clippy --all-targets --all-features -- -D warningscleancargo buildcleancargo test— all suites green (977 lib + 970 integration + 126 + 49 + 20 + 7 + 6 + 6 + 5 = ~2166 tests)cargo audit— no advisories on the lockfileavocado vm start/vm update --check/vm reset -yround-trip on macOSavocado completion zshregistered into\$fpath, TAB completes extensions/runtimes/targets/signing keysavocado init --output json --name testwrites NDJSON terminating incompleteavocado provision --list --output jsonagainst a project with installed SDK