Complete just completions: Justfile recipe generator - #307
Conversation
`just.json` shipped Fig's JavaScript `generators.script`/`postProcess` for recipe arguments, which Warp ignores, so `just <TAB>` fell back to filesystem path suggestions instead of listing Justfile recipes. Add a Rust `just` generator that reads recipes from `just --dump --dump-format json`, falling back to `--list` and `--summary` for older releases, plus a variables generator for `--set`, and point the spec's recipe arguments (top-level args and `--show`) at them. Co-Authored-By: Warp Agent <agent@warp.dev>
|
@warp-agent-staging[bot] I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds Rust-backed dynamic generators for Justfile recipes and variables, then wires the just signature to use them for recipe and variable arguments.
Concerns
- The variadic recipe argument is now backed by an unconditional recipe-name generator, which drops the previous arity/trigger behavior for parameterized recipes.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| "script": "_NuFrRa_n=>{let e=g(n);return d(e)}", | ||
| "postProcess": "_NuFrRa_(n,e)=>{let i=c(n);if(i===null)return[];let{recipeArity:s,maxArity:r}=h(i),t=Math.min(r,e.length-2);for(let a=0;a<t;a++){let p=e.length-2-a,u=e[p],l=s.get(u);if(l!==void 0){if(l>a)return[];break}}return m(i,{showRecipeParameters:!0})}" | ||
| } | ||
| "generatorName": "recipes" |
There was a problem hiding this comment.
deploy env:, just deploy <TAB> will suggest recipe names instead of allowing the env value; port the arity check before wiring this unconditional generator here.
## Description Updates `warp-command-signatures` from `5e08807c` to `fe352669` so the client picks up the new `vagrant` completion spec. This is the client-side half of APP-3965; the spec itself merged in warpdotdev/command-signatures#306. Closes #9781 ### Merged PRs picked up by this bump - Add completion spec: Vagrant (vagrant) (warpdotdev/command-signatures#306) — the reason for this bump - Complete just completions: Justfile recipe generator (warpdotdev/command-signatures#307) - Add completion spec: tcpdump (warpdotdev/command-signatures#305) `fe352669` is the current `main` head of `warpdotdev/command-signatures` and is #306's merge commit. The diff is 3 lines — the `rev` in `Cargo.toml` and the two matching `source` lines in `Cargo.lock`. The two revs have **identical dependency manifests** (verified with `git diff 5e08807c fe352669 -- Cargo.toml '*/Cargo.toml'`, empty), so no other lockfile entry legitimately changes and no unrelated dependency churn rides along. `cargo metadata --locked` passes, confirming the lockfile is consistent. ## Verification **Testing-exempt category: dependency/version bump.** No regression test is added — the change is a git rev plus its lockfile consequence, so a unit test here could only assert the new rev string rather than detect a logic defect. The completion data itself is tested in `command-signatures`. The client-side resolution and UI checks below are the meaningful proof, and they are the whole point of this PR. ### Visual proof: `vagrant` completions in the running client Captured against a `warp-oss` build of **this PR's branch** (so the completions come from the pinned rev `fe352669`, not a local path override), running on an Xvfb display. The Vagrant CLI is not installed on the capture machine and is not needed — both generators are filesystem reads, so a fixture project (`.vagrant/machines/{web/virtualbox,db/libvirt,worker/docker}`) and a fixture box store were seeded. - **`vagrant <TAB>`** — the full static subcommand list with descriptions, in spec order (`autocomplete`, `box`, `cloud`, `destroy`, `docker-exec`, `docker-logs`, `docker-run`, `global-status`, `halt`, `help`, `init`, `list-commands`, `login`, `package`, `plugin`, `port`, `powershell`, `provider`, `provision`, `push`, `rdp`, `reload`, `resume`, `rsync`, `rsync-auto`, `snapshot`, `ssh`, `ssh-config`, `status`, `suspend`, `up`, `upload`, `validate`, `version`, `winrm`, `winrm-config`), followed by the global flags. - **`vagrant up <TAB>`** — the `vagrant_machines` generator resolving live against the fixture project: `db` described as `libvirt`, `web` as `virtualbox`, `worker` as `docker`, followed by `up`'s own flags (`--provision`/`--no-provision`, `--provider`, `--destroy-on-error`, …). - **`vagrant box remove <TAB>`** — the `vagrant_boxes` generator, **with the `-VAGRANTSLASH-` / `-VAGRANTCOLON-` un-escaping applied**: the on-disk directories `hashicorp-VAGRANTSLASH-bionic64`, `ubuntu-VAGRANTSLASH-focal64`, `generic-VAGRANTSLASH-alpine318`, and `registry.example.com-VAGRANTCOLON-8080-VAGRANTSLASH-internal-base` render as `hashicorp/bionic64`, `ubuntu/focal64`, `generic/alpine318`, and `registry.example.com:8080/internal-base`. No literal `VAGRANTSLASH`/`VAGRANTCOLON` text appears anywhere in the menu. One cosmetic note from the capture, not caused by this PR: the longest fixture entry (`registry.example.com:8080/internal-base`, an artificially long name invented for the un-escaping test) renders with its `Installed box` description column squeezed to empty, while the shorter names show it. The generator attaches that description unconditionally, so this is dropdown column truncation on an unusually long name rather than missing data. ### Deterministic checks - **`vagrant` resolves through warp's own completer registry.** Ran an ad-hoc (uncommitted) test against `CommandRegistry::global_instance()` — the same registry `crates/warp_completer/src/signatures/legacy/mod.rs` builds from the embedded signatures. Result: `registry.signature("vagrant")` returns `Some`, description `"Build and manage reproducible virtual machine environments"`, **36 subcommands**, and the nested `box` group resolves to `add, list, outdated, prune, remove, repackage, update, help`. - **Crate-level check against the exact feature set `warp_completer` enables.** Exercised `warp_command_signatures::signature_by_name("vagrant")` and `dynamic_command_signature_data()` with `default-features = false, features = ["embed-signatures"]`, matching what `warp_completer` enables on non-wasm. Result: signature resolves with all 36 subcommands, nested groups populated (`cloud`: auth/box/provider/publish/search/version; `plugin`: install/license/list/uninstall/update/repair/expunge; `snapshot`: delete/list/pop/push/restore/save), 19 options on `vagrant up`, and both `vagrant_machines` and `vagrant_boxes` generators registered in `dynamic_command_signature_data()`. An unknown command still resolves to `None`, confirming embedded data is genuinely being read. - **Before/after.** The same check against the *old* pin `5e08807c` returns `NOT FOUND` for `vagrant` with no generators registered, so this bump is what delivers the signature. - **`./script/format --check`** — clean. - **`cargo clippy -p warp_completer --all-targets --locked -- -D warnings`** — clean. - **`cargo check -p warp_completer --locked`** — clean. - **`cargo metadata --locked`** — passes. - **`cargo test -p warp_completer --locked`** — 138 passed, 25 failed. Those 25 failures are **pre-existing and unrelated**: the identical command on a clean `origin/master` checkout without this change produces the byte-identical `138 passed; 25 failed`. They all panic in `warp_features` with "Tried to check FeatureFlag::CloudEnvironments before feature flags were initialized", which happens because a single-crate test run does not pull in `warp_features/test-util` the way a workspace run does. Not introduced here. - The workspace-wide `./script/presubmit` was not run — disproportionate to a manifest-only pin, and CI covers it. Worth flagging for reviewers: the spec-surface regression tests in `command-signatures` cover the JSON there, but **nothing in this repo will fail if the `vagrant` signature is later dropped or renamed upstream** — the checks above are one-time confirmations, not standing guards. CHANGELOG-IMPROVEMENT: Added completions for `vagrant`, including its nested `box`, `cloud`, `plugin`, and `snapshot` command groups plus dynamic machine and box names. Originating thread: https://warpdev.slack.com/archives/C0BDQDW8V5E/p1785980828616589 <!-- oz:computer-use-videos start --> ### Computer-use video recordings [](https://oz.staging.warp.dev/artifacts/019fd53d-2cda-72e8-b3b4-75eb7b11a7c9) **Warp vagrant command-completion dropdowns**: Demonstrating Warp's completion dropdown for three command lines: "vagrant ", "vagrant up ", and "vagrant box remove ", pausing on each dropdown. <!-- oz:computer-use-videos end --> <!-- oz:computer-use-screenshots start --> <details> <summary>Computer-use screenshots (3)</summary>  Warp completion dropdown after typing "vagrant " showing autocomplete, box, cloud, destroy, docker-exec, docker-logs.  Warp completion dropdown after typing "vagrant up " showing db (libvirt), web (virtualbox), worker (docker), then flags --color, --debug, --debug-timestamp.  Warp completion dropdown after typing "vagrant box remove " showing box names with literal slashes/colon: generic/alpine318, hashicorp/bionic64, registry.example.com:8080/internal-base, ubuntu/focal64, then flags --all, --all-architectures. </details> <!-- oz:computer-use-screenshots end --> ### Rework changes - **[IMPORTANT] `Cargo.toml` — visual proof of `vagrant <TAB>` required.** Addressed. Built `warp-oss` from this PR's branch (not a local signatures path override, so the capture exercises the pinned rev) and captured a video plus three screenshots of `vagrant <TAB>`, `vagrant up <TAB>` (the `vagrant_machines` generator), and `vagrant box remove <TAB>` (the `vagrant_boxes` generator including `-VAGRANTSLASH-`/`-VAGRANTCOLON-` un-escaping). Embedded above and posted to the Linear ticket. The previous "no GUI/computer-use proof" caveat has been removed rather than left beside the new evidence. - No code changes in this cycle — the diff is unchanged at 3 lines across `Cargo.toml` and `Cargo.lock`. <!-- factory-agent: {"source":"factory-agent","task_id":"APP-3965","task_source":"linear","task_url":"https://linear.app/warpdotdev/issue/APP-3965/add-vagrant-completions","oz_run_id":"019fd50c-bdf9-71f9-98f4-305716f44f2f","repo":"warpdotdev/warp","review_rework_attempts":1} --> _This PR was generated with [Oz](https://warp.dev/oz)._ Co-authored-by: Warp Agent <agent@warp.dev>
Summary
just <TAB>offered filesystem paths instead of Justfile recipes.json/just.jsonalready describedjust's flags, but its recipe arguments carried Fig's JavaScriptgenerators.script/postProcess— which Warp ignores — and there was no Rust generator behind them, so the completer fell through to the path templates.This adds the missing Rust generators and points the spec at them:
src/generators/just.rs— arecipesgenerator and avariablesgenerator, registered ingenerators/mod.rs.recipesprefersjust --unstable --dump --dump-format json(carries doc comments and theprivateflag), falling back tojust --listand thenjust --summaryfor olderjustreleases. Private recipes (leading_or[private]) are omitted, matchingjust's own listing behavior, and a recipe's doc comment becomes its description (Just recipewhen it has none).Priority::Global(Importance::More(Order(80))), the same rankmaketargets use, so they sort above the path suggestions for the same position.justnot being installed all end with empty stdout and an empty suggestion list — never a panic.json/just.json— the variadic recipe argument and--shownow use"generatorName": "recipes";--set's variable argument uses"generatorName": "variables". The Fig JS generator blobs are removed. Flags and options are untouched, so they stay completable.Verification
script/presubmit(prettier,cargo fmt --check,cargo clippy -D warnings,cargo test) passes — 115 tests, 9 new.Regression test:
test_just_spec_wires_recipe_arguments_to_the_recipes_generatorasserts the spec's recipe arguments resolve to therecipesgenerator. It fails onmain(assertion failed: recipe_argument.argument_types.contains(&recipes)) and passes with this change.The remaining tests cover the post-processing against output captured from a real
just1.58.0 run over a Justfile with documented, undocumented, parameterized, grouped,_-private and[private]-attribute recipes:test_dump_json_lists_public_recipes_with_docs— public recipes with their docs, both private recipes dropped.test_dump_json_recipes_outrank_path_suggestions— recipes carry a global priority.test_list_output_lists_recipes_and_skips_group_headings—--listparsing,[group]headings skipped.test_list_output_with_only_private_recipes_is_empty,test_list_output_keeps_a_hash_inside_a_parameter_default,test_summary_output_lists_recipes.test_unusable_output_yields_no_suggestions— empty, whitespace-only, and malformed output all yield zero suggestions.test_variables_are_listed.The generator's shell command was also run end to end against
just1.58.0: it returns the JSON dump in a Justfile directory, and exits non-zero with empty stdout both with no Justfile present and withjustoff$PATH.No computer-use proof is attached: this repo is a headless library with no rendered surface of its own, and the change cannot be seen in the client until the
warppin below moves.Follow-up required to ship
warpdotdev/warppinswarp-command-signaturesby git rev in its rootCargo.toml. That rev must be bumped after this PR merges for the completions to reach the client; that bump is deliberately not part of this PR.Originating thread: https://warpdev.slack.com/archives/C0BDQDW8V5E/p1785982310270809
Source issue: warpdotdev/warp#1906
Conversation: https://staging.warp.dev/conversation/e450180d-3523-4c00-8d34-59a96e0edf7f
Run: https://oz.staging.warp.dev/runs/019fd4e0-3937-72e5-9624-4be092502e6f
This PR was generated with Oz.