mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 21:05:51 +00:00
* feat: 适配 zed acp 协议 * docs: 完善 acp 文档 * feat: integrate feature branches + daemon/job 命令层级化 + 跨平台后台引擎 Cherry-picked from origin/lint/preview (637c908), excluding lint-only changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: correct detectMimeFromBase64 to decode raw bytes from base64 Cherry-picked from origin/lint/preview (ee36954). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: daemon 子进程 spawn 跨平台修复 + CliLaunchSpec 集中化重构 Cherry-picked from origin/lint/preview (c5f52cd), excluding lint-only formatting changes. - 新建 src/utils/cliLaunch.ts: 集中化 CLI 子进程启动层 - 修复 --daemon-worker=kind 等号格式解析 - 修复 daemon/bg fast path 缺少 setShellIfWindows() - 修复 checkPathExists 用 existsSync 替代 execSync('dir') - 7 个 spawn 站点迁移到 CliLaunchSpec Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: merge tsconfig.base.json into tsconfig.json with full compiler options The cherry-pick from637c908dropped jsx/strict/etc settings when removing tsconfig.base.json. This commit restores them in a single tsconfig.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: merge tsconfig.base.json into tsconfig.json with full compiler options The cherry-pick from637c908dropped jsx/strict/etc settings when removing tsconfig.base.json. This commit restores them in a single tsconfig.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
153 lines
4.6 KiB
TypeScript
153 lines
4.6 KiB
TypeScript
import { readdir, readFile, writeFile, cp } from 'fs/promises'
|
|
import { join } from 'path'
|
|
import { getMacroDefines } from './scripts/defines.ts'
|
|
|
|
const outdir = 'dist'
|
|
|
|
// Step 1: Clean output directory
|
|
const { rmSync } = await import('fs')
|
|
rmSync(outdir, { recursive: true, force: true })
|
|
|
|
// Default features that match the official CLI build.
|
|
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
|
|
const DEFAULT_BUILD_FEATURES = [
|
|
'AGENT_TRIGGERS_REMOTE',
|
|
'CHICAGO_MCP',
|
|
'VOICE_MODE',
|
|
'SHOT_STATS',
|
|
'PROMPT_CACHE_BREAK_DETECTION',
|
|
'TOKEN_BUDGET',
|
|
// P0: local features
|
|
'AGENT_TRIGGERS',
|
|
'ULTRATHINK',
|
|
'BUILTIN_EXPLORE_PLAN_AGENTS',
|
|
'LODESTONE',
|
|
// P1: API-dependent features
|
|
'EXTRACT_MEMORIES',
|
|
'VERIFICATION_AGENT',
|
|
'KAIROS_BRIEF',
|
|
'AWAY_SUMMARY',
|
|
'ULTRAPLAN',
|
|
// P2: daemon + remote control server
|
|
'DAEMON',
|
|
// ACP (Agent Client Protocol) agent mode
|
|
'ACP',
|
|
// PR-package restored features
|
|
'WORKFLOW_SCRIPTS',
|
|
'HISTORY_SNIP',
|
|
'CONTEXT_COLLAPSE',
|
|
'MONITOR_TOOL',
|
|
'FORK_SUBAGENT',
|
|
// 'UDS_INBOX',
|
|
'KAIROS',
|
|
'COORDINATOR_MODE',
|
|
'LAN_PIPES',
|
|
'BG_SESSIONS',
|
|
'TEMPLATES',
|
|
// 'REVIEW_ARTIFACT', // API 请求无响应,需进一步排查 schema 兼容性
|
|
// P3: poor mode (disable extract_memories + prompt_suggestion)
|
|
'POOR',
|
|
]
|
|
|
|
// Collect FEATURE_* env vars → Bun.build features
|
|
const envFeatures = Object.keys(process.env)
|
|
.filter(k => k.startsWith('FEATURE_'))
|
|
.map(k => k.replace('FEATURE_', ''))
|
|
const features = [...new Set([...DEFAULT_BUILD_FEATURES, ...envFeatures])]
|
|
|
|
// Step 2: Bundle with splitting
|
|
const result = await Bun.build({
|
|
entrypoints: ['src/entrypoints/cli.tsx'],
|
|
outdir,
|
|
target: 'bun',
|
|
splitting: true,
|
|
define: getMacroDefines(),
|
|
features,
|
|
})
|
|
|
|
if (!result.success) {
|
|
console.error('Build failed:')
|
|
for (const log of result.logs) {
|
|
console.error(log)
|
|
}
|
|
process.exit(1)
|
|
}
|
|
|
|
// Step 3: Post-process — replace Bun-only `import.meta.require` with Node.js compatible version
|
|
const files = await readdir(outdir)
|
|
const IMPORT_META_REQUIRE = 'var __require = import.meta.require;'
|
|
const COMPAT_REQUIRE = `var __require = typeof import.meta.require === "function" ? import.meta.require : (await import("module")).createRequire(import.meta.url);`
|
|
|
|
let patched = 0
|
|
for (const file of files) {
|
|
if (!file.endsWith('.js')) continue
|
|
const filePath = join(outdir, file)
|
|
const content = await readFile(filePath, 'utf-8')
|
|
if (content.includes(IMPORT_META_REQUIRE)) {
|
|
await writeFile(
|
|
filePath,
|
|
content.replace(IMPORT_META_REQUIRE, COMPAT_REQUIRE),
|
|
)
|
|
patched++
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
let bunPatched = 0
|
|
const BUN_DESTRUCTURE = /var \{([^}]+)\} = globalThis\.Bun;?/g
|
|
const BUN_DESTRUCTURE_SAFE = 'var {$1} = typeof globalThis.Bun !== "undefined" ? globalThis.Bun : {};'
|
|
for (const file of files) {
|
|
if (!file.endsWith('.js')) continue
|
|
const filePath = join(outdir, file)
|
|
const content = await readFile(filePath, 'utf-8')
|
|
if (BUN_DESTRUCTURE.test(content)) {
|
|
await writeFile(
|
|
filePath,
|
|
content.replace(BUN_DESTRUCTURE, BUN_DESTRUCTURE_SAFE),
|
|
)
|
|
bunPatched++
|
|
}
|
|
}
|
|
BUN_DESTRUCTURE.lastIndex = 0
|
|
|
|
console.log(
|
|
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for import.meta.require, ${bunPatched} for Bun destructure)`,
|
|
)
|
|
|
|
// Step 4: Copy native .node addon files (audio-capture)
|
|
const vendorDir = join(outdir, 'vendor', 'audio-capture')
|
|
await cp('vendor/audio-capture', vendorDir, { recursive: true })
|
|
console.log(`Copied vendor/audio-capture/ → ${vendorDir}/`)
|
|
|
|
// Step 5: Bundle download-ripgrep script as standalone JS for postinstall
|
|
const rgScript = await Bun.build({
|
|
entrypoints: ['scripts/download-ripgrep.ts'],
|
|
outdir,
|
|
target: 'node',
|
|
})
|
|
if (!rgScript.success) {
|
|
console.error('Failed to bundle download-ripgrep script:')
|
|
for (const log of rgScript.logs) {
|
|
console.error(log)
|
|
}
|
|
// Non-fatal — postinstall fallback to bun run scripts/download-ripgrep.ts
|
|
} else {
|
|
console.log(`Bundled download-ripgrep script to ${outdir}/`)
|
|
}
|
|
|
|
// Step 6: Generate cli-bun and cli-node executable entry points
|
|
const cliBun = join(outdir, 'cli-bun.js')
|
|
const cliNode = join(outdir, 'cli-node.js')
|
|
|
|
await writeFile(cliBun, '#!/usr/bin/env bun\nimport "./cli.js"\n')
|
|
|
|
await writeFile(cliNode, '#!/usr/bin/env node\nimport "./cli.js"\n')
|
|
|
|
// Make both executable
|
|
const { chmodSync } = await import('fs')
|
|
chmodSync(cliBun, 0o755)
|
|
chmodSync(cliNode, 0o755)
|
|
|
|
console.log(`Generated ${cliBun} (shebang: bun) and ${cliNode} (shebang: node)`)
|