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
32 changes: 31 additions & 1 deletion src/term-commands/brain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, test } from 'bun:tes
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { checkForUpdates } from './brain.js';
import { checkForUpdates, compareVersions } from './brain.js';

/**
* Tests for the cache-only checkForUpdates function.
Expand Down Expand Up @@ -88,3 +88,33 @@ describe('checkForUpdates', () => {
expect(result.updateAvailable).toBe(false);
});
});

describe('compareVersions', () => {
test('equal versions return 0', () => {
expect(compareVersions('260403.1', '260403.1')).toBe(0);
});

test('a > b returns positive', () => {
expect(compareVersions('260403.2', '260403.1')).toBeGreaterThan(0);
});

test('a < b returns negative', () => {
expect(compareVersions('260403.1', '260403.2')).toBeLessThan(0);
});

test('handles multi-digit segments correctly (the bug)', () => {
// String comparison: "260403.9" > "260403.10" → true (wrong)
// Numeric comparison: 9 < 10 → correct
expect(compareVersions('260403.10', '260403.9')).toBeGreaterThan(0);
expect(compareVersions('260403.9', '260403.10')).toBeLessThan(0);
});

test('handles different segment counts', () => {
expect(compareVersions('260403.1.1', '260403.1')).toBeGreaterThan(0);
expect(compareVersions('260403', '260403.0')).toBe(0);
});

test('handles major version differences', () => {
expect(compareVersions('260404.1', '260403.99')).toBeGreaterThan(0);
});
});
25 changes: 18 additions & 7 deletions src/term-commands/brain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ const BRAIN_REPO = 'github:automagik-dev/genie-brain';
const BRAIN_DIR = 'node_modules/@automagik/genie-brain';
const CACHE_PATH = join(homedir(), '.genie', 'brain-version-check.json');

/** Compare dot-separated version strings numerically (e.g., "260403.9" vs "260403.10"). */
export function compareVersions(a: string, b: string): number {
const partsA = a.split('.').map(Number);
const partsB = b.split('.').map(Number);
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const diff = (partsA[i] ?? 0) - (partsB[i] ?? 0);
if (diff !== 0) return diff;
}
return 0;
}

// ── Helpers ────────────────────────────────────────────────────────────────

/** Read brain version from its local package.json. Returns undefined on failure. */
Expand Down Expand Up @@ -76,7 +87,7 @@ function refreshVersionCache(localVersion?: string): void {
// Compare: strip prefix digit for comparison (dev uses 1.x, main uses 0.x)
const localCore = version.replace(/^\d+\./, '');
const latestCore = latestVersion.replace(/^\d+\./, '');
const updateAvailable = latestCore > localCore;
const updateAvailable = compareVersions(latestCore, localCore) > 0;

// Write cache
const cacheDir = join(homedir(), '.genie');
Expand Down Expand Up @@ -138,13 +149,13 @@ async function updateBrain(): Promise<boolean> {

console.log(`\n Updated: ${oldVersion} → ${newVersion}`);

// Run migrations (warn on failure, don't abort)
// Run migrations via subprocess — import() cache returns stale pre-update
// module, so new migrations would be skipped. A fresh bun process loads
// the rebuilt code from disk.
try {
const brain = await import(BRAIN_PKG);
if (brain.runAllMigrations) {
await brain.runAllMigrations();
console.log(' Migrations applied.');
}
const migrateScript = `const b = require('${BRAIN_PKG}'); if (b.runAllMigrations) b.runAllMigrations().then(() => process.exit(0)).catch((e) => { console.error(e); process.exit(1); }); else process.exit(0);`;
execSync(`bun -e "${migrateScript}"`, { cwd: BRAIN_DIR, stdio: 'inherit' });
console.log(' Migrations applied.');
} catch {
console.log(' Migration skipped. Run: genie brain migrate');
}
Expand Down
Loading