Skip to content

add: persistent tasks source pref. and runner.toml lsp#76

Merged
kjanat merged 10 commits into
masterfrom
feat/tasks-source-preference
Jul 1, 2026
Merged

add: persistent tasks source pref. and runner.toml lsp#76
kjanat merged 10 commits into
masterfrom
feat/tasks-source-preference

Conversation

@kjanat

@kjanat kjanat commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Two related changes: a persistent way to choose which source runs an ambiguous task, and an editor language server that surfaces config validation/docs.

[tasks] — persistent task-source preference

A task name can exist under more than one source (e.g. a package.json script and a turbo task). Previously the only way to pick the winner was per-invocation (package.json:build, --pm bun, --runner turbo); the only file knob, [task_runner].prefer, accepted task runners only (not package managers) and restricted candidates — so prefer = ["turbo"] hard-rejected a package.json script instead of ranking it.

New [tasks] section:

[tasks]
prefer = ["turbo", "bun"]                  # rank-only global order: turbo, then package.json (bun)

[tasks.overrides]
dev   = "bun"                              # per-task pins beat the global order
build = "turbo"
  • [tasks].prefer — rank-only global order. Labels may be task runners, package managers (bun/npm/… → package.json; denodeno.json then package.json), or source names. Never hard-rejects an unlisted source — it only reorders ties.
  • [tasks.overrides] — per-task pins that beat the global order for specific names.
  • Both ride the existing select_task_entry/source_priority machinery, so an explicit source:task qualifier, --runner, or --pm/RUNNER_PM still outranks the file.

Deprecates [task_runner].prefer in favour of [tasks].prefer: existing configs keep working (with their original restrictive behaviour) and now emit a migration warning; when both are set, [tasks] wins. The key is flagged "deprecated": true in the committed JSON Schema and dropped from the config init scaffold.

runner lsp — language server for runner.toml

Built with --features lsp (gated like man/schema), exposed as runner lsp over stdio. Reuses the CLI's own internals so editor feedback can't drift from runner itself:

  • diagnostics — the exact runner config validate pipeline (TOML parse, unknown keys, resolver field/policy validation) plus deprecation hints, mapped to buffer ranges and tagged DEPRECATED where appropriate;
  • hover — section/field docs sourced from the generated JSON Schema (the RunnerConfig doc comments — single source of truth);
  • completion — section names, field names, and value sets (schema enums plus the code-driven [tasks] runner/PM/source label vocabulary and booleans).

runner lsp is intercepted before project detection / config load, so it starts even when the on-disk file is currently invalid — exactly when its diagnostics matter most. The server is small and synchronous (full-text sync, one tiny document at a time). New deps (lsp-server, lsp-types) and the lsp module are feature-gated; default builds are unchanged. To enable reuse, config::collect_unknown_keys, config::deprecation_warnings (factored out of config::load), and cmd::schema::config_schema are now pub(crate).

Testing

  • New unit tests for selection ranking, per-task pins, precedence, label parsing, the deprecation warning, and every LSP feature (diagnostics severities/tags/ranges, hover, completion contexts, position mapping).
  • Full suite green under --all-features; clippy clean (--all-features and default, -D warnings); cargo fmt + dprint clean; JSON Schema regenerated with no drift.
  • Manual end-to-end checks: ranking flips with [tasks].prefer, pins override the order, legacy [task_runner].prefer still works with a deprecation warning; and the LSP binary driven through a real stdio session emits correctly-anchored diagnostics and hover, with a clean shutdown.

Notes

  • v1 of the LSP is scoped to runner.toml. Natural follow-ups: project-aware completion of real task names for [tasks.overrides] keys, and hover/diagnostics in task files (justfile/package.json).

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
runner 4e3a4f5 Commit Preview URL

Branch Preview URL
Jul 01 2026, 05:53 PM

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • cr:review
🚫 Excluded labels (none allowed) (2)
  • wip
  • cr:skip

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fdc67bde-45ea-4133-aa6b-9363407410c0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a feature-gated runner lsp stdio language server for runner.toml, with hover, completion, diagnostics, and schema-backed text anchoring. It also introduces a persistent [tasks] configuration section with global prefer ordering and per-task overrides, while deprecating [task_runner].prefer and wiring the new preferences through config loading, resolver parsing, task selection, schema generation, and docs.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Editor
  participant runner_lsp as runner lsp
  participant Diagnostics
  participant Resolver
  participant SchemaIndex

  Editor->>runner_lsp: didOpen / didChange runner.toml
  runner_lsp->>Diagnostics: compute(text, index)
  Diagnostics->>Resolver: validate_config(config)
  Resolver-->>Diagnostics: diagnostics result
  Diagnostics-->>runner_lsp: publishDiagnostics payload
  runner_lsp-->>Editor: publishDiagnostics notification

  Editor->>runner_lsp: hover / completion request
  runner_lsp->>SchemaIndex: look up section/field docs
  SchemaIndex-->>runner_lsp: schema-backed hover/completion data
  runner_lsp-->>Editor: Hover / CompletionItem[]
