From 67b0c3925f35605b2c05f638f7f93c1229b011aa Mon Sep 17 00:00:00 2001 From: rldyourmnd Date: Tue, 4 Aug 2026 20:12:21 +0500 Subject: [PATCH] fix(probe): correct command-default-location flag, owner-only probe umask, robust binary resolution Three independent defects in install-cli's stage version probe and binary resolution, all blocking install-cli on the pinned 2470.4 release: 1. The probe passed --command-default-locations (plural), which Junie's CLI does not accept. The supported flag is --command-default-location (singular) for commands, while config/mcp/skill/model stay plural. The probe and the launch flag builder both used the plural form, so the probe exited non-zero with 'no such option --command-default-locations'. 2. Junie is a JVM app that writes runtime state (~/.junie) under the isolated probe HOME. Under an ambient umask (e.g. 022) that state is not private, and require_private_directory rejected it. Run the probe under an owner-only umask (0o077) via preexec_fn so anything Junie creates is already private. 3. resolve_junie_binary only caught FileNotFoundError when probing candidate paths. When versions//junie is the launcher script (a regular file), lstat on versions//junie/bin/junie raises NotADirectoryError, which escaped the loop and crashed install-cli. Catch NotADirectoryError too so the next candidate (the launcher itself) is tried. --- cli-tools/nddev_junie_cli.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cli-tools/nddev_junie_cli.py b/cli-tools/nddev_junie_cli.py index 8139983..2dda164 100644 --- a/cli-tools/nddev_junie_cli.py +++ b/cli-tools/nddev_junie_cli.py @@ -225,7 +225,7 @@ "--agent-location", "--agent-default-location", "--command-location", - "--command-default-locations", + "--command-default-location", "--extensions-default-location", "--guidelines-filename", "--model-location", @@ -4317,7 +4317,12 @@ def resolve_junie_binary(version_dir: Path, target: Path) -> Path: for candidate in candidates: try: info = candidate.lstat() - except FileNotFoundError: + except (FileNotFoundError, NotADirectoryError): + # FileNotFoundError: candidate does not exist. + # NotADirectoryError: an earlier path component is a regular file + # (e.g. versions//junie is the launcher script, so + # versions//junie/bin/junie cannot be traversed). Either way + # this candidate is not the binary; try the next one. continue try: require_current_owner(info, "Junie binary") @@ -4695,7 +4700,7 @@ def run_stage_version_probe(stage_home: Path, version: str, timeout: int) -> Non "false", "--command-location", str(commands), - "--command-default-locations", + "--command-default-location", "false", "--model-default-locations", "false", @@ -4711,6 +4716,12 @@ def run_stage_version_probe(stage_home: Path, version: str, timeout: int) -> Non capture_output=True, check=False, timeout=timeout, + # Junie is a JVM app that writes runtime state (~/.junie) under the + # isolated probe HOME. Force an owner-only umask so anything it + # creates is already private and survives the + # require_private_directory check that follows, regardless of the + # caller's ambient umask. + preexec_fn=lambda: os.umask(0o077), ) except FileNotFoundError as exc: fail(f"stage Junie version probe command is missing: {exc}") @@ -6800,7 +6811,7 @@ def build_launch_plan_locked(target: Path, child_args: list[str]) -> LaunchPlan: "false", "--command-location", str((canonical / "commands").resolve()), - "--command-default-locations", + "--command-default-location", "false", "--model-default-locations", "false",