From d5f1495f12f40c6c06c964fc981fe640be4a28aa Mon Sep 17 00:00:00 2001 From: Imanol Maiztegui Date: Wed, 17 Jun 2026 17:03:15 +0200 Subject: [PATCH] refactor(build): remove sidecar models-snapshot distribution The models snapshot is now embedded directly in the compiled binary, eliminating the need for a separate models-snapshot.json file alongside the CLI executable. - Delete script/kilocode/models-snapshot.ts build-time preparation - Delete src/kilocode/provider/models-snapshot.ts runtime loader - Remove snapshot copy steps from vscode, jetbrains, and opencode builds - Remove snapshot existence checks from PrepareLocalCliTask/CheckCliTask - Remove snapshot-related .gitignore and .prettierignore entries - Simplify watch-cli, local-bin, and build scripts - Update smoke test error messages to say "embedded" not "sidecar" - Simplify models-snapshot tests to validate parsing only - Remove models-snapshot from extract-source-links skip list --- .github/workflows/publish.yml | 2 +- .prettierignore | 4 - .../backend/cli/KiloBackendCliManager.kt | 3 - .../src/main/kotlin/CheckCliTask.kt | 2 +- .../src/main/kotlin/PrepareLocalCliTask.kt | 14 +-- packages/kilo-jetbrains/script/build.ts | 13 +- packages/kilo-vscode/script/build.ts | 6 - packages/kilo-vscode/script/local-bin.ts | 18 +-- packages/kilo-vscode/script/watch-cli.ts | 16 +-- packages/opencode/.gitignore | 3 - packages/opencode/script/build.ts | 13 +- .../script/kilocode/models-snapshot.ts | 76 ----------- .../src/kilocode/provider/models-snapshot.ts | 32 ----- .../kilocode/provider/models-snapshot.test.ts | 118 ++++-------------- script/extract-source-links.ts | 2 +- 15 files changed, 42 insertions(+), 280 deletions(-) delete mode 100644 packages/opencode/script/kilocode/models-snapshot.ts delete mode 100644 packages/opencode/src/kilocode/provider/models-snapshot.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e937c9a36fe..c2f0f56de15 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -288,7 +288,7 @@ jobs: $output = & $binary --pure models anthropic if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } if (-not ($output -match "(?m)^anthropic/")) { - throw "Compiled Windows binary did not list Anthropic models from the sidecar snapshot" + throw "Compiled Windows binary did not list Anthropic models from the embedded snapshot" } } finally { Remove-Item -Recurse -Force $root -ErrorAction SilentlyContinue diff --git a/.prettierignore b/.prettierignore index fd44c32aa5d..874473b595c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,7 +4,3 @@ packages/desktop/src/bindings.ts # alignment, which creates large spurious diffs on any unrelated content change. # See AGENTS.md "Markdown Tables" and script/check-md-table-padding.ts. *.md - -packages/opencode/src/provider/models-snapshot.ts -packages/opencode/src/provider/models-snapshot.js -packages/opencode/src/provider/models-snapshot.d.ts diff --git a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt index 5ad06704ee7..fffa73461d0 100644 --- a/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt +++ b/packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt @@ -88,17 +88,14 @@ class KiloBackendCliManager( val platform = platform() val exe = if (SystemInfo.isWindows) "kilo.exe" else "kilo" val target = File(PathManager.getSystemPath(), "kilo/bin/$exe") - val snapshot = File(target.parentFile, "models-snapshot.json") if (forceExtract) { log.info("Force re-extracting CLI resources under ${target.parentFile.absolutePath}") if (target.exists()) target.delete() - if (snapshot.exists()) snapshot.delete() forceExtract = false } extractResource("cli/$platform/$exe", target, executable = true) - extractResource("cli/$platform/models-snapshot.json", snapshot, executable = false) return target } diff --git a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/CheckCliTask.kt b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/CheckCliTask.kt index 5ad5b22e00d..dffe15e5169 100644 --- a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/CheckCliTask.kt +++ b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/CheckCliTask.kt @@ -45,7 +45,7 @@ abstract class CheckCliTask : DefaultTask() { val missing = platforms.get().filter { platform -> val d = File(resolved, platform) val exe = if (platform.startsWith("windows")) "kilo.exe" else "kilo" - !File(d, exe).exists() || !File(d, "models-snapshot.json").exists() + !File(d, exe).exists() } if (missing.isNotEmpty()) { throw GradleException( diff --git a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/PrepareLocalCliTask.kt b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/PrepareLocalCliTask.kt index 0a65e8f4dbd..dc1501154f7 100644 --- a/packages/kilo-jetbrains/build-tasks/src/main/kotlin/PrepareLocalCliTask.kt +++ b/packages/kilo-jetbrains/build-tasks/src/main/kotlin/PrepareLocalCliTask.kt @@ -26,8 +26,8 @@ import javax.inject.Inject * 4. Each entry on `PATH` * 5. Common install locations (`~/.bun/bin`, `/opt/homebrew/bin`, `/usr/local/bin`) * - * After Bun finishes, the task verifies the expected binary and models snapshot exist so that - * Rosetta / architecture mismatches surface with a clear error message. + * After Bun finishes, the task verifies the expected binary exists so that Rosetta / architecture + * mismatches surface with a clear error message. */ @DisableCachingByDefault(because = "Local developer bootstrap task that shells out to Bun") abstract class PrepareLocalCliTask : DefaultTask() { @@ -47,8 +47,7 @@ abstract class PrepareLocalCliTask : DefaultTask() { @TaskAction fun run() { val expected = binary() - val snapshot = snapshot() - if (expected.exists() && snapshot.exists()) { + if (expected.exists()) { logger.lifecycle("CLI binary already exists at ${expected.absolutePath}") return } @@ -72,19 +71,12 @@ abstract class PrepareLocalCliTask : DefaultTask() { "This can happen if Bun and Gradle are running under different architectures." ) } - if (!snapshot.exists()) { - throw GradleException("Expected CLI models snapshot was not created at ${snapshot.absolutePath}.") - } } private fun binary(): File { return File(File(dir.get().asFile, platform()), exe()) } - private fun snapshot(): File { - return File(File(dir.get().asFile, platform()), "models-snapshot.json") - } - private fun platform(): String { return "${os()}-${arch()}" } diff --git a/packages/kilo-jetbrains/script/build.ts b/packages/kilo-jetbrains/script/build.ts index 90e9518c608..5652d4d6711 100644 --- a/packages/kilo-jetbrains/script/build.ts +++ b/packages/kilo-jetbrains/script/build.ts @@ -13,7 +13,6 @@ * Local: builds only current platform (--single). * Production: builds all platforms. * 2. Copies them into backend/build/generated/cli/cli/{os}/kilo[.exe] - * plus models-snapshot.json sidecars. * so they end up inside the backend jar at /cli/{os}/kilo. * 3. Invokes Gradle to build the plugin. */ @@ -54,17 +53,13 @@ function distBinPath(os: string, exe: string): string { return join(distDir, `@kilocode/cli-${os}`, "bin", exe) } -function distSnapshotPath(os: string): string { - return join(distDir, `@kilocode/cli-${os}`, "bin", "models-snapshot.json") -} - function hasDist(): boolean { if (production) { - return platforms.every((p) => existsSync(distBinPath(p.os, p.exe)) && existsSync(distSnapshotPath(p.os))) + return platforms.every((p) => existsSync(distBinPath(p.os, p.exe))) } const tag = localPlatformTag() const local = platforms.find((p) => p.os === tag) - return local ? existsSync(distBinPath(local.os, local.exe)) && existsSync(distSnapshotPath(local.os)) : false + return local ? existsSync(distBinPath(local.os, local.exe)) : false } async function prepareCli() { @@ -90,8 +85,7 @@ async function prepareCli() { let copied = 0 for (const p of platforms) { const src = distBinPath(p.os, p.exe) - const snapshot = distSnapshotPath(p.os) - if (!existsSync(src) || !existsSync(snapshot)) { + if (!existsSync(src)) { missing.push(p.os) continue } @@ -100,7 +94,6 @@ async function prepareCli() { mkdirSync(dir, { recursive: true }) const dest = join(dir, p.exe) cpSync(src, dest) - cpSync(snapshot, join(dir, "models-snapshot.json")) chmodSync(dest, 0o755) copied++ log(`Copied ${relative(root, src)} -> ${relative(root, dest)}`) diff --git a/packages/kilo-vscode/script/build.ts b/packages/kilo-vscode/script/build.ts index 45257a191c5..56f65d9f5c0 100644 --- a/packages/kilo-vscode/script/build.ts +++ b/packages/kilo-vscode/script/build.ts @@ -69,19 +69,13 @@ for (const config of targets) { const sourceBinary = join(cliDistDir, config.cliDir, "bin", config.binary) const targetBinary = join(binDir, config.binary) - const sourceSnapshot = join(cliDistDir, config.cliDir, "bin", "models-snapshot.json") - const targetSnapshot = join(binDir, "models-snapshot.json") if (!existsSync(sourceBinary)) { throw new Error(`CLI binary not found at ${sourceBinary}`) } - if (!existsSync(sourceSnapshot)) { - throw new Error(`CLI models snapshot not found at ${sourceSnapshot}`) - } console.log(` 📥 Copying binary from ${config.cliDir}/bin/${config.binary}...`) await $`cp ${sourceBinary} ${targetBinary}` - await $`cp ${sourceSnapshot} ${targetSnapshot}` await copyTreeSitterResources(sourceBinary, targetBinary) if (config.binary !== "kilo.exe") { diff --git a/packages/kilo-vscode/script/local-bin.ts b/packages/kilo-vscode/script/local-bin.ts index 2fd0a765db9..9547b67aaef 100644 --- a/packages/kilo-vscode/script/local-bin.ts +++ b/packages/kilo-vscode/script/local-bin.ts @@ -29,10 +29,7 @@ const indexingDir = join(packagesDir, "kilo-indexing") const targetBinDir = join(kiloVscodeDir, "bin") const binName = process.platform === "win32" ? "kilo.exe" : "kilo" const targetBinPath = join(targetBinDir, binName) -const snapshotName = "models-snapshot.json" -const targetSnapshotPath = join(targetBinDir, snapshotName) const versionFile = join(targetBinDir, ".cli-version") -const devSnapshotPath = join(opencodeDir, "src", "provider", snapshotName) function log(msg: string) { console.log(`[local-bin] ${msg}`) @@ -102,7 +99,6 @@ async function findKiloBinaryInOpencodeDist(): Promise { try { statSync(preferred) if (!hasTreeSitterResources(preferred)) return null - if (!existsSync(snapshotForBinary(preferred))) return null return preferred } catch { // fall through to generic search @@ -129,7 +125,6 @@ async function findKiloBinaryInOpencodeDist(): Promise { } if (e.isFile() && (e.name === "kilo" || e.name === "kilo.exe") && basename(dirname(p)) === "bin") { if (!hasTreeSitterResources(p)) continue - if (!existsSync(snapshotForBinary(p))) continue return p } } @@ -137,10 +132,6 @@ async function findKiloBinaryInOpencodeDist(): Promise { return null } -function snapshotForBinary(file: string): string { - return join(dirname(file), snapshotName) -} - async function ensureBuiltBinary(): Promise { const found = await findKiloBinaryInOpencodeDist() if (found) return found @@ -191,7 +182,6 @@ async function writeSourceWrapper() { ].join("\n"), ) chmodSync(targetBinPath, 0o755) - if (existsSync(devSnapshotPath)) await $`cp ${devSnapshotPath} ${targetSnapshotPath}` await ensureFfmpegForTarget(currentFfmpegTarget(), targetBinDir) const hash = await cliSourceHash() @@ -204,11 +194,10 @@ async function writeSourceWrapper() { async function main() { const targetFile = Bun.file(targetBinPath) const exists = await targetFile.exists() - const snapshotExists = await Bun.file(targetSnapshotPath).exists() - const ready = exists && snapshotExists + const ready = exists const stale = ready && !forceRebuild && (await isStale()) - const rebuild = forceRebuild || stale || (exists && !snapshotExists) + const rebuild = forceRebuild || stale if (ready && !rebuild) { const st = statSync(targetBinPath) @@ -226,7 +215,6 @@ async function main() { if (exists && rebuild) { log(stale ? `CLI source has changed — rebuilding.` : `Refreshing existing CLI resources.`) rmSync(targetBinPath) - if (existsSync(targetSnapshotPath)) rmSync(targetSnapshotPath) if (forceRebuild || stale) { removeDist() } @@ -243,9 +231,7 @@ async function main() { return null }) if (!sourceBinPath) return - const sourceSnapshotPath = snapshotForBinary(sourceBinPath) await $`mkdir -p ${targetBinDir}` - await $`cp ${sourceSnapshotPath} ${targetSnapshotPath}` await $`cp ${sourceBinPath} ${targetBinPath}` await copyTreeSitterResources(sourceBinPath, targetBinPath) chmodSync(targetBinPath, 0o755) diff --git a/packages/kilo-vscode/script/watch-cli.ts b/packages/kilo-vscode/script/watch-cli.ts index 2d0ff2b371c..cf90082f38d 100644 --- a/packages/kilo-vscode/script/watch-cli.ts +++ b/packages/kilo-vscode/script/watch-cli.ts @@ -7,7 +7,7 @@ * CLI backend without manual rebuild steps. */ import { watch, chmodSync } from "node:fs" -import { dirname, join, relative } from "node:path" +import { join, relative } from "node:path" import { $ } from "bun" import { copyTreeSitterResources } from "../src/services/cli-backend/cli-resources" @@ -17,7 +17,6 @@ const opencodeDir = join(packagesDir, "opencode") const opencodeSrcDir = join(opencodeDir, "src") const targetBinDir = join(kiloVscodeDir, "bin") const targetBinPath = join(targetBinDir, "kilo") -const snapshotName = "models-snapshot.json" let building = false let pending = false @@ -31,10 +30,6 @@ function sourceBinaryPath(): string { return join(opencodeDir, "dist", `@kilocode/cli-${process.platform}-${process.arch}`, "bin", "kilo") } -function snapshotPath(binary: string): string { - return join(dirname(binary), snapshotName) -} - async function rebuild() { if (building) { pending = true @@ -56,18 +51,12 @@ async function rebuild() { installed = true const source = sourceBinaryPath() - const snapshot = snapshotPath(source) if (!(await Bun.file(source).exists())) { log(`ERROR: Build completed but no binary found at ${relative(packagesDir, source)}`) return } - if (!(await Bun.file(snapshot).exists())) { - log(`ERROR: Build completed but no models snapshot found at ${relative(packagesDir, snapshot)}`) - return - } await $`mkdir -p ${targetBinDir}` - await $`cp ${snapshot} ${join(targetBinDir, snapshotName)}` await $`cp ${source} ${targetBinPath}` await copyTreeSitterResources(source, targetBinPath) chmodSync(targetBinPath, 0o755) @@ -93,9 +82,8 @@ let timer: ReturnType | null = null watch(opencodeSrcDir, { recursive: true }, (_event, filename) => { if (!filename) return - // Skip non-source files and build-generated files + // Skip test files if (filename.endsWith(".test.ts") || filename.endsWith(".test.tsx")) return - if (filename.includes("models-snapshot")) return if (timer) clearTimeout(timer) timer = setTimeout(() => { diff --git a/packages/opencode/.gitignore b/packages/opencode/.gitignore index 81668738db7..932b09924cb 100644 --- a/packages/opencode/.gitignore +++ b/packages/opencode/.gitignore @@ -3,9 +3,6 @@ dist dist-* gen app.log -src/provider/models-snapshot.js -src/provider/models-snapshot.d.ts -src/provider/models-snapshot.json script/build-*.ts temporary-*.md .artifacts diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index e5feea1d1b9..a3ac6301fdc 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -7,7 +7,6 @@ import path from "path" import { fileURLToPath } from "url" import { createSolidTransformPlugin } from "@opentui/solid/bun-plugin" import { createRequire } from "module" // kilocode_change -import { prepareModelsSnapshot } from "./kilocode/models-snapshot" // kilocode_change const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -104,7 +103,7 @@ async function copyKiloConsole(input: string, outputDir: string) { } // kilocode_change end -// kilocode_change start - validate compiled binaries load the sidecar models snapshot +// kilocode_change start - validate compiled binaries load the embedded models snapshot function smokeEnv(root: string) { const env = { ...process.env } delete env.KILO_MODELS_PATH @@ -129,7 +128,7 @@ async function smokeModels(binaryPath: string) { try { const out = await $`${binaryPath} --pure models anthropic`.env(smokeEnv(root)).text() if (out.split(/\r?\n/).some((line) => line.startsWith("anthropic/"))) return - throw new Error("Compiled binary did not list Anthropic models from the sidecar snapshot") + throw new Error("Compiled binary did not list Anthropic models from the embedded snapshot") } finally { await fs.promises .rm(root, { recursive: true, force: true }) @@ -250,13 +249,6 @@ const targets = singleFlag }) : allTargets -// kilocode_change start - prepare one validated models snapshot before any target compile -const snapshot = await prepareModelsSnapshot() -console.log( - `Prepared models snapshot from ${snapshot.source} (${snapshot.providers} providers, ${snapshot.models} models)`, -) -// kilocode_change end - await $`rm -rf dist` const kiloConsoleDist = await buildKiloConsole() // kilocode_change @@ -338,7 +330,6 @@ for (const item of targets) { }, }) - await fs.promises.copyFile(snapshot.path, path.resolve(dir, `dist/${name}/bin/models-snapshot.json`)) // kilocode_change await copyTreeSitterWasms(path.resolve(dir, `dist/${name}/bin`)) // kilocode_change await copyKiloConsole(kiloConsoleDist, path.resolve(dir, `dist/${name}/bin`)) // kilocode_change diff --git a/packages/opencode/script/kilocode/models-snapshot.ts b/packages/opencode/script/kilocode/models-snapshot.ts deleted file mode 100644 index 81a81431164..00000000000 --- a/packages/opencode/script/kilocode/models-snapshot.ts +++ /dev/null @@ -1,76 +0,0 @@ -import fs from "fs/promises" -import path from "path" -import { parseModelsSnapshot } from "../../src/kilocode/provider/models-snapshot-shape" - -export const MODELS_SNAPSHOT_PATH = path.resolve(import.meta.dir, "../../src/provider/models-snapshot.json") - -const STALE = [ - path.resolve(import.meta.dir, "../../src/provider/models-snapshot.js"), - path.resolve(import.meta.dir, "../../src/provider/models-snapshot.d.ts"), -] - -type Fetcher = (input: string, init?: RequestInit) => Promise - -export interface PrepareModelsSnapshotOptions { - input?: string - output?: string - source?: string - fetcher?: Fetcher -} - -async function content(opts: PrepareModelsSnapshotOptions) { - const input = opts.input ?? process.env.MODELS_DEV_API_JSON - if (input) { - return { - source: input, - text: await Bun.file(input).text(), - } - } - - const base = opts.source ?? process.env.KILO_MODELS_URL ?? "https://models.dev" - const url = `${base.replace(/\/+$/, "")}/api.json` - const fetcher = opts.fetcher ?? fetch - const res = await fetcher(url, { signal: AbortSignal.timeout(20_000) }) - if (!res.ok) throw new Error(`Failed to download models snapshot from ${url}: ${res.status} ${res.statusText}`) - return { - source: url, - text: await res.text(), - } -} - -async function replace(file: string, body: string) { - await fs.mkdir(path.dirname(file), { recursive: true }) - const tmp = path.join(path.dirname(file), `.models-snapshot.${process.pid}.${Date.now()}.tmp`) - try { - await fs.writeFile(tmp, body) - await fs.rename(tmp, file) - } catch (err) { - await fs - .rm(tmp, { force: true }) - .catch((cause) => console.warn(`Failed to remove temporary models snapshot ${tmp}`, cause)) - throw err - } -} - -async function cleanup(file: string) { - if (path.resolve(file) !== MODELS_SNAPSHOT_PATH) return - await Promise.all( - STALE.map((item) => - fs.rm(item, { force: true }).catch((err) => console.warn(`Failed to remove stale models snapshot ${item}`, err)), - ), - ) -} - -export async function prepareModelsSnapshot(opts: PrepareModelsSnapshotOptions = {}) { - const out = path.resolve(opts.output ?? MODELS_SNAPSHOT_PATH) - const raw = await content(opts) - const parsed = parseModelsSnapshot(raw.text, raw.source) - await replace(out, `${JSON.stringify(parsed.data)}\n`) - await cleanup(out) - return { - path: out, - source: raw.source, - providers: parsed.stats.providers, - models: parsed.stats.models, - } -} diff --git a/packages/opencode/src/kilocode/provider/models-snapshot.ts b/packages/opencode/src/kilocode/provider/models-snapshot.ts deleted file mode 100644 index 2ce1f237408..00000000000 --- a/packages/opencode/src/kilocode/provider/models-snapshot.ts +++ /dev/null @@ -1,32 +0,0 @@ -import path from "path" -import { parseModelsSnapshot, type ModelsSnapshot } from "./models-snapshot-shape" - -const NAME = "models-snapshot.json" -const FILE = path.resolve(import.meta.dir, "../../provider/models-snapshot.json") - -function parse(text: string, source: string): ModelsSnapshot | undefined { - try { - return parseModelsSnapshot(text, source).data - } catch (err) { - console.warn(`Failed to load models snapshot from ${source}`, err) - return undefined - } -} - -async function load(file: string) { - const local = Bun.file(file) - if (!(await local.exists())) return undefined - return parse(await local.text(), file) -} - -export async function loadModelsSnapshotFrom(files: readonly string[]) { - for (const file of files) { - const found = await load(file) - if (found) return found - } - return undefined -} - -export async function loadModelsSnapshot() { - return loadModelsSnapshotFrom([path.join(path.dirname(process.execPath), NAME), FILE]) -} diff --git a/packages/opencode/test/kilocode/provider/models-snapshot.test.ts b/packages/opencode/test/kilocode/provider/models-snapshot.test.ts index 3eff1439971..01c929d3be8 100644 --- a/packages/opencode/test/kilocode/provider/models-snapshot.test.ts +++ b/packages/opencode/test/kilocode/provider/models-snapshot.test.ts @@ -1,9 +1,5 @@ import { describe, expect, test } from "bun:test" -import fs from "fs/promises" -import os from "os" -import path from "path" -import { prepareModelsSnapshot } from "../../../script/kilocode/models-snapshot" -import { loadModelsSnapshotFrom } from "../../../src/kilocode/provider/models-snapshot" +import { parseModelsSnapshot } from "../../../src/kilocode/provider/models-snapshot-shape" const fixture = { anthropic: { @@ -29,101 +25,41 @@ const fixture = { }, } -async function tmp() { - return fs.mkdtemp(path.join(os.tmpdir(), "models-snapshot-test-")) -} +describe("models snapshot validation", () => { + test("accepts a valid snapshot and reports its size", () => { + const parsed = parseModelsSnapshot(JSON.stringify(fixture)) -describe("models snapshot preparation", () => { - test("accepts and canonicalizes a valid snapshot", async () => { - const root = await tmp() - try { - const input = path.join(root, "api.json") - const out = path.join(root, "models-snapshot.json") - await Bun.write(input, JSON.stringify(fixture, null, 2)) - - const info = await prepareModelsSnapshot({ input, output: out }) - - expect(info.providers).toBe(1) - expect(info.models).toBe(1) - expect(await Bun.file(out).text()).toBe(`${JSON.stringify(fixture)}\n`) - } finally { - await fs.rm(root, { recursive: true, force: true }) - } + expect(parsed.data).toEqual(fixture) + expect(parsed.stats).toEqual({ providers: 1, models: 1 }) + expect(JSON.stringify(parsed.data)).toBe(JSON.stringify(fixture)) }) - test("fails invalid JSON before replacing the output", async () => { - const root = await tmp() - try { - const input = path.join(root, "api.json") - const out = path.join(root, "models-snapshot.json") - await Bun.write(input, "{") - await Bun.write(out, "previous") - - await expect(prepareModelsSnapshot({ input, output: out })).rejects.toThrow("not valid JSON") - expect(await Bun.file(out).text()).toBe("previous") - } finally { - await fs.rm(root, { recursive: true, force: true }) - } + test("fails invalid JSON", () => { + expect(() => parseModelsSnapshot("{")).toThrow("not valid JSON") }) - test("fails empty snapshots", async () => { - const root = await tmp() - try { - const input = path.join(root, "api.json") - const out = path.join(root, "models-snapshot.json") - await Bun.write(input, "{}") - - await expect(prepareModelsSnapshot({ input, output: out })).rejects.toThrow("at least one provider") - expect(await Bun.file(out).exists()).toBe(false) - } finally { - await fs.rm(root, { recursive: true, force: true }) - } + test("fails empty snapshots", () => { + expect(() => parseModelsSnapshot("{}")).toThrow("at least one provider") }) - test("fails malformed provider data", async () => { - const root = await tmp() - try { - const input = path.join(root, "api.json") - const out = path.join(root, "models-snapshot.json") - await Bun.write( - input, - JSON.stringify({ - anthropic: { - id: "anthropic", - name: "Anthropic", - env: ["ANTHROPIC_API_KEY"], - models: { - broken: { - id: "broken", - name: "Broken", - limit: { - context: 100, - }, - }, + test("fails malformed provider data", () => { + const value = { + anthropic: { + id: "anthropic", + name: "Anthropic", + env: ["ANTHROPIC_API_KEY"], + models: { + broken: { + id: "broken", + name: "Broken", + limit: { + context: 100, }, }, - }), - ) - - await expect(prepareModelsSnapshot({ input, output: out })).rejects.toThrow("limit.output") - expect(await Bun.file(out).exists()).toBe(false) - } finally { - await fs.rm(root, { recursive: true, force: true }) - } - }) -}) - -describe("models snapshot runtime loader", () => { - test("loads the first valid snapshot file", async () => { - const root = await tmp() - try { - const missing = path.join(root, "missing.json") - const file = path.join(root, "models-snapshot.json") - await Bun.write(file, JSON.stringify(fixture)) - - await expect(loadModelsSnapshotFrom([missing, file])).resolves.toEqual(fixture) - } finally { - await fs.rm(root, { recursive: true, force: true }) + }, + }, } + + expect(() => parseModelsSnapshot(JSON.stringify(value))).toThrow("limit.output") }) }) diff --git a/script/extract-source-links.ts b/script/extract-source-links.ts index a22c5c79614..40760820501 100755 --- a/script/extract-source-links.ts +++ b/script/extract-source-links.ts @@ -86,7 +86,7 @@ const SKIP_DIRS = ["node_modules", ".storybook", "stories", "test", "tests", "__ const SKIP_PATH_SEGMENTS = ["continuedev"] // Individual files to skip (data files full of non-user-facing URLs) -const SKIP_FILES = ["models-snapshot.ts", "models-snapshot.js", "check-forbidden-strings.ts"] // kilocode_change +const SKIP_FILES = ["check-forbidden-strings.ts"] // kilocode_change function shouldExclude(url: string): boolean { return EXCLUDE_PATTERNS.some((re) => re.test(url))