Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 503a40f46b | |||
| a889ed8402 | |||
| 64f79dc3be | |||
| c5b55c1bf9 | |||
| 2934f30084 | |||
| 33fe4940e1 | |||
| 2fa91489c8 | |||
| 4233ee7de6 | |||
| 03cff1b749 | |||
| ecf885d67f | |||
| 9a57642d3a | |||
| 604110272f | |||
| b32dd4549d | |||
| 0135ad99ad | |||
| 9018c7afdb | |||
| 65d7f1994c | |||
| ce2f19cc48 | |||
| f6fe94463e | |||
| c57f5a29e8 | |||
| 8f6800f508 | |||
| 722d59b6d5 | |||
| b51b2d7675 | |||
| 975b4876cc | |||
| 30e863c9b8 | |||
| c6491372d0 | |||
| 04c8ef2ecc | |||
| b759df5b0e | |||
| 173d18bea8 | |||
| c587a64320 | |||
| 17ec716dbf | |||
| e443a8fa51 | |||
| 9dd1eeff2f | |||
| dc2fdc7cc7 | |||
| 1d15e30f3c | |||
| 4319afc08f | |||
| 074ea844dc | |||
| 4692c3e2ef | |||
| b1c6249f03 | |||
| 2de3d309b4 | |||
| f10d179ace | |||
| 7e15974be9 | |||
| fac9341e73 | |||
| 58f1bd49cb | |||
| 91f77ea571 | |||
| dd9cd782a7 | |||
| d7a729ca68 | |||
| 4c0a655a1c | |||
| 2c759fe6fa |
@@ -0,0 +1,16 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{json,yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# pre-commit hook: 对暂存的文件运行 Biome 检查
|
||||||
|
# 仅检查 src/ 下的 .ts/.tsx/.js/.jsx 文件
|
||||||
|
|
||||||
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '^src/.*\.(ts|tsx|js|jsx)$')
|
||||||
|
|
||||||
|
if [ -z "$STAGED_FILES" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running Biome lint on staged files..."
|
||||||
|
|
||||||
|
# 使用 biome lint 对暂存文件进行检查(仅 lint,不格式化,不自动修复)
|
||||||
|
echo "$STAGED_FILES" | xargs bunx biome lint --no-errors-on-unmatched
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Biome lint failed. Fix errors or use --no-verify to bypass."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, feature/*]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: bun run lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: bun test
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: bun run build
|
||||||
@@ -7,3 +7,4 @@ coverage
|
|||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
*.suo
|
*.suo
|
||||||
|
*.lock
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a **reverse-engineered / decompiled** version of Anthropic's official Claude Code CLI tool. The goal is to restore core functionality while trimming secondary capabilities. Many modules are stubbed or feature-flagged off. The codebase has ~1341 tsc errors from decompilation (mostly `unknown`/`never`/`{}` types) — these do **not** block Bun runtime execution.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
bun install
|
||||||
|
|
||||||
|
# Dev mode (direct execution via Bun)
|
||||||
|
bun run dev
|
||||||
|
# equivalent to: bun run src/entrypoints/cli.tsx
|
||||||
|
|
||||||
|
# Pipe mode
|
||||||
|
echo "say hello" | bun run src/entrypoints/cli.tsx -p
|
||||||
|
|
||||||
|
# Build (outputs dist/cli.js, ~25MB)
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
No test runner is configured. No linter is configured.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Runtime & Build
|
||||||
|
|
||||||
|
- **Runtime**: Bun (not Node.js). All imports, builds, and execution use Bun APIs.
|
||||||
|
- **Build**: `bun build src/entrypoints/cli.tsx --outdir dist --target bun` — single-file bundle.
|
||||||
|
- **Module system**: ESM (`"type": "module"`), TSX with `react-jsx` transform.
|
||||||
|
- **Monorepo**: Bun workspaces — internal packages live in `packages/` resolved via `workspace:*`.
|
||||||
|
|
||||||
|
### Entry & Bootstrap
|
||||||
|
|
||||||
|
1. **`src/entrypoints/cli.tsx`** — True entrypoint. Injects runtime polyfills at the top:
|
||||||
|
- `feature()` always returns `false` (all feature flags disabled, skipping unimplemented branches).
|
||||||
|
- `globalThis.MACRO` — simulates build-time macro injection (VERSION, BUILD_TIME, etc.).
|
||||||
|
- `BUILD_TARGET`, `BUILD_ENV`, `INTERFACE_TYPE` globals.
|
||||||
|
2. **`src/main.tsx`** — Commander.js CLI definition. Parses args, initializes services (auth, analytics, policy), then launches the REPL or runs in pipe mode.
|
||||||
|
3. **`src/entrypoints/init.ts`** — One-time initialization (telemetry, config, trust dialog).
|
||||||
|
|
||||||
|
### Core Loop
|
||||||
|
|
||||||
|
- **`src/query.ts`** — The main API query function. Sends messages to Claude API, handles streaming responses, processes tool calls, and manages the conversation turn loop.
|
||||||
|
- **`src/QueryEngine.ts`** — Higher-level orchestrator wrapping `query()`. Manages conversation state, compaction, file history snapshots, attribution, and turn-level bookkeeping. Used by the REPL screen.
|
||||||
|
- **`src/screens/REPL.tsx`** — The interactive REPL screen (React/Ink component). Handles user input, message display, tool permission prompts, and keyboard shortcuts.
|
||||||
|
|
||||||
|
### API Layer
|
||||||
|
|
||||||
|
- **`src/services/api/claude.ts`** — Core API client. Builds request params (system prompt, messages, tools, betas), calls the Anthropic SDK streaming endpoint, and processes `BetaRawMessageStreamEvent` events.
|
||||||
|
- Supports multiple providers: Anthropic direct, AWS Bedrock, Google Vertex, Azure.
|
||||||
|
- Provider selection in `src/utils/model/providers.ts`.
|
||||||
|
|
||||||
|
### Tool System
|
||||||
|
|
||||||
|
- **`src/Tool.ts`** — Tool interface definition (`Tool` type) and utilities (`findToolByName`, `toolMatchesName`).
|
||||||
|
- **`src/tools.ts`** — Tool registry. Assembles the tool list; some tools are conditionally loaded via `feature()` flags or `process.env.USER_TYPE`.
|
||||||
|
- **`src/tools/<ToolName>/`** — Each tool in its own directory (e.g., `BashTool`, `FileEditTool`, `GrepTool`, `AgentTool`).
|
||||||
|
- Tools define: `name`, `description`, `inputSchema` (JSON Schema), `call()` (execution), and optionally a React component for rendering results.
|
||||||
|
|
||||||
|
### UI Layer (Ink)
|
||||||
|
|
||||||
|
- **`src/ink.ts`** — Ink render wrapper with ThemeProvider injection.
|
||||||
|
- **`src/ink/`** — Custom Ink framework (forked/internal): custom reconciler, hooks (`useInput`, `useTerminalSize`, `useSearchHighlight`), virtual list rendering.
|
||||||
|
- **`src/components/`** — React components rendered in terminal via Ink. Key ones:
|
||||||
|
- `App.tsx` — Root provider (AppState, Stats, FpsMetrics).
|
||||||
|
- `Messages.tsx` / `MessageRow.tsx` — Conversation message rendering.
|
||||||
|
- `PromptInput/` — User input handling.
|
||||||
|
- `permissions/` — Tool permission approval UI.
|
||||||
|
- Components use React Compiler runtime (`react/compiler-runtime`) — decompiled output has `_c()` memoization calls throughout.
|
||||||
|
|
||||||
|
### State Management
|
||||||
|
|
||||||
|
- **`src/state/AppState.tsx`** — Central app state type and context provider. Contains messages, tools, permissions, MCP connections, etc.
|
||||||
|
- **`src/state/store.ts`** — Zustand-style store for AppState.
|
||||||
|
- **`src/bootstrap/state.ts`** — Module-level singletons for session-global state (session ID, CWD, project root, token counts).
|
||||||
|
|
||||||
|
### Context & System Prompt
|
||||||
|
|
||||||
|
- **`src/context.ts`** — Builds system/user context for the API call (git status, date, CLAUDE.md contents, memory files).
|
||||||
|
- **`src/utils/claudemd.ts`** — Discovers and loads CLAUDE.md files from project hierarchy.
|
||||||
|
|
||||||
|
### Feature Flag System
|
||||||
|
|
||||||
|
All `feature('FLAG_NAME')` calls come from `bun:bundle` (a build-time API). In this decompiled version, `feature()` is polyfilled to always return `false` in `cli.tsx`. This means all Anthropic-internal features (COORDINATOR_MODE, KAIROS, PROACTIVE, etc.) are disabled.
|
||||||
|
|
||||||
|
### Stubbed/Deleted Modules
|
||||||
|
|
||||||
|
| Module | Status |
|
||||||
|
|--------|--------|
|
||||||
|
| Computer Use (`@ant/*`) | Stub packages in `packages/@ant/` |
|
||||||
|
| `*-napi` packages (audio, image, url, modifiers) | Stubs in `packages/` (except `color-diff-napi` which is fully implemented) |
|
||||||
|
| Analytics / GrowthBook / Sentry | Empty implementations |
|
||||||
|
| Magic Docs / Voice Mode / LSP Server | Removed |
|
||||||
|
| Plugins / Marketplace | Removed |
|
||||||
|
| MCP OAuth | Simplified |
|
||||||
|
|
||||||
|
### Key Type Files
|
||||||
|
|
||||||
|
- **`src/types/global.d.ts`** — Declares `MACRO`, `BUILD_TARGET`, `BUILD_ENV` and internal Anthropic-only identifiers.
|
||||||
|
- **`src/types/internal-modules.d.ts`** — Type declarations for `bun:bundle`, `bun:ffi`, `@anthropic-ai/mcpb`.
|
||||||
|
- **`src/types/message.ts`** — Message type hierarchy (UserMessage, AssistantMessage, SystemMessage, etc.).
|
||||||
|
- **`src/types/permissions.ts`** — Permission mode and result types.
|
||||||
|
|
||||||
|
## Working with This Codebase
|
||||||
|
|
||||||
|
- **Don't try to fix all tsc errors** — they're from decompilation and don't affect runtime.
|
||||||
|
- **`feature()` is always `false`** — any code behind a feature flag is dead code in this build.
|
||||||
|
- **React Compiler output** — Components have decompiled memoization boilerplate (`const $ = _c(N)`). This is normal.
|
||||||
|
- **`bun:bundle` import** — In `src/main.tsx` and other files, `import { feature } from 'bun:bundle'` works at build time. At dev-time, the polyfill in `cli.tsx` provides it.
|
||||||
|
- **`src/` path alias** — tsconfig maps `src/*` to `./src/*`. Imports like `import { ... } from 'src/utils/...'` are valid.
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
# Claude Code 项目运行记录
|
|
||||||
|
|
||||||
> 项目: `/Users/konghayao/code/ai/claude-code`
|
|
||||||
> 日期: 2026-03-31
|
|
||||||
> 包管理器: bun
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 一、项目目标
|
|
||||||
|
|
||||||
**将 claude-code 项目运行起来,必要时可以删减次级能力。**
|
|
||||||
|
|
||||||
这是 Anthropic 官方 Claude Code CLI 工具的源码反编译/逆向还原项目。
|
|
||||||
|
|
||||||
### 核心保留能力
|
|
||||||
|
|
||||||
- API 通信(Anthropic SDK / Bedrock / Vertex)
|
|
||||||
- Bash/FileRead/FileWrite/FileEdit 等核心工具
|
|
||||||
- REPL 交互界面(ink 终端渲染)
|
|
||||||
- 对话历史与会话管理
|
|
||||||
- 权限系统(基础)
|
|
||||||
- Agent/子代理系统
|
|
||||||
|
|
||||||
### 已删减的次级能力
|
|
||||||
|
|
||||||
| 模块 | 处理方式 |
|
|
||||||
|------|----------|
|
|
||||||
| Computer Use (`@ant/computer-use-*`) | stub |
|
|
||||||
| Claude for Chrome (`@ant/claude-for-chrome-mcp`) | stub |
|
|
||||||
| Magic Docs / Voice Mode / LSP Server | 移除 |
|
|
||||||
| Analytics / GrowthBook / Sentry | 空实现 |
|
|
||||||
| Plugins/Marketplace / Desktop Upsell | 移除 |
|
|
||||||
| Ultraplan / Tungsten / Auto Dream | 移除 |
|
|
||||||
| MCP OAuth/IDP | 简化 |
|
|
||||||
| DAEMON / BRIDGE / BG_SESSIONS / TEMPLATES 等 | feature flag 关闭 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 二、当前状态:Dev 模式已可运行
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# dev 运行
|
|
||||||
bun run dev
|
|
||||||
# 直接运行
|
|
||||||
bun run src/entrypoints/cli.tsx
|
|
||||||
# 测试 -p 模式
|
|
||||||
echo "say hello" | bun run src/entrypoints/cli.tsx -p
|
|
||||||
# 构建
|
|
||||||
bun run build
|
|
||||||
```
|
|
||||||
|
|
||||||
| 测试 | 结果 |
|
|
||||||
|------|------|
|
|
||||||
| `--version` | `2.1.87 (Claude Code)` |
|
|
||||||
| `--help` | 完整帮助信息输出 |
|
|
||||||
| `-p` 模式 | 成功调用 API 返回响应 |
|
|
||||||
|
|
||||||
### TS 类型错误说明
|
|
||||||
|
|
||||||
仍有 ~1341 个 tsc 错误,绝大多数是反编译产生的源码级类型问题(unknown/never/{}),**不影响 Bun 运行时**。不再逐个修复。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 三、关键修复记录
|
|
||||||
|
|
||||||
### 3.1 自动化 stub 生成
|
|
||||||
|
|
||||||
通过 3 个脚本自动处理了缺失模块问题:
|
|
||||||
- `scripts/create-type-stubs.mjs` — 生成 1206 个 stub 文件
|
|
||||||
- `scripts/fix-default-stubs.mjs` — 修复 120 个默认导出 stub
|
|
||||||
- `scripts/fix-missing-exports.mjs` — 补全 81 个模块的 161 个缺失导出
|
|
||||||
|
|
||||||
### 3.2 手动类型修复
|
|
||||||
|
|
||||||
- `src/types/global.d.ts` — MACRO 宏、内部函数声明
|
|
||||||
- `src/types/internal-modules.d.ts` — `@ant/*` 等私有包类型声明
|
|
||||||
- `src/entrypoints/sdk/` — 6 个 SDK 子模块 stub
|
|
||||||
- 泛型类型修复(DeepImmutable、AttachmentMessage 等)
|
|
||||||
- 4 个 `export const default` 非法语法修复
|
|
||||||
|
|
||||||
### 3.3 运行时修复
|
|
||||||
|
|
||||||
**Commander 非法短标志**:`-d2e, --debug-to-stderr` → `--debug-to-stderr`(反编译错误)
|
|
||||||
|
|
||||||
**`bun:bundle` 运行时 Polyfill**(`src/entrypoints/cli.tsx` 顶部):
|
|
||||||
```typescript
|
|
||||||
const feature = (_name: string) => false; // 所有 feature flag 分支被跳过
|
|
||||||
(globalThis as any).MACRO = { VERSION: "2.1.87", ... }; // 绕过版本检查
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 四、关键文件清单
|
|
||||||
|
|
||||||
| 文件 | 用途 |
|
|
||||||
|------|------|
|
|
||||||
| `src/entrypoints/cli.tsx` | 入口文件(含 MACRO/feature polyfill) |
|
|
||||||
| `src/main.tsx` | 主 CLI 逻辑(Commander 定义) |
|
|
||||||
| `src/types/global.d.ts` | 全局变量/宏声明 |
|
|
||||||
| `src/types/internal-modules.d.ts` | 内部 npm 包类型声明 |
|
|
||||||
| `src/entrypoints/sdk/*.ts` | SDK 类型 stub |
|
|
||||||
| `src/types/message.ts` | Message 系列类型 stub |
|
|
||||||
| `scripts/create-type-stubs.mjs` | 自动 stub 生成脚本 |
|
|
||||||
| `scripts/fix-default-stubs.mjs` | 修复默认导出 stub |
|
|
||||||
| `scripts/fix-missing-exports.mjs` | 补全缺失导出 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 五、Monorepo 改造(2026-03-31)
|
|
||||||
|
|
||||||
### 5.1 背景
|
|
||||||
|
|
||||||
`color-diff-napi` 原先是手工放在 `node_modules/` 下的 stub 文件,导出的是普通对象而非 class,导致 `new ColorDiff(...)` 报错:
|
|
||||||
```
|
|
||||||
ERROR Object is not a constructor (evaluating 'new ColorDiff(patch, firstLine, filePath, fileContent)')
|
|
||||||
```
|
|
||||||
同时 `@ant/*`、其他 `*-napi` 包也只有 `declare module` 类型声明,无运行时实现。
|
|
||||||
|
|
||||||
### 5.2 方案
|
|
||||||
|
|
||||||
将项目改造为 **Bun workspaces monorepo**,所有内部包统一放在 `packages/` 下,通过 `workspace:*` 依赖解析。
|
|
||||||
|
|
||||||
### 5.3 创建的 workspace 包
|
|
||||||
|
|
||||||
| 包名 | 路径 | 类型 |
|
|
||||||
|------|------|------|
|
|
||||||
| `color-diff-napi` | `packages/color-diff-napi/` | 完整实现(~1000行 TS,从 `src/native-ts/color-diff/` 移入) |
|
|
||||||
| `modifiers-napi` | `packages/modifiers-napi/` | stub(macOS 修饰键检测) |
|
|
||||||
| `audio-capture-napi` | `packages/audio-capture-napi/` | stub |
|
|
||||||
| `image-processor-napi` | `packages/image-processor-napi/` | stub |
|
|
||||||
| `url-handler-napi` | `packages/url-handler-napi/` | stub |
|
|
||||||
| `@ant/claude-for-chrome-mcp` | `packages/@ant/claude-for-chrome-mcp/` | stub |
|
|
||||||
| `@ant/computer-use-mcp` | `packages/@ant/computer-use-mcp/` | stub(含 subpath exports: sentinelApps, types) |
|
|
||||||
| `@ant/computer-use-input` | `packages/@ant/computer-use-input/` | stub |
|
|
||||||
| `@ant/computer-use-swift` | `packages/@ant/computer-use-swift/` | stub |
|
|
||||||
|
|
||||||
### 5.4 新增的 npm 依赖
|
|
||||||
|
|
||||||
| 包名 | 原因 |
|
|
||||||
|------|------|
|
|
||||||
| `@opentelemetry/semantic-conventions` | 构建报错缺失 |
|
|
||||||
| `fflate` | `src/utils/dxt/zip.ts` 动态 import |
|
|
||||||
| `vscode-jsonrpc` | `src/services/lsp/LSPClient.ts` import |
|
|
||||||
| `@aws-sdk/credential-provider-node` | `src/utils/proxy.ts` 动态 import |
|
|
||||||
|
|
||||||
### 5.5 关键变更
|
|
||||||
|
|
||||||
- `package.json`:添加 `workspaces`,添加所有 workspace 包和缺失 npm 依赖
|
|
||||||
- `src/types/internal-modules.d.ts`:删除已移入 monorepo 的 `declare module` 块,仅保留 `bun:bundle`、`bun:ffi`、`@anthropic-ai/mcpb`
|
|
||||||
- `src/native-ts/color-diff/` → `packages/color-diff-napi/src/`:移动并内联了对 `stringWidth` 和 `logError` 的依赖
|
|
||||||
- 删除 `node_modules/color-diff-napi/` 手工 stub
|
|
||||||
|
|
||||||
### 5.6 构建验证
|
|
||||||
|
|
||||||
```
|
|
||||||
$ bun run build
|
|
||||||
Bundled 5326 modules in 491ms
|
|
||||||
cli.js 25.74 MB (entry point)
|
|
||||||
```
|
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 5.1.x | :white_check_mark: |
|
||||||
|
| 5.0.x | :x: |
|
||||||
|
| 4.0.x | :white_check_mark: |
|
||||||
|
| < 4.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Use this section to tell people how to report a vulnerability.
|
||||||
|
|
||||||
|
Tell them where to go, how often they can expect to get an update on a
|
||||||
|
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||||
|
declined, etc.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
尽可能实现下面的包, 使得与主包的关系完全吻合
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
- [x] `url-handler-napi` — URL 处理 NAPI 模块 (签名修正,保持 null fallback)
|
||||||
|
- [x] `modifiers-napi` — 修饰键检测 NAPI 模块 (Bun FFI + Carbon)
|
||||||
|
- [x] `audio-capture-napi` — 音频捕获 NAPI 模块 (SoX/arecord)
|
||||||
|
- [x] `color-diff-napi` — 颜色差异计算 NAPI 模块 (纯 TS 实现)
|
||||||
|
- [x] `image-processor-napi` — 图像处理 NAPI 模块 (sharp + osascript 剪贴板)
|
||||||
|
|
||||||
|
- [x] `@ant/computer-use-swift` — Computer Use Swift 原生模块 (macOS JXA/screencapture 实现)
|
||||||
|
- [x] `@ant/computer-use-mcp` — Computer Use MCP 服务 (类型安全 stub + sentinel apps + targetImageSize)
|
||||||
|
- [x] `@ant/computer-use-input` — Computer Use 输入模块 (macOS AppleScript/JXA 实现)
|
||||||
|
<!-- - [ ] `@ant/claude-for-chrome-mcp` — Chrome MCP 扩展 -->
|
||||||
|
|
||||||
|
## 工程化能力
|
||||||
|
|
||||||
|
- [x] 代码格式化与校验
|
||||||
|
- [x] 冗余代码检查
|
||||||
|
- [x] git hook 的配置
|
||||||
|
- [x] 代码健康度检查
|
||||||
|
- [x] Biome lint 规则调优(适配反编译代码,关闭格式化避免大规模 diff)
|
||||||
|
- [x] 单元测试基础设施搭建 (test runner 配置)
|
||||||
|
- [x] CI/CD 流水线 (GitHub Actions)
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"includes": ["**", "!!**/dist", "!!**/packages/@ant"]
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineWidth": 80
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"suspicious": {
|
||||||
|
"noExplicitAny": "off",
|
||||||
|
"noAssignInExpressions": "off",
|
||||||
|
"noDoubleEquals": "off",
|
||||||
|
"noRedeclare": "off",
|
||||||
|
"noImplicitAnyLet": "off",
|
||||||
|
"noGlobalIsNan": "off",
|
||||||
|
"noFallthroughSwitchClause": "off",
|
||||||
|
"noShadowRestrictedNames": "off",
|
||||||
|
"noArrayIndexKey": "off",
|
||||||
|
"noConsole": "off",
|
||||||
|
"noConfusingLabels": "off",
|
||||||
|
"useIterableCallbackReturn": "off"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"useConst": "off",
|
||||||
|
"noNonNullAssertion": "off",
|
||||||
|
"noParameterAssign": "off",
|
||||||
|
"useDefaultParameterLast": "off",
|
||||||
|
"noUnusedTemplateLiteral": "off",
|
||||||
|
"useTemplate": "off",
|
||||||
|
"useNumberNamespace": "off",
|
||||||
|
"useNodejsImportProtocol": "off",
|
||||||
|
"useImportType": "off"
|
||||||
|
},
|
||||||
|
"complexity": {
|
||||||
|
"noForEach": "off",
|
||||||
|
"noBannedTypes": "off",
|
||||||
|
"noUselessConstructor": "off",
|
||||||
|
"noStaticOnlyClass": "off",
|
||||||
|
"useOptionalChain": "off",
|
||||||
|
"noUselessSwitchCase": "off",
|
||||||
|
"noUselessFragments": "off",
|
||||||
|
"noUselessTernary": "off",
|
||||||
|
"noUselessLoneBlockStatements": "off",
|
||||||
|
"noUselessEmptyExport": "off",
|
||||||
|
"useArrowFunction": "off",
|
||||||
|
"useLiteralKeys": "off"
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noUnusedVariables": "off",
|
||||||
|
"noUnusedImports": "off",
|
||||||
|
"useExhaustiveDependencies": "off",
|
||||||
|
"noSwitchDeclarations": "off",
|
||||||
|
"noUnreachable": "off",
|
||||||
|
"useHookAtTopLevel": "off",
|
||||||
|
"noVoidTypeReturn": "off",
|
||||||
|
"noConstantCondition": "off",
|
||||||
|
"noUnusedFunctionParameters": "off"
|
||||||
|
},
|
||||||
|
"a11y": {
|
||||||
|
"recommended": false
|
||||||
|
},
|
||||||
|
"nursery": {
|
||||||
|
"recommended": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "single",
|
||||||
|
"semicolons": "asNeeded",
|
||||||
|
"arrowParentheses": "asNeeded",
|
||||||
|
"trailingCommas": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"includes": ["**/*.tsx"],
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"semicolons": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"lineWidth": 120
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"includes": ["scripts/**", "packages/**", "**/*.js", "**/*.mjs", "**/*.jsx"],
|
||||||
|
"formatter": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assist": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { readdir, readFile, writeFile } from "fs/promises";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
const outdir = "dist";
|
||||||
|
|
||||||
|
// Step 1: Clean output directory
|
||||||
|
const { rmSync } = await import("fs");
|
||||||
|
rmSync(outdir, { recursive: true, force: true });
|
||||||
|
|
||||||
|
// Step 2: Bundle with splitting
|
||||||
|
const result = await Bun.build({
|
||||||
|
entrypoints: ["src/entrypoints/cli.tsx"],
|
||||||
|
outdir,
|
||||||
|
target: "bun",
|
||||||
|
splitting: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for Node.js compat)`,
|
||||||
|
);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[test]
|
||||||
|
root = "."
|
||||||
|
timeout = 10000
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
# 文档修正计划
|
||||||
|
|
||||||
|
> 目标:补充源码级洞察,让每篇文档从"概念科普"升级为"逆向工程白皮书"水准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第一梯队:空壳页,需要大幅重写
|
||||||
|
|
||||||
|
### 1. `safety/sandbox.mdx` — 沙箱机制 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:35 行,只列了"文件系统/网络/进程/时间"四个维度,没有任何实现细节。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 补充 macOS `sandbox-exec` 的实际调用方式,展示沙箱 profile 的关键片段
|
||||||
|
- 说明 `getSandboxConfig()` 的判定逻辑:哪些命令走沙箱、哪些跳过
|
||||||
|
- 补充 `dangerouslyDisableSandbox` 参数的设计权衡
|
||||||
|
- 加入 Linux 平台的沙箱差异对比(seatbelt vs namespace)
|
||||||
|
- 展示一次命令执行从权限检查→沙箱包裹→实际执行的完整链路
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. `introduction/what-is-claude-code.mdx` — 什么是 Claude Code ✅ DONE
|
||||||
|
|
||||||
|
**现状**:39 行,纯营销文案,和"普通聊天 AI"的对比表太低级。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 砍掉"能做什么"的泛泛列表,改为一个具体的端到端示例(从用户输入→系统处理→最终输出)
|
||||||
|
- 用一张简化架构图替代文字描述,让读者 30 秒建立直觉
|
||||||
|
- 补充 Claude Code 的技术定位:不是 IDE 插件、不是 Web Chat,而是 terminal-native agentic system
|
||||||
|
- 加入与 Cursor / Copilot / Aider 等工具的定位差异(架构层面而非功能清单)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. `introduction/why-this-whitepaper.mdx` — 为什么写这份白皮书 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:40 行,全是空话,四张 Card 只是后续章节标题的预告。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 明确定位:这是对 Anthropic 官方 CLI 的逆向工程分析,不是官方文档
|
||||||
|
- 列出逆向过程中发现的 3-5 个最意外/最精妙的设计决策(吊住读者胃口)
|
||||||
|
- 说明白皮书的阅读路线图:推荐的阅读顺序和每个章节解决什么问题
|
||||||
|
- 补充"这份白皮书不是什么"——不是使用教程,不是 API 文档
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. `safety/why-safety-matters.mdx` — 为什么安全至关重要 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:40 行,只列了显而易见的风险,"安全 vs 效率的平衡"只有 3 个 bullet。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 从源码角度展示安全体系的全景图:权限规则 → 沙箱 → Plan Mode → 预算上限 → Hooks 的纵深防御链
|
||||||
|
- 补充 Claude 自身 System Prompt 中的安全指令("执行前确认"、"优先可逆操作"等),展示 AI 端的安全约束
|
||||||
|
- 用真实场景说明"安全 vs 效率"的工程权衡:比如 Read 工具为什么免审批、Bash 工具为什么要逐条确认
|
||||||
|
- 加入 Prompt Injection 防御的简要说明(tool result 中的恶意内容如何被系统标记)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第二梯队:有骨架但太浅,需要补肉
|
||||||
|
|
||||||
|
### 5. `conversation/streaming.mdx` — 流式响应 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:43 行,只说了"流式好"和 3 行 provider 表。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 补充 `BetaRawMessageStreamEvent` 的核心事件类型及其含义
|
||||||
|
- 展示文本 chunk 和 tool_use block 交织的状态机流转
|
||||||
|
- 说明流式中的错误处理:网络断开、API 限流、token 超限时的重试/降级策略
|
||||||
|
- 补充 `processStreamEvents()` 的核心逻辑:如何从事件流中分离出文本、工具调用、usage 统计
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. `tools/search-and-navigation.mdx` — 搜索与导航 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:43 行,只说 Glob 和 Grep 存在。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 补充 ripgrep 二进制的内嵌方式(vendor 目录、平台适配)
|
||||||
|
- 说明搜索结果的 head_limit 默认 250 的设计原因(token 预算)
|
||||||
|
- 展示 ToolSearch 的实现:如何用语义匹配在 50+ 工具(含 MCP)中找到最相关的
|
||||||
|
- 补充 Glob 按修改时间排序的意义:最近修改的文件最可能与当前任务相关
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. `tools/task-management.mdx` — 任务管理 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:50 行,只有流程 Steps 和状态展示的 4 个 bullet。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 补充任务的数据模型:id / subject / description / status / blockedBy / blocks / owner
|
||||||
|
- 说明依赖管理的实现:blockedBy 如何阻止任务被认领、完成一个任务后如何自动解锁下游
|
||||||
|
- 展示任务与 Agent 工具的联动:子 Agent 如何认领任务、报告进度
|
||||||
|
- 补充 activeForm 字段的 UX 设计:进行中任务的 spinner 动画文案
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. `context/token-budget.mdx` — Token 预算管理 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:55 行,预算控制只有 3 张 Card 各一句话。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 补充 `contextWindowTokens` 和 `maxOutputTokens` 的动态计算逻辑
|
||||||
|
- 说明缓存 breakpoint 的放置策略:System Prompt 中不变内容在前、变化内容在后的原因
|
||||||
|
- 展示工具输出截断的具体机制:超长结果如何被 truncate、何时触发 micro-compact
|
||||||
|
- 补充 token 计数的实现:`countTokens` 的调用时机和近似 vs 精确计数的权衡
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. `agent/worktree-isolation.mdx` — Worktree 隔离 ✅ DONE
|
||||||
|
|
||||||
|
**现状**:55 行,只描述了 git worktree 的概念。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 展示 `.claude/worktrees/` 的目录结构和分支命名规则
|
||||||
|
- 说明 worktree 的生命周期:创建时机(`isolation: "worktree"`)→ 子 Agent 执行 → 完成/放弃 → 自动清理
|
||||||
|
- 补充 worktree 与子 Agent 的绑定关系:Agent 结束时如何判断 keep or remove
|
||||||
|
- 加入 EnterWorktree / ExitWorktree 工具的交互设计
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. `extensibility/custom-agents.mdx` — 自定义 Agent ✅ DONE
|
||||||
|
|
||||||
|
**现状**:56 行,只有配置表和示例表。
|
||||||
|
|
||||||
|
**修正方向**:
|
||||||
|
- 展示 agent markdown 文件的完整 frontmatter 格式(name / description / model / allowedTools 等)
|
||||||
|
- 说明 agent 如何被加载和注入 System Prompt:`loadAgentDefinitions()` 的发现和合并逻辑
|
||||||
|
- 展示工具限制的实现:allowedTools 如何过滤工具列表
|
||||||
|
- 补充 agent 与 subagent_type 参数的关联:Agent 工具如何指定使用自定义 Agent
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
title: "协调者与蜂群模式 - 多 Agent 高级编排"
|
||||||
|
description: "详解 Claude Code 多 Agent 高级协作模式:Coordinator Mode 协调者模式和 Agent Swarms 蜂群模式的设计理念、调度策略和适用场景。"
|
||||||
|
keywords: ["协调者模式", "蜂群模式", "Agent Swarm", "多 Agent 协作", "任务编排"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:介绍 Coordinator Mode 和 Agent Swarms */}
|
||||||
|
|
||||||
|
## 两种协作模式
|
||||||
|
|
||||||
|
子 Agent 是"临时帮手"——主 Agent 派出去做一件事就回来。对于更复杂的协作需求,Claude Code 提供了两种高级模式:
|
||||||
|
|
||||||
|
## Coordinator Mode:一个指挥,多个执行
|
||||||
|
|
||||||
|
就像一个团队 leader 带着几个开发者:
|
||||||
|
|
||||||
|
- **Coordinator**(协调者):负责理解需求、拆解任务、分配工作、汇总结果
|
||||||
|
- **Workers**(执行者):各自领取任务独立执行,通过邮箱向 Coordinator 汇报
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─── Worker A (重构 API)
|
||||||
|
│
|
||||||
|
Coordinator ──┼─── Worker B (更新测试)
|
||||||
|
│
|
||||||
|
└─── Worker C (更新文档)
|
||||||
|
```
|
||||||
|
|
||||||
|
Coordinator 不自己写代码,它的职责是**编排**——确保所有 Worker 的工作能拼合在一起。
|
||||||
|
|
||||||
|
## Agent Swarms:蜂群式协作
|
||||||
|
|
||||||
|
比 Coordinator 更松散的协作模式:
|
||||||
|
|
||||||
|
- 多个 Agent 以对等身份同时工作
|
||||||
|
- 没有中心化的指挥者
|
||||||
|
- 通过消息邮箱互相通信和协调
|
||||||
|
- 适合"各自负责一块、偶尔需要沟通"的场景
|
||||||
|
|
||||||
|
## Teammate 机制
|
||||||
|
|
||||||
|
进程内的"队友"——一种更轻量的协作方式:
|
||||||
|
|
||||||
|
- 在同一个进程内运行,共享部分基础设施状态
|
||||||
|
- 有独立的对话上下文和工具权限
|
||||||
|
- 适合"我需要一个搭档帮忙看看这段代码"的场景
|
||||||
|
|
||||||
|
## 任务类型
|
||||||
|
|
||||||
|
支撑多 Agent 协作的是丰富的任务类型:
|
||||||
|
|
||||||
|
| 任务类型 | 用途 |
|
||||||
|
|----------|------|
|
||||||
|
| **LocalAgentTask** | 本地子 Agent 任务 |
|
||||||
|
| **LocalShellTask** | 后台 shell 命令 |
|
||||||
|
| **InProcessTeammateTask** | 进程内队友 |
|
||||||
|
| **RemoteAgentTask** | 远程 Agent |
|
||||||
|
| **DreamTask** | 后台自主任务 |
|
||||||
|
|
||||||
|
每种任务类型都有自己的生命周期管理、状态追踪和通信方式。
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
title: "子 Agent 机制 - AI 分身术与任务委派"
|
||||||
|
description: "深入解析 Claude Code 子 Agent 机制:主 Agent 如何通过 AgentTool 委派子任务,子 Agent 的生命周期管理、工具继承和结果回传。"
|
||||||
|
keywords: ["子 Agent", "Agent 分身", "任务委派", "AgentTool", "多 Agent"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:解释子 Agent 机制的设计和应用场景 */}
|
||||||
|
|
||||||
|
## 为什么需要子 Agent
|
||||||
|
|
||||||
|
有些任务太大,一个 AI 实例忙不过来:
|
||||||
|
|
||||||
|
- "在 5 个不同的文件中分别找到并修复同类 bug"
|
||||||
|
- "一边重构后端 API,一边更新前端调用"
|
||||||
|
- "研究这个库的用法,同时修改我们的代码"
|
||||||
|
|
||||||
|
## 分身术的运作方式
|
||||||
|
|
||||||
|
Claude Code 中的 Agent 工具让 AI 能够**启动另一个 AI 实例**来处理子任务:
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
<Step title="主 Agent 分析任务">
|
||||||
|
主 Agent 判断任务可以被拆解为独立的子任务
|
||||||
|
</Step>
|
||||||
|
<Step title="启动子 Agent">
|
||||||
|
通过 Agent 工具创建一个或多个子 Agent,每个子 Agent 收到一个清晰的子任务描述
|
||||||
|
</Step>
|
||||||
|
<Step title="并行执行">
|
||||||
|
多个子 Agent 可以同时工作,互不干扰
|
||||||
|
</Step>
|
||||||
|
<Step title="结果汇总">
|
||||||
|
子 Agent 完成后,结果返回给主 Agent,主 Agent 汇总并呈现给用户
|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
## 子 Agent 的边界
|
||||||
|
|
||||||
|
子 Agent 不是和主 Agent 完全一样的——它有明确的能力边界:
|
||||||
|
|
||||||
|
| 特性 | 主 Agent | 子 Agent |
|
||||||
|
|------|---------|---------|
|
||||||
|
| 可用工具 | 全部工具 | 受限子集(不能再启动子 Agent 等) |
|
||||||
|
| 上下文 | 完整的会话历史 | 只有主 Agent 给的任务描述 |
|
||||||
|
| 权限 | 用户设定 | 继承主 Agent 的权限,或更严格 |
|
||||||
|
| 状态 | 可修改全局状态 | 隔离的状态空间 |
|
||||||
|
|
||||||
|
## 通信方式
|
||||||
|
|
||||||
|
主 Agent 和子 Agent 之间通过**消息邮箱**通信:
|
||||||
|
|
||||||
|
- 主 Agent 通过 `Agent` 工具启动子 Agent
|
||||||
|
- 子 Agent 通过 `SendMessage` 工具向主 Agent 报告进度
|
||||||
|
- 这种松耦合的通信方式让 Agent 可以异步协作
|
||||||
|
|
||||||
|
## 适用场景
|
||||||
|
|
||||||
|
<CardGroup cols={2}>
|
||||||
|
<Card title="并行研究" icon="magnifying-glass">
|
||||||
|
多个子 Agent 同时搜索不同方向的信息
|
||||||
|
</Card>
|
||||||
|
<Card title="分治修改" icon="code-branch">
|
||||||
|
把大规模修改拆分到多个子 Agent 并行执行
|
||||||
|
</Card>
|
||||||
|
<Card title="前后台配合" icon="layer-group">
|
||||||
|
一个子 Agent 在后台运行测试,主 Agent 继续写代码
|
||||||
|
</Card>
|
||||||
|
<Card title="隔离实验" icon="flask">
|
||||||
|
在 worktree 中启动子 Agent 尝试一个方案,不影响主分支
|
||||||
|
</Card>
|
||||||
|
</CardGroup>
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
---
|
||||||
|
title: "Worktree 隔离 - Git Worktree 实现文件级隔离"
|
||||||
|
description: "揭秘 Claude Code 的 git worktree 隔离机制:子 Agent 如何获得独立工作空间,worktree 创建/销毁生命周期、路径命名规则和安全防护。"
|
||||||
|
keywords: ["Worktree", "git worktree", "文件隔离", "多 Agent 隔离", "并行安全"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:揭示 worktree 的创建/销毁生命周期、路径命名规则、hook 机制和退出时的安全防护 */}
|
||||||
|
|
||||||
|
## 为什么需要文件级隔离
|
||||||
|
|
||||||
|
多 Agent 并行工作时,共享同一工作目录会导致三类冲突:
|
||||||
|
|
||||||
|
1. **写入冲突**:两个 Agent 同时编辑 `config.ts`,后写的覆盖前写的
|
||||||
|
2. **状态干扰**:Agent A 的测试依赖某个环境状态,Agent B 的修改破坏了它
|
||||||
|
3. **不可区分**:半完成的修改混在一起,无法分辨哪些是哪个 Agent 的
|
||||||
|
|
||||||
|
Git worktree 是 git 原生的解决方案——在同一个仓库中创建多个独立工作目录,每个在自己的分支上。
|
||||||
|
|
||||||
|
## 目录结构与命名规则
|
||||||
|
|
||||||
|
Worktree 文件统一存放在仓库根目录下的 `.claude/worktrees/`:
|
||||||
|
|
||||||
|
```
|
||||||
|
<repo-root>/
|
||||||
|
├── .claude/
|
||||||
|
│ └── worktrees/
|
||||||
|
│ ├── fix-auth-bug/ # worktree 工作目录
|
||||||
|
│ │ ├── .git # 指向主仓库的链接文件
|
||||||
|
│ │ └── src/... # 独立的文件系统视图
|
||||||
|
│ └── add-dark-mode/ # 另一个 worktree
|
||||||
|
│ └── ...
|
||||||
|
├── src/ # 主工作目录(不受影响)
|
||||||
|
└── .git/ # 主仓库
|
||||||
|
```
|
||||||
|
|
||||||
|
分支命名规则为 `worktree/<slug>`,其中 slug 由 `validateWorktreeSlug()` 校验:每个 `/` 分隔的段只允许字母、数字、`.`、`_`、`-`,总长 ≤64 字符。未指定时使用 plan slug 自动生成。
|
||||||
|
|
||||||
|
## 创建流程:EnterWorktreeTool
|
||||||
|
|
||||||
|
`EnterWorktreeTool`(`src/tools/EnterWorktreeTool/EnterWorktreeTool.ts`)的执行链路:
|
||||||
|
|
||||||
|
```
|
||||||
|
EnterWorktreeTool.call({ name? })
|
||||||
|
↓
|
||||||
|
1. 检查是否已在 worktree 中(防嵌套)
|
||||||
|
↓
|
||||||
|
2. 解析到主仓库根目录(findCanonicalGitRoot)
|
||||||
|
如果当前已在 worktree 内,chdir 到主仓库
|
||||||
|
↓
|
||||||
|
3. 生成 slug(用户提供或 plan slug)
|
||||||
|
↓
|
||||||
|
4. createWorktreeForSession(sessionId, slug)
|
||||||
|
├── 有 WorktreeCreate hook?
|
||||||
|
│ └── 执行 hook,返回 hook 指定的路径(支持非 git VCS)
|
||||||
|
└── 无 hook → git 原生路径:
|
||||||
|
a. getOrCreateWorktree(repoRoot, slug)
|
||||||
|
├── 快速恢复:检查 worktree 目录是否已存在
|
||||||
|
│ └── 读取 .git 指针文件的 HEAD SHA(无子进程)
|
||||||
|
└── 新建:
|
||||||
|
i. mkdir .claude/worktrees/(recursive)
|
||||||
|
ii. fetch origin/<default-branch>(有缓存则跳过)
|
||||||
|
iii. git worktree add -b worktree/<slug> <path> <base>
|
||||||
|
iv. performPostCreationSetup()(sparse checkout 等)
|
||||||
|
↓
|
||||||
|
5. 更新进程状态:
|
||||||
|
- process.chdir(worktreePath)
|
||||||
|
- setCwd(worktreePath)
|
||||||
|
- setOriginalCwd(worktreePath)
|
||||||
|
- saveWorktreeState(session) → 持久化到项目配置
|
||||||
|
- clearSystemPromptSections() → 重新计算系统提示中的 cwd 信息
|
||||||
|
- clearMemoryFileCaches() → 重新加载 worktree 中的 CLAUDE.md
|
||||||
|
↓
|
||||||
|
6. 返回 worktreePath 和 worktreeBranch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hook 优先的架构
|
||||||
|
|
||||||
|
`createWorktreeForSession()` 首先检查 `hasWorktreeCreateHook()`——如果用户在 settings.json 中配置了 `WorktreeCreate` hook,系统完全不调用 git,而是执行 hook 命令并将返回的路径作为 worktree 路径。这允许非 git 版本控制系统(如 Pijul、Mercurial)通过 hook 接入。
|
||||||
|
|
||||||
|
### 快速恢复路径
|
||||||
|
|
||||||
|
`getOrCreateWorktree()` 有一个关键优化:如果目标路径已存在,直接读取 `.git` 指针文件获取 HEAD SHA(纯文件 I/O,无子进程),跳过整个 `fetch` + `worktree add` 流程。在大仓库中 `fetch` 需要 6-8 秒,这个优化将恢复场景的延迟降到接近 0。
|
||||||
|
|
||||||
|
## 退出流程:ExitWorktreeTool
|
||||||
|
|
||||||
|
`ExitWorktreeTool`(`src/tools/ExitWorktreeTool/ExitWorktreeTool.ts`)支持两种退出策略:
|
||||||
|
|
||||||
|
### keep:保留 worktree
|
||||||
|
|
||||||
|
```
|
||||||
|
keepWorktree()
|
||||||
|
↓
|
||||||
|
1. chdir 回 originalCwd
|
||||||
|
2. 清空 currentWorktreeSession
|
||||||
|
3. 更新项目配置(activeWorktreeSession = undefined)
|
||||||
|
4. worktree 目录和分支保留在磁盘上
|
||||||
|
```
|
||||||
|
|
||||||
|
用户可以通过 `cd <worktreePath>` 继续工作,或稍后手动合并。
|
||||||
|
|
||||||
|
### remove:删除 worktree
|
||||||
|
|
||||||
|
有严格的**安全防护**:
|
||||||
|
|
||||||
|
```
|
||||||
|
validateInput() — 第一道防线
|
||||||
|
↓
|
||||||
|
1. 检查是否在 EnterWorktree 创建的会话中
|
||||||
|
(手动创建的 worktree 不会被删除)
|
||||||
|
↓
|
||||||
|
2. countWorktreeChanges(worktreePath, originalHeadCommit)
|
||||||
|
├── git status --porcelain → 统计未提交文件数
|
||||||
|
├── git rev-list --count <originalHead>..HEAD → 统计新提交数
|
||||||
|
└── 返回 null(git 失败时)→ fail-closed(拒绝删除)
|
||||||
|
↓
|
||||||
|
3. 有未提交文件或新提交?
|
||||||
|
→ 拒绝,要求 discard_changes: true 确认
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
call() — 实际执行
|
||||||
|
↓
|
||||||
|
1. 重新计数变更(validateInput 和 call 之间可能有新修改)
|
||||||
|
2. 如果有 tmux session → killTmuxSession()
|
||||||
|
3. cleanupWorktree()
|
||||||
|
├── hook-based → 执行 WorktreeRemove hook
|
||||||
|
└── git-based → git worktree remove --force + git branch -D
|
||||||
|
4. restoreSessionToOriginalCwd()
|
||||||
|
- setCwd(originalCwd)
|
||||||
|
- setOriginalCwd(originalCwd)
|
||||||
|
- 如果 projectRoot 是 worktree 时才恢复(防误触)
|
||||||
|
- 更新 hooks config snapshot
|
||||||
|
- 清空系统提示和 memory 缓存
|
||||||
|
```
|
||||||
|
|
||||||
|
### fail-closed 设计
|
||||||
|
|
||||||
|
`countWorktreeChanges()` 在以下情况返回 `null`("未知,假设不安全"):
|
||||||
|
- `git status` 或 `git rev-list` 退出非零(锁文件、损坏的索引)
|
||||||
|
- `originalHeadCommit` 未定义(hook-based worktree 没有设置基线 commit)
|
||||||
|
|
||||||
|
返回 `null` 时,`validateInput` 拒绝删除——宁可让用户手动处理,也不冒险丢失工作。
|
||||||
|
|
||||||
|
## 与 Agent 工具的联动
|
||||||
|
|
||||||
|
Agent 工具(`AgentTool`)的 `isolation` 参数决定子 Agent 是否在 worktree 中运行:
|
||||||
|
|
||||||
|
- `isolation: "worktree"` → 调用 `createWorktreeForSession()`,子 Agent 在独立 worktree 中执行
|
||||||
|
- 无 isolation → 子 Agent 共享主工作目录
|
||||||
|
|
||||||
|
子 Agent 结束时的处理:
|
||||||
|
- **成功**:主 Agent 通过 `ExitWorktreeTool(action: "keep")` 保留 worktree,然后手动合并
|
||||||
|
- **失败/放弃**:主 Agent 通过 `ExitWorktreeTool(action: "remove", discard_changes: true)` 清理
|
||||||
|
|
||||||
|
## Session 状态持久化
|
||||||
|
|
||||||
|
`WorktreeSession` 对象通过 `saveCurrentProjectConfig()` 持久化到磁盘,包含:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
originalCwd: string, // 进入 worktree 前的工作目录
|
||||||
|
worktreePath: string, // worktree 的绝对路径
|
||||||
|
worktreeName: string, // slug
|
||||||
|
worktreeBranch?: string, // 分支名(如 worktree/fix-auth)
|
||||||
|
originalBranch?: string, // 进入前的分支
|
||||||
|
originalHeadCommit?: string, // 进入前的 HEAD commit(用于变更统计)
|
||||||
|
sessionId: string, // 创建此 worktree 的会话 ID
|
||||||
|
tmuxSessionName?: string, // 关联的 tmux session
|
||||||
|
hookBased?: boolean, // 是否由 hook 创建
|
||||||
|
creationDurationMs?: number, // 创建耗时(分析用)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这使得 session 恢复(`--resume`)时能正确还原 worktree 上下文——即使进程重启,`getCurrentWorktreeSession()` 从项目配置中读取状态。
|
||||||
|
|
||||||
|
## Sparse Checkout 优化
|
||||||
|
|
||||||
|
对于大型 monorepo,worktree 支持 `sparsePaths` 配置——只检出特定目录而非整个仓库。这在 210K 文件的仓库中将 worktree 创建时间从数十秒降到几秒。
|
||||||
|
|
||||||
|
配置位于 `getInitialSettings().worktree?.sparsePaths`,在 `performPostCreationSetup()` 中应用。
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
title: "上下文压缩 - Compaction 优雅遗忘机制"
|
||||||
|
description: "详解 Claude Code 上下文压缩策略:当对话 token 接近 200K 上限时,如何通过 Compaction 机制智能压缩历史消息,保留关键信息。"
|
||||||
|
keywords: ["上下文压缩", "Compaction", "token 管理", "对话压缩", "上下文窗口"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:解释 Compaction 机制的设计和策略 */}
|
||||||
|
|
||||||
|
## 为什么需要压缩
|
||||||
|
|
||||||
|
每次 API 调用的 token 有上限(通常 200K)。一场长时间的编程对话可能产生:
|
||||||
|
|
||||||
|
- 大量的文件内容(AI 读了几十个文件)
|
||||||
|
- 长篇的命令输出(构建日志、测试结果)
|
||||||
|
- 往返的对话历史
|
||||||
|
|
||||||
|
不压缩的话,很快就会撞到 token 上限,对话被迫终止。
|
||||||
|
|
||||||
|
<Frame caption="上下文压缩前后对比">
|
||||||
|
<img src="/docs/images/compaction.png" alt="上下文压缩示意图" />
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
## 压缩的策略
|
||||||
|
|
||||||
|
Claude Code 提供了多层压缩机制:
|
||||||
|
|
||||||
|
<AccordionGroup>
|
||||||
|
<Accordion title="自动压缩">
|
||||||
|
当 token 接近上限时,系统自动触发压缩。AI 生成一份当前对话的**摘要**,替换掉早期的详细消息。效果就像人类的"记忆"——记住要点,忘记细节。
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="手动压缩">
|
||||||
|
用户可以随时通过 `/compact` 命令主动触发压缩。可以附带提示语(如 `/compact 聚焦在认证模块的修改上`),引导 AI 保留特定信息。
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Micro Compact">
|
||||||
|
更细粒度的局部压缩——不是压缩整个对话,而是压缩某些特别长的工具输出(比如一个 5000 行的测试日志)。
|
||||||
|
</Accordion>
|
||||||
|
</AccordionGroup>
|
||||||
|
|
||||||
|
## 压缩边界
|
||||||
|
|
||||||
|
压缩后,系统在消息历史中插入一个"边界标记"。后续的 API 调用只发送边界之后的消息:
|
||||||
|
|
||||||
|
```
|
||||||
|
[早期的 50 条消息] ← 被压缩
|
||||||
|
[压缩摘要边界] ← 一段浓缩的摘要
|
||||||
|
[后续的 10 条消息] ← 正常发送
|
||||||
|
```
|
||||||
|
|
||||||
|
这个设计保证了:
|
||||||
|
- 压缩后的摘要为 AI 提供了历史上下文
|
||||||
|
- 新的对话不受旧消息的 token 负担
|
||||||
|
- 用户无感知——对话继续自然进行
|
||||||
|
|
||||||
|
## 压缩前后的 Hooks
|
||||||
|
|
||||||
|
压缩是一个可能丢失信息的操作,因此系统允许用户在压缩前后执行自定义脚本:
|
||||||
|
|
||||||
|
- **Pre-compact Hook**:压缩前执行,可以标记"这些信息不能丢"
|
||||||
|
- **Post-compact Hook**:压缩后执行,可以验证关键信息是否保留
|
||||||
|
|
||||||
|
## 什么信息会被保留
|
||||||
|
|
||||||
|
压缩不是简单的截断,AI 会智能地决定保留什么:
|
||||||
|
|
||||||
|
- 用户的核心需求和目标
|
||||||
|
- 重要的决策和原因
|
||||||
|
- 当前工作的状态(改了哪些文件、做到哪一步)
|
||||||
|
- 之前犯过的错误(避免重蹈覆辙)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
title: "项目记忆系统 - AI 跨对话记忆机制"
|
||||||
|
description: "解析 Claude Code 项目记忆系统:CLAUDE.md 文件、用户偏好存储和上下文缓存如何让 AI 跨对话记住项目特性和个人偏好。"
|
||||||
|
keywords: ["项目记忆", "CLAUDE.md", "AI 记忆", "跨对话", "上下文缓存"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:解释记忆系统如何让 AI 变得'有记忆' */}
|
||||||
|
|
||||||
|
## AI 的记忆困境
|
||||||
|
|
||||||
|
大语言模型没有真正的记忆。每次新对话,它都是一张白纸。用户不得不反复解释"我的项目用 Bun 不用 Node"、"commit 消息用中文"。
|
||||||
|
|
||||||
|
## 记忆系统的解决方案
|
||||||
|
|
||||||
|
Claude Code 通过一个基于文件的持久化记忆系统来模拟"跨会话记忆":
|
||||||
|
|
||||||
|
<CardGroup cols={2}>
|
||||||
|
<Card title="用户记忆" icon="user">
|
||||||
|
关于用户的信息:角色、偏好、技术背景
|
||||||
|
</Card>
|
||||||
|
<Card title="反馈记忆" icon="message">
|
||||||
|
用户对 AI 行为的纠正和肯定
|
||||||
|
</Card>
|
||||||
|
<Card title="项目记忆" icon="folder">
|
||||||
|
项目中的非代码信息:谁负责什么、截止日期
|
||||||
|
</Card>
|
||||||
|
<Card title="参考记忆" icon="link">
|
||||||
|
外部资源的位置:Issue tracker、Dashboard URL
|
||||||
|
</Card>
|
||||||
|
</CardGroup>
|
||||||
|
|
||||||
|
## 记忆的读写时机
|
||||||
|
|
||||||
|
| 时机 | 动作 |
|
||||||
|
|------|------|
|
||||||
|
| 每次对话开始 | 加载记忆索引(MEMORY.md),相关记忆注入 System Prompt |
|
||||||
|
| 用户纠正 AI | AI 自动判断是否值得记住,写入反馈记忆 |
|
||||||
|
| 用户说"记住这个" | 立即保存到对应类型的记忆文件 |
|
||||||
|
| 用户说"忘掉这个" | 找到并删除对应的记忆条目 |
|
||||||
|
| 记忆可能过期时 | 使用前先验证(文件还在?函数还存在?),过期则更新或删除 |
|
||||||
|
|
||||||
|
## 记忆 vs 代码注释 vs CLAUDE.md
|
||||||
|
|
||||||
|
| | 记忆 | 代码注释 | CLAUDE.md |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 存储位置 | `~/.claude/` 目录 | 代码文件中 | 项目目录中 |
|
||||||
|
| 谁能看到 | 只有当前用户 | 所有开发者 | 所有使用 Claude Code 的人 |
|
||||||
|
| 适合存什么 | 个人偏好、非公开的上下文 | 代码逻辑解释 | 项目约定、开发指南 |
|
||||||
|
| 跨项目 | 是 | 否 | 否 |
|
||||||
|
|
||||||
|
## 不该存什么
|
||||||
|
|
||||||
|
记忆系统明确规定了不应存储的内容:
|
||||||
|
|
||||||
|
- 代码结构和架构(读代码就知道)
|
||||||
|
- git 历史(`git log` 就能查)
|
||||||
|
- 调试方案(修复已在代码中)
|
||||||
|
- CLAUDE.md 里已有的内容(避免重复)
|
||||||
|
- 临时性任务状态(用任务系统)
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
title: "System Prompt 动态组装 - AI 工作记忆构建"
|
||||||
|
description: "深入解析 Claude Code 的 System Prompt 动态组装过程:如何将 CLAUDE.md、项目上下文、工具定义和用户偏好拼装为 AI 的工作记忆。"
|
||||||
|
keywords: ["System Prompt", "系统提示词", "动态组装", "CLAUDE.md", "上下文构建"]
|
||||||
|
---
|
||||||
|
|
||||||
|
{/* 本章目标:解释 System Prompt 的组装过程和设计思想 */}
|
||||||
|
|
||||||
|
## 什么是 System Prompt
|
||||||
|
|
||||||
|
每次调用 AI API 时,都需要发送一个 System Prompt——它是 AI 的"人设说明书",告诉 AI:
|
||||||
|
|
||||||
|
- 你是谁(Claude Code,一个编程助手)
|
||||||
|
- 你能做什么(可用工具列表)
|
||||||
|
- 你在什么环境(操作系统、当前目录、git 状态)
|
||||||
|
- 你需要遵守什么规则(安全规范、输出格式)
|
||||||
|
|
||||||
|
## 不是静态模板,而是动态组装
|
||||||
|
|
||||||
|
Claude Code 的 System Prompt 不是一段写死的文本,而是根据当前环境**实时组装**的:
|
||||||
|
|
||||||
|
<Frame caption="System Prompt 的 6 大组成部分">
|
||||||
|
<img src="/docs/images/system-prompt-assembly.png" alt="System Prompt 动态组装图" />
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
| 组成部分 | 内容 | 来源 |
|
||||||
|
|----------|------|------|
|
||||||
|
| 基础人设 | 角色定义、行为准则 | 内置模板 |
|
||||||
|
| 环境信息 | 操作系统、shell 类型、当前日期 | 运行时检测 |
|
||||||
|
| Git 状态 | 当前分支、最近提交、工作区状态 | `git` 命令输出 |
|
||||||
|
| 项目知识 | CLAUDE.md 文件内容 | 项目目录层级扫描 |
|
||||||
|
| 记忆文件 | 用户偏好、项目约定 | 持久化记忆系统 |
|
||||||
|
| 工具说明 | 每个可用工具的描述和参数 | 工具注册表 |
|
||||||
|
|
||||||
|
## CLAUDE.md:项目级知识注入
|
||||||
|
|
||||||
|
这是 Claude Code 最巧妙的设计之一。在项目根目录放一个 `CLAUDE.md` 文件,就能让 AI "理解" 你的项目:
|
||||||
|
|
||||||
|
- **项目概述**:这个项目做什么、用了什么技术栈
|
||||||
|
- **开发约定**:代码风格、命名规范、分支策略
|
||||||
|
- **常用命令**:怎么构建、怎么测试、怎么部署
|
||||||
|
- **注意事项**:已知的坑、特殊的配置
|
||||||
|
|
||||||
|
系统会自动发现并合并多级 CLAUDE.md:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.claude/CLAUDE.md ← 用户全局(个人偏好)
|
||||||
|
└── /project/CLAUDE.md ← 项目根目录(团队共享)
|
||||||
|
└── /project/src/CLAUDE.md ← 子目录(模块特定)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 缓存策略
|
||||||
|
|
||||||
|
System Prompt 的 token 消耗不小(可能占总量的 30%+)。为了降低成本,系统使用了缓存机制:
|
||||||
|
|
||||||
|
- 不变的部分(基础人设、工具说明)可以跨请求复用
|
||||||
|
- 变化的部分(git 状态、记忆文件)每次重新生成
|
||||||
|
- 缓存节点的位置经过精心设计,最大化缓存命中率
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user