Skip to content
Open
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"scripts": {
"start": "./bin/claude-proxy-supervisor.sh",
"proxy": "./bin/claude-proxy-supervisor.sh",
"build": "rm -rf dist && bun build bin/cli.ts src/proxy/server.ts --outdir dist --target node --splitting --external @anthropic-ai/claude-agent-sdk --entry-naming '[name].js' && tsc -p tsconfig.build.json",
"postbuild": "node scripts/fix-bun-exports.mjs && node --check dist/cli.js && node --check dist/server.js && test -f dist/proxy/server.d.ts",
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun build bin/cli.ts src/proxy/server.ts --outdir dist --target node --splitting --external @anthropic-ai/claude-agent-sdk --entry-naming \"[name].js\" && tsc -p tsconfig.build.json",
"postbuild": "node scripts/fix-bun-exports.mjs && node --check dist/cli.js && node --check dist/server.js && node -e \"if(!require('fs').existsSync('dist/proxy/server.d.ts'))process.exit(1)\"",
"postinstall": "node ./node_modules/@anthropic-ai/claude-code/install.cjs 2>/dev/null || true",
"prepublishOnly": "bun run build",
"test": "bun test --path-ignore-patterns '**/*session-store*' --path-ignore-patterns '**/*proxy-async-ops*' --path-ignore-patterns '**/*models-auth-status*' --path-ignore-patterns '**/*proxy-context-usage-store*' --path-ignore-patterns '**/*proxy-passthrough-thinking*' --path-ignore-patterns '**/*session-recovery*' --path-ignore-patterns '**/*models.test*' && bun test src/__tests__/proxy-async-ops.test.ts && bun test src/__tests__/proxy-session-store.test.ts && bun test src/__tests__/session-store-pruning.test.ts && bun test src/__tests__/proxy-session-store-locking.test.ts && bun test src/__tests__/proxy-context-usage-store.test.ts && bun test src/__tests__/models-auth-status.test.ts && bun test src/__tests__/proxy-passthrough-thinking.test.ts && bun test src/__tests__/proxy-session-recovery.test.ts && bun test src/__tests__/models.test.ts",
Expand Down
23 changes: 15 additions & 8 deletions scripts/fix-bun-exports.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/

import { readFileSync, writeFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { glob } from "glob";

/**
Expand Down Expand Up @@ -63,15 +65,19 @@ export function patchSource(src) {
out = out.replace(blocks[0][0], cleaned);
}

// Remove subsequent blocks whose real symbols are all in the canonical set
// Deduplicate subsequent blocks against the canonical set
for (let i = blocks.length - 1; i >= 1; i--) {
const block = blocks[i][0];
const symbols = extractExportSymbols(block);
if (
symbols.length === 0 ||
symbols.every((s) => canonicalSymbols.has(s))
) {
const novel = symbols.filter((s) => !canonicalSymbols.has(s));
if (novel.length === 0) {
out = out.replace(block, "");
} else if (novel.length < symbols.length) {
const cleaned = `export { ${novel.join(", ")} };`;
out = out.replace(block, cleaned);
for (const s of novel) canonicalSymbols.add(s);
} else {
for (const s of symbols) canonicalSymbols.add(s);
}
}
}
Expand All @@ -90,7 +96,7 @@ export async function fixBunExports(distDir) {
const files = await glob("**/*.js", { cwd: distDir });
let totalFixed = 0;
for (const rel of files) {
const path = distDir + rel;
const path = join(distDir, rel);
const src = readFileSync(path, "utf-8");
const out = patchSource(src);
if (out !== src) {
Expand All @@ -103,8 +109,9 @@ export async function fixBunExports(distDir) {
}

// CLI entry — only runs when invoked directly, not when imported by tests.
if (import.meta.url === `file://${process.argv[1]}`) {
const distDir = new URL("../dist/", import.meta.url).pathname;
const __filename = fileURLToPath(import.meta.url);
if (process.argv[1] && resolve(process.argv[1]) === __filename) {
const distDir = resolve(dirname(__filename), "..", "dist");
const totalFixed = await fixBunExports(distDir);
if (totalFixed > 0) {
console.log(`fix-bun-exports: patched ${totalFixed} file(s)`);
Expand Down
18 changes: 14 additions & 4 deletions src/__tests__/fix-bun-exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,25 @@ describe("patchSource (pure)", () => {
expect(out).toContain("realThing")
})

it("keeps a subsequent export block whose symbols are NOT all in the first", () => {
// The first block is the buggy one (smaller). Don't drop the second
// just because we picked the wrong canonical — leave both in place
// so a human can see the bug rather than us silently masking it.
it("rewrites a subsequent block to keep only novel symbols when there is partial overlap", () => {
const input =
`export {\n doStuff\n};\n\nexport {\n doStuff,\n realThing\n};\n`
const out = patchSource(input)
const matches = out.match(/^export \{/gm) || []
expect(matches.length).toBe(2)
expect(out).toContain("export { realThing };")
expect(out).not.toMatch(/export \{[^}]*doStuff[^}]*realThing/)
})

it("deduplicates a partial-overlap block matching bun's tokenRefresh pattern", () => {
const input =
`export {\n stopBg,\n startBg,\n ensureFresh\n};\n\n` +
`export { logCtx, claudeLog, ensureFresh, startBg, stopBg };\n`
const out = patchSource(input)
const matches = out.match(/^export \{/gm) || []
expect(matches.length).toBe(2)
expect(out).toContain("export { logCtx, claudeLog };")
expect(out).not.toMatch(/export \{[^}]*stopBg[^}]*claudeLog/)
})

it("collapses 3+ consecutive blank lines to 2", () => {
Expand Down