feat: recency-aware channel/version API for CI consumers (#3) - #4
Conversation
Expose the RouterOS version facts CI consumers (centrs) need, so they can
import them instead of scraping `quickchr version` stdout.
- Re-export version helpers from the public entry (`resolveVersion`,
`resolveAllVersions`, `parseVersionParts`, `compareRouterOsVersion`,
`isValidVersion`, `isProvisioningSupportedVersion`, `CHANNELS`, `Channel`).
- Add recency API: `classifyChannels`/`resolveChannelStatuses` (maturity +
aheadOfStable) and `selectActiveChannels`/`resolveActiveChannels` (released
channels always + pre-release at/ahead of a reference, default stable).
Pure variants take a `Record<Channel,string>` for network-free tests.
- Fix `compareRouterOsVersion`: order pre-release suffixes
`betaN < rcN < release < patch` (was stripping suffix → all equal).
Behavior change for pre-release comparisons; release-vs-release consumers
(cache-prune, doctor stale-image) unaffected.
- Add `version --json` ({channel: version}) and `doctor --json`
({ok, checks, staleImages}); exit code still reflects doctor `ok`.
- Tests: comparator suffix ordering, recency fixtures (pure + mocked-fetch
wrappers), CLI json shape. Docs: CHANGELOG, MANUAL, README, BACKLOG.
Quickchr owns version facts + recency; merge-gating policy stays in the
consumer. Out of scope, tracked in BACKLOG: networks/disk `--json`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 31 minutes and 8 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughAdds suffix-aware RouterOS version comparison ( ChangesRecency-aware channel/version API for CI consumers
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Address self-review findings on #4: - cmdDoctor: only pre-compute staleImages (a network long-term lookup when the cache is non-empty) in --json mode. In human mode print the checks first, then do the lookup, so `quickchr doctor` no longer blanks the terminal on the network before showing any output. - MANUAL.md: replace the broken `§[Library API]` shortcut-reference link with plain prose. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a public, recency-aware RouterOS channel/version API (library + CLI JSON output) so CI consumers can import version facts instead of scraping CLI text, while fixing RouterOS pre-release version ordering.
Changes:
- Export version/channel helpers from the package entry (
src/index.ts), including recency classification + “active channels” selection. - Fix
compareRouterOsVersionto orderbetaN < rcN < release < patch, and add unit coverage. - Add
--jsontoquickchr versionandquickchr doctor, with unit tests and docs/changelog updates.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/unit/versions.test.ts | Adds comparator suffix tests + recency/active-channel tests + network-wrapper tests. |
| test/unit/cli-version-doctor.test.ts | Adds CLI-level tests asserting version --json / doctor --json emit clean JSON. |
| src/lib/versions.ts | Implements suffix-aware comparator and adds channel recency/active-channel APIs. |
| src/index.ts | Re-exports version/channel utilities via the public entry point. |
| src/cli/index.ts | Adds version --json and doctor --json, refactors stale-cache image detection helper. |
| README.md | Documents new version/channel library API and CLI JSON option. |
| MANUAL.md | Documents doctor --json, version --json, and the new library helpers. |
| CHANGELOG.md | Adds unreleased entries for the new exports/CLI flags and comparator fix. |
| BACKLOG.md | Marks issue #3 items complete and records follow-up JSON gaps. |
| import type { Arch, Channel } from "./types.ts"; | ||
| import { QuickCHRError } from "./types.ts"; | ||
| import { CHANNELS, QuickCHRError } from "./types.ts"; | ||
| import { fetchResilient } from "./net.ts"; | ||
|
|
| const results = await Promise.all( | ||
| channels.map(async (ch) => [ch, await resolveVersion(ch)] as const), | ||
| CHANNELS.map(async (ch) => [ch, await resolveVersion(ch)] as const), | ||
| ); |
| export function classifyChannels(versions: Record<Channel, string>): ChannelStatus[] { | ||
| const stableVersion = versions.stable; | ||
| return CHANNELS.map((channel) => ({ | ||
| channel, |
| return CHANNELS.filter((channel) => { | ||
| if (channelMaturity(channel) === "released") return true; | ||
| return compareRouterOsVersion(versions[channel], referenceVersion) >= 0; | ||
| }); |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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`:
- Line 19: Standardize the hyphenation of "prerelease" across all documentation
files to match the canonical type definition ChannelMaturity in
src/lib/versions.ts which uses "prerelease" without a hyphen. Search for all
occurrences of "pre-release" (with hyphen) in documentation files including
MANUAL.md line 548 and any other docs, and replace them with "prerelease" (no
hyphen) to maintain consistency with the actual API type definition.
In `@MANUAL.md`:
- Around line 557-562: The import block in MANUAL.md around line 557 is
incomplete and missing the re-exported helper functions `resolveVersion`,
`parseVersionParts`, `isValidVersion`, and `isProvisioningSupportedVersion` that
are documented in CHANGELOG.md as being exported from the public
`@tikoci/quickchr` entry point. Add these missing imports to the existing import
block, and then include a brief explanation after the code block describing when
these basic helper functions should be used, such as for pre-flight version
validation checks before calling start(). Alternatively, if this section is
intended to cover only the recency-classification API, add a clarifying note
that points readers to CHANGELOG.md for the complete list of re-exported
functions.
🪄 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 Plus
Run ID: 45b6ce95-850b-4a2c-b604-404f2981570c
📒 Files selected for processing (9)
BACKLOG.mdCHANGELOG.mdMANUAL.mdREADME.mdsrc/cli/index.tssrc/index.tssrc/lib/versions.tstest/unit/cli-version-doctor.test.tstest/unit/versions.test.ts
| `isProvisioningSupportedVersion`, `CHANNELS`, and the `Channel` type — no more | ||
| blocked deep `src/lib/...` imports. | ||
| - Recency-aware channel API: `resolveChannelStatuses()` / `classifyChannels()` | ||
| classify each channel by `maturity` (`released` | `prerelease`) and |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Standardize hyphenation of "prerelease" across docs.
Line 19 uses prerelease (no hyphen), which matches the upstream type definition (ChannelMaturity = "released" | "prerelease" in src/lib/versions.ts). However, MANUAL.md line 548 and other docs use "pre-release" (with hyphen). Standardize all documentation to use prerelease (no hyphen) to match the canonical form in the codebase.
Locations to update (search and replace)
- MANUAL.md line 548: "prerelease" (currently shows "pre-release")
- Any other occurrences of "pre-release" in docs should become "prerelease" when referring to the API type or classifier
Also applies to: 548-548
🧰 Tools
🪛 LanguageTool
[uncategorized] ~19-~19: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...ach channel by maturity (released | prerelease) and aheadOfStable; `resolveActive...
(EN_WORD_COHERENCY)
🤖 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 `@CHANGELOG.md` at line 19, Standardize the hyphenation of "prerelease" across
all documentation files to match the canonical type definition ChannelMaturity
in src/lib/versions.ts which uses "prerelease" without a hyphen. Search for all
occurrences of "pre-release" (with hyphen) in documentation files including
MANUAL.md line 548 and any other docs, and replace them with "prerelease" (no
hyphen) to maintain consistency with the actual API type definition.
Source: Linters/SAST tools
| ```ts | ||
| import { | ||
| resolveAllVersions, compareRouterOsVersion, | ||
| resolveChannelStatuses, resolveActiveChannels, | ||
| classifyChannels, selectActiveChannels, channelMaturity, | ||
| CHANNELS, type Channel, type ChannelStatus, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Incomplete import block — missing re-exported helpers from CHANGELOG.
The import block omits resolveVersion, parseVersionParts, isValidVersion, and isProvisioningSupportedVersion, which are documented in CHANGELOG.md lines 14–16 as being re-exported from the public @tikoci/quickchr entry point.
Either add these to the import block and explain their use (e.g., for pre-flight version validation), or clarify that this section covers only the recency-classification API and point readers to CHANGELOG for the full re-export list.
Proposed fix: Expand the import block to include all re-exported version helpers
import {
+ resolveVersion, resolveAllVersions, parseVersionParts,
- resolveAllVersions, compareRouterOsVersion,
+ compareRouterOsVersion, isValidVersion, isProvisioningSupportedVersion,
resolveChannelStatuses, resolveActiveChannels,
classifyChannels, selectActiveChannels, channelMaturity,
CHANNELS, type Channel, type ChannelStatus,
} from "`@tikoci/quickchr`";Then optionally add a brief line after the code block explaining when the basic helpers are useful (e.g., "Use isValidVersion and isProvisioningSupportedVersion to validate versions in pre-flight checks before calling start()").
🤖 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 `@MANUAL.md` around lines 557 - 562, The import block in MANUAL.md around line
557 is incomplete and missing the re-exported helper functions `resolveVersion`,
`parseVersionParts`, `isValidVersion`, and `isProvisioningSupportedVersion` that
are documented in CHANGELOG.md as being exported from the public
`@tikoci/quickchr` entry point. Add these missing imports to the existing import
block, and then include a brief explanation after the code block describing when
these basic helper functions should be used, such as for pre-flight version
validation checks before calling start(). Alternatively, if this section is
intended to cover only the recency-classification API, add a clarifying note
that points readers to CHANGELOG.md for the complete list of re-exported
functions.
Address PR #4 review feedback: - types.ts: CHANNELS is now `readonly Channel[]` + `Object.freeze`d, so neither library code (which iterates it in versions.ts) nor consumers can mutate the canonical channel order at runtime (Copilot). Root-cause fix at the source — no per-call snapshot. Updated the one `as string[]` cast that assumed mutability; added a frozen-array anchor test. - MANUAL.md: note the entry also re-exports the lower-level version helpers (resolveVersion, parseVersionParts, isValidVersion, isProvisioningSupportedVersion) for pre-flight checks (CodeRabbit). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the reviews — addressed in 713b757 and 6a58f28. Copilot — CodeRabbit — MANUAL import block incomplete: added a line noting the entry also re-exports the lower-level helpers ( CodeRabbit — CI — Integration (linux/x86_64) failure: unrelated to this change. 34/35 integration tests passed, including every path this PR touches ( |
Closes #3.
What
Exposes the RouterOS version/channel facts CI consumers (centrs) need, so they can
importthem instead of scrapingquickchr versionstdout. centrs keeps the merge-gate policy; quickchr owns version facts + recency classification.1. Public version exports (#3 ask 1)
src/index.tsnow re-exports the version helpers, soimport { resolveAllVersions } from "@tikoci/quickchr"works (no blocked deepsrc/lib/...paths):resolveVersion,resolveAllVersions,parseVersionParts,compareRouterOsVersion,isValidVersion,isProvisioningSupportedVersion,CHANNELS, and theChanneltype.2.
version --json(#3 ask 2)Offline emits
{}. Human output unchanged.3. Suffix-aware comparator (#3 ask 3 — bug)
compareRouterOsVersionnow orders pre-release suffixes:7.24beta2<7.24rc1<7.24<7.24.1(previously thebeta/rcsuffix was stripped, so those compared equal).4. Recency / active-channels API (#3 ask 4 — the smarts)
"Active" = every released channel (stable, long-term — always, even when long-term sits behind stable) plus any pre-release channel at or ahead of a reference channel (default
stable). Answers "what's worth booting," never "what must pass."Other
--jsongaps (per issue comment)Audited the CLI: added
doctor --json({ ok, checks, staleImages }, exit still reflectsok) — it was already flagged centrs-facing in BACKLOG.networks/disk--jsonare tracked as a P3 follow-up in BACKLOG (out of scope here to keep the PR focused).Acceptance / DoD
import { resolveAllVersions, compareRouterOsVersion, resolveActiveChannels, type Channel } from "@tikoci/quickchr"works (no deep path)quickchr version --jsonemits a stable channel→version objectcompareRouterOsVersion("7.24beta2","7.24rc1") < 0,("7.24rc1","7.24") < 0,("7.24beta1","7.24beta2") < 0— unit-testedresolveActiveChannels()returns released channels + pre-release at/ahead of stable — unit-tested with a fixture wheretestingis behind stable (excluded) anddevelopmentis ahead (included)Test plan
bun test test/unit/— 566 pass / 0 fail (adds comparator suffix cases, recency fixtures — pure + mocked-fetch wrappers, CLI--jsonshape tests)bun run check— biome + tsc + markdownlint + cspell cleanquickchr version --json,quickchr doctor --json, and a public-entry import smoke forselectActiveChannels/compareRouterOsVersionDesign boundary
Quickchr owns version facts + recency classification; the must-pass gate (which channels may red a merge) stays in the consumer (centrs).
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
--jsonoutput option todoctorandversionCLI commands for CI/automation workflowsBug Fixes
Documentation