perf: cache the CLI catalog with validated startup fallback

Ports #6 with optional-field validation, conversion before cache writes, an upstream-specific cache directory, and startup regression tests.

Co-authored-by: dualface <dualface@gmail.com>
This commit is contained in:
Kashyab Ambarani
2026-09-25 03:41:59 -07:00
co-authored by dualface
parent 5d6090ae46
commit e6b5247cc0
5 changed files with 331 additions and 20 deletions
+65
View File
@@ -0,0 +1,65 @@
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import {
catalogCachePath,
isUsableCatalog,
isCatalogCacheFresh,
readCatalogCache,
writeCatalogCache,
} from "../src/catalog-cache.ts";
const catalog = {
families: [{
family_label: "SWE-2",
family_uid: "swe-2",
slug: "swe-2",
variants: [{ model_uid: "swe-2-high", label: "SWE-2 High" }],
}],
};
test("writes and reads a validated catalog atomically", (t) => {
const directory = mkdtempSync(join(tmpdir(), "pi-devin-cache-"));
t.after(() => rmSync(directory, { recursive: true, force: true }));
const path = join(directory, "nested", "models.json");
writeCatalogCache(catalog, path, 1_000);
assert.deepEqual(readCatalogCache(path), { catalog, fetchedAt: 1_000 });
assert.equal(JSON.parse(readFileSync(path, "utf8")).version, 1);
});
test("rejects malformed cache content", (t) => {
const directory = mkdtempSync(join(tmpdir(), "pi-devin-cache-"));
t.after(() => rmSync(directory, { recursive: true, force: true }));
const path = join(directory, "models.json");
writeFileSync(path, JSON.stringify({ version: 1, fetchedAt: 1_000, catalog: { families: [{}] } }));
assert.throws(() => readCatalogCache(path), /Invalid Devin model catalog cache/);
});
test("rejects catalogs without usable model families", () => {
assert.equal(isUsableCatalog({ families: [] }), false);
assert.equal(isUsableCatalog({
families: [{ family_label: "Empty", family_uid: "empty", slug: "empty", variants: [] }],
}), false);
});
test("checks cache age and future timestamps", () => {
const cached = { catalog, fetchedAt: 1_000 };
assert.equal(isCatalogCacheFresh(cached, 1_500, 500), true);
assert.equal(isCatalogCacheFresh(cached, 1_501, 500), false);
assert.equal(isCatalogCacheFresh(cached, 999, 500), false);
});
test("uses XDG cache directory when configured", () => {
assert.equal(catalogCachePath({ XDG_CACHE_HOME: "/cache" }, "/home/test"), "/cache/pi-devin/models.json");
assert.equal(catalogCachePath({}, "/home/test"), "/home/test/.cache/pi-devin/models.json");
});
for (const [field, value] of Object.entries({ cost_summary: {}, max_context_tokens: "1000", max_output_tokens: -1, model_uid: "", is_beta: "yes" })) {
test(`rejects invalid ${field} before model conversion`, () => {
const malformed = structuredClone(catalog);
malformed.families[0].variants[0][field] = value;
assert.equal(isUsableCatalog(malformed), false);
});
}