diff --git a/ROADMAP.md b/ROADMAP.md index e7fdccf..60d873b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,7 +7,7 @@ every tool. This is where that brain is headed. Direction, not promises — shaped by the two field reports this project is grounded in (the SDLC pain-point map and the ecosystem landscape). Open a Discussion to weigh in. -## Now (`master`, v0.12.1) +## Now (`master`, v0.12.2) The substrate is fully graded — decision math replaces every keyword heuristic: exemplar k-NN routing, entropy secret detection, noisy-OR goal-drift over paths **and** the identifiers a file diff --git a/scripts/bump.mjs b/scripts/bump.mjs index 626e85d..0e5e4e7 100644 --- a/scripts/bump.mjs +++ b/scripts/bump.mjs @@ -21,6 +21,8 @@ * package.json, package-lock.json (root "version" + packages[""].version), * .claude-plugin/plugin.json, .codex-plugin/plugin.json, * CITATION.cff (version + date-released), landing/index.html (display string), + * ROADMAP.md ("## Now" marker version, so `forge docs check`'s roadmap-freshness + * guard never trails a release this same script just cut), * CHANGELOG.md ([Unreleased] rotated under "## [X.Y.Z] - " + compare links). * * Prints ONLY the new version on stdout (diagnostics go to stderr) so callers can @@ -239,6 +241,18 @@ export function rotateChangelog(changelog, newVersion, prevVersion, date) { return out; } +/** + * Rewrites the version in ROADMAP.md's "## Now" marker (e.g. "## Now (`master`, v0.12.0)") + * to `newVersion`. Only that line is touched — other version mentions elsewhere in the + * document (e.g. "Shipped — Substrate v2 ... v0.5.0") are left alone. No-op (returns + * `roadmap` unchanged) if there's no "## Now" heading to update. + */ +export function bumpRoadmapNow(roadmap, newVersion) { + return roadmap.replace(/^(##\s+Now\b[^\n]*)$/m, (line) => + line.replace(/v\d+\.\d+(?:\.\d+)?/, `v${newVersion}`), + ); +} + // --------------------------------------------------------------------------- // File mutation // --------------------------------------------------------------------------- @@ -326,6 +340,13 @@ export function applyBump(root, currentVersion, newVersion, date) { write(landingRel, landing.replace(/forgekit v\d+\.\d+\.\d+/g, `forgekit v${newVersion}`)); } + const roadmapRel = "ROADMAP.md"; + const roadmap = readIfExists(path.join(root, roadmapRel)); + if (roadmap !== null) { + const updated = bumpRoadmapNow(roadmap, newVersion); + if (updated !== roadmap) write(roadmapRel, updated); + } + const clRel = "CHANGELOG.md"; const changelog = readIfExists(path.join(root, clRel)); if (changelog !== null) { diff --git a/test/bump.test.js b/test/bump.test.js index 3333ae8..76e0170 100644 --- a/test/bump.test.js +++ b/test/bump.test.js @@ -5,6 +5,7 @@ import path from "node:path"; import { test } from "node:test"; import { applyBump, + bumpRoadmapNow, changelogBody, collectVersions, computeNext, @@ -192,6 +193,26 @@ test("setUnreleasedBody fills an empty [Unreleased] and rotateChangelog then acc assert.match(rotated, /## \[0\.5\.0\] - 2026-07-11\n\n### Added\n\n- a new thing/); }); +// --------------------------------------------------------------------------- +// ROADMAP "Now" marker +// --------------------------------------------------------------------------- + +test("bumpRoadmapNow updates only the Now marker's version", () => { + const roadmap = + "# Roadmap\n\n## Now (`master`, v0.12.0)\n\nSome text.\n\n" + + "## Shipped — Substrate v2 (v0.5.0)\n\nOlder text mentioning v0.5.0 again.\n"; + const out = bumpRoadmapNow(roadmap, "0.12.1"); + assert.match(out, /## Now \(`master`, v0\.12\.1\)/); + // untouched: version mentions outside the "## Now" line survive verbatim + assert.match(out, /## Shipped — Substrate v2 \(v0\.5\.0\)/); + assert.match(out, /Older text mentioning v0\.5\.0 again\./); +}); + +test("bumpRoadmapNow is a no-op when there's no Now heading", () => { + const roadmap = "# Roadmap\n\nNo heading here.\n"; + assert.equal(bumpRoadmapNow(roadmap, "1.0.0"), roadmap); +}); + // --------------------------------------------------------------------------- // CHANGELOG rotation // --------------------------------------------------------------------------- @@ -280,6 +301,7 @@ function makeFixture() { w(".codex-plugin/plugin.json", '{\n "name": "fixture",\n "version": "0.4.0"\n}\n'); w("CITATION.cff", 'cff-version: 1.2.0\nversion: 0.4.0\ndate-released: "2026-07-06"\n'); w("landing/index.html", '
forgekit v0.4.0 · MIT
\n'); + w("ROADMAP.md", "# Roadmap\n\n## Now (`master`, v0.4.0)\n\nSome text.\n"); w("CHANGELOG.md", CHANGELOG); return dir; } @@ -295,6 +317,7 @@ test("applyBump updates every version field in a fixture tree", () => { ".codex-plugin/plugin.json", "CHANGELOG.md", "CITATION.cff", + "ROADMAP.md", "landing/index.html", "package-lock.json", "package.json", @@ -311,6 +334,7 @@ test("applyBump updates every version field in a fixture tree", () => { assert.match(read("CITATION.cff"), /^version: 0\.5\.0$/m); assert.match(read("CITATION.cff"), /^date-released: "2026-07-07"$/m); assert.match(read("landing/index.html"), /forgekit v0\.5\.0/); + assert.match(read("ROADMAP.md"), /## Now \(`master`, v0\.5\.0\)/); assert.match(read("CHANGELOG.md"), /## \[0\.5\.0\] - 2026-07-07/); } finally { fs.rmSync(dir, { recursive: true, force: true });