Loading

Possibly related PRs

  • kjanat/runner#22: Touches the same resolver and task-selection pipeline that now consumes [tasks] preferences and overrides.
  • kjanat/runner#71: Also changes same-name task ranking and forced-source precedence in src/cmd/run/select.rs.

Suggested labels: enhancement, documentation, area: cli

Poem

Ahoy, the config stopped wobblin’ at last,
And the LSP now speaks fast.
Deprecated keys can sulk in the foam,
While hover and completions find home.
Cheers, the bloody thing is cleaner now.

🚥 Pre-merge checks | ✅ 7 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Semver Version Bump Validation ⚠️ Warning Source code changed, but Cargo.toml stayed 0.15.0 on both master and HEAD; this feature batch is backward-compatible, so a MINOR bump is required. Bump Cargo.toml to the next MINOR (e.g. 0.16.0) and keep any other version file in sync.
✅ Passed checks (7 passed)
Check name Status Explanation
Description check ✅ Passed The description directly covers the new tasks preference system and runner.toml language server.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 30.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Changelog Update ✅ Passed PASS: source files changed and CHANGELOG.md was updated under [Unreleased] with Added/Deprecated entries; no version bump is present in Cargo.toml.
Agents.Md Documentation Updated ✅ Passed No AGENTS.md exists anywhere in the repo, so there was naught to update despite the CLI/LSP/config changes.
Title check ✅ Passed The title clearly matches the PR’s two main additions: persistent tasks source preferences and the runner.toml LSP.

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​lsp-types@​0.97.010010093100100
Addedcargo/​lsp-server@​0.8.010010094100100

View full report

@kjanat kjanat self-assigned this Jul 1, 2026
@kjanat kjanat added the cr:review Allow CodeRabbit review label Jul 1, 2026
kjanat added 3 commits July 1, 2026 17:12
A task name that exists under more than one source (e.g. a package.json
script *and* a turbo task) had no persistent, declarative way to choose
which one wins — only per-invocation knobs (package.json:build, --pm bun,
--runner turbo). The only file knob, [task_runner].prefer, accepted task
runners only (not package managers) and *restricted* candidates, so
prefer = ["turbo"] hard-rejected a package.json script instead of ranking it.

Add a [tasks] section:
- [tasks].prefer: rank-only global order over sources. Labels may be task
  runners, package managers (bun/npm/... -> package.json; deno -> deno.json
  then package.json), or source names. Never hard-rejects unlisted sources.
- [tasks.overrides]: per-task pins (build = "turbo", dev = "bun") that beat
  the global order for those names.
Both ride the existing select_task_entry/source_priority machinery, so an
explicit source:task qualifier, --runner, or --pm/RUNNER_PM still outranks
the file.

Deprecate [task_runner].prefer in favor of [tasks].prefer: it keeps its
original restrictive behavior for existing configs but emits a migration
warning (superseded when [tasks] is also set), is flagged deprecated in the
committed JSON Schema, and is dropped from the `config init` scaffold.
Build with `--features lsp` to get a stdio LSP for runner.toml, exposed as the
`runner lsp` subcommand (gated like `man`/`schema`). It reuses the CLI's own
internals so editor feedback never drifts from `runner` itself:

- diagnostics: the exact `runner config validate` pipeline (TOML parse, unknown
  keys, resolver field/policy validation) plus the deprecation hints, mapped to
  buffer ranges and tagged (DEPRECATED) where appropriate;
- hover: section/field docs sourced from the generated JSON Schema, i.e. the
  RunnerConfig doc comments;
- completion: section names, field names, and value sets — schema enums plus the
  code-driven label vocabulary ([tasks] runner/PM/source labels, booleans).

Dependencies (lsp-server, lsp-types) and the lsp module are feature-gated, so
default builds are unchanged. The server is small and synchronous (full-text
sync, one tiny document at a time). `runner lsp` is intercepted before project
detection / config load so it starts even when the on-disk file is invalid —
exactly when its diagnostics are most useful.

To enable reuse, `config::collect_unknown_keys`, `config::deprecation_warnings`
(factored out of `config::load`), and `cmd::schema::config_schema` are now
pub(crate).
CI's `dprint check` formats Cargo.toml via tombi and Rust via nightly rustfmt.
Two files drifted from that: the `lsp` feature's dependency array wasn't
alphabetically sorted, and a `format!` string in the deprecation warning wrapped
past the nightly-rustfmt width. No behavior change.
@coderabbitai coderabbitai Bot added area: cli Argument parsing, commands, and CLI UX enhancement New feature or request labels Jul 1, 2026
@kjanat kjanat removed the cr:review Allow CodeRabbit review label Jul 1, 2026
@kjanat kjanat force-pushed the feat/tasks-source-preference branch from 2e642db to 4ed3264 Compare July 1, 2026 15:20
Ship the runner.toml language server (`runner lsp`) in default builds rather
than gating it behind an opt-in feature — editor support should work out of the
box. `default` now includes `lsp` (which pulls in `schema`). The feature itself
is unchanged and can still be disabled with --no-default-features.
@kjanat kjanat force-pushed the feat/tasks-source-preference branch from 132c963 to c09591c Compare July 1, 2026 15:27
@kjanat kjanat added the cr:review Allow CodeRabbit review label Jul 1, 2026
coderabbitai[bot]

