Releases: kjanat/runner
Releases · kjanat/runner
v0.14.0
Changed
- Built-in verb dispatch is split between the two surfaces. The explicit
runner <verb>subcommand —install,clean,list,info,
completions— is now always the built-in and is never shadowed by a
same-named project task. The run path (run <verb>/runner run <verb>)
runs a same-named task when one exists, and otherwise falls back to that
built-in's default form instead of the package-manager exec path (so
run installwith noinstalltask installs dependencies rather than
attemptingbunx install). Previously the precedence was reversed:
runner installdeferred to a task namedinstall(e.g. aMakefile
installtarget), which surprised projects whoseinstallmeans "install
the built artifact" rather than "install dependencies". Reach a same-named
task withrun install/runner run install; the built-in default for
infoon the run path is a plain task list (no deprecation warning, which
remains specific to the explicitrunner infosubcommand). See
#55 - The
runalias now forwards--help/-hand--version/-Vto the
task when they follow a task name:run <task> --helpreaches the
task's own help instead of printingrun's (previouslyrun <task> --
was required).run --help/--versionwith no task — including after
global flags likerun --pm npm --help— still print this binary's own
help/version, andrun <task> -- --helpstill forwards literally. The
runner runsubcommand is unchanged. Because-h/--help/-V/
--versionare no longer clap arguments on the alias, they are
documented in the help footer rather than the options list.
What's Changed
Full Changelog: v0.13.1...v0.14.0
v0.13.1
Added
runner doctor --jsonschema v3 (now the default fordoctor):
the flat detection dump becomes a structured diagnostic inventory —
invocation/environment/runnerprovenance, per-ecosystems
decisions with aconfidencegrade derived from the resolution step
(override/manifest/lockfile → high, PATH probe → medium, legacy npm
fallback → low, failure → none), tasksourcesas first-class objects,
fqn-keyedtaskswith effectiveresolvedcommands, PATH-probed
tools, duplicate-task-nameconflicts(which task wins, which are
shadowed, and why), flatteneddiagnostics, and a self-describing
resolutionpolicy block. Implements the formerdoctor.v3-draft
schema; the real output validates against both the committed
doctor.v3.schema.jsonand the original draft. Draft shapes nothing
can emit yet (rich dependency edges, workspace identity, probe errors)
are deferred, not declared. v1/v2 remain available via
--schema-version; human output is unchanged.runner why --jsonschema v3 (now the default forwhy): the
report is restructured around{task, match}candidate pairs plus a
decisionblock. Each task carries a stable identity
(fqn=root:<kind>#<name>,provider,kind— cargo aliases are
now labeledcargo-alias), its origin (sourcefile,
source_pointerkey path), and resolution data (definition,
resolvedcommand preview,cwd, siblingaliases,
dependencies). Thematchhalf exposes the exact run-time selection
key (source_priority,depth,display_order, alias-last), and
decision.strategynames the branch taken (single-candidate,
ranked,filtered,exec-fallback). Implements the former
why.v3-draftexample, which the real output now reproduces verbatim;
v1/v2 stay available via--schema-version.listremains at v2 — its
v3 draft is still under review, and it rejects--schema-version 3
rather than mislabel output.schema --allemits the committed
schemas/why.v3.schema.json, and the example validates against it.- Both v3 schemas use the
<scope>:<kind>#<name>fqn form, with#
separating the structured prefix from the verbatim task name so a name
containing:(e.g. an npm scriptfmt:update) stays unambiguous. - Deno tasks now run without the
denobinary. Adeno.json/
deno.jsonctask whose command is a leaf shell command executes
in-process via the embeddeddeno_task_shell(deno's own cross-platform
task shell) whendenoisn't onPATH; withdenoinstalled it still
shells out todeno taskfor full fidelity. Theunstable-deno-exec
feature flips the default to self-exec-first. Tasks that invokedeno
themselves or declaredependenciesstill need the binary. The shell
engine lives in a reusabletool::shellso other shell-string task
sources can build on it later. - Deno task descriptions. The object form
("build": { "command": "…", "description": "…" }) is now parsed and
the description surfaces inrunner list/why/doctor, alongside
the existing bare-string form. runner listand the barerunnerview now print a duplicate-name
conflict footer. When two sources define the same task name (e.g. a
justrunrecipe andcargo run), it names the source that
runner run <name>actually dispatches and the ones it shadows — using
the same precedence as dispatch — so a silently shadowed task no longer
goes unnoticed.
Changed
- Cargo built-in aliases now fold under their canonical subcommand in
runner listand the barerunnerview.b/c/d/t/r/rmare
shown as aliases of the promotedbuild/check/doc/test/run/
removetasks (e.g.test (t)) instead of standing alone; both the
canonical name and the short form still dispatch. Aliases that carry
extra arguments (bb,cl,rq, …) keep their own rows. Promoting
run/removecan collide with a same-namedjust/other task — that
collision now surfaces in the conflict footer above rather than hiding. runner doctor --json(v3) now probes package-manager and task-runner
versions via<tool> --version(previously only the Node runtime
carried a version), reports a per-taskself_executableflag (true for
deno tasks runner can run through the embedded shell), and derives the
Deno tool'srequiredfrom it. Node is included inecosystems/
toolswhenever a resolver or task signal implies it, not only when a
Node package manager was lockfile-detected.- The committed v3 schemas (
doctor.v3.schema.json,
why.v3.schema.json) setadditionalProperties: falsethroughout, so
validation catches stray or misspelled fields in real output instead of
silently accepting them.
What's Changed
- Emit JSON output schemas by @kjanat in #50
- Forward --help/--version to task in
runalias by @kjanat in #54
Full Changelog: v0.13.0...v0.13.1
v0.13.0
Added
runner doctor(andinfo --json) now classify PATH-probe hits that
are Volta shims and resolve them to the real provisioned binary via
volta which: thePATH probeline shows
npm=<shim> -> <real bin> (volta), or
(volta shim, not provisioned)when Volta fronts a tool it has no
version of. JSON gains an additivesignals.node.volta_shimsmap
(omitted on hosts without Volta; no schema bump). Display only —
execution still spawns the shim, which performs Volta's per-project
version selection.
Changed
runner installnow honors the--pm/RUNNER_PMoverride: when set,
only that package manager installs (previously the override was
ignored and every detected PM installed — e.g. a project with both
bun.lockanddeno.jsonalways randeno installtoo, writing an
unwanteddeno.lock). An override naming a PM that detection did not
find refuses the install with exit code 2. runner.toml
[pm].node/[pm].pythoncontinue to scope script dispatch only.- Invalid
--pm/RUNNER_PM/--runner/RUNNER_RUNNERvalues now produce
a readable error: the message names the source that carried the value,
escapes control characters (no more raw ANSI codes), truncates long
garbage, and — when the value contains line breaks — hints that it
looks like captured command output with the correctly quoted PowerShell
spelling. (An unquoted$env:RUNNER_PM=denoexecutes deno and assigns
its REPL banner to the variable.)
Fixed
runner doctorno longer dies when aRUNNER_*override variable
holds an unparseable value — the condition it exists to diagnose. The
invalid value is ignored for the report and surfaced as anenv:
warning (human output and thewarningsarray ofdoctor --json,
additively — no schema bump). Every other command, and an explicit bad
--pm/--runnerflag even on doctor, still fails fast.- Node version constraints are now evaluated with real range semantics
(via thesemvercrate) instead of a prefix match that treated
>=22.22.2as=22.22.2. Operators (>=,>,<=,<,=),
caret/tilde ranges, space-separated AND comparators,||unions,
hyphen ranges, andxwildcards all match per node-semver rules, so
engines.node: ">=22.22.2"no longer warns on Node 22.22.3 or 25.9.0.
Bare versions (.nvmrc20.11) keep the stricter
prefix-at-segment-boundary behavior; unevaluable inputs (lts/*) fall
back to the previous prefix match. - Task dispatch now prepends every existing
node_modules/.binbetween
the project directory and the filesystem root (nearest first) to the
child'sPATH, the waynpm run/pnpm run/bun rundo for
package.jsonscripts. Tools that runner spawns directly —turbo
forturbo.jsontasks, and the bare-binary exec fallback — used to
inherit the shell'sPATHunchanged, so a devDependency-onlyturbo
failed withError: No such file or directory (os error 2)unless it
was also installed globally. On Windows, bare program names are
additionally re-resolved against those bin dirs withPATHEXT, since
CreateProcessWwould never find the.cmdshims npm and pnpm
install there. Local bins now shadow global installs for the spawned
task and everything it launches, matching Node package-manager
semantics. - The no-argument project-info banner no longer leaks the Windows
.exe
suffix in its title line (e.g.run.exe 0.12.2). It now shows the same
run/runneridentity as--version,--help, and theUsage:
line. The banner had its own copy of the arg0-parsing helper that
skipped the.exestripping done everywhere else; it now reuses the
canonicalbin_name_from_arg0. runner mannow works on Windows under--features manbuilds. The
subcommand was gatednot(windows), so withexternal_subcommandin
play it silently degraded to task dispatch (bun man→ "Script not
found") instead of rendering. Rendering is pureclap_mangenwith no
OS-specific code, so the gate bought nothing and is gone.install.shruns under any POSIXsh. It carried a#!/usr/bin/env bashshebang, butcurl … | shignores the shebang, so the bash-only
set -o pipefailaborted on line 2 under dash/busybox — the default
/bin/shon the-musltargets. Rewritten POSIX-clean. It also picks
the install dir more intelligently now: reuse an already-installed
runner's directory (verified by its-Vbanner, so a systemrun/
runneris never clobbered), otherwise prefer~/binor
~/.local/binalready onPATH(then one that exists), falling back
to~/.local/bin.
What's Changed
- fix(info): strip Windows .exe suffix from project-info banner title by @kjanat in #44
- fix(run): put project-local node_modules/.bin dirs on the task's PATH by @kjanat in #47
- Version range semantics, PM-override install, self-diagnosing errors, doctor resilience, Volta shims by @kjanat in #45
Full Changelog: v0.12.2...v0.13.0
v0.12.2
Fixed
runner completionsnow detects PowerShell when$SHELLis unset or
unrecognized by falling back to the presence of$PSModulePath, which
pwsh exports on every platform (it never sets$SHELL). A recognized
$SHELLstill takes precedence, so a pwsh session launched from bash
keeps completing for the login shell. Previously bare
runner completionsalways errored under pwsh.
Full Changelog: v0.12.1...v0.12.2
v0.12.1
Added
pyproject.toml[project.scripts]entry points (PEP 621 console
scripts) are now extracted as runnable tasks for Python projects. They
surface under thepyproject.tomlsource inrunner list(with the
entry-point target shown as the description) and dispatch via the
detected Python package manager'srunsubcommand —uv run <name>,
poetry run <name>, orpipenv run <name>. Previously a uv/poetry
project's declared scripts were invisible torunner, which detected
the package manager but listed no tasks.- AUR distribution channel. Two packages on the Arch User Repository:
runner-run-bin(prebuilt binaries forx86_64,aarch64,armv7h)
andrunner-run(source build forx86_64,aarch64).-bin
provides/conflictsrunner-run, so install whichever you prefer —
https://aur.archlinux.org/packages/runner-run-bin and
https://aur.archlinux.org/packages/runner-run. - Shell completions shipped by both AUR packages and auto-loaded from
the canonical system dirs: bash at
/usr/share/bash-completion/completions/{runner,run}, zsh at
/usr/share/zsh/site-functions/{_runner,_run}, fish at
/usr/share/fish/vendor_completions.d/{runner,run}.fish. PowerShell
on Linux has no autoload convention, so the pwsh script is installed
at/usr/share/runner/runner.ps1for users to dot-source from their
$PROFILE. Completions are clap-dynamic — the shell shells out to
the binary for candidates, so tab-completing in a project picks up
the current task list frompackage.json/turbo.json/
Justfile/ etc., not a static snapshot. .github/workflows/aur-release.ymlpublishes both packages on every
release: publishedevent (with manualworkflow_dispatch+
dry-runfor validation). Gated behind a dedicatedaurGitHub
Environment so theAUR_SSH_PRIVATE_KEYsecret is only readable from
that job. Per-pkgconcurrency:group serializes manual + automatic
triggers for the same package without blocking the other matrix leg..github/scripts/publish/aur-prepare.shrewritespkgver/pkgrel
in the checked-in PKGBUILDs and, for the-binpackage, injects
per-archsha256sums_*read directly from the release's published
.sha256companion assets (avoids theupdpkgsumshost-arch-only
limitation). Strict semver regex on the version input refuses
anything containing&,/,\, or newlines before anysed
runs.- Man pages for
runner,run, and each subcommand. Rendered from the
clap command tree by amansubcommand gated behind theman
feature (off by default — never in the shipped binary, never committed)
and shipped by every channel: crates.io (in the published crate), npm
(facademanfield), both AUR packages (/usr/share/man/man1/), and a
runner-<tag>-man.tar.gzGitHub release asset thatinstall.shand
runner-run-binpull from.man runner/man runwork everywhere.
Security
- All third-party
uses:incrates-release.yml,npm-release.yml,
andrelease.ymlpinned to commit SHAs (with a# vNtrailing
comment for readability), so an upstream tag rewrite or
account-takeover cannot silently swap in a different action build. persist-credentials: falseadded to everyactions/checkoutstep
inrelease.yml, soGITHUB_TOKENis not persisted into git config.- Release verification no longer saves Rust caches from pull request
runs, preventing untrusted PRs from persisting cache contents.
Fixed
runner list,runner run, andrunner whynow find
pyproject.tomlscripts and Python package-manager signals from
nested directories (bounded by the containing VCS root), so running
fromsrc/inside a uv/poetry/pipenv project still surfaces and
dispatches[project.scripts]tasks.runner whynow reports Python package-manager resolution for
pyproject.tomltasks, including--pmand[pm].python
overrides, matching the actualrunner rundispatch path.runner list --sourceinvalid-label help now includes
pyproject.tomlin the accepted source list.- Restore the
multiple_crate_versionsClippy allow so CI accepts the
current unavoidable duplicate transitive crate versions while keeping
the broaderclippy::cargodeny group enabled. - Hide the feature-only
runner mangenerator from shippedrunner.1
output, so installed man pages no longer document an unavailable
subcommand.
What's Changed
- feat(aur): publish runner-run + runner-run-bin with shell completions by @kjanat in #35
- docs: document AUR install channel in README, site, and changelog by @kjanat in #36
- Man pages: render from the CLI, ship on every channel by @kjanat in #37
- Surface pyproject.toml [project.scripts] as runnable tasks by @kjanat in #39
Full Changelog: v0.12.0...v0.12.1
v0.12.0
Added
- GitHub Actions log grouping for task output. Sequential and single
task runs wrap each execution in arunner: <task>section, emitted
as::group::/::endgroup::workflow commands under GitHub Actions
(and left untouched in a plain terminal). Toggle with
[github].group_outputinrunner.toml(defaulttrue). - Grouped parallel (
-p) output. Each task's stdout/stderr is captured
and printed as one contiguousrunner: <task>block when that task
finishes (completion order — first done, first shown), instead of
interleaving lines live. Under GitHub Actions the block is a::group::
section; elsewhere it gets a plain colored header. Defaults diverge by
environment so CI and local can differ:[github].group_parallel
(defaulttrue, only when[github].group_outputis alsotrue)
governs runs under GitHub Actions,[parallel].grouped(default
false) governs runs elsewhere. Opting out on either path restores the
live[<task>]-prefixed multiplexer. [github]and[parallel]sections inrunner.toml, reflected in the
generated JSON schema, for the grouping toggles above.actions-rsdependency for emitting GitHub Actions workflow commands.
What's Changed
Full Changelog: v0.11.0...v0.12.0
v0.11.0
Added
- Task chaining for
runner runandrunner install. New-s/
--sequentialand-p/--parallelflags turn the trailing
positionals into a chain:runner run -s build test lintruns
the three tasks in order;runner run -p test:unit test:e2e
fans them out concurrently.runner install build testchains
install → build → test (install head is always sequential;-p
is rejected oninstall). - Failure policies for chains. Default is fail-fast (sequential
stops on first non-zero; parallel lets running siblings finish,
doesn't start new ones).-k/--keep-goingruns every task
to completion regardless of failures, with the chain's final
exit code reflecting the first failure.--kill-on-fail
(parallel only) terminates siblings immediately when one fails.
-kand--kill-on-failare mutually exclusive across CLI,
env, and config — conflicting layers surface
ResolveError::ConflictingFailurePolicywith the offending
source named. [chain]section inrunner.tomlplusRUNNER_KEEP_GOING/
RUNNER_KILL_ON_FAILenv-var mirrors. Same resolver-chain
precedence as the rest of the policy knobs: CLI > env > config.
Env layer is presence-authoritative —RUNNER_KEEP_GOING=0
overrides[chain].keep_going = truein config, not just the
default.- Line-prefix multiplexer for parallel chain output. Each task's
piped stdout/stderr is captured by a reader thread, prefixed
with[<task-name>](right-padded to the longest name, colored
from an 8-slot deterministic palette), and forwarded to the
parent's stdout/stderr. HonorsNO_COLORand non-TTY parents. - Resolver-warning deduplication across chain dispatch. Per-task
warnings collect into a sharedHashSet, then emit once at the
end sorted byDisplayso output order is stable across runs.
Changed
runner install --frozen <tasks>now propagates the--frozen
flag into the synthetic install head of the chain, so the
install step runs lockfile-only when the flag is set. Previous
behavior silently dropped the flag in chain mode.- Root single-binary Go task name now derives from the
module
path ingo.mod(last segment, with a/vNmajor-version
suffix dropped to match how Go names the built binary) instead
of the project directory name, so cloning a repo into a
differently-named directory no longer changes the task name.
Falls back to the directory name only whengo.modis absent
or has no parseablemoduleline.
Fixed
- Node script discovery is no longer gated on a detected
package manager. Apackage.jsonwithscriptsbut no
lockfile and nopackageManager/devEnginesfield (a
typical pnpm-workspace member directory) reported "No project
detected" andrunner run buildfell through to a bogus
bun build. Manifest presence is now the Node signal; which
PM dispatches scripts is the resolver's runtime job. A
manifest-less subdirectory still lists ancestor scripts, but
only when it provably sits inside a JS monorepo
(workspace-root-aware, VCS-bounded), so an unrelated outer
project'spackage.jsonis never silently adopted.
#32 - Detection now mirrors the resolver's package-manager chain
(packageManager→devEngines.packageManager→
enclosing-workspace lockfile/manifest), sorunner info/
runner installfrom a workspace member target the
workspace's tool instead of resolving nothing. Corepack
semantics preserved: a present-but-unparseable legacy
packageManagerstill warns and is not silently superseded by
devEngines.
What's Changed
- Task chaining:
run -s/-pchain mode +install <tasks>by @kjanat in #27 - fix(detect): decouple node script discovery from PM detection + mirror resolver PM chain by @kjanat in #32
Full Changelog: v0.10.0...v0.11.0
v0.10.0
Added
- mise task extraction and dispatch.
misewas previously
detection-only —runnerlisted it under "Task Runners" but its
tasks were invisible torunner listandrunner run <task>.
NewTaskSource::MiseTomlmakes mise a first-class source: tasks
declared inmise.toml/.mise.toml(and the*.local.toml,
mise/config.toml,.config/mise.tomlcompanions in mise's
documented precedence) appear in listings, participate in the
selection priority, and dispatch viamise run <task>. - Bacon-style two-tier extraction for mise. Primary path shells
out tomise tasks --json— authoritative across mise's config
layering and file-based tasks (mise-tasks/*); fallback parses
the first project-local config whenmiseisn't on$PATH.
Both paths exclude hidden tasks (hide = true),
underscore-prefixed names, and tasks whosesourcelives
outside the project root (so global /~/.config/mise/*tasks
don't pollute the project's task list). Empty or
whitespace-onlydescription = ""values are treated as
missing so the renderer falls through to therunbody or
filereference instead of showing a blank column. Aliases
come through as separate entries pointing at their target,
mirroring the justfile shape.
Fixed
- Resolver no longer dispatches through a Node package manager in
projects with no Node-ecosystem evidence (#23).runner run <unknown-task>in a Go-only repo withbuninstalled used to
warn "no node signals matched" and then runbun <task>anyway;
theFallbackPolicy::ProbePATH probe now requires a
package.json(or equivalent manifest) somewhere upward of
ctx.rootbefore it considers the canonical Node order.
Without that evidence the resolver returns the existing soft
NoSignalsFoundsentinel andcmd::run::run_pm_exec_fallback
spawns the target directly on$PATH— no more wrong-ecosystem
dispatch.
What's Changed
Full Changelog: v0.9.0...v0.10.0
v0.9.0
Added
- Unified package-manager resolution chain.
runner runnow follows a
documented 8-step precedence — qualified syntax →--pm/--runner
→RUNNER_PM/RUNNER_RUNNER→runner.toml→package.json
(packageManagerthendevEngines.packageManager) → lockfile →
PATHprobe → terminal error — making toolchain selection
predictable across Corepack, antfu/ni, mise, and pnpm v11+
conventions. Newsrc/resolver/module owns the chain end-to-end. --pm/--runnerglobal flags withRUNNER_PM/RUNNER_RUNNER
env-var mirrors. Cross-ecosystem overrides like--pm cargoagainst
a Node project fall through to detection rather than hijacking
dispatch. CLI wins over env; empty env strings are treated as unset.runner.tomlproject config ([pm],[task_runner],
[resolution],[sources.*]). Per-ecosystem PM overrides apply
only when the named PM matches the requested ecosystem;
[resolution].fallbackcontrols the no-signal behavior.devEngines.packageManagerparsing frompackage.json(OpenJS
proposal, npm 10.9+). Single-object and array forms supported with
per-entryonFail(ignore/warn/error).downloadcollapses to
warnsince runner is not an installer. The legacypackageManager
field still wins when both are present; manifest declarations win
over lockfile signals (Corepack semantics) and emit apackage.json
warning when they disagree.- Semver enforcement on
devEngines.version. When the declared range
doesn't match the installed PM's--version,onFail=warnemits a
warning andonFail=errorbails. Unparseable ranges or missing
--versionoutput skip the check silently so a partially-broken
environment never blocks dispatch. --fallbackpolicy (probedefault |npmlegacy |error) with
RUNNER_FALLBACKenv mirror. The default replaces the silentnpm
fallback with a canonical-order PATH probe (bun > pnpm > yarn > npm); when nothing matches, the user sees an actionable error
listing every source that was checked.--explainflag (RUNNER_EXPLAINenv). Emits a one-line trace
describing which chain step produced the PM decision:· runner resolved: pnpm via package.json "packageManager".runner doctorsubcommand. Dumps every signal the resolver
considers: detected PMs/runners, override sources in effect (with
origin attribution), manifest declarations, lockfile presence,
PATH probe results for each Node PM, the final decision, and any
warnings.--jsonemits schema-versioned output for jq/scripts/bug
reports.runner why <task>subcommand. Walks the source-selection chain for
a single task: lists every candidate source with its(priority, depth, display_order, alias)tuple, names the winner, and renders
the PM resolution trace when apackage.jsonscript is picked.
--jsonavailable.- Passthrough-wrapper detection generalized to every supported task
runner. Apackage.jsonscript like"build": "just build"is now
recognized as a thin wrapper aroundjustand deduped from
completion candidates when the underlying runner exposes a same-
named task. Recognized runners: turbo, just, make, task (go-task),
nx, bacon, mise. Ecosystemenum (Node/Deno/Python/Rust/Go/Ruby/Php)
formalizing the PM-to-ecosystem mapping used by override scoping.
Changed
Task.passthrough_to_turbo: boolreplaced byTask.passthrough_to: Option<TaskRunner>so wrappers around any runner — not just turbo —
can be attributed at detection time and used by completion.cmd::run::runsignature now takes a&ResolutionOverridesso the
resolver-chosen PM also flows through the no-task fallback paths
(bun testspecial case,npx-style exec).--pm npmagainst a
Bun-detected project now correctly suppresses the bun-test fallback.- Task selection unified into a single sort key
(source_priority, source_depth, display_order, alias_last). Replaces the Deno-only
depth path with a generic tiebreak that applies to every source.
Every non-workspace-aware source now walks ancestors upward when
computingsource_depthso the tiebreak actually distinguishes
nested Makefile/Justfile/Taskfile/bacon.toml configs from
workspace-root ones. Resolver::resolve_node_pmreturnsResult<ResolvedPm>so manifest
onFail=errorand--fallback errorcan bubble up structured
errors instead of bailing inside the resolver.
Fixed
package.jsonpackageManager: "deno@…"projects no longer require
adeno.jsonalongside to be recognized as a Deno project.- Stale doc comment on
detect::push_package_json_tasksupdated to
reflect that passthrough detection covers every known runner, not
just turbo.
What's Changed
Full Changelog: v0.8.1...v0.9.0
v0.8.1
Fixed
Error: program not foundon Windows whenrunner run <script>dispatches
through npm / yarn / pnpm (issue #20). Bare-name spawns now walk
PATH×PATHEXTso.cmd/.batshims (npm.cmd, yarn.cmd, pnpm.cmd)
resolve the same way they do under cmd.exe / PowerShell. Same fix covers
every other Windows-shimmed tool runner dispatches: turbo, deno, make,
task, just, composer, poetry, pipenv, uv, bundle, go, bacon, and the
runner run <bin>arbitrary-target fallback. Non-Windows targets are
unchanged.
What's Changed
Full Changelog: v0.8.0...v0.8.1