Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions scripts/bump.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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] - <date>" + compare links).
*
* Prints ONLY the new version on stdout (diagnostics go to stderr) so callers can
Expand Down Expand Up @@ -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
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -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) {
Expand Down
24 changes: 24 additions & 0 deletions test/bump.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import path from "node:path";
import { test } from "node:test";
import {
applyBump,
bumpRoadmapNow,
changelogBody,
collectVersions,
computeNext,
Expand Down Expand Up @@ -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
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -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", '<div class="mono">forgekit v0.4.0 · MIT</div>\n');
w("ROADMAP.md", "# Roadmap\n\n## Now (`master`, v0.4.0)\n\nSome text.\n");
w("CHANGELOG.md", CHANGELOG);
return dir;
}
Expand All @@ -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",
Expand All @@ -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 });
Expand Down
Loading