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
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ of these in sync:
| `package.json` | `.version` ← **source of truth** | you bump it (`npm version`) |
| `package-lock.json` | `.version` + `.packages[""].version` | `npm version`; checked by `check:version` (CI) |
| `docs/roadmap.md` | `Current version: **X.Y.Z**` line | `version-sync`; checked by `check:version` (CI) |
| `docs/llm-guide.md` | `Version: **X.Y.Z**` header line | `version-sync`; checked by `check:version` (CI) |
| `configurator/package.json` | `.version` | `version-sync`; checked by `check:version` (CI) |
| `configurator/package-lock.json` | `.version` + `.packages[""].version` | `version-sync`; checked by `check:version` (CI) |
| `dist/*.css` (unminified) | `/*! SLASHED vX.Y.Z */` comment header | **build-derived** — stamped from `package.json`/tag by `bundle.js`; `dist/*.css` is git-ignored, so it cannot drift. `release.yml` re-verifies the stamp before publishing |
| Configurator UI version pill | baked in via Vite `__SLASHED_VERSION__` at build time | **build-derived** — injected from root `package.json` at Vite build; cannot drift |

The first five rows are the ones you ever sync; the last two are **build-derived**
The first six rows are the ones you ever sync; the last two are **build-derived**
(regenerated from `package.json` at build time and not committed as text you edit),
so `version-sync`/`check:version` intentionally don't touch them — never hand-edit them.

Expand Down
2 changes: 1 addition & 1 deletion docs/llm-guide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Slashed Framework — LLM Reference Guide

> Version: **0.6.15** · Tokens: **686** · Prefix: `--sf-`
> Version: **0.7.16** · Tokens: **686** · Prefix: `--sf-`

---

Expand Down
16 changes: 14 additions & 2 deletions scripts/check-version-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Checks:
// 1. package-lock.json version (root and packages[""]) === package.json
// 2. docs/roadmap.md "Current version" === package.json
// 3. docs/llm-guide.md "Version" header === package.json
//
// Note: configurator/src/data/api-index.generated.json no longer stores a
// frameworkVersion field — the version is injected at Vite build time from the
Expand Down Expand Up @@ -55,15 +56,26 @@ if (!m) {
);
}

// 3. configurator/package.json must match package.json.
// 3. docs/llm-guide.md "Version" header must match package.json.
const llmGuide = read('docs/llm-guide.md');
const guideMatch = llmGuide.match(/Version:\s*\*\*([^*]+)\*\*/);
if (!guideMatch) {
errors.push('docs/llm-guide.md: "Version" header not found');
} else if (guideMatch[1].trim() !== version) {
errors.push(
`docs/llm-guide.md version "${guideMatch[1].trim()}" != package.json "${version}"`,
);
}

// 4. configurator/package.json must match package.json.
const configPkg = JSON.parse(read('configurator/package.json'));
if (configPkg.version !== version) {
errors.push(
`configurator/package.json version "${configPkg.version}" != package.json "${version}"`,
);
}

// 4. configurator/package-lock.json must match package.json.
// 5. configurator/package-lock.json must match package.json.
const configLock = JSON.parse(read('configurator/package-lock.json'));
if (configLock.version !== version) {
errors.push(
Expand Down
12 changes: 10 additions & 2 deletions scripts/version-sync.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node
// Propagates the version from package.json to every other artifact that must
// stay in sync: docs/roadmap.md, configurator/package.json, and both lock files
// under configurator/.
// stay in sync: docs/roadmap.md, docs/llm-guide.md, configurator/package.json,
// and both lock files under configurator/.
//
// Does NOT touch the root package-lock.json — that is updated by npm itself
// when `npm version` runs (called by the release-it after:bump hook before this
Expand Down Expand Up @@ -70,6 +70,14 @@ changed += sync(
`roadmap version = ${version}`
) ? 1 : 0;

// ── docs/llm-guide.md ────────────────────────────────────────────────────────
changed += sync(
'docs/llm-guide.md',
new RegExp(`(Version:\\s*\\*\\*)${SEMVER_RE.source}(\\*\\*)`),
`$1${version}$2`,
`llm-guide version = ${version}`
) ? 1 : 0;

// ── configurator/package.json + package-lock.json ───────────────────────────
function syncJsonVersion(rel, label) {
const filePath = path.join(ROOT, rel);
Expand Down
17 changes: 17 additions & 0 deletions tests/check-version-sync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function buildFixture(version = '1.2.3') {

fs.mkdirSync(path.join(dir, 'docs'));
fs.writeFileSync(path.join(dir, 'docs', 'roadmap.md'), `Current version: **${version}**\n`);
fs.writeFileSync(path.join(dir, 'docs', 'llm-guide.md'), `> Version: **${version}** · Tokens: **1**\n`);

fs.mkdirSync(path.join(dir, 'configurator'));
fs.writeFileSync(path.join(dir, 'configurator', 'package.json'), JSON.stringify({ version }));
Expand Down Expand Up @@ -98,6 +99,22 @@ describe('check-version-sync failure cases', () => {
assert.ok(r.stderr.includes('"Current version"'), r.stderr);
});

test('fails when docs/llm-guide.md version differs', () => {
const dir = buildFixture();
fs.writeFileSync(path.join(dir, 'docs', 'llm-guide.md'), '> Version: **9.9.9** · Tokens: **1**\n');
const r = runChecker(dir);
assert.equal(r.status, 1, 'expected exit 1 for mismatched llm-guide.md');
assert.ok(r.stderr.includes('llm-guide.md version'), r.stderr);
});

test('fails when docs/llm-guide.md has no "Version" header', () => {
const dir = buildFixture();
fs.writeFileSync(path.join(dir, 'docs', 'llm-guide.md'), '# LLM Guide\n\nNo version here.\n');
const r = runChecker(dir);
assert.equal(r.status, 1, 'expected exit 1 for missing llm-guide version line');
assert.ok(r.stderr.includes('"Version"'), r.stderr);
});

test('fails when configurator/package.json version differs', () => {
const dir = buildFixture();
fs.writeFileSync(
Expand Down
8 changes: 8 additions & 0 deletions tests/version-sync.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ function buildFixture(target = '2.0.0', oldVersion = '1.2.3') {
path.join(dir, 'docs', 'roadmap.md'),
`# Roadmap\n\nCurrent version: **${oldVersion}**\n\nMore text.\n`,
);
fs.writeFileSync(
path.join(dir, 'docs', 'llm-guide.md'),
`# LLM Guide\n\n> Version: **${oldVersion}** · Tokens: **1** · Prefix: \`--sf-\`\n\nMore text.\n`,
);

fs.mkdirSync(path.join(dir, 'configurator'));
fs.writeFileSync(
Expand Down Expand Up @@ -69,6 +73,10 @@ describe('version-sync writer', () => {
assert.match(roadmap, /Current version: \*\*2\.0\.0\*\*/, 'roadmap.md not updated');
assert.doesNotMatch(roadmap, /1\.2\.3/, 'roadmap.md still contains the old version');

const llmGuide = fs.readFileSync(path.join(dir, 'docs', 'llm-guide.md'), 'utf8');
assert.match(llmGuide, /Version: \*\*2\.0\.0\*\*/, 'llm-guide.md not updated');
assert.doesNotMatch(llmGuide, /1\.2\.3/, 'llm-guide.md still contains the old version');

assert.equal(readJson(path.join(dir, 'configurator', 'package.json')).version, '2.0.0');

const lock = readJson(path.join(dir, 'configurator', 'package-lock.json'));
Expand Down