feat: 补充构建配置,实现 Claude Code 源码编译

添加缺失的项目配置文件,使源码快照可以成功编译和运行:
- package.json: 85+ 依赖项 + 构建脚本
- tsconfig.json: TypeScript + JSX + src/ 路径别名
- globals.d.ts: MACRO 构建常量 + bun:bundle 类型声明
- scripts/build.ts: Bun 构建脚本(feature flag polyfill + MACRO 注入 + 内部包 stub + 缺失源文件自动 stub)
- BUILD_GUIDE.md: 中文编译文档
- 修 Commander.js v13 的 -d2e 短标志兼容问题

构建脚本通过 missingSourceStubPlugin 插件自动检测并 stub 缺失的源文件,
无需在源码树中手动创建 stub 文件。

构建结果:dist/cli.js (11.7 MB),CLI 可正常启动并显示交互式终端 UI。

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
buddy
abel533 1 month ago committed by liuzenghui
parent 16a676ffa3
commit 83fb08926d
  1. 2
      .gitignore
  2. 207
      BUILD_GUIDE.md
  3. 1379
      bun.lock
  4. 77
      globals.d.ts
  5. 104
      package.json
  6. 477
      scripts/build.ts
  7. 2
      src/main.tsx
  8. 28
      tsconfig.json

2
.gitignore vendored

@ -0,0 +1,2 @@
dist
node_modules

