fix: 构建时替换 feature flags,修复 CoStrict provider 递归解析,默认启用 BUDDY

- build.ts: 构建产物中手动替换 feature('FLAG_NAME') 为 true/false,
  使构建后的产物正确响应 feature flag,不再依赖运行时环境变量。
- src/utils/model/model.ts: 修复 CoStrict provider 下 getDefaultSonnetModel
  和 getDefaultHaikuModel 的递归调用问题,返回具体模型名。
- src/buddy/useBuddyNotification.tsx: 移除 BUDDY 功能的日期限制,默认启用。
This commit is contained in:
y574444354 2026-04-29 14:38:44 +08:00
parent 9191df6949
commit 5864d1a9a7
3 changed files with 30 additions and 12 deletions

View File

@ -1,7 +1,6 @@
import { readdir, readFile, writeFile, cp } from 'fs/promises' import { readdir, readFile, writeFile, cp } from 'fs/promises'
import { join } from 'path' import { join } from 'path'
import { getMacroDefines } from './scripts/defines.ts' import { getMacroDefines, DEFAULT_BUILD_FEATURES } from './scripts/defines.ts'
import { DEFAULT_BUILD_FEATURES } from './scripts/defines.ts'
const outdir = 'dist' const outdir = 'dist'
@ -52,6 +51,26 @@ for (const file of files) {
} }
} }
// Step 3.5: Replace feature('FLAG_NAME') with true/false at build time
// Bun.build does not natively replace feature flags, so we do it manually here
// to match the behavior of vite-plugin-feature-flags.ts.
const FEATURE_CALL_RE = /feature\s*\(\s*['"]([\w]+)['"]\s*\)/g
let featureReplaced = 0
for (const file of files) {
if (!file.endsWith('.js')) continue
const filePath = join(outdir, file)
const content = await readFile(filePath, 'utf-8')
let matchCount = 0
const transformed = content.replace(FEATURE_CALL_RE, (match, flagName) => {
matchCount++
return features.includes(flagName) ? 'true' : 'false'
})
if (matchCount > 0) {
await writeFile(filePath, transformed)
featureReplaced += matchCount
}
}
// Also patch unguarded globalThis.Bun destructuring from third-party deps // Also patch unguarded globalThis.Bun destructuring from third-party deps
// (e.g. @anthropic-ai/sandbox-runtime) so Node.js doesn't crash at import time. // (e.g. @anthropic-ai/sandbox-runtime) so Node.js doesn't crash at import time.
let bunPatched = 0 let bunPatched = 0
@ -72,7 +91,7 @@ for (const file of files) {
BUN_DESTRUCTURE.lastIndex = 0 BUN_DESTRUCTURE.lastIndex = 0
console.log( console.log(
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for import.meta.require, ${bunPatched} for Bun destructure)`, `Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for import.meta.require, ${bunPatched} for Bun destructure, ${featureReplaced} feature flags)`,
) )
// Step 4: Copy native .node addon files (audio-capture) and vendored binaries (ripgrep) // Step 4: Copy native .node addon files (audio-capture) and vendored binaries (ripgrep)

View File

@ -15,11 +15,8 @@ export function isBuddyTeaserWindow(): boolean {
} }
export function isBuddyLive(): boolean { export function isBuddyLive(): boolean {
if (process.env.USER_TYPE === 'ant') return true // BUDDY 功能已默认启用,不再受日期限制
const d = new Date() return true
return (
d.getFullYear() > 2026 || (d.getFullYear() === 2026 && d.getMonth() >= 3)
)
} }
function RainbowText({ text }: { text: string }): React.ReactNode { function RainbowText({ text }: { text: string }): React.ReactNode {

View File

@ -153,8 +153,9 @@ export function getDefaultOpusModel(): ModelName {
// @[MODEL LAUNCH]: Update the default Sonnet model (3P providers may lag so keep defaults unchanged). // @[MODEL LAUNCH]: Update the default Sonnet model (3P providers may lag so keep defaults unchanged).
export function getDefaultSonnetModel(): ModelName { export function getDefaultSonnetModel(): ModelName {
const provider = getAPIProvider() const provider = getAPIProvider()
// CoStrict has no sonnet alias — use the main loop model to stay on the same provider // CoStrict has no sonnet alias — return a concrete default to avoid recursive
if (provider === 'costrict') return getMainLoopModel() // resolution (getMainLoopModel → getDefaultMainLoopModel → getDefaultSonnetModel).
if (provider === 'costrict') return getModelStrings().sonnet46
// For OpenAI provider, check OPENAI_DEFAULT_SONNET_MODEL first // For OpenAI provider, check OPENAI_DEFAULT_SONNET_MODEL first
if (provider === 'openai' && process.env.OPENAI_DEFAULT_SONNET_MODEL) { if (provider === 'openai' && process.env.OPENAI_DEFAULT_SONNET_MODEL) {
return process.env.OPENAI_DEFAULT_SONNET_MODEL return process.env.OPENAI_DEFAULT_SONNET_MODEL
@ -177,8 +178,9 @@ export function getDefaultSonnetModel(): ModelName {
// @[MODEL LAUNCH]: Update the default Haiku model (3P providers may lag so keep defaults unchanged). // @[MODEL LAUNCH]: Update the default Haiku model (3P providers may lag so keep defaults unchanged).
export function getDefaultHaikuModel(): ModelName { export function getDefaultHaikuModel(): ModelName {
const provider = getAPIProvider() const provider = getAPIProvider()
// CoStrict has no haiku alias — use the main loop model to stay on the same provider // CoStrict has no haiku alias — return a concrete default to avoid recursive
if (provider === 'costrict') return getMainLoopModel() // resolution (getMainLoopModel → getDefaultMainLoopModel → getDefaultHaikuModel).
if (provider === 'costrict') return getModelStrings().haiku45
// For OpenAI provider, check OPENAI_DEFAULT_HAIKU_MODEL first // For OpenAI provider, check OPENAI_DEFAULT_HAIKU_MODEL first
if (provider === 'openai' && process.env.OPENAI_DEFAULT_HAIKU_MODEL) { if (provider === 'openai' && process.env.OPENAI_DEFAULT_HAIKU_MODEL) {
return process.env.OPENAI_DEFAULT_HAIKU_MODEL return process.env.OPENAI_DEFAULT_HAIKU_MODEL