This comment was marked as resolved.

kjanat added 2 commits July 1, 2026 19:06
- lsp completion: surface `tasks.overrides` in header completion (nested
  object-typed fields, not just top-level sections); quote string-typed
  value completions (`pm.node`, `tasks.prefer`, ...) so they insert valid
  TOML instead of a bare word, while booleans stay unquoted.
- lsp diagnostics: anchor `[tasks.overrides]` resolver errors to the
  offending entry (`"task": ...`), not the section header.
- lsp text: `line_range` now strips a trailing `\r` on CRLF buffers.
- config: the `[task_runner].prefer` deprecation warning now names
  whichever `[tasks]` knob actually superseded it (`prefer` vs
  `overrides`) instead of always claiming `tasks.prefer` is set.
- resolver: `[tasks].prefer = ["nx"]` (a label recognized but resolving
  to no `TaskSource`) no longer looks unset and wrongly falls back to
  the deprecated, more restrictive `[task_runner].prefer`.
- schema: `[tasks].prefer`/`[tasks.overrides]` values are constrained to
  the closed label vocabulary via a new shared
  `types::task_source_labels()`, instead of open strings.
- README: drop the stale `--features lsp` install note now that `lsp`
  ships by default.
lsp-types 0.95 dropped its `url`/`serde_derive` deps in favor of its own
`Uri` (backed by `fluent-uri`), replacing `lsp_types::Url`. Migrate
`cmd::lsp::mod` off `Url` onto `Uri`, and adjust the one `.path()`
call site: `fluent_uri`'s `Path` needs `.as_str()` where `url::Url::path()`
returned `&str` directly.
@coderabbitai coderabbitai Bot added the documentation Improvements or additions to documentation label Jul 1, 2026
coderabbitai[bot]

This comment was marked as low quality.

`--dir` was the only flag using clap's native `env = "RUNNER_DIR"`
attribute instead of the repo's pattern (manual `env_suffix()`-styled
help + env fallback at the call site). That both skipped the cyan
styling every other `[env: VAR]` suffix gets and leaked the variable's
current value into the help text (`[env: RUNNER_DIR=]` when set but
empty). Give it a `DIR_HELP` string like `PM_HELP`/`RUNNER_HELP` and
drop the native `env` attribute — `configured_project_dir` already
reads `$RUNNER_DIR` independently, so behavior is unchanged.

`-k/--keep-going` and `-K/--kill-on-fail` are genuinely backed by
`RUNNER_KEEP_GOING`/`RUNNER_KILL_ON_FAIL` at the resolver layer
(`resolve_failure_policy`), but their help text never said so, unlike
every sibling env-backed flag. Add the missing `[env: ...]` suffixes.
@kjanat kjanat changed the title feat: persistent [tasks] source preference + runner.toml language server add: persistent tasks source pref. and runner.toml lsp Jul 1, 2026
@kjanat kjanat removed the cr:review Allow CodeRabbit review label Jul 1, 2026
kjanat added 2 commits July 1, 2026 20:38
`quiet` was added after doctor v3 shipped, so requiring it in the
current schema made older v3 payloads fail validation. Keep the field
emitted and typed, but optional in the generated schema, and refresh the
example plus release note wording.
- `build-packages.ts` now detects non-CI runs (`GITHUB_ACTIONS`
  unset): it builds the host target's tarball on demand with
  `cargo bbr` when the download is missing, and treats every other
  target's missing tarball as skippable rather than a hard failure.
  A bare `build-packages` now "just works" on any dev machine
  instead of erroring on absent cross-platform artifacts.
- Rename the CI dist artifact `npm-dist` -> `dist` (release.yml
  upload, npm-release.yml download, CHANGELOG note) now that
  release.yml is its sole producer and the `npm-` prefix is stale.
@kjanat

kjanat commented Jul 1, 2026

Copy link
Copy Markdown
Owner Author

Follow-up issue for Rust state duplication / schema drift cleanup: #77

@kjanat kjanat added the tech debt Known compromise or shortcut to revisit later label Jul 1, 2026
@kjanat kjanat merged commit d7f0874 into master Jul 1, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Argument parsing, commands, and CLI UX documentation Improvements or additions to documentation enhancement New feature or request tech debt Known compromise or shortcut to revisit later

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant