Conversation
📝 Walkthrough
WalkthroughPackage renamed from ChangesCrate Publication and Release Automation
🚥 Pre-merge checks | ✅ 7 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (7 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
⚔️ Resolve merge conflicts
✨ Simplify code
Comment |
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
runner | 01dac4f | Commit Preview URL Branch Preview URL |
May 09 2026, 01:31 AM |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
Cargo.toml (1)
2-3:⚠️ Potential issue | 🟠 Major | ⚡ Quick winArrr — bump this to a MAJOR release for the crate rename.
Line 2 changes the published crate identity (
runner→runner-run), which is a breaking change for consumers; Line 3 at0.7.0under-signals that break.Suggested patch
-version = "0.7.0" +version = "1.0.0"As per coding guidelines, “If the PR introduces breaking changes (removal or renaming of public APIs, changes to function signatures, deleted exported symbols, or incompatible config changes), MAJOR must increment.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Cargo.toml` around lines 2 - 3, The crate rename in Cargo.toml changes the published package identity (name = "runner-run") which is a breaking change, so update the version string from "0.7.0" to a new MAJOR release (e.g., "1.0.0" or appropriate next major) to signal the breaking change; modify the version field in Cargo.toml to the new MAJOR version and ensure any related CI/release metadata that reads the version is updated to match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Around line 13-14: Update the `[Unreleased]` compare-link in the CHANGELOG
footer so it no longer points to `v0.6.0...HEAD`; replace the old tag portion
with the new release tag (e.g., `vX.Y.Z...HEAD`) so the `[Unreleased]` link
correctly compares the new tag to HEAD. Locate the `[Unreleased]` link in the
footer (the compare URL currently containing `v0.6.0...HEAD`) and update it to
`vX.Y.Z...HEAD`, ensuring the bracketed `[Unreleased]` text remains unchanged.
---
Duplicate comments:
In `@Cargo.toml`:
- Around line 2-3: The crate rename in Cargo.toml changes the published package
identity (name = "runner-run") which is a breaking change, so update the version
string from "0.7.0" to a new MAJOR release (e.g., "1.0.0" or appropriate next
major) to signal the breaking change; modify the version field in Cargo.toml to
the new MAJOR version and ensure any related CI/release metadata that reads the
version is updated to match.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: efcc71f0-539e-4ddb-a3e2-ff1c0099a799
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (2)
CHANGELOG.mdCargo.toml
📜 Review details
⏰ Context from checks skipped due to timeout of 18000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: verify
- GitHub Check: Workers Builds: runner
- GitHub Check: Analyze (actions)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (rust)
🧰 Additional context used
📓 Path-based instructions (2)
@(package.json|pyproject.toml|setup.py|Cargo.toml|go.mod|pom.xml|build.gradle|VERSION)
📄 CodeRabbit inference engine (Custom checks)
@(package.json|pyproject.toml|setup.py|Cargo.toml|go.mod|pom.xml|build.gradle|VERSION): If any source code files (excluding tests, docs, CI, markdown, or comments-only changes) are modified, then a version field MUST be updated in one of the following files if present in the repo: package.json, pyproject.toml, setup.py, Cargo.toml, go.mod, pom.xml, build.gradle, or a VERSION file.
The new version MUST follow SemVer (MAJOR.MINOR.PATCH). If the PR introduces breaking changes (removal or renaming of public APIs, changes to function signatures, deleted exported symbols, or incompatible config changes), MAJOR must increment. If it adds backward-compatible functionality, MINOR must increment. If it only fixes bugs without changing public APIs, PATCH must increment.
Files:
Cargo.toml
**/CHANGELOG.md
📄 CodeRabbit inference engine (Custom checks)
**/CHANGELOG.md: If any source code files (excluding tests, docs, CI, markdown, or comments-only changes) are modified, CHANGELOG.md MUST also be modified in the same PR.
If a version bump is detected, CHANGELOG.md MUST contain a new section header matching the exact new version number in the format: '## [X.Y.Z] - YYYY-MM-DD'.
If NO version bump is detected, the changes in the PR MUST be added under the existing '## [Unreleased]' section in CHANGELOG.md. The entry MUST describe the changes (e.g., Added, Changed, Fixed, Removed).
Files:
CHANGELOG.md
🧠 Learnings (1)
📚 Learning: 2026-03-26T16:14:15.754Z
Learnt from: kjanat
Repo: kjanat/runner PR: 1
File: src/tool/go_task.rs:64-81
Timestamp: 2026-03-26T16:14:15.754Z
Learning: If code uses let-chains (e.g., `if let Some(x) = foo && ... && let Some(y) = bar`), ensure the crate’s `Cargo.toml` sets `package.edition = "2024"`. Rust 2021/earlier should not be used with let-chains; require 2024 specifically for compilation.
Applied to files:
Cargo.toml
🔇 Additional comments (1)
Cargo.toml (1)
28-30: Good call:[lib] name = "runner"preserves import compatibility.Nice move — this keeps existing
runner::...paths stable while publishing underrunner-run.
Single static page deployed via Cloudflare Workers Static Assets.
Paper-zine + terminal hybrid: cream/ink/moss/tomato palette, monospace
throughout, one fake-terminal inset that mirrors actual `runner` and
`runner list` output (field widths and group labels match
src/cmd/{info,list}.rs).
Click-to-copy install commands (npm/cargo/curl), responsive grid of
supported package managers / task runners / sources, MIT footer.
No build step, no deps. `wrangler.jsonc` declares the Static Assets
binding and the `runner.kjanat.com` custom-domain route;
`workers_dev: false` keeps the *.workers.dev URL hidden. `_headers`
ships strict CSP, HSTS, and edge cache. README at repo root gains a
single Website: link.
site/wrangler.jsonc points $schema at ./node_modules/wrangler/ config-schema.json — make that real. Add a private package.json declaring wrangler ^4.87.0 as devDependency, plus dev/deploy/tail scripts. bun install populates node_modules; .gitignore keeps node_modules and .wrangler out of git.
Format with tabs and trailing commas via dprint (typescript + svg plugins added at the workspace root). Add site/biome.json: lint on, formatter off (dprint owns format). Drop the local wrangler devDep in favour of `bunx wrangler` via npm scripts; bun.lock removed. README updated to use `bun --cwd=site dev|deploy`.
- prefers-color-scheme: dark — warm-graphite background, cream ink, brighter moss + tomato. Terminal block stays dark in both modes. color-scheme: light dark hints form controls + scrollbars. - Wordmark cursor: 11s loop — solid ~10s, quick double-blink, repeat. Stops being wallpaper noise; reads as a tiny heartbeat instead. - Terminal cursor: 5 iterations then settles solid, like a real prompt awaiting input. - Cargo install command corrected: cargo install --git=https:// github.com/kjanat/runner/ runner (not the unpublished crate name).
- install grid is now single-column at every breakpoint. Previously the primary npm row spanned full-width while cargo + curl were forced into half-cells — the shortest command got the most space, the longer ones overflowed. Stacking flips that. - "cargo · from source" label clarifies it builds from the git tip, not a published crate. Visible cargo command is now full (no ellipsis) since the box has the room. - Demo-terminal title row "runner 0.6.0" is now real anchors, matching the CLI's OSC8 hyperlinks: runner → repo, 0.6.0 → release tag. Added background: transparent on .term .link[:hover] so the global a:hover moss-swap doesn't bleed into the terminal.
dprint expanded the `idle-double-blink` keyframes block and the cargo install button onto multiple lines — bringing both inline with the rest of the file's already-expanded style. No behaviour change. Trim "— task execution backends not wired up" from the nx/mise caveat. "detection-only" already says it; the longer form leaked implementation roadmap into a user-facing line.
Real fixes the linter caught:
- "use strict" pragma at top of inline script
- Drop unused `const r = document.createRange()` (leftover from a
fallback path that was never reached)
- Destructure `const { cmd } = btn.dataset`
- Annotate the empty execCommand catch (best-effort fallback)
- Extract setTimeout's 1400ms into TOAST_MS
Disabled rules that fight the design (all nursery/style):
- noExcessiveLinesPerFile — single-file is the entire premise
- noHexColors — six-colour palette doesn't need oklch ceremony
- useBaseline — `::selection` is universal in target browsers
- noMagicNumbers — animation timings are local literals
Add `lint` script alias so `bun lint` works without typing `biome`.
Verified: html-validate exit 0, biome lint exit 0.
New section between the demo and the matrix that surfaces the binary's killer feature: dynamic, per-project tab completion. - Two copy-buttons: `eval "$(runner completions)"` (auto-detects $SHELL — covers bash/zsh/fish in one line) and the powershell pipeline equivalent. - Fake terminal showing `runner <TAB>` resolving to grouped candidates — package.json scripts, justfile recipes, justfile aliases, then built-in commands. Mirrors the real `_describe` group headers (`-- source --`). - One liner about path-typed flags delegating to the shell's own file completer (`--dir <TAB>` → `~/`, globs, cdpath). Single eval registers BOTH `runner` and `run` thanks to the sibling-binary detection in cmd/completions.rs.
17,429 → 14,572 bytes (-2,857, -16.4%). Now fits in the initial congestion window (10 × 1460 = 14,600) so a fresh visitor's first flight delivers the whole page — single round-trip, even uncompressed. Brotli compressed: 3,619 bytes. Cuts: - Drop inline SVG favicon (-344) → empty data: URI - Drop OG url + type metas (-180); shorten description copy (-100) - Drop view-source easter comments + verbose section comments (-280) - Trim font stack: drop "IBM Plex Mono" + "DejaVu Sans Mono" (-50) - Drop text-rendering, font-feature-settings, -webkit-text-size-adjust, -webkit-appearance — modern browsers don't need any of them (-200) - Drop .meta-tight / .meta-loose helper classes (consolidate to .meta) - Drop .term box-shadow (decorative, invisible against dark bg) - Drop text-decoration-thickness + from-font keywords on a (-90) - Inline single-use --term-bg/--term-link/--term-green vars (-130) - Shorten --term-dim/--term-bold to 3-digit hex (-15) - Refactor footer: drop .sep span structure for inline text (-200) - Drop the textarea fallback in the click-to-copy script. The site is https-only, modern clipboard API works in all secure contexts; catch fails silently (-450). Both validators clean: html-validate exit 0, biome lint exit 0.
- site/public/favicon.svg: serve the icon as a 241-byte file rather than inlining a data: URI. HTML now references it as `<link rel="icon" href="favicon.svg">` (31 bytes vs ~500 inline). - index.html: 14,505 bytes — 95 under IW10 (14,600). Trim font stack to ui-monospace/Menlo/Consolas/monospace so dprint keeps it on one line; trim meta description; drop og:description. - .dprint.json: bump markup printWidth to 160 so dprint stops splitting one-line meta tags into multi-line forms. - .zed/settings.json: associate .ico as SVG syntax for the editor. Both validators clean.
Rename favicon.svg → favicon.ico (same SVG bytes) and override the Content-Type via `_headers` to `image/svg+xml`. Browsers auto-request `/favicon.ico` regardless of the `<link>` tag; Cloudflare's extension-based MIME detection would otherwise serve it as `image/x-icon`, which the browser refuses to parse as SVG — especially with `X-Content-Type-Options: nosniff` set globally. Bumped `Cache-Control` on the icon to 1d/30d since favicons rarely change. Updated `<link rel="icon">` href to match.
`287659d` dropped the local `wrangler` devDep in favour of `bunx wrangler`, which left the `$schema` reference at `./node_modules/wrangler/config-schema.json` — a path that only resolves after a hypothetical install that no longer happens. Editors (Zed, VSCode) couldn't pick up schema completions/validation on a fresh clone. Switch to `https://www.unpkg.com/wrangler/config-schema.json` so the schema resolves without any local install. Tracks latest, same as `bunx wrangler` does at runtime.
Below 40rem (~640px) the install grid and terminal blocks were overflowing the viewport — `.copy .cmd` had `white-space: nowrap`, so the longer `cargo install --git=...` command pushed the box wider than the screen and forced horizontal scroll on the whole page. Tighten `main` padding (3rem → 2.5rem 1.1rem), shrink `.copy` and `.term` type, and let command text wrap with `overflow-wrap: anywhere` so URLs break cleanly. Pull `hr.rule` margin in too — the section gaps felt cavernous once the rest scaled down. No desktop change; rules are scoped to `(max-width: 40rem)`.
Add `public/404.html` and flip `not_found_handling` from `single-page-application` to `404-page` so wrangler serves the file on unmatched paths instead of rewriting to `/`. The page mirrors the main site's palette + mono stack and shows a fake `runner <requested-path>` error line so the 404 reads like the CLI itself rather than a generic browser page. Also flip `workers_dev` to `true` so the *.workers.dev preview URL stays reachable alongside the custom domain.
- mobile: copy buttons no longer blow out viewport. min-width: 0 on .copy lets the grid item shrink below min-content; word-break and overflow-wrap on .cmd let long URLs wrap. html/body get overflow-x: hidden as a safety net. - copy: only mark "copied" when clipboard.writeText resolves; on failure, surface "Copy failed" via a polite live region so screen readers announce the result. - README: 404.html now listed in the layout tree.
The .toast spans say "copied" visually, but we already announce copy status via the polite live region. Marking them aria-hidden keeps screen readers from reading the toast text alongside the button name and the announcement.
.matrix ul forced two columns at every viewport. On phones that's a cramped newspaper split — package.json / turbo.json wrap awkwardly. Override to columns: 1 inside the existing 40rem media query.
Single-column 12-item list ate half the screen. Switch the matrix lists to flex-wrap with bullet separators on mobile, so they read as a compact inline group (npm · yarn · pnpm · …) and reflow naturally to the available width.
Replaces the bare "Website:" line with a small block linking the landing page (with a pointer to its source under site/) and the npm package. Adds two shields.io badges at the top: npm version of runner-run and MIT license.
## Summary - Static landing page deployed to Cloudflare Workers Assets, served at `runner.kjanat.com`. - Single `index.html` (~3.6 KB brotli) + `404.html` (~1 KB brotli); whole first response fits inside TCP IW10 with headroom. - Self-contained styles, light/dark via `prefers-color-scheme`, mobile breakpoint at 40 rem. - Wrangler config: custom domain route, `workers_dev: true`, `not_found_handling: "404-page"`, observability on. - Auxiliary: `_headers`, `robots.txt`, SVG favicon served as `favicon.ico`, biome + dprint config.
Replace the raw `public/` flow with `src/` → `dist/` driven by
`build.ts`: Bun bundles `index.html` / `404.html`, strips the
empty JS chunks Bun emits for script-less HTML, and substitutes
`{{version}}`, `{{repo}}`, `{{authorName}}`, etc. from
`Cargo.toml` so the site and the crate share one source of
truth for metadata.
Add `dev.ts`: serves `dist/`, watches `src/`, `public/`, and
`Cargo.toml`, debounces rebuilds at 80ms, and pings a tiny
WebSocket-reload snippet injected into served HTML.
Wrangler: asset dir → `./dist`, worker renamed `runner-site`
→ `runner`, `preview_urls: true`. Top-level `.gitignore`
follows the layout change (drop `npm/dist/`, `npm/downloads/`;
add `dist/`, `downloads/`, `.wrangler/`, `.dev.vars*`) and
dprint now ignores `**/dist`. Site `biome.json` gains
experimental HTML parsing for the templated files.
Consolidate the GitHub composite action, runner.kjanat.com landing page, templated `site/build.ts` flow, README badges, npm publish script refactor, `package-release-asset.sh` checksum filename fix, `build-packages.ts` `Target.build` union expansion, and openbsd residue removal under Added / Changed / Fixed. Side housekeeping: reformat the inline `reloadSnippet` in `site/dev.ts` from a one-liner to a readable IIFE, and add a `repository` field (with `directory: site`) to `site/package.json` so npm/registry tooling resolves the workspace correctly.
Replace the em-dash continuation with a `div.meta` wrapping two `<p>` blocks so the path-flag note and the `~/`/glob/`cdpath` example read as separate beats instead of one long sentence.
Move the Cloudflare Web Analytics beacon out of `src/index.html`
and into `build.ts`, injected only when `build({ analytics: true })`
is passed. The CLI entry sets it; `bun run dev` and library
imports leave the snippet out so local previews don't phone home.
`deploy` now chains `bun run build` before `wrangler deploy` so
the published `dist/` always has a freshly injected beacon, and
`_headers` adds `https://static.cloudflareinsights.com` to the CSP
`script-src` so the script actually loads.
Side tweaks: bump `--term-dim` `#888` → `#b3b3b3` for legible
secondary text, brighten `.term .green` to `#9bea9b`, and fold
`visibility` into the copy `.toast` transition so the hidden
state is also hidden from assistive tech, not just visually faded.
`.term .green` and `.term .link` baked in `#9bea9b` / `#b9d4b3` that drifted from the rest of the term palette and ignored the light/dark token swap. Reuse `--term-bold` / `--term-fg` so both themes pick the right shade, and bump `.green` to weight 700 to match the surrounding bold spans.
- `Cargo.toml`: bump `[lints.clippy.cargo]` warn → deny. Add
`.cargo/config.toml` aliases `l`/`lint`/`t`/`bin-run`/`bin-runner`
so the stricter clippy gate is one keystroke locally.
- `npm/scripts/build-packages.ts`: swap deprecated `cargo
read-manifest` for `cargo metadata --no-deps`, picking the
workspace's `workspace_default_members[0]` by id (falls back to
the first package for non-virtual single-member workspaces).
Bump `maxBuffer` to 64 MiB so large metadata payloads don't trip
Node's 1 MiB default.
- `site/build.ts`: parallelize empty-chunk `rm` and HTML token
substitution via `Promise.all` instead of serial awaits.
- `site/biome.json`: convert `correctness`/`suspicious` to
`{ recommended: true }` objects so domain rules layer cleanly,
and replace `organizeImports` with `useSortedProperties` /
`noDuplicateClasses` / `useSortedInterfaceMembers`.
- `site/src/styles/*`: factor design tokens (`--radius-*`,
`--ring-*`, `--dur-*`, `--ls-caps`, `--text-micro`/`--text-xs`,
`--term-bg`/`--term-green`/`--term-red`), add `a:focus-visible`
ring, `.meta a:hover` invert, `.term ::selection` themed
selection, and reflow properties to match the new biome sort.
- `site/package.json`: add `fmt` → `bunx dprint fmt`.
- Skip beacon injection outside CI / GitHub Actions so local builds don't emit telemetry; warn instead of throw on missing `</body>`. - Allow overriding the Cloudflare beacon token via `CF_BEACON_TOKEN`; literal kept as fallback. - Build full GitHub Pages URL under GH Actions instead of a repo-relative path. - Add `dir` option (`"relative" | "full"`) to `build()` so the size summary can print absolute paths; toggle via `FULL` env. - Emit external sourcemaps when `SENTRY_DSN` is set. - `bd` script runs `bun --silent` to keep summary output clean.
`publicPath` had a precedence bug: `env["PUBLIC_PATH"] || isCI ? X : Y` parses as `(... || ...) ? X : Y`, so a literal `PUBLIC_PATH` value never reached `Bun.build` — it acted as a boolean toggle that always picked the GH-pages or `runner.kjanat.com` branch. The hardcoded prod URL also leaked into Cloudflare Workers preview deploys and tripped CSP `'self'` (page on `*.workers.dev`, assets on `runner.kjanat.com`). Replace with `env["PUBLIC_PATH"] || githubPagesUrl() || "/"`: explicit override wins, GH Pages still gets its `/<repo>/` prefix, everything else stays same-origin so preview URLs and local builds load assets without a CSP fight. `public/_headers`: drop the `/favicon.ico` override block — the icon ships as an SVG via `<link rel="icon">`, so nothing routes through `/favicon.ico` to need a content-type override.
Flatten the alias list into composable array-form commands so the common loops are one keystroke and longer forms layer on top: `bb` builds both bins, `bbr` is `bb --release`, `cl` is the bare clippy invocation, `l` adds the deny flags on top of `cl`, `r` is `run`, `rr` is `run --release`, and `rbin-run`/`rbin-runner` re-use `bin-run`/`bin-runner` with `--release` instead of duplicating the flag list. Adds `i`, `meta`, and `t` gains `--all-targets`. `justfile` now defers to those aliases (`cargo i`, `cargo bin-run`, `cargo bin-runner`) so each entry point has one source of truth for which bin/profile/flags it compiles. Side: swap the `#:schema` URL from a local absolute path to the published gist bundle so the file resolves on machines without the schema repo cloned, and set `term.hyperlinks = false` since some terminals mangle the OSC-8 escapes cargo emits.
Add `.rustfmt.toml` pinning the project's `cargo fmt` baseline: `max_width=100`, 4-space indent, 2024 edition/style, plus a commented appendix of the unstable knobs to revisit once they stabilise. Reproducible formatting across machines, no more diff churn from per-user defaults. `bin/run` / `bin/runner`: drop the `BIN` indirection, swap `--quiet` for `CARGO_TERM_QUIET=true` (covers cargo's "Compiling/Finished" chatter, not just stdout), and build with `--release` so the PATH shims spawn an optimised binary instead of recompiling a debug build on every invocation. `bin/runner` relies on `default-run = "runner"` to drop `--bin` entirely. `justfile`, follow-up to cc8fd33: - Inline the private `shim` recipe into `default` so the env passthrough is one hop instead of two. - Flip `run` / `runner` default profile `release` → `dev` for faster local rebuilds; `PROFILE=release` still overrides. - Swap `cargo read-manifest` → `cargo metadata --format-version 1` for the npm name/scope lookups, matching what `build-packages.ts` already does and surviving the eventual removal of `read-manifest`. - `test-release`: parse `npm/targets.json` with `jq` instead of a `node -p require(...)` heredoc, use the new `cargo bbr` alias instead of the inline `cargo build --bin runner --bin run --release`, and collapse the dual-command loop into one `for bin in runner run` pass. - Fix `dowloads-dir` → `downloads-dir` typo.
Replace `${{ secrets.GITHUB_TOKEN }}` with `${{ github.token }}`
for `taiki-e/create-gh-release-action`,
`taiki-e/upload-rust-binary-action`, and the `cargo-build-std`
packaging step. Same token in practice, but `github.token` is
the documented context handle and doesn't require the secret to
be wired through explicitly — keeps fork PR runs and composite
calls working without extra plumbing.
`release-dryrun.yml` build-std step: drop the inline `cargo
+nightly build --release --locked --bin runner --bin run --target
"${{ matrix.target }}"` and move `--target` into
`CARGO_BUILD_TARGET` env. With `default-run = "runner"` and the
two-bin layout already covered by the alias chain, the bare
`cargo +nightly build --release --locked` matches what the rest
of the matrix runs and stays in sync if the bin list grows.
Collapse the now-single-line `run:` off its `|`, and pull
`matrix.target` into a step-level `target` env so the verify
loop reads `target/${target}/release/${bin}` instead of inlining
the `${{ }}` expansion mid-path.
`release-dryrun.yml` matrix: alphabetise the `workflow_dispatch`
target choice list (was loosely grouped by OS, drifted out of
order); compact the single-key `outputs:` / `with:` / `env:` /
`matrix:` blocks to flow style; rewrite the `INPUT_TARGET` jq
filter as one `jq --arg t` call with `$t == "all" or .rust ==
$t` instead of a bash `if`/`else` switching between two filter
strings.
Both workflows: replace `matrix.build-tool == 'a' ||
matrix.build-tool == 'b'` chains with `contains(fromJSON('["a",
"b"]'), matrix.build-tool)` so the allowlist is one literal
instead of an N-way `||` that grows with each new build tool.
`release.yml`: bump `npm-dist` artifact retention 7 → 14 days so
the npm publish window has more slack before artifacts expire.
`.cargo/config.toml`: append a commented `[target.<triple>]` /
`[target.<cfg>]` / `[target.<triple>.<links>]` reference block
as scaffolding for future per-target `rustflags` / `runner` /
build-script overrides. Pure documentation — no behaviour change.
Replace `${{ X && A || B }}` ternaries with `case(X, A, B)` across
`npm-release.yml`, `release-dryrun.yml`, and `release.yml` so the
selector is one expression instead of a short-circuit chain that
silently picks the wrong branch when `A` is falsy. Touches both
`run-name` strings and the `build-tool` cargo-cross-toolchain
remap.
`release.yml`: drop the redundant `matrix.experimental == true` —
`continue-on-error` already coerces, the `== true` was noise.
`npm-release.yml` triggers: add `release: { types: [published] }`
so a published GH Release fires the publish path directly, and
constrain the existing `workflow_run` to `branches: [v*]` so only
tag-driven release runs trigger npm publish (was firing on every
release.yml completion). Hoist `RELEASE_TAG` / `RUN_ID` /
`EVENT_NAME` / `INPUT_DIST_TAG` / `INPUT_DRY_RUN` / `REGISTRY` from
the job's `env:` to workflow-level `env:` so the same trusted
metadata is available to every job that grows here later, and
flow-compact the single-key `environment:` block. Switch
`setup-node` to read `node-version` and `registry-url` from
`env.NODE_VERSION` / `env.REGISTRY` instead of the inline literal,
keeping the registry pin in one place.
Multiline `description:` strings on `run-id` and `dist-tag` swap
`>-` for `|-` so the explanatory line breaks survive into the
dispatch UI instead of being folded into one paragraph.
Surface `[alias]` entries from the merged `.cargo/config.toml`
chain (cwd→root→`$CARGO_HOME`) plus cargo's built-ins as
`runner` tasks. Recursive alias references expand fully so
`runner list` shows the resolved command (`l → clippy
--all-targets --all-features -- -D warnings`), and built-ins
(`b/c/d/t/r/rm`) always surface even without a user config.
User redefinitions of built-ins are silently ignored to match
cargo's own resolution rule.
`runner run <alias>` shells out to `cargo <alias> <args...>`
so cargo's runtime resolution stays authoritative — no
re-implementing precedence in `runner`.
`Cargo.toml`: add `toml` (parse + serde, no default features)
to read alias tables. `src/types.rs` adds the `CargoAliases`
variant with label `"cargo"` (synthetic — no single file
backs it). `src/cmd/{list,run}.rs` pick the deepest
applicable config for OSC8 / nearest-source ranking, falling
back to `Cargo.toml`'s directory when only built-ins apply.
Side:
- `.cargo/config.toml`: `bin-run`/`bin-runner` get `--quiet`
(less cargo chatter through the shims), add `comp` →
`bin-runner -- completions`.
- `justfile`: rename `list` → `ls`.
- `CHANGELOG.md`: log this feature and catch up unreleased
site/build entries (publicPath fix, CI-only beacon,
`build-packages` metadata switch, `dir` toggle, sourcemap
gating).
Renames the package on crates.io to runner-run (the bare `runner` name is
already taken). Pin [lib] name = "runner" so existing src/{main,bin}.rs
references to the library crate keep working unchanged.
Adds .github/workflows/crates-release.yml mirroring npm-release.yml: runs
on successful tag-triggered release.yml or manual dispatch, verifies the
tag matches Cargo.toml version, dry-runs publish, then uploads with
CARGO_REGISTRY_TOKEN under the crates-io environment.
Move `app.ts` → `app/copy.ts` and `icon.svg` → `assets/icon.svg` so the flat `src/` root has room to grow without another rename pass: copy-button code sits in a named module beside future UI scripts, and static media lives under one prefix that maps onto cache headers / CSP cleanly. Update the two `<link rel="icon">` and the index `<script src>` to the new paths so `dist/` regenerates without 404s. Side: add `bd` → `bun run build` since it's the most-typed local command.
`runner list` and `runner run` both needed "the file that
represents the cargo-aliases source for this root" — deepest
applicable `.cargo/config{,.toml}`, falling back to
`Cargo.toml` for built-ins-only projects. Both grew the same
seven-line `find_configs(root).into_iter().next().or_else(…)`
block, primed to drift apart.
Extract `tool::cargo_aliases::find_anchor` and call it from
both. `cmd/list.rs` keeps the OSC8 link target; `cmd/run.rs`
keeps the depth-based ranking — same behaviour, one source of
truth.
CodeQL flagged the previous workflow_run + checkout-of-tag pattern as "untrusted code in a privileged context" (security/code-scanning #7-9): workflow_run runs with secrets, and `cargo publish` executes build.rs from the tag-controlled checkout, which would let a malicious tag exfiltrate CARGO_REGISTRY_TOKEN. Switch the trigger to `release: types: [published]`. release.yml still creates the release as a draft — a maintainer must review and click publish, which becomes the human gate. The `crates-io` environment's required reviewers are the second gate. workflow_dispatch is preserved for manual republishes.
`build()` now returns the emitted file list with bytes so callers (and the CLI) can report compressed sizes without a second disk read. The CLI prints a sorted `raw / gzip / br` table at quality 9/11 to mirror what a CDN actually serves, surfacing budget regressions next to the build. HTML post-processing reads from `Bun.build` outputs in memory instead of re-reading `dist/`, and `copyTree` returns the bytes it copied so `public/` files land in the same `DistFile[]` the summary walks. Derive `publicPath` per env: `PUBLIC_PATH` wins, GitHub Actions falls back to `/<repo>` for Pages previews, other CI to the prod URL, local to `./`. Lets PR previews and local builds emit working asset URLs without a config flag. `biome.json`: turn `complexity.useLiteralKeys` off so the env bracket access (`env["PUBLIC_PATH"]`) needed under `noPropertyAccessFromIndexSignature` doesn't trip the linter.
`local __runner_g` (no assignment) at the start of Pass 2 redeclared a variable already localized by Pass 1. zsh treats `typeset NAME` without an assignment as the *display* form, so every grouped TAB completion printed `__runner_g=<last Pass 1 tag>` to the terminal. Normally invisible — `zle redisplay` redraws the input line and covers it — but oh-my-zsh's `COMPLETION_WAITING_DOTS` widget prints its indicator before invoking the completion. Our spurious typeset print sandwiched next to the dots, and `redisplay` only repaints the input portion: both the dots and `__runner_g=Options` survived alongside the menu, e.g. `runner waiting... __runner_g=Options ` lingering on the prompt line for every TAB. Switch to `local __runner_g=` (explicit empty assignment): the declaration stays, but `typeset` with a value skips the display path. Both `runner` and `run` binaries inherit the fix since the template is shared.
Two CodeRabbit findings on the crates-release workflow: - actions/checkout resolves bare refs to a branch first, then a tag, so a branch sharing a tag's name would silently checkout the wrong commit on workflow_dispatch input. Pin the ref to refs/tags/<tag> explicitly. - cargo publish would die with an opaque auth error if CARGO_REGISTRY_TOKEN isn't wired up. Compute HAS_CARGO_REGISTRY_TOKEN at job-level (so the secret value never lands in a step env) and fail fast with a clear message before the publish step runs.
The package rename to runner-run isn't strictly breaking — runner-run has never been published to crates.io and the bare `runner` name on the registry belongs to someone else, so there's no prior consumer to break. But a lot of work has accumulated under [Unreleased] since v0.6.0 (composite action, cargo-aliases task source, landing page, templated site build, npm publish hardening, BSD packaging fixes, and now crates.io publishing), so cut a 0.7.0 section dated today and let this PR's tag carry all of it.
8a785e0 to
01dac4f
Compare
There was a problem hiding this comment.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.dprint.json (1)
25-30: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winExclude
downloads/here too.Arrr,
downloads/is now treated as generated repo state in.gitignore, but dprint will still crawl it. That’s needless formatter churn waiting to happen once fetched assets land there.🧹 Proposed fix
"excludes": [ "**/*.lock", "**/node_modules", "**/samples", "**/target", - "**/dist" + "**/dist", + "**/downloads" ],🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.dprint.json around lines 25 - 30, The excludes array in .dprint.json currently omits the downloads directory, so add an entry for downloads (e.g., "downloads" or "**/downloads") to the "excludes" array so dprint won't crawl or format files under downloads; update the "excludes" value where the "excludes" array is defined to include that new pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/npm-release.yml:
- Line 50: The workflow currently wraps inputs.dry-run with fromJSON in the
INPUT_DRY_RUN env (INPUT_DRY_RUN: ${{ fromJSON(inputs.dry-run) }}), causing a
type mismatch because inputs.dry-run is already a boolean; remove the fromJSON
wrapper and assign the boolean directly (use inputs.dry-run as-is for
INPUT_DRY_RUN), or if you need null-safety for non-dispatch runs add a
conditional/default around inputs.dry-run rather than calling fromJSON.
In @.github/workflows/release-dryrun.yml:
- Around line 107-115: The taiki-e/upload-rust-binary-action step ("build
(taiki-e dry-run)" using taiki-e/upload-rust-binary-action@v1) is missing an
explicit ref for manual workflow_dispatch runs and the archive name uses an
undefined literal $tag; fix by adding a ref input to the action (e.g., set ref
to a tag input like refs/tags/${{ github.event.inputs.tag }} or to
github.ref_name when appropriate) and either define a workflow_dispatch input
named tag or replace the archive value to use a valid expression (e.g., a
derived/defined tag variable or github.ref_name) so archive no longer contains
the literal $tag.
In `@bin/runner`:
- Around line 20-23: The wrapper script bin/runner invokes cargo without the
--locked flag, allowing local runs to update Cargo.lock and diverge from
CI/release builds; update the cargo invocation in the exec line (the command
starting with exec env CARGO_TERM_QUIET=true \ cargo run --release
--manifest-path="${MANIFEST}" -- "$@") to include the --locked flag so cargo run
is invoked with --locked (e.g., cargo run --release
--manifest-path="${MANIFEST}" --locked -- "$@"), ensuring local runs use the
locked dependency graph.
In `@justfile`:
- Around line 47-49: The pkg lookup using jq can return an empty string which
later causes build-packages and the symlink step to fail silently; after the jq
assignment to pkg (the variable pkg in the justfile), immediately check if pkg
is empty and, if so, print a clear error message including the host-triple and
exit non‑zero to fail fast (so build-packages doesn't get only=""). Ensure you
reference the same pkg variable and the host-triple placeholder in the message.
- Around line 6-7: The jq selectors in justfile currently look up a package by
the old crate name ("runner") and return empty after the rename; change
npm-pkg-name and npm-pkg-scope to first resolve the workspace default member
(same approach as build-packages.ts) and then select the package whose id
matches that default member, extracting .metadata.npm.name and
.metadata.npm.subpkgscope; specifically, run cargo metadata and use jq to get
the workspace default member id, then select the package with that id (matching
.id) and return its metadata.npm.name / metadata.npm.subpkgscope instead of
select(.name == "runner").
In `@site/biome.json`:
- Around line 10-13: The Biome config's files.includes currently patterns
everything (files.includes) which causes generated output to be crawled; update
the includes list (the "files" -> "includes" entry) to explicitly exclude the
build output (e.g., add a negative glob for dist such as "!!dist/**") so that
the generated dist/ directory is ignored by Biome and not linted or scanned.
In `@site/build.ts`:
- Around line 107-111: The regex built for emptyScript interpolates raw chunk
names from emptyChunks which may contain regex metacharacters; update the
construction so you escape each chunk name before joining (e.g., map emptyChunks
to an escapeRegExp function that backslashes special chars) and then use the
escaped alternation in the RegExp constructor (keep the rest of the pattern and
flags the same) so the RegExp only matches exact chunk filenames; ensure the
escape helper is applied where emptyChunks is spread into the alternation used
for emptyScript.
In `@site/dev.ts`:
- Around line 89-103: The timer callback currently bails out when rebuilding is
true, dropping that file-change event; modify this by introducing a
queued/needsRebuild boolean (or reuse the existing pending variable) so that if
rebuilding is true you mark needsRebuild = true and return, and then after the
try/finally in the setTimeout callback (or at the end of the build
success/failure path inside the finally where rebuilding is set false) check
needsRebuild and if true clear it and schedule another setTimeout to run build
again (or call the same callback) so no file-change events are lost; update
references in the module to use the new queued flag and ensure sockets and
build() usage remain unchanged.
In `@site/public/_headers`:
- Line 6: The CSP in site/public/_headers currently allows the Cloudflare
Insights script via script-src but lacks a connect-src entry, so add a
connect-src directive that permits connections to https://cloudflareinsights.com
(and any subdomains used) so the Web Analytics beacon can send RUM data; update
the Content-Security-Policy line (the header string) to include connect-src
'self' https://cloudflareinsights.com and ensure this aligns with the script
injection in site/build.ts that adds the Cloudflare Web Analytics script.
In `@site/README.md`:
- Around line 5-7: The README is out of date: update its description to reflect
the actual pipeline by replacing the "no build/deps" claim with notes that the
site is built into ./dist using the build tooling defined in site/package.json
(mention the build script and any toolchain referenced), correct the Worker name
from runner-site to runner to match site/wrangler.jsonc, and update the
layout/source section to document the current public -> build -> dist flow
(including that ./dist is the deployed asset directory rather than
public/index.html). Ensure you reference site/package.json (build script),
site/wrangler.jsonc (name: "runner"), and the ./dist output directory so readers
can find the canonical sources.
In `@site/src/404.html`:
- Around line 19-21: The 404 currently prints the literal "<requested-path>" and
"searched: /" inside the <pre class="term"> output; update the template so these
reflect the real path by using client-side JS to replace the <span
class="dim"><requested-path></span> and the trailing "/" with
window.location.pathname (e.g., select the <pre class="term"> or the specific
<span class="dim"> nodes and set their textContent to window.location.pathname),
or alternatively remove those echoed path nodes entirely if you prefer not to
display the requested path.
In `@site/src/index.html`:
- Around line 40-43: The cargo install command shown in the copy button still
references the old crate name "runner"; update the command string in the button
with data-cmd and the visible span (span class="cmd") to the new package name
"runner-run" so both the data-cmd attribute value and the displayed command text
change from "cargo install --git={{repo}}/ runner" / "runner" to "cargo install
--git={{repo}}/ runner-run" / "runner-run" (locate the button element with
class="copy" and the nested span.cmd to make the edits).
In `@site/src/styles/index.css`:
- Around line 5-15: The .visually-hidden utility is using the deprecated clip
property (clip: rect(...)), which Stylelint flags; replace that deprecated rule
with the modern equivalent by removing clip: rect(0, 0, 0, 0) and adding a
clip-path based solution (e.g., clip-path: inset(50%)) so the .visually-hidden
rule uses clip-path instead of clip while keeping the existing positioning,
size, overflow, and white-space semantics.
- Around line 295-299: The CSS rule for the selector ".copy .cmd" contains the
deprecated declaration "word-break: break-word"; remove that property (or reset
it to the default) since "overflow-wrap: anywhere" already provides the intended
wrapping behavior—update the ".copy .cmd" block to drop "word-break: break-word"
so Stylelint stops flagging it.
In `@src/tool/cargo_aliases.rs`:
- Around line 47-50: display_command currently joins tokens with spaces and
loses quoting for tokens that contain whitespace (mismatching what tokenize()
produces); update ExtractedAlias::display_command to quote/escape any token that
contains whitespace or special characters before joining so the rendered string
reflects the real argv shape (e.g., wrap space-containing tokens in quotes and
escape internal quotes/backslashes), using the same tokenization assumptions as
tokenize() to ensure symmetry between tokenize() and display_command().
- Around line 157-163: The loop that iterates aliases from
read_alias_table(path) currently silently skips failures from tokenize(&value),
causing invalid aliases to disappear; instead, when tokenize returns None or an
error, return/bubble an error with context including the alias name and the
config path. Replace the `continue` in the for loop (and the analogous site
around lines 198-204) so that failures from tokenize(&value) produce an
anyhow::Error (or use bail!/Context) that includes the alias `name` and
`path.display()` before returning, rather than inserting nothing into `merged`.
---
Outside diff comments:
In @.dprint.json:
- Around line 25-30: The excludes array in .dprint.json currently omits the
downloads directory, so add an entry for downloads (e.g., "downloads" or
"**/downloads") to the "excludes" array so dprint won't crawl or format files
under downloads; update the "excludes" value where the "excludes" array is
defined to include that new pattern.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0522fb8d-9b35-40f5-8277-a8a6c22f86d8
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.locksite/bun.lockis excluded by!**/*.locksite/src/assets/icon.svgis excluded by!**/*.svg
📒 Files selected for processing (39)
.cargo/config.toml.dprint.json.github/workflows/crates-release.yml.github/workflows/npm-release.yml.github/workflows/release-dryrun.yml.github/workflows/release.yml.gitignore.rustfmt.toml.zed/settings.jsonCHANGELOG.mdCargo.tomlREADME.mdbin/runbin/runnerjustfilenpm/scripts/build-packages.tssite/.dprint.jsonsite/README.mdsite/biome.jsonsite/build.tssite/dev.tssite/package.jsonsite/public/_headerssite/public/robots.txtsite/src/404.htmlsite/src/app/copy.tssite/src/index.htmlsite/src/styles/404.csssite/src/styles/base.csssite/src/styles/index.csssite/tsconfig.jsonsite/wrangler.jsoncsrc/cmd/list.rssrc/cmd/run.rssrc/complete/grouped.zshsrc/detect.rssrc/tool/cargo_aliases.rssrc/tool/mod.rssrc/types.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 18000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Workers Builds: runner
- GitHub Check: Analyze (rust)
- GitHub Check: Analyze (actions)
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (3)
.github/**/*.{yml,yaml}
⚙️ CodeRabbit configuration file
Do not ever warn about stylistic yamllint shit. Do warn about security related shit. Insecure shell handling of user supplied / defined strings: think of branch names, inputs, pr content, anything needs to be string interpolation and permission safe.
Files:
.github/workflows/release.yml.github/workflows/release-dryrun.yml.github/workflows/npm-release.yml.github/workflows/crates-release.yml
@(package.json|pyproject.toml|setup.py|Cargo.toml|go.mod|pom.xml|build.gradle|VERSION)
📄 CodeRabbit inference engine (Custom checks)
@(package.json|pyproject.toml|setup.py|Cargo.toml|go.mod|pom.xml|build.gradle|VERSION): If any source code files (excluding tests, docs, CI, markdown, or comments-only changes) are modified, then a version field MUST be updated in one of the following files if present in the repo: package.json, pyproject.toml, setup.py, Cargo.toml, go.mod, pom.xml, build.gradle, or a VERSION file.
The new version MUST follow SemVer (MAJOR.MINOR.PATCH). If the PR introduces breaking changes (removal or renaming of public APIs, changes to function signatures, deleted exported symbols, or incompatible config changes), MAJOR must increment. If it adds backward-compatible functionality, MINOR must increment. If it only fixes bugs without changing public APIs, PATCH must increment.
Files:
Cargo.toml
**/CHANGELOG.md
📄 CodeRabbit inference engine (Custom checks)
**/CHANGELOG.md: If any source code files (excluding tests, docs, CI, markdown, or comments-only changes) are modified, CHANGELOG.md MUST also be modified in the same PR.
If a version bump is detected, CHANGELOG.md MUST contain a new section header matching the exact new version number in the format: '## [X.Y.Z] - YYYY-MM-DD'.
If NO version bump is detected, the changes in the PR MUST be added under the existing '## [Unreleased]' section in CHANGELOG.md. The entry MUST describe the changes (e.g., Added, Changed, Fixed, Removed).
Files:
CHANGELOG.md
🧠 Learnings (8)
📚 Learning: 2026-03-26T20:05:44.851Z
Learnt from: kjanat
Repo: kjanat/runner PR: 1
File: src/cmd/mod.rs:67-75
Timestamp: 2026-03-26T20:05:44.851Z
Learning: In Rust, `std::process::Command` does not provide getters for stdio configuration, so whether `Stdio::inherit()` (or other `Stdio::*` settings) was applied cannot be asserted via pure unit tests without spawning a process and inspecting OS-level fds. When reviewing Rust code, do not flag “missing unit test coverage” for stdio configuration on `std::process::Command` as a code issue—treat the explicit `Command::stdin/stdout/stderr` setter calls in the source as the meaningful guarantee.
Applied to files:
src/tool/mod.rssrc/detect.rssrc/cmd/run.rssrc/cmd/list.rssrc/types.rssrc/tool/cargo_aliases.rs
📚 Learning: 2026-04-21T15:16:40.277Z
Learnt from: kjanat
Repo: kjanat/runner PR: 4
File: src/tool/just.rs:132-133
Timestamp: 2026-04-21T15:16:40.277Z
Learning: In Rust, if a method like `ExtractedTask::name() -> &str` returns a borrowed `&str` tied to `&self`, then using `sort_unstable_by_key(|t| t.name())` should be avoided because `by_key` requires the key to not borrow from the element being sorted (it will fail to compile due to the key’s lifetime). Do not recommend `sort_unstable_by_key` as a simplification in this situation. If you need an allocation-free and idiomatic comparison, use `sort_unstable_by(|a, b| a.name().cmp(b.name()))` instead. Using `.to_owned()` inside `by_key` is an alternative but allocates a `String` per element.
Applied to files:
src/tool/mod.rssrc/detect.rssrc/cmd/run.rssrc/cmd/list.rssrc/types.rssrc/tool/cargo_aliases.rs
📚 Learning: 2026-05-04T23:28:17.947Z
Learnt from: kjanat
Repo: kjanat/runner PR: 5
File: src/lib.rs:222-223
Timestamp: 2026-05-04T23:28:17.947Z
Learning: When reviewing Rust `rustdoc` comments (`/// ...`), treat a trailing backslash (`\`) at the end of a comment line as valid CommonMark syntax for a hard line break (rendered as `<br>`). Do not flag such trailing backslashes as papercuts or recommend removing them unless there is clear evidence they are unintended (e.g., they are not in the `rustdoc` comment context or the surrounding formatting contradicts the intended CommonMark hard-break usage).
Applied to files:
src/tool/mod.rssrc/detect.rssrc/cmd/run.rssrc/cmd/list.rssrc/types.rssrc/tool/cargo_aliases.rs
📚 Learning: 2026-03-26T20:08:23.153Z
Learnt from: kjanat
Repo: kjanat/runner PR: 1
File: src/detect.rs:22-22
Timestamp: 2026-03-26T20:08:23.153Z
Learning: In `src/detect.rs` within the `kjanat/runner` codebase, `detect()` is intentionally infallible and should return `ProjectContext` directly. Parsing/I/O failures from task extractors (which return `anyhow::Result<Vec<String>>`) must be recorded by `push_extracted_tasks` into `ProjectContext.warnings` as `DetectionWarning` entries and then emitted to stderr via `cmd::print_warnings`. When reviewing, do not flag `detect()` for “swallowing errors” as long as failures are routed into the warnings-list design (i.e., they’re preserved in `ProjectContext.warnings`, not dropped silently).
Applied to files:
.rustfmt.toml.dprint.json.gitignore
📚 Learning: 2026-05-04T22:42:28.879Z
Learnt from: kjanat
Repo: kjanat/runner PR: 5
File: CHANGELOG.md:8-27
Timestamp: 2026-05-04T22:42:28.879Z
Learning: In `CHANGELOG.md`, do not treat a `## [Unreleased]` section as an error/mismatch during development PRs even if `Cargo.toml` includes an in-progress version bump. The versioned header format `## [X.Y.Z] - YYYY-MM-DD` should only be added at release/tag time; this repo’s `CHANGELOG.md` includes a “Post-release checklist” confirming that behavior. Only flag changelog/version mismatches if they contradict the intended workflow described in `CHANGELOG.md`.
Applied to files:
.rustfmt.toml.dprint.json.gitignore
📚 Learning: 2026-05-02T17:50:01.271Z
Learnt from: kjanat
Repo: kjanat/runner PR: 5
File: .gitignore:4-4
Timestamp: 2026-05-02T17:50:01.271Z
Learning: In this repository, `package-lock.json` is intentionally added to `.gitignore` and should not be committed. In future reviews, do not flag the absence/presence of `package-lock.json` as an issue as long as `.gitignore` continues to exclude it intentionally.
Applied to files:
.gitignore
📚 Learning: 2026-05-04T15:23:38.296Z
Learnt from: kjanat
Repo: kjanat/runner PR: 5
File: .github/workflows/release.yml:73-73
Timestamp: 2026-05-04T15:23:38.296Z
Learning: For GitHub Actions workflows in this repository (kjanat/runner), maintain the maintainer’s preference for “floating” action tags (e.g., `v6`, `v7`) instead of pinned full commit SHAs. During code review, do not flag action usages in `.github/workflows/**/*.yml` for not being pinned to full commit SHAs or suggest switching to SHA pinning.
Applied to files:
.github/workflows/release.yml.github/workflows/release-dryrun.yml.github/workflows/npm-release.yml.github/workflows/crates-release.yml
📚 Learning: 2026-03-26T16:14:15.754Z
Learnt from: kjanat
Repo: kjanat/runner PR: 1
File: src/tool/go_task.rs:64-81
Timestamp: 2026-03-26T16:14:15.754Z
Learning: If code uses let-chains (e.g., `if let Some(x) = foo && ... && let Some(y) = bar`), ensure the crate’s `Cargo.toml` sets `package.edition = "2024"`. Rust 2021/earlier should not be used with let-chains; require 2024 specifically for compilation.
Applied to files:
Cargo.toml
🪛 actionlint (1.7.12)
.github/workflows/npm-release.yml
[error] 50-50: 1st argument of function call is not assignable. "bool" cannot be assigned to "string". called function type is "fromJSON(string) -> any"
(expression)
🪛 ast-grep (0.42.1)
site/build.ts
[warning] 107-110: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(
<script[^>]+src="\\.?/?(?:${[...emptyChunks].join("|")})"[^>]*></script>,
"g",
)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🪛 Betterleaks (1.1.2)
site/build.ts
[high] 16-16: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 LanguageTool
CHANGELOG.md
[uncategorized] ~35-~35: The official name of this software platform is spelled with a capital “H”.
Context: ...ake zero API calls (tag resolved from github.action_ref); version: latest trigg...
(GITHUB)
[grammar] ~90-~90: Ensure spelling is correct
Context: ...he runner-run npm version and the MIT licence. ### Changed - Cloudflare Web Analytics beac...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 Stylelint (17.10.0)
site/src/styles/base.css
[error] 25-25: Expected empty line before declaration (declaration-empty-line-before)
(declaration-empty-line-before)
[error] 14-14: Expected "Menlo" to be "menlo" (value-keyword-case)
(value-keyword-case)
[error] 14-14: Expected "Consolas" to be "consolas" (value-keyword-case)
(value-keyword-case)
site/src/styles/index.css
[error] 298-298: Deprecated keyword "break-word" for property "word-break" (declaration-property-value-keyword-no-deprecated)
(declaration-property-value-keyword-no-deprecated)
[error] 14-14: Deprecated property "clip" (property-no-deprecated)
(property-no-deprecated)
🪛 YAMLlint (1.38.0)
.github/workflows/release-dryrun.yml
[error] 47-47: too many spaces inside braces
(braces)
[error] 47-47: too many spaces inside braces
(braces)
[error] 60-60: too many spaces inside braces
(braces)
[error] 60-60: too many spaces inside braces
(braces)
[error] 85-85: too many spaces inside braces
(braces)
[error] 85-85: too many spaces inside braces
(braces)
[error] 92-92: too many spaces inside braces
(braces)
[error] 92-92: too many spaces inside braces
(braces)
[error] 97-97: too many spaces inside braces
(braces)
[error] 97-97: too many spaces inside braces
(braces)
[error] 102-102: too many spaces inside braces
(braces)
[error] 102-102: too many spaces inside braces
(braces)
[error] 135-135: too many spaces inside braces
(braces)
[error] 135-135: too many spaces inside braces
(braces)
.github/workflows/npm-release.yml
[warning] 10-10: truthy value should be one of [false, true]
(truthy)
[error] 11-11: too many spaces inside braces
(braces)
[error] 11-11: too many spaces inside braces
(braces)
[error] 14-14: too many spaces inside braces
(braces)
[error] 14-14: too many spaces inside braces
(braces)
[error] 65-65: too many spaces inside braces
(braces)
[error] 65-65: too many spaces inside braces
(braces)
🔇 Additional comments (12)
.zed/settings.json (1)
15-16: Aye, this be a clean config change.
lspcloses properly, comma placement is correct, and the newfile_typesmapping is valid JSON..github/workflows/npm-release.yml (1)
94-95: Nice cleanup: single-source config for Node version and registry.Using
env.NODE_VERSIONandenv.REGISTRYhere reduces drift across steps. Good hardening for maintainability.src/complete/grouped.zsh (1)
85-92: Nice catch on the zshlocalleak.Aye, explicitly zeroing
__runner_ghere is the right fix; it stops the stray redisplay junk without touching the completion grouping logic.justfile (1)
17-18: Belay that concern—the alias be checked in proper.The cargo config already defines
i = ["install", "--path", "."]in the repository, socargo iwill work fine as coded. No need to be changin' nothin' here. The plank stays steady, me hearties.> Likely an incorrect or invalid review comment.README.md (1)
3-4: Badges and public links are aligned, matey.These updates are clean and consistent with the
runner-runpackage naming.Also applies to: 8-10
src/cmd/list.rs (1)
45-45: Cargo alias source is wired into list rendering correctly, arr.Grouping and source-path resolution both include
TaskSource::CargoAliases, so list output coverage is complete.Also applies to: 164-164
site/wrangler.jsonc (1)
1-17: Wrangler static-assets config looks shipshape, matey.
assets.directory, route, and compatibility settings are set up coherently for deployment.src/detect.rs (1)
272-274: Cargo alias extraction integration is solid, matey.Nice touch handling alias-read failures as
DetectionWarninginstead of aborting task detection.Also applies to: 277-300
src/cmd/run.rs (1)
136-136: Run-path support for Cargo aliases is properly threaded through, arr.Both source-directory selection and command construction now cover
TaskSource::CargoAliases.Also applies to: 252-252
site/package.json (1)
12-30: Site tooling manifest is well organized, matey.Script coverage for build/dev/deploy/check flows looks complete and consistent.
site/src/app/copy.ts (1)
1-23: Clipboard interaction flow is clean and resilient, arr.Success/failure feedback and temporary button state are handled clearly.
.github/workflows/crates-release.yml (1)
64-111: Security gating here is clean and release-safe.Explicit tag namespacing, tag↔version verification, mandatory dry-run, and token preflight make the publish path robust.
| RUN_ID: ${{ case(contains(github.event_name, 'workflow_dispatch'), inputs.run-id, github.event.workflow_run.id) }} | ||
| EVENT_NAME: ${{ github.event_name }} | ||
| INPUT_DIST_TAG: ${{ inputs.dist-tag }} | ||
| INPUT_DRY_RUN: ${{ fromJSON(inputs.dry-run) }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "1) Confirm the problematic expression exists:"
rg -n -C2 'INPUT_DRY_RUN:\s*\$\{\{\s*fromJSON\(inputs\.dry-run\)\s*\}\}' .github/workflows/npm-release.yml || true
echo
echo "2) Run actionlint (if available) to verify the type error:"
if command -v actionlint >/dev/null 2>&1; then
actionlint -oneline .github/workflows/npm-release.yml
else
echo "actionlint not found in this environment. Install it and rerun:"
echo " actionlint -oneline .github/workflows/npm-release.yml"
fiRepository: kjanat/runner
Length of output: 506
Ahoy! INPUT_DRY_RUN is typoed to Davy Jones' locker — Line 50 will keel over.
inputs.dry-run be a boolean from workflow_dispatch, but fromJSON() be expectin' a string. Actionlint be hollerin' the error clear as cannon fire: "bool" cannot be assigned to "string". This'll break yer workflow evaluation faster than a ship without a rudder.
Fix: Hoist the boolean straight up without the fromJSON() wrapper:
🏴☠️ Correct fix
- INPUT_DRY_RUN: ${{ fromJSON(inputs.dry-run) }}
+ INPUT_DRY_RUN: ${{ inputs.dry-run }}Or if ye be needin' null-safety on non-dispatch events:
- INPUT_DRY_RUN: ${{ fromJSON(inputs.dry-run) }}
+ INPUT_DRY_RUN: ${{ inputs.dry-run || false }}Verified with actionlint — the type error be real as Blackbeard's beard. Get this shiplapped and squared away, matey.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| INPUT_DRY_RUN: ${{ fromJSON(inputs.dry-run) }} | |
| INPUT_DRY_RUN: ${{ inputs.dry-run }} |
🧰 Tools
🪛 actionlint (1.7.12)
[error] 50-50: 1st argument of function call is not assignable. "bool" cannot be assigned to "string". called function type is "fromJSON(string) -> any"
(expression)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/npm-release.yml at line 50, The workflow currently wraps
inputs.dry-run with fromJSON in the INPUT_DRY_RUN env (INPUT_DRY_RUN: ${{
fromJSON(inputs.dry-run) }}), causing a type mismatch because inputs.dry-run is
already a boolean; remove the fromJSON wrapper and assign the boolean directly
(use inputs.dry-run as-is for INPUT_DRY_RUN), or if you need null-safety for
non-dispatch runs add a conditional/default around inputs.dry-run rather than
calling fromJSON.
| - name: build (taiki-e dry-run) | ||
| if: matrix.build-tool == 'cargo' || matrix.build-tool == 'cross' || matrix.build-tool == 'cargo-cross-toolchain' | ||
| if: contains(fromJSON('["cargo", "cross", "cargo-cross-toolchain"]'), matrix.build-tool) | ||
| uses: taiki-e/upload-rust-binary-action@v1 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| token: ${{ github.token }} | ||
| bin: runner,run | ||
| target: ${{ matrix.target }} | ||
| build-tool: ${{ matrix.build-tool == 'cargo-cross-toolchain' && 'cargo' || matrix.build-tool }} | ||
| build-tool: ${{ case(matrix.build-tool == 'cargo-cross-toolchain', 'cargo', matrix.build-tool) }} | ||
| archive: runner-$tag-$target |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/release-dryrun.ymlRepository: kjanat/runner
Length of output: 6093
🌐 Web query:
taiki-e/upload-rust-binary-action event support workflow_dispatch tag variable
💡 Result:
taiki-e/upload-rust-binary-action supports choosing the Git tag/release target via the action input ref (a fully-formed tag ref like refs/tags/<tag>), which you can set from a workflow_dispatch input variable. Key points (from the action’s docs/code): 1) The action has an input named ref described as “Fully-formed tag ref for this release”, and the README shows using it like ref: refs/tags/my_tag. [1] 2) Internally, the action uses ${{ inputs.ref }} to derive tag (it slices off the refs/tags/ prefix). [2] 3) Therefore, if your workflow is triggered by workflow_dispatch, you can define a workflow_dispatch input (e.g., tag) and pass it into the action by constructing ref: refs/tags/${{ github.event.inputs.tag }} (or equivalent expression). This is consistent with the action documentation that accepts ref for uploading to arbitrary tags beyond push tag events. [1] Minimal example workflow snippet: on: workflow_dispatch: inputs: tag: required: true type: string jobs: upload: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: taiki-e/upload-rust-binary-action@v1 with: bin: my-binary token: ${{ secrets.GITHUB_TOKEN }} # Upload assets to an arbitrary tag ref: refs/tags/${{ github.event.inputs.tag }} Note: Without specifying ref, the action defaults to GITHUB_REF (via ref=${INPUT_REF:-"${GITHUB_REF:-}"} in main.sh). [2]
Citations:
- 1: https://github.com/taiki-e/upload-rust-binary-action
- 2: https://github.com/taiki-e/upload-rust-binary-action/blob/main/main.sh
This action won't work right on manual dispatch without passin' ref—and $tag ain't even defined.
Aye, the action does support workflow_dispatch, but only if ye feed it an explicit ref parameter (like ref: refs/tags/${{ github.event.inputs.tag }}). Without it, the action falls back to GITHUB_REF, which'll be a branch ref on manual runs, not a tag. Plus, that archive: runner-$tag-$target be usin' a literal string $tag that's never defined anywhere in this workflow—it won't expand, just sit there like dead weight in the archive name. With dry-run: true, it won't break spectacularly, but ye'll get archives named runner-$tag-$target instead of somethin' sane. Either pass a proper ref input to the action for manual runs or remove the $tag reference from archive and let the action handle its own naming. (github.com)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release-dryrun.yml around lines 107 - 115, The
taiki-e/upload-rust-binary-action step ("build (taiki-e dry-run)" using
taiki-e/upload-rust-binary-action@v1) is missing an explicit ref for manual
workflow_dispatch runs and the archive name uses an undefined literal $tag; fix
by adding a ref input to the action (e.g., set ref to a tag input like
refs/tags/${{ github.event.inputs.tag }} or to github.ref_name when appropriate)
and either define a workflow_dispatch input named tag or replace the archive
value to use a valid expression (e.g., a derived/defined tag variable or
github.ref_name) so archive no longer contains the literal $tag.
| exec env CARGO_TERM_QUIET=true \ | ||
| cargo run --release \ | ||
| --manifest-path="${MANIFEST}" \ | ||
| -- "$@" |
There was a problem hiding this comment.
Keep the wrapper on the locked dependency graph.
Aye, every release path in this PR builds with a locked resolve, but this wrapper does not. That leaves local bin/runner invocations free to drift from CI/release behavior and to rewrite Cargo.lock when the graph changes.
🛠 Proposed fix
exec env CARGO_TERM_QUIET=true \
cargo run --release \
+ --locked \
--manifest-path="${MANIFEST}" \
-- "$@"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| exec env CARGO_TERM_QUIET=true \ | |
| cargo run --release \ | |
| --manifest-path="${MANIFEST}" \ | |
| -- "$@" | |
| exec env CARGO_TERM_QUIET=true \ | |
| cargo run --release \ | |
| --locked \ | |
| --manifest-path="${MANIFEST}" \ | |
| -- "$@" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/runner` around lines 20 - 23, The wrapper script bin/runner invokes cargo
without the --locked flag, allowing local runs to update Cargo.lock and diverge
from CI/release builds; update the cargo invocation in the exec line (the
command starting with exec env CARGO_TERM_QUIET=true \ cargo run --release
--manifest-path="${MANIFEST}" -- "$@") to include the --locked flag so cargo run
is invoked with --locked (e.g., cargo run --release
--manifest-path="${MANIFEST}" --locked -- "$@"), ensuring local runs use the
locked dependency graph.
| npm-pkg-name := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.name'` | ||
| npm-pkg-scope := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.subpkgscope'` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cargo metadata --no-deps --format-version 1 | jq -r '
{
workspace_default_members,
package_names: [.packages[].name],
selected_runner: ([.packages[] | select(.name == "runner")][0].name // "<none>"),
selected_runner_run: ([.packages[] | select(.name == "runner-run")][0].name // "<none>"),
default_member_npm_name: (
.workspace_default_members[0] as $id
| [.packages[] | select(.id == $id) | .metadata.npm.name][0] // "<none>"
),
default_member_npm_scope: (
.workspace_default_members[0] as $id
| [.packages[] | select(.id == $id) | .metadata.npm.subpkgscope][0] // "<none>"
)
}'Repository: kjanat/runner
Length of output: 542
🏁 Script executed:
head -n 10 justfile | cat -nRepository: kjanat/runner
Length of output: 602
Arr, them jq selectors be ghost-hunting the old crate name, matey.
After the rename to runner-run, that select(.name == "runner") be coming back empty as a dead man's coffers. Leaves npm-pkg-name and npm-pkg-scope blank as bleached bones, which means test-release starts walking through bad npm/dist/... paths and the whole thing goes belly-up.
Time to fix this proper-like: resolve the workspace default member here, just like build-packages.ts does.
Suggested fix
-npm-pkg-name := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.name'`
-npm-pkg-scope := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.subpkgscope'`
+npm-pkg-name := `cargo metadata --no-deps --format-version 1 | jq -r '.workspace_default_members[0] as $id | .packages[] | select(.id == $id) | .metadata.npm.name'`
+npm-pkg-scope := `cargo metadata --no-deps --format-version 1 | jq -r '.workspace_default_members[0] as $id | .packages[] | select(.id == $id) | .metadata.npm.subpkgscope'`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| npm-pkg-name := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.name'` | |
| npm-pkg-scope := `cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "runner").metadata.npm.subpkgscope'` | |
| npm-pkg-name := `cargo metadata --no-deps --format-version 1 | jq -r '.workspace_default_members[0] as $id | .packages[] | select(.id == $id) | .metadata.npm.name'` | |
| npm-pkg-scope := `cargo metadata --no-deps --format-version 1 | jq -r '.workspace_default_members[0] as $id | .packages[] | select(.id == $id) | .metadata.npm.subpkgscope'` |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@justfile` around lines 6 - 7, The jq selectors in justfile currently look up
a package by the old crate name ("runner") and return empty after the rename;
change npm-pkg-name and npm-pkg-scope to first resolve the workspace default
member (same approach as build-packages.ts) and then select the package whose id
matches that default member, extracting .metadata.npm.name and
.metadata.npm.subpkgscope; specifically, run cargo metadata and use jq to get
the workspace default member id, then select the package with that id (matching
.id) and return its metadata.npm.name / metadata.npm.subpkgscope instead of
select(.name == "runner").
| pkg="$(jq -r --arg t '{{ host-triple }}' '.targets[] | select(.rust == $t) | .pkg' npm/targets.json)" | ||
| echo "→ host: {{ host-triple }} (${pkg})" | ||
|
|
There was a problem hiding this comment.
Fail fast if the host triple has no target mapping.
If that jq query returns an empty string, the script keeps sailing: build-packages gets only="", which means “build everything”, and the later symlink step goes off the rails with a blank package name. Guard pkg right after the lookup.
Suggested fix
pkg="$(jq -r --arg t '{{ host-triple }}' '.targets[] | select(.rust == $t) | .pkg' npm/targets.json)"
+ if [[ -z "${pkg}" ]]; then
+ echo "✗ no npm target mapping for host triple {{ host-triple }}"
+ exit 1
+ fi
echo "→ host: {{ host-triple }} (${pkg})"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pkg="$(jq -r --arg t '{{ host-triple }}' '.targets[] | select(.rust == $t) | .pkg' npm/targets.json)" | |
| echo "→ host: {{ host-triple }} (${pkg})" | |
| pkg="$(jq -r --arg t '{{ host-triple }}' '.targets[] | select(.rust == $t) | .pkg' npm/targets.json)" | |
| if [[ -z "${pkg}" ]]; then | |
| echo "✗ no npm target mapping for host triple {{ host-triple }}" | |
| exit 1 | |
| fi | |
| echo "→ host: {{ host-triple }} (${pkg})" | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@justfile` around lines 47 - 49, The pkg lookup using jq can return an empty
string which later causes build-packages and the symlink step to fail silently;
after the jq assignment to pkg (the variable pkg in the justfile), immediately
check if pkg is empty and, if so, print a clear error message including the
host-triple and exit non‑zero to fail fast (so build-packages doesn't get
only=""). Ensure you reference the same pkg variable and the host-triple
placeholder in the message.
| <button class="copy" type="button" data-cmd="cargo install --git={{repo}}/ runner"> | ||
| <span class="label">cargo · from source</span> | ||
| <span class="cmd">cargo install --git={{repo}}/ runner</span> | ||
| <span class="toast" aria-hidden="true">copied</span> |
There was a problem hiding this comment.
Update the cargo install command to the renamed crate package.
Lines 40-43 still copy/install runner; this PR renames the published package to runner-run, so the current button command is stale.
Suggested fix
- <button class="copy" type="button" data-cmd="cargo install --git={{repo}}/ runner">
+ <button class="copy" type="button" data-cmd="cargo install --git {{repo}} runner-run">
<span class="label">cargo · from source</span>
- <span class="cmd">cargo install --git={{repo}}/ runner</span>
+ <span class="cmd">cargo install --git {{repo}} runner-run</span>
<span class="toast" aria-hidden="true">copied</span>
</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button class="copy" type="button" data-cmd="cargo install --git={{repo}}/ runner"> | |
| <span class="label">cargo · from source</span> | |
| <span class="cmd">cargo install --git={{repo}}/ runner</span> | |
| <span class="toast" aria-hidden="true">copied</span> | |
| <button class="copy" type="button" data-cmd="cargo install --git {{repo}} runner-run"> | |
| <span class="label">cargo · from source</span> | |
| <span class="cmd">cargo install --git {{repo}} runner-run</span> | |
| <span class="toast" aria-hidden="true">copied</span> | |
| </button> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/index.html` around lines 40 - 43, The cargo install command shown in
the copy button still references the old crate name "runner"; update the command
string in the button with data-cmd and the visible span (span class="cmd") to
the new package name "runner-run" so both the data-cmd attribute value and the
displayed command text change from "cargo install --git={{repo}}/ runner" /
"runner" to "cargo install --git={{repo}}/ runner-run" / "runner-run" (locate
the button element with class="copy" and the nested span.cmd to make the edits).
| .visually-hidden { | ||
| position: absolute; | ||
| width: 1px; | ||
| height: 1px; | ||
| padding: 0; | ||
| margin: -1px; | ||
| overflow: hidden; | ||
| white-space: nowrap; | ||
| border: 0; | ||
| clip: rect(0, 0, 0, 0); | ||
| } |
There was a problem hiding this comment.
Ye’ve got a lint blocker in the visually-hidden utility.
Line 14 uses deprecated clip, and Stylelint is already flagging it as an error. Swap to the modern clipping pattern so this sheet passes lint cleanly.
Suggested fix
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
white-space: nowrap;
border: 0;
- clip: rect(0, 0, 0, 0);
+ clip-path: inset(50%);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .visually-hidden { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| margin: -1px; | |
| overflow: hidden; | |
| white-space: nowrap; | |
| border: 0; | |
| clip: rect(0, 0, 0, 0); | |
| } | |
| .visually-hidden { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| margin: -1px; | |
| overflow: hidden; | |
| white-space: nowrap; | |
| border: 0; | |
| clip-path: inset(50%); | |
| } |
🧰 Tools
🪛 Stylelint (17.10.0)
[error] 14-14: Deprecated property "clip" (property-no-deprecated)
(property-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/styles/index.css` around lines 5 - 15, The .visually-hidden utility
is using the deprecated clip property (clip: rect(...)), which Stylelint flags;
replace that deprecated rule with the modern equivalent by removing clip:
rect(0, 0, 0, 0) and adding a clip-path based solution (e.g., clip-path:
inset(50%)) so the .visually-hidden rule uses clip-path instead of clip while
keeping the existing positioning, size, overflow, and white-space semantics.
| .copy .cmd { | ||
| overflow-x: visible; | ||
| font-size: 0.85rem; | ||
| word-break: break-word; | ||
| overflow-wrap: anywhere; |
There was a problem hiding this comment.
word-break: break-word be deprecated here too.
Line 298 is another Stylelint error. overflow-wrap: anywhere already handles the wrap behavior in this block, so keep word-break at its default or drop it entirely.
Suggested fix
.copy .cmd {
overflow-x: visible;
font-size: 0.85rem;
- word-break: break-word;
overflow-wrap: anywhere;
white-space: normal;
}🧰 Tools
🪛 Stylelint (17.10.0)
[error] 298-298: Deprecated keyword "break-word" for property "word-break" (declaration-property-value-keyword-no-deprecated)
(declaration-property-value-keyword-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/src/styles/index.css` around lines 295 - 299, The CSS rule for the
selector ".copy .cmd" contains the deprecated declaration "word-break:
break-word"; remove that property (or reset it to the default) since
"overflow-wrap: anywhere" already provides the intended wrapping behavior—update
the ".copy .cmd" block to drop "word-break: break-word" so Stylelint stops
flagging it.
| impl ExtractedAlias { | ||
| /// Render the expansion as a space-separated string for descriptions. | ||
| pub(crate) fn display_command(&self) -> String { | ||
| self.expansion.join(" ") |
There was a problem hiding this comment.
The rendered command loses quoting.
tokenize() preserves a single token like a b, but display_command() prints it as a b with no quoting, so the description can show the wrong argv shape. Quote/escape whitespace-bearing tokens before joining so runner list matches reality.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tool/cargo_aliases.rs` around lines 47 - 50, display_command currently
joins tokens with spaces and loses quoting for tokens that contain whitespace
(mismatching what tokenize() produces); update ExtractedAlias::display_command
to quote/escape any token that contains whitespace or special characters before
joining so the rendered string reflects the real argv shape (e.g., wrap
space-containing tokens in quotes and escape internal quotes/backslashes), using
the same tokenization assumptions as tokenize() to ensure symmetry between
tokenize() and display_command().
| let aliases = | ||
| read_alias_table(path).with_context(|| format!("reading {}", path.display()))?; | ||
| for (name, value) in aliases { | ||
| let Some(tokens) = tokenize(&value) else { | ||
| continue; | ||
| }; | ||
| merged.insert(name, tokens); |
There was a problem hiding this comment.
Don’t silently drop busted aliases.
If tokenize() fails here, the alias just vanishes from detection/listing and the caller never gets a warning. Bubble an error with the alias name/path instead of continue-ing, or ye’ll make invalid configs look like “no alias found”.
Suggested fix
- let Some(tokens) = tokenize(&value) else {
- continue;
- };
+ let tokens = tokenize(&value)
+ .with_context(|| format!("invalid cargo alias `{name}` in {}", path.display()))?;
merged.insert(name, tokens);-fn tokenize(value: &AliasValue) -> Option<Vec<String>> {
+fn tokenize(value: &AliasValue) -> anyhow::Result<Vec<String>> {
match value {
- AliasValue::Arr(tokens) => (!tokens.is_empty()).then(|| tokens.clone()),
+ AliasValue::Arr(tokens) if !tokens.is_empty() => Ok(tokens.clone()),
+ AliasValue::Arr(_) => anyhow::bail!("alias expansion must not be empty"),
AliasValue::Str(raw) => {
- let split = shlex::split(raw)?;
- (!split.is_empty()).then_some(split)
+ let split = shlex::split(raw).ok_or_else(|| anyhow::anyhow!("invalid shell quoting"))?;
+ if split.is_empty() {
+ anyhow::bail!("alias expansion must not be empty");
+ }
+ Ok(split)
}
}
}Also applies to: 198-204
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tool/cargo_aliases.rs` around lines 157 - 163, The loop that iterates
aliases from read_alias_table(path) currently silently skips failures from
tokenize(&value), causing invalid aliases to disappear; instead, when tokenize
returns None or an error, return/bubble an error with context including the
alias name and the config path. Replace the `continue` in the for loop (and the
analogous site around lines 198-204) so that failures from tokenize(&value)
produce an anyhow::Error (or use bail!/Context) that includes the alias `name`
and `path.display()` before returning, rather than inserting nothing into
`merged`.
Summary
This PR adds support for publishing the
runnercrate to crates.io and renames the package torunner-runto avoid conflicts with existing crates.Key Changes
runnertorunner-runinCargo.tomlto comply with crates.io naming requirementsCargo.tomlto expose the crate as a library while maintaining the binary.github/workflows/crates-release.yml) that:Cargo.tomlversion before publishingImplementation Details
release.ymlworkflow run on version tags (starting with 'v') or via manualworkflow_dispatchCargo.tomlbefore any publish attemptCARGO_REGISTRY_TOKENsecret for actual crate publicationhttps://claude.ai/code/session_014R4NQ7rUaJVZ2s36Kxe4WT