diff --git a/scripts/build.ts b/scripts/build.ts index 7ea17ce2..13004430 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -367,9 +367,17 @@ export const SeverityNumber = {}; const full = pathMod.join(dir, ent.name) if (ent.isDirectory()) { walk(full); continue } if (!/\.(ts|tsx)$/.test(ent.name)) continue - const code: string = fs.readFileSync(full, 'utf-8') + const rawCode: string = fs.readFileSync(full, 'utf-8') const fileDir = pathMod.dirname(full) + // Strip comments before scanning for imports/requires. + // The regex scanner matches require()/import() patterns + // inside JSDoc comments, causing false-positive missing + // module detection that breaks the build with noop stubs. + const code = rawCode + .replace(/\/\*[\s\S]*?\*\//g, '') // block comments + .replace(/\/\/.*$/gm, '') // line comments + // Collect static imports: import { X } from '...' for (const m of code.matchAll(/import\s+(?:\{([^}]*)\}|(\w+))?\s*(?:,\s*\{([^}]*)\})?\s*from\s+['"](.*?)['"]/g)) { checkAndRegister(m[4], fileDir, m[1] || m[3] || '') diff --git a/src/constants/promptIdentity.test.ts b/src/constants/promptIdentity.test.ts index b8eb28cd..818e7d0e 100644 --- a/src/constants/promptIdentity.test.ts +++ b/src/constants/promptIdentity.test.ts @@ -1,5 +1,16 @@ import { afterEach, expect, test } from 'bun:test' +// MACRO is replaced at build time by Bun.define but not in test mode. +// Define it globally so tests that import modules using MACRO don't crash. +;(globalThis as Record).MACRO = { + VERSION: '99.0.0', + DISPLAY_VERSION: '0.0.0-test', + BUILD_TIME: new Date().toISOString(), + ISSUES_EXPLAINER: 'report the issue at https://github.com/anthropics/claude-code/issues', + PACKAGE_URL: '@gitlawb/openclaude', + NATIVE_PACKAGE_URL: undefined, +} + import { getSystemPrompt, DEFAULT_AGENT_PROMPT } from './prompts.js' import { CLI_SYSPROMPT_PREFIXES, getCLISyspromptPrefix } from './system.js' import { CLAUDE_CODE_GUIDE_AGENT } from '../tools/AgentTool/built-in/claudeCodeGuideAgent.js' diff --git a/src/utils/context.test.ts b/src/utils/context.test.ts index 72c6bd43..3ce3fde7 100644 --- a/src/utils/context.test.ts +++ b/src/utils/context.test.ts @@ -9,6 +9,7 @@ import { const originalEnv = { CLAUDE_CODE_USE_OPENAI: process.env.CLAUDE_CODE_USE_OPENAI, CLAUDE_CODE_MAX_OUTPUT_TOKENS: process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS, + OPENAI_MODEL: process.env.OPENAI_MODEL, } afterEach(() => { @@ -23,11 +24,17 @@ afterEach(() => { process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS = originalEnv.CLAUDE_CODE_MAX_OUTPUT_TOKENS } + if (originalEnv.OPENAI_MODEL === undefined) { + delete process.env.OPENAI_MODEL + } else { + process.env.OPENAI_MODEL = originalEnv.OPENAI_MODEL + } }) test('deepseek-chat uses provider-specific context and output caps', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('deepseek-chat')).toBe(128_000) expect(getModelMaxOutputTokens('deepseek-chat')).toEqual({ @@ -40,6 +47,7 @@ test('deepseek-chat uses provider-specific context and output caps', () => { test('deepseek-chat clamps oversized max output overrides to the provider limit', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS = '32000' + delete process.env.OPENAI_MODEL expect(getMaxOutputTokensForModel('deepseek-chat')).toBe(8_192) }) @@ -47,6 +55,7 @@ test('deepseek-chat clamps oversized max output overrides to the provider limit' test('gpt-4o uses provider-specific context and output caps', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('gpt-4o')).toBe(128_000) expect(getModelMaxOutputTokens('gpt-4o')).toEqual({ @@ -59,6 +68,7 @@ test('gpt-4o uses provider-specific context and output caps', () => { test('gpt-4o clamps oversized max output overrides to the provider limit', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS = '32000' + delete process.env.OPENAI_MODEL expect(getMaxOutputTokensForModel('gpt-4o')).toBe(16_384) }) @@ -66,6 +76,7 @@ test('gpt-4o clamps oversized max output overrides to the provider limit', () => test('gpt-5.4 family uses provider-specific context and output caps', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('gpt-5.4')).toBe(1_050_000) expect(getModelMaxOutputTokens('gpt-5.4')).toEqual({ @@ -98,6 +109,7 @@ test('gpt-5.4 family keeps large max output overrides within provider limits', ( test('MiniMax-M2.7 uses explicit provider-specific context and output caps', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('MiniMax-M2.7')).toBe(204_800) expect(getModelMaxOutputTokens('MiniMax-M2.7')).toEqual({ @@ -110,6 +122,7 @@ test('MiniMax-M2.7 uses explicit provider-specific context and output caps', () test('unknown openai-compatible models use the 128k fallback window (not 8k, see #635)', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('some-unknown-3p-model')).toBe(128_000) }) @@ -117,6 +130,7 @@ test('unknown openai-compatible models use the 128k fallback window (not 8k, see test('MiniMax-M2.5 and M2.1 use explicit provider-specific context and output caps', () => { process.env.CLAUDE_CODE_USE_OPENAI = '1' delete process.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS + delete process.env.OPENAI_MODEL expect(getContextWindowForModel('MiniMax-M2.5')).toBe(204_800) expect(getContextWindowForModel('MiniMax-M2.5-highspeed')).toBe(204_800) diff --git a/src/utils/openclaudePaths.test.ts b/src/utils/openclaudePaths.test.ts index a69db922..42246e58 100644 --- a/src/utils/openclaudePaths.test.ts +++ b/src/utils/openclaudePaths.test.ts @@ -76,7 +76,9 @@ describe('OpenClaude paths', () => { }) test('local installer uses openclaude wrapper path', async () => { - delete process.env.CLAUDE_CONFIG_DIR + // Force .openclaude config home so the test doesn't fall back to + // ~/.claude when ~/.openclaude doesn't exist on this machine. + process.env.CLAUDE_CONFIG_DIR = join(homedir(), '.openclaude') const { getLocalClaudePath } = await importFreshLocalInstaller() expect(getLocalClaudePath()).toBe(