@ -0,0 +1,207 @@
# Claude Code 源码编译指南
> 本文档记录了为 Claude Code 源码快照补充缺失配置文件并成功编译运行的完整过程。
## 概述
Claude Code 的源码快照仅包含 `src/` 目录和 `README.md`,缺少所有构建配置文件。本指南涵盖了从零开始恢复构建环境的全部步骤。
---
## 补充的配置文件
### 1. `package.json`
项目的核心配置文件,定义了:
- **包名**: `@anthropic-ai/claude-code`
- **入口点**: `src/entrypoints/cli.tsx`
- **构建产物**: `dist/cli.js`
- **脚本命令**:
- `bun run build` — 执行构建脚本
- `bun run dev` — 直接运行源码(开发模式)
- `bun run typecheck` — TypeScript 类型检查
**依赖项分为三类:**
| 分类 | 数量 | 示例 |
|------|------|------|
| 公开 npm 包 | ~75 个 | `react`, `chalk`, `zod`, `@anthropic-ai/sdk` |
| Anthropic 内部包(需 stub) | ~10 个 | `@ant/*`, `@anthropic-ai/sandbox-runtime` |
| 开发依赖 | ~13 个 | `typescript`, `@types/react`, `@types/bun` |
### 2. `tsconfig.json`
TypeScript 编译配置,关键设置:
- **模块系统**: ESNext + bundler resolution
- **JSX**: `react-jsx`(React 19 的新 JSX 转换)
- **路径别名**: `src/*``./src/*`(项目中大量使用 `import from 'src/...'` 格式的导入)
- **目标**: ESNext(Bun 原生支持)
- **类型**: 同时包含 `bun-types``node` 类型定义
### 3. `globals.d.ts`
全局类型声明文件,定义了:
- **`MACRO` 常量**:构建时注入的宏定义
- `MACRO.VERSION` — 版本号
- `MACRO.BUILD_TIME` — 构建时间戳
- `MACRO.PACKAGE_URL` — npm 包地址
- `MACRO.NATIVE_PACKAGE_URL` — 原生包地址
- `MACRO.FEEDBACK_CHANNEL` — 反馈渠道
- `MACRO.ISSUES_EXPLAINER` — 问题报告说明
- `MACRO.VERSION_CHANGELOG` — 版本变更日志
- **`bun:bundle` 模块**:Bun 构建时特性标志(feature flags)模块的类型声明
- **内部包的类型 stub**:为不公开的 Anthropic 内部包提供类型定义
### 4. `scripts/build.ts`
核心构建脚本,使用 Bun 的 `Bun.build()` API,处理以下关键问题:
#### a) `bun:bundle` Feature Flags 处理
原始代码使用 `import { feature } from 'bun:bundle'` 进行编译时死代码消除。构建脚本通过自定义 Bun 插件为 `feature()` 函数提供 polyfill,所有特性标志在外部构建中默认返回 `false`
```
PROACTIVE, KAIROS, BRIDGE_MODE, DAEMON, VOICE_MODE,
AGENT_TRIGGERS, MONITOR_TOOL, COORDINATOR_MODE,
ABLATION_BASELINE, DUMP_SYSTEM_PROMPT, CHICAGO_MCP
```
#### b) `MACRO.*` 构建时常量注入
通过 `Bun.build()``define` 选项在编译时替换所有 `MACRO.*` 引用为实际值。
#### c) 内部包 Stub 插件
为不公开的 Anthropic 内部包(`@ant/*`、`@anthropic-ai/sandbox-runtime` 等)提供内联 stub,确保编译时所有命名导出都能正确解析,同时不引入运行时依赖。
#### d) 缺失源文件自动 Stub 插件
源码快照中缺少部分文件(被 `feature()` 特性标志保护或属于内部模块)。构建脚本通过 `missingSourceStubPlugin` 插件**在构建时自动检测并 stub 这些缺失文件**,无需在源码树中手动创建 stub 文件:
- 通过 `onResolve` 钩子拦截所有源文件导入,检测目标文件是否存在于磁盘
- 不存在的文件自动重定向到虚拟 `missing-source` 命名空间
- 对需要特定 named exports 的模块(如 `connectorText`、`protectedNamespace` 等)提供精确 stub
- 其余缺失模块返回通用 `export default {}`
- `.md``.txt` 文件返回空字符串,`.d.ts` 文件返回 `export {}`
- 构建日志中以 `⚠ Auto-stubbing missing module:` 标记自动 stub 的模块
#### e) 外部依赖处理
所有公开 npm 包标记为 `external`,不打包进产物,运行时从 `node_modules` 解析。
### 5. 源码修复
`src/main.tsx` 中的 `-d2e` 短标志格式与 Commander.js v13 不兼容(v13 要求短标志为单个字符),已修改为仅使用 `--debug-to-stderr` 长标志。
---
## 编译步骤
### 前提条件
- [Bun](https://bun.sh) ≥ 1.1(推荐 1.3+)
- Windows / macOS / Linux
### 步骤 1:安装依赖
```bash
bun install
```
这将安装约 600+ 个包(含传递依赖),耗时约 1-2 分钟。
### 步骤 2:执行构建
```bash
bun run build
```
构建脚本将:
1. 初始化 `bun:bundle` feature flag polyfill
2. 注入 `MACRO.*` 构建时常量
3. 为内部 Anthropic 包生成内联 stub
4. 自动检测并 stub 源码快照中缺失的源文件
5. 打包 `src/entrypoints/cli.tsx` 入口点
6. 输出到 `dist/cli.js`(约 11.7 MB)和 `dist/cli.js.map`
### 步骤 3:验证运行
```bash
# 检查版本
bun dist/cli.js --version
# 输出: 1.0.0-research (Claude Code)
# 查看帮助
bun dist/cli.js --help
# 启动交互式界面(需要 API Key)
bun dist/cli.js
```
### 自定义版本号
```bash
CLAUDE_CODE_VERSION=2.0.0 bun run build
```
---
## 构建产物
| 文件 | 大小 | 说明 |
|------|------|------|
| `dist/cli.js` | ~11.7 MB | 主程序包(ESM 格式) |
| `dist/cli.js.map` | ~38.6 MB | Source Map |
---
## 技术要点
### 架构概览
```
入口点: src/entrypoints/cli.tsx
↓ (动态导入)
主程序: src/main.tsx (Commander.js CLI)
终端 UI: src/ink/ (自定义 Ink 实现 + React 19)
核心系统:
├── src/tools/ (~40 个工具实现)
├── src/commands/ (~50 个斜杠命令)
├── src/services/ (API、MCP、OAuth、分析)
├── src/hooks/ (权限系统)
└── src/coordinator/ (多智能体协调)
```
### 关键技术栈
| 组件 | 技术 |
|------|------|
| 运行时 | Bun |
| 语言 | TypeScript (strict) |
| 终端 UI | React 19 + 自定义 Ink fork |
| CLI 框架 | Commander.js 13 |
| Schema 验证 | Zod v3 |
| 协议 | MCP SDK, LSP |
| API | Anthropic SDK |
| 遥测 | OpenTelemetry 2.x |
| 布局引擎 | 纯 TypeScript yoga-layout 实现 |
### 注意事项
1. **内部包不可用**:`@ant/*` 系列包和部分 `@anthropic-ai/*` 包不在公共 npm 上发布,相关功能(Chrome 集成、计算机使用、沙箱运行时等)在此构建中不可用。
2. **Feature Flags 全部禁用**:所有 `bun:bundle` 特性标志默认返回 `false`,这意味着实验性功能(语音、守护进程、协调器模式等)的代码路径已被消除。
3. **需要 API Key 才能实际使用**:虽然 CLI 可以编译和启动(完整的终端 UI、主题选择等均正常),但实际使用需要 Anthropic API Key 或 OAuth 登录。
4. **React Reconciler 版本**:项目使用了 `useEffectEvent` Hook,需要 `react-reconciler@0.33.0`(而非 0.31.0),该版本才实现了 `useEffectEvent` 调度器。
5. **内部包 Stub 需完整方法签名**:某些内部包(如 `@anthropic-ai/sandbox-runtime``SandboxManager`)的 stub 需要包含完整的静态方法(如 `isSupportedPlatform`、`checkDependencies`、`wrapWithSandbox` 等),否则运行时在访问未定义属性时会报错。构建脚本已为所有已知的内部类提供了完整方法签名。
6. **非官方构建**:此构建仅用于教育和安全研究目的,不代表 Anthropic 官方发布。

1379
bun.lock

File diff suppressed because it is too large Load Diff

77
globals.d.ts vendored

@ -0,0 +1,77 @@
/**
* Global type declarations for Claude Code build-time constants.
*
* MACRO is defined at bundle time via Bun's --define flag.
* bun:bundle provides compile-time feature flags for dead code elimination.
*/
// Build-time macro constants injected via --define
declare const MACRO: {
/** Application version string, e.g. "1.0.0" */
VERSION: string;
/** ISO 8601 build timestamp, e.g. "2026-03-31T00:00:00Z" */
BUILD_TIME: string;
/** npm package URL, e.g. "@anthropic-ai/claude-code" */
PACKAGE_URL: string;
/** Native package URL for platform-specific binaries */
NATIVE_PACKAGE_URL: string | undefined;
/** Feedback channel URL or description */
FEEDBACK_CHANNEL: string;
/** Instructions for reporting issues */
ISSUES_EXPLAINER: string;
/** Version changelog content */
VERSION_CHANGELOG: string;
};
// Bun's bundle-time feature flag module
declare module "bun:bundle" {
/**
* Returns true if the named feature flag is enabled at bundle time.
* Used for dead code elimination disabled branches are stripped entirely.
*/
export function feature(name: string): boolean;
}
// Stub declarations for internal Anthropic packages that are not publicly available
declare module "@ant/claude-for-chrome-mcp" {
const mod: any;
export default mod;
export const runClaudeInChromeMcpServer: () => Promise<void>;
}
declare module "@ant/computer-use-input" {
const mod: any;
export default mod;
}
declare module "@ant/computer-use-mcp" {
const mod: any;
export default mod;
export const runComputerUseMcpServer: () => Promise<void>;
}
declare module "@ant/computer-use-swift" {
const mod: any;
export default mod;
}
declare module "@anthropic-ai/claude-agent-sdk" {
const mod: any;
export default mod;
}
declare module "@anthropic-ai/mcpb" {
const mod: any;
export default mod;
}
declare module "@anthropic-ai/sandbox-runtime" {
const mod: any;
export default mod;
}
declare module "color-diff-napi" {
export function diff(a: string, b: string): any;
const mod: any;
export default mod;
}

@ -0,0 +1,104 @@
{
"name": "@anthropic-ai/claude-code",
"version": "1.0.0-research",
"description": "Claude Code CLI - Source snapshot for research",
"type": "module",
"main": "src/entrypoints/cli.tsx",
"bin": {
"claude": "dist/cli.js"
},
"scripts": {
"build": "bun run scripts/build.ts",
"dev": "bun run src/entrypoints/cli.tsx",
"typecheck": "bun x tsc --noEmit"
},
"dependencies": {
"@alcalzone/ansi-tokenize": "^0.1.0",
"@anthropic-ai/bedrock-sdk": "^0.12.0",
"@anthropic-ai/sdk": "^0.39.0",
"@anthropic-ai/vertex-sdk": "^0.6.0",
"@aws-sdk/client-bedrock": "^3.750.0",
"@aws-sdk/client-bedrock-runtime": "^3.750.0",
"@aws-sdk/client-sts": "^3.750.0",
"@azure/identity": "^4.6.0",
"@commander-js/extra-typings": "^13.1.0",
"@growthbook/growthbook": "^1.4.0",
"@modelcontextprotocol/sdk": "^1.11.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.200.0",
"@opentelemetry/core": "^2.0.0",
"@opentelemetry/resources": "^2.0.0",
"@opentelemetry/sdk-logs": "^0.200.0",
"@opentelemetry/sdk-metrics": "^2.0.0",
"@opentelemetry/sdk-trace-base": "^2.0.0",
"@opentelemetry/semantic-conventions": "^1.28.0",
"ajv": "^8.17.0",
"asciichart": "^1.5.0",
"auto-bind": "^5.0.0",
"axios": "^1.7.0",
"bidi-js": "^1.0.0",
"chalk": "^5.4.0",
"chokidar": "^4.0.0",
"cli-boxes": "^3.0.0",
"code-excerpt": "^4.0.0",
"commander": "^13.1.0",
"diff": "^7.0.0",
"emoji-regex": "^10.4.0",
"env-paths": "^3.0.0",
"execa": "^9.5.0",
"fflate": "^0.8.0",
"figures": "^6.1.0",
"fuse.js": "^7.0.0",
"get-east-asian-width": "^1.3.0",
"google-auth-library": "^9.15.0",
"highlight.js": "^11.11.0",
"https-proxy-agent": "^7.0.0",
"ignore": "^7.0.0",
"indent-string": "^5.0.0",
"jsonc-parser": "^3.3.0",
"lodash-es": "^4.17.0",
"lru-cache": "^11.0.0",
"marked": "^15.0.0",
"p-map": "^7.0.0",
"picomatch": "^4.0.0",
"proper-lockfile": "^4.1.0",
"qrcode": "^1.5.0",
"react": "^19.0.0",
"react-reconciler": "0.33.0",
"semver": "^7.6.0",
"sharp": "^0.33.0",
"shell-quote": "^1.8.0",
"signal-exit": "^4.1.0",
"stack-utils": "^2.0.0",
"strip-ansi": "^7.1.0",
"supports-hyperlinks": "^3.1.0",
"tree-kill": "^1.2.0",
"turndown": "^7.2.0",
"type-fest": "^4.30.0",
"undici": "^7.3.0",
"usehooks-ts": "^3.1.0",
"vscode-jsonrpc": "^8.2.0",
"vscode-languageserver-protocol": "^3.17.0",
"vscode-languageserver-types": "^3.17.0",
"wrap-ansi": "^9.0.0",
"ws": "^8.18.0",
"xss": "^1.0.0",
"yaml": "^2.7.0",
"zod": "^3.25.0"
},
"devDependencies": {
"@types/bun": "^1.2.0",
"@types/diff": "^7.0.0",
"@types/lodash-es": "^4.17.0",
"@types/node": "^22.0.0",
"@types/proper-lockfile": "^4.1.0",
"@types/qrcode": "^1.5.0",
"@types/react": "^19.0.0",
"@types/react-reconciler": "^0.28.0",
"@types/semver": "^7.5.0",
"@types/shell-quote": "^1.7.0",
"@types/stack-utils": "^2.0.0",
"@types/ws": "^8.5.0",
"typescript": "^5.7.0"
}
}

@ -0,0 +1,477 @@
/**
* Build script for Claude Code using Bun's bundler API.
*
* Handles:
* - MACRO.* build-time constant injection
* - bun:bundle feature flag polyfill (all flags default to false)
* - src/ path alias resolution
* - Internal Anthropic package stubs
*
* Usage: bun run scripts/build.ts
*/
import { type BunPlugin } from "bun";
import { existsSync, mkdirSync } from "fs";
import { dirname, join, relative } from "path";
const PROJECT_ROOT = join(import.meta.dir, "..");
const OUT_DIR = join(PROJECT_ROOT, "dist");
// Ensure output directory exists
mkdirSync(OUT_DIR, { recursive: true });
// Build-time MACRO values
const VERSION = process.env.CLAUDE_CODE_VERSION || "1.0.0-research";
const BUILD_TIME = new Date().toISOString();
const PACKAGE_URL = "@anthropic-ai/claude-code";
const FEEDBACK_CHANNEL = "https://github.com/anthropics/claude-code/issues";
const ISSUES_EXPLAINER =
"report issues at https://github.com/anthropics/claude-code/issues";
const VERSION_CHANGELOG = "";
// Feature flags — all disabled by default for external builds
const FEATURE_FLAGS: Record<string, boolean> = {
PROACTIVE: false,
KAIROS: false,
BRIDGE_MODE: false,
DAEMON: false,
VOICE_MODE: false,
AGENT_TRIGGERS: false,
MONITOR_TOOL: false,
COORDINATOR_MODE: false,
ABLATION_BASELINE: false,
DUMP_SYSTEM_PROMPT: false,
CHICAGO_MCP: false,
};
/**
* Plugin to handle `bun:bundle` imports.
* The `feature()` function returns false for all flags in external builds.
*/
const bunBundlePlugin: BunPlugin = {
name: "bun-bundle-polyfill",
setup(build) {
build.onResolve({ filter: /^bun:bundle$/ }, (args) => {
return {
path: "bun:bundle",
namespace: "bun-bundle-polyfill",
};
});
build.onLoad(
{ filter: /.*/, namespace: "bun-bundle-polyfill" },
(args) => {
const featureFnBody = Object.entries(FEATURE_FLAGS)
.map(([k, v]) => ` if (name === ${JSON.stringify(k)}) return ${v};`)
.join("\n");
return {
contents: `
export function feature(name) {
${featureFnBody}
return false;
}
`,
loader: "js",
};
}
);
},
};
/**
* Plugin to provide inline stubs for internal Anthropic packages.
* Each package gets properly named exports to satisfy static analysis.
*/
const internalPackageStubPlugin: BunPlugin = {
name: "internal-package-stubs",
setup(build) {
// Map of package names to their required value exports
const packageExports: Record<string, string[]> = {
"@ant/claude-for-chrome-mcp": [
"BROWSER_TOOLS[]",
"createClaudeForChromeMcpServer",
],
"@ant/computer-use-input": [],
"@ant/computer-use-mcp": [
"API_RESIZE_PARAMS{}",
"DEFAULT_GRANT_FLAGS{}",
"bindSessionContext",
"buildComputerUseTools",
"createComputerUseMcpServer",
"targetImageSize",
"getSentinelCategory",
],
"@ant/computer-use-mcp/sentinelApps": ["getSentinelCategory"],
"@ant/computer-use-mcp/types": [
"DEFAULT_GRANT_FLAGS{}",
"getSentinelCategory",
],
"@ant/computer-use-swift": [],
"@anthropic-ai/claude-agent-sdk": [],
"@anthropic-ai/mcpb": [],
"@anthropic-ai/sandbox-runtime": [
"SandboxManager",
"SandboxRuntimeConfigSchema",
"SandboxViolationStore",
],
"@anthropic-ai/foundry-sdk": [],
"color-diff-napi": ["ColorDiff", "ColorFile", "getSyntaxTheme"],
"modifiers-napi": ["isModifierPressed"],
};
// Match any package in our map (including subpaths like @ant/computer-use-mcp/types)
build.onResolve(
{ filter: /^(@ant\/|@anthropic-ai\/(sandbox-runtime|claude-agent-sdk|mcpb|foundry-sdk)|color-diff-napi|modifiers-napi)/ },
(args) => ({
path: args.path,
namespace: "internal-stub",
})
);
build.onLoad(
{ filter: /.*/, namespace: "internal-stub" },
(args) => {
// Find the best matching exports for this path
const exports = packageExports[args.path] || [];
const exportLines = exports
.map((name) => {
// Array exports (name[])
if (name.endsWith("[]")) {
const cleanName = name.slice(0, -2);
return `export const ${cleanName} = [];`;
}
// Object exports (name{})
if (name.endsWith("{}")) {
const cleanName = name.slice(0, -2);
return `export const ${cleanName} = {};`;
}
// ColorDiff/ColorFile need render() method
if (name === "ColorDiff" || name === "ColorFile") {
return `export class ${name} { constructor(...a){} render(...a){ return null; } static create(...a){ return new ${name}(); } }`;
}
if (
name === "SandboxManager" ||
name === "SandboxViolationStore"
) {
return `export class ${name} {
constructor(...a){}
static create(...a){ return new ${name}(); }
static isSupportedPlatform(){ return false; }
static checkDependencies(...a){ return { satisfied: false, missing: [] }; }
static wrapWithSandbox(...a){ return a[0]; }
static initialize(...a){ return Promise.resolve(); }
static updateConfig(...a){}
static reset(){ return Promise.resolve(); }
static getFsReadConfig(){ return {}; }
static getFsWriteConfig(){ return {}; }
static getNetworkRestrictionConfig(){ return {}; }
static getIgnoreViolations(){ return {}; }
static getAllowUnixSockets(){ return false; }
static getAllowLocalBinding(){ return false; }
static getEnableWeakerNestedSandbox(){ return false; }
static getProxyPort(){ return 0; }
static getSocksProxyPort(){ return 0; }
static getLinuxHttpSocketPath(){ return ''; }
static getLinuxSocksSocketPath(){ return ''; }
static waitForNetworkInitialization(){ return Promise.resolve(); }
static getSandboxViolationStore(){ return new ${name === 'SandboxManager' ? 'SandboxViolationStore' : name}(); }
static annotateStderrWithSandboxFailures(...a){ return a[0]; }
static cleanupAfterCommand(){ return Promise.resolve(); }
dispose(){}
}`;
}
if (name === "SandboxRuntimeConfigSchema") {
return `export const ${name} = { parse: (...a) => ({}), safeParse: (...a) => ({ success: true, data: {} }) };`;
}
if (
name.startsWith("create") ||
name.startsWith("build") ||
name.startsWith("bind") ||
name.startsWith("get") ||
name === "targetImageSize"
) {
return `export function ${name}(...args) { return {}; }`;
}
// Default: export as empty object/array
if (name.endsWith("[]")) {
const cleanName = name.slice(0, -2);
return `export const ${cleanName} = [];`;
}
return `export const ${name} = {};`;
})
.join("\n");
return {
contents: `// Stub: ${args.path}\nexport default {};\n${exportLines}\n`,
loader: "js",
};
}
);
},
};
/**
* Plugin to auto-stub missing source files at build time.
* When the bundler encounters an import to a file that doesn't exist on disk,
* this plugin provides a stub implementation instead of failing the build.
* This eliminates the need for physical stub files in the source tree.
*/
const missingSourceStubPlugin: BunPlugin = {
name: "missing-source-stubs",
setup(build) {
// 需要特定 named exports 的缺失模块(key: 相对路径,不含扩展名)
const specificStubs: Record<string, string> = {
"src/types/connectorText": [
"export default {};",
"export function isConnectorTextBlock(block) { return block?.type === 'connector_text'; }",
].join("\n"),
"src/utils/protectedNamespace": [
"export default {};",
"export const PROTECTED_NAMESPACE_PREFIXES = [];",
"export function isProtectedNamespace(_name) { return false; }",
].join("\n"),
"src/tools/WorkflowTool/constants": [
"export default {};",
"export const WORKFLOW_TOOL_NAME = 'workflow';",
].join("\n"),
"src/utils/filePersistence/types": [
"export default {};",
"export const DEFAULT_UPLOAD_CONCURRENCY = 5;",
"export const FILE_COUNT_LIMIT = 1000;",
"export const OUTPUTS_SUBDIR = 'outputs';",
].join("\n"),
"src/tools/REPLTool/REPLTool": [
"export default {};",
"export const REPLTool = { name: 'repl', description: 'REPL tool (stub)' };",
].join("\n"),
"src/tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool": [
"export default {};",
"export const SuggestBackgroundPRTool = { name: 'suggest_background_pr', description: 'stub' };",
].join("\n"),
"src/tools/TungstenTool/TungstenLiveMonitor": [
"export default {};",
"export const TungstenLiveMonitor = {};",
].join("\n"),
"src/tools/TungstenTool/TungstenTool": [
"export default {};",
"export const TungstenTool = { name: 'tungsten', description: 'Tungsten tool (stub)' };",
].join("\n"),
"src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool": [
"export default {};",
"export const VerifyPlanExecutionTool = { name: 'verify_plan_execution', description: 'stub' };",
].join("\n"),
"src/assistant/AssistantSessionChooser": [
"export default {};",
"export const AssistantSessionChooser = () => null;",
].join("\n"),
"src/components/agents/SnapshotUpdateDialog": [
"export default {};",
"export const SnapshotUpdateDialog = () => null;",
].join("\n"),
"src/commands/assistant/assistant": [
"export default {};",
"export const NewInstallWizard = () => null;",
"export function computeDefaultInstallDir() { return ''; }",
].join("\n"),
"src/services/remoteManagedSettings/securityCheck": [
"export default {};",
"export function checkManagedSettingsSecurity() { return { ok: true }; }",
"export function handleSecurityCheckResult() {}",
].join("\n"),
};
build.onResolve({ filter: /\.(?:ts|tsx|js|jsx|md|txt)$/ }, (args) => {
if (args.namespace !== "file") return;
let basePath: string;
if (args.path.startsWith("src/")) {
basePath = join(PROJECT_ROOT, args.path);
} else if (args.path.startsWith(".") || args.path.startsWith("/")) {
if (!args.importer) return;
basePath = join(dirname(args.importer), args.path);
} else {
return;
}
// 对 .js/.jsx 导入尝试 .ts/.tsx 变体
const candidates = [basePath];
if (basePath.endsWith(".js")) {
const base = basePath.slice(0, -3);
candidates.push(base + ".ts", base + ".tsx", base + ".d.ts");
} else if (basePath.endsWith(".jsx")) {
const base = basePath.slice(0, -4);
candidates.push(base + ".tsx", base + ".ts");
}
for (const c of candidates) {
if (existsSync(c)) return;
}
// 文件不存在 → 重定向到 stub 命名空间
let stubKey = relative(PROJECT_ROOT, basePath).replace(/\\/g, "/");
if (stubKey.endsWith(".js") || stubKey.endsWith(".jsx")) {
stubKey = stubKey.replace(/\.jsx?$/, "");
}
return { path: stubKey, namespace: "missing-source" };
});
build.onLoad({ filter: /.*/, namespace: "missing-source" }, (args) => {
const key = args.path;
if (key.endsWith(".md") || key.endsWith(".txt")) {
return { contents: `export default '';`, loader: "js" };
}
if (key.endsWith(".d.ts")) {
return { contents: `export {};`, loader: "js" };
}
const stubContent = specificStubs[key];
if (stubContent !== undefined) {
return { contents: stubContent, loader: "js" };
}
console.log(` Auto-stubbing missing module: ${key}`);
return { contents: `export default {};`, loader: "js" };
});
},
};
console.log("🔨 Building Claude Code...");
console.log(` Version: ${VERSION}`);
console.log(` Build time: ${BUILD_TIME}`);
console.log(` Output: ${OUT_DIR}`);
console.log(` Feature flags: all disabled (external build)`);
console.log("");
const result = await Bun.build({
entrypoints: [join(PROJECT_ROOT, "src/entrypoints/cli.tsx")],
outdir: OUT_DIR,
target: "bun",
format: "esm",
splitting: false,
sourcemap: "external",
minify: false,
plugins: [bunBundlePlugin, internalPackageStubPlugin, missingSourceStubPlugin],
define: {
"MACRO.VERSION": JSON.stringify(VERSION),
"MACRO.BUILD_TIME": JSON.stringify(BUILD_TIME),
"MACRO.PACKAGE_URL": JSON.stringify(PACKAGE_URL),
"MACRO.NATIVE_PACKAGE_URL": "undefined",
"MACRO.FEEDBACK_CHANNEL": JSON.stringify(FEEDBACK_CHANNEL),
"MACRO.ISSUES_EXPLAINER": JSON.stringify(ISSUES_EXPLAINER),
"MACRO.VERSION_CHANGELOG": JSON.stringify(VERSION_CHANGELOG),
},
external: [
// Node.js built-ins
"node:*",
"fs",
"fs/promises",
"path",
"crypto",
"os",
"util",
"url",
"http",
"https",
"net",
"tls",
"dns",
"stream",
"events",
"buffer",
"child_process",
"process",
"readline",
"tty",
"v8",
"zlib",
"async_hooks",
"perf_hooks",
// Keep all npm deps external (not bundled)
"@alcalzone/ansi-tokenize",
"@anthropic-ai/sdk",
"@aws-sdk/client-bedrock-runtime",
"@commander-js/extra-typings",
"@growthbook/growthbook",
"@modelcontextprotocol/sdk",
"@opentelemetry/*",
"ajv",
"asciichart",
"auto-bind",
"axios",
"bidi-js",
"chalk",
"chokidar",
"cli-boxes",
"code-excerpt",
"diff",
"emoji-regex",
"env-paths",
"execa",
"figures",
"fuse.js",
"get-east-asian-width",
"google-auth-library",
"highlight.js",
"https-proxy-agent",
"ignore",
"indent-string",
"jsonc-parser",
"lodash-es",
"lru-cache",
"marked",
"p-map",
"picomatch",
"proper-lockfile",
"qrcode",
"react",
"react-reconciler",
"semver",
"shell-quote",
"signal-exit",
"stack-utils",
"strip-ansi",
"supports-hyperlinks",
"tree-kill",
"type-fest",
"undici",
"usehooks-ts",
"vscode-jsonrpc",
"vscode-languageserver-protocol",
"vscode-languageserver-types",
"wrap-ansi",
"ws",
"xss",
"zod",
"@anthropic-ai/bedrock-sdk",
"@anthropic-ai/vertex-sdk",
"@anthropic-ai/foundry-sdk",
"@azure/identity",
"@aws-sdk/client-bedrock",
"@aws-sdk/client-sts",
"fflate",
"yaml",
"sharp",
"modifiers-napi",
"turndown",
],
});
if (!result.success) {
console.error("❌ Build failed!");
for (const log of result.logs) {
console.error(` ${log.message}`);
}
process.exit(1);
} else {
console.log(`✅ Build succeeded!`);
console.log(` Output files:`);
for (const output of result.outputs) {
const sizeKB = (output.size / 1024).toFixed(1);
console.log(` ${output.path} (${sizeKB} KB)`);
}
}

@ -973,7 +973,7 @@ async function run(): Promise<CommanderCommand> {
// If not provided but flag is present, value will be true
// The actual filtering is handled in debug.ts by parsing process.argv
return true;
}).addOption(new Option('-d2e, --debug-to-stderr', 'Enable debug mode (to stderr)').argParser(Boolean).hideHelp()).option('--debug-file <path>', 'Write debug logs to a specific file path (implicitly enables debug mode)', () => true).option('--verbose', 'Override verbose mode setting from config', () => true).option('-p, --print', 'Print response and exit (useful for pipes). Note: The workspace trust dialog is skipped when Claude is run with the -p mode. Only use this flag in directories you trust.', () => true).option('--bare', 'Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1. Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings (OAuth and keychain are never read). 3P providers (Bedrock/Vertex/Foundry) use their own credentials. Skills still resolve via /skill-name. Explicitly provide context via: --system-prompt[-file], --append-system-prompt[-file], --add-dir (CLAUDE.md dirs), --mcp-config, --settings, --agents, --plugin-dir.', () => true).addOption(new Option('--init', 'Run Setup hooks with init trigger, then continue').hideHelp()).addOption(new Option('--init-only', 'Run Setup and SessionStart:startup hooks, then exit').hideHelp()).addOption(new Option('--maintenance', 'Run Setup hooks with maintenance trigger, then continue').hideHelp()).addOption(new Option('--output-format <format>', 'Output format (only works with --print): "text" (default), "json" (single result), or "stream-json" (realtime streaming)').choices(['text', 'json', 'stream-json'])).addOption(new Option('--json-schema <schema>', 'JSON Schema for structured output validation. ' + 'Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}').argParser(String)).option('--include-hook-events', 'Include all hook lifecycle events in the output stream (only works with --output-format=stream-json)', () => true).option('--include-partial-messages', 'Include partial message chunks as they arrive (only works with --print and --output-format=stream-json)', () => true).addOption(new Option('--input-format <format>', 'Input format (only works with --print): "text" (default), or "stream-json" (realtime streaming input)').choices(['text', 'stream-json'])).option('--mcp-debug', '[DEPRECATED. Use --debug instead] Enable MCP debug mode (shows MCP server errors)', () => true).option('--dangerously-skip-permissions', 'Bypass all permission checks. Recommended only for sandboxes with no internet access.', () => true).option('--allow-dangerously-skip-permissions', 'Enable bypassing all permission checks as an option, without it being enabled by default. Recommended only for sandboxes with no internet access.', () => true).addOption(new Option('--thinking <mode>', 'Thinking mode: enabled (equivalent to adaptive), disabled').choices(['enabled', 'adaptive', 'disabled']).hideHelp()).addOption(new Option('--max-thinking-tokens <tokens>', '[DEPRECATED. Use --thinking instead for newer models] Maximum number of thinking tokens (only works with --print)').argParser(Number).hideHelp()).addOption(new Option('--max-turns <turns>', 'Maximum number of agentic turns in non-interactive mode. This will early exit the conversation after the specified number of turns. (only works with --print)').argParser(Number).hideHelp()).addOption(new Option('--max-budget-usd <amount>', 'Maximum dollar amount to spend on API calls (only works with --print)').argParser(value => {
}).addOption(new Option('--debug-to-stderr', 'Enable debug mode (to stderr)').argParser(Boolean).hideHelp()).option('--debug-file <path>', 'Write debug logs to a specific file path (implicitly enables debug mode)', () => true).option('--verbose', 'Override verbose mode setting from config', () => true).option('-p, --print', 'Print response and exit (useful for pipes). Note: The workspace trust dialog is skipped when Claude is run with the -p mode. Only use this flag in directories you trust.', () => true).option('--bare', 'Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1. Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings (OAuth and keychain are never read). 3P providers (Bedrock/Vertex/Foundry) use their own credentials. Skills still resolve via /skill-name. Explicitly provide context via: --system-prompt[-file], --append-system-prompt[-file], --add-dir (CLAUDE.md dirs), --mcp-config, --settings, --agents, --plugin-dir.', () => true).addOption(new Option('--init', 'Run Setup hooks with init trigger, then continue').hideHelp()).addOption(new Option('--init-only', 'Run Setup and SessionStart:startup hooks, then exit').hideHelp()).addOption(new Option('--maintenance', 'Run Setup hooks with maintenance trigger, then continue').hideHelp()).addOption(new Option('--output-format <format>', 'Output format (only works with --print): "text" (default), "json" (single result), or "stream-json" (realtime streaming)').choices(['text', 'json', 'stream-json'])).addOption(new Option('--json-schema <schema>', 'JSON Schema for structured output validation. ' + 'Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}').argParser(String)).option('--include-hook-events', 'Include all hook lifecycle events in the output stream (only works with --output-format=stream-json)', () => true).option('--include-partial-messages', 'Include partial message chunks as they arrive (only works with --print and --output-format=stream-json)', () => true).addOption(new Option('--input-format <format>', 'Input format (only works with --print): "text" (default), or "stream-json" (realtime streaming input)').choices(['text', 'stream-json'])).option('--mcp-debug', '[DEPRECATED. Use --debug instead] Enable MCP debug mode (shows MCP server errors)', () => true).option('--dangerously-skip-permissions', 'Bypass all permission checks. Recommended only for sandboxes with no internet access.', () => true).option('--allow-dangerously-skip-permissions', 'Enable bypassing all permission checks as an option, without it being enabled by default. Recommended only for sandboxes with no internet access.', () => true).addOption(new Option('--thinking <mode>', 'Thinking mode: enabled (equivalent to adaptive), disabled').choices(['enabled', 'adaptive', 'disabled']).hideHelp()).addOption(new Option('--max-thinking-tokens <tokens>', '[DEPRECATED. Use --thinking instead for newer models] Maximum number of thinking tokens (only works with --print)').argParser(Number).hideHelp()).addOption(new Option('--max-turns <turns>', 'Maximum number of agentic turns in non-interactive mode. This will early exit the conversation after the specified number of turns. (only works with --print)').argParser(Number).hideHelp()).addOption(new Option('--max-budget-usd <amount>', 'Maximum dollar amount to spend on API calls (only works with --print)').argParser(value => {
const amount = Number(value);
if (isNaN(amount) || amount <= 0) {
throw new Error('--max-budget-usd must be a positive number greater than 0');

@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"lib": ["ESNext"],
"types": ["bun-types", "node"],
"paths": {
"src/*": ["./src/*"]
},
"baseUrl": ".",
"rootDir": "."
},
"include": ["src/**/*.ts", "src/**/*.tsx", "scripts/**/*.ts", "globals.d.ts"],
"exclude": ["node_modules", "dist"]
}
Loading…
Cancel
Save