# @bysking/b-code 中文文档

规范地址：https://npmcn.com/package/%40bysking/b-code/

版本：3\.4\.4
npm 元数据更新时间：2026-11-07T13:20:35.479Z
中文译文更新时间：2026-11-08T21:50:49.805Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40bysking/b-code
原文对照：https://npmcn.com/package/%40bysking/b-code/?lang=original
项目主页：https://github.com/bysking/b-code#readme
源码仓库：https://github.com/bysking/b-code

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：41.1 kB，5 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=24
- 运行依赖：0 个
- 首次发布：2026-08-19T11:21:59.235Z
- 最新版本发布：2026-11-07T13:20:35.327Z
- 近 30 天下载量：2978（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：28（近 12 个月 28 个）

## 中文简介

从零构建的编码助手 — 你自己的 B-Code，运行在终端里（要求 Node.js >= 24, 推荐>=26.2.0）

## 安装

```sh
npm install @bysking/b-code
```

也可以使用：`pnpm add @bysking/b-code`、`yarn add @bysking/b-code`、`bun add @bysking/b-code`

## README

# B Code (bcode)

一个从零构建的编码 Agent CLI —— 你自己的 Claude Code。

在终端里用自然语言下达任务：读代码、改文件、跑命令、写计划，全程可见工具调用与权限审批。

> 版本变更见 [CHANGELOG.md](https://npmcn.com/package/%40bysking/b-code/CHANGELOG.md)。

## 安装

```bash
npm i -g @bysking/b-code    # 全局安装（推荐）
npx -y @bysking/b-code      # 或免安装直接运行
```

安装后得到 `bcode` 命令。**无需安装 Node 或 Bun** —— 发布版是单文件可执行程序， 运行时已嵌入（支持平台见「[安装与分发](https://npmcn.com/package/%40bysking/b-code/#readme-%E5%AE%89%E8%A3%85%E4%B8%8E%E5%88%86%E5%8F%91)」）。

从本仓库开发：

```bash
bun install && bun run dev     # OpenTUI 只能跑在 Bun 上
```

## 快速开始

**One-shot（执行一条指令后退出）：**

```bash
bcode "Read the README and summarize what this project does"
```

**REPL（交互式多轮对话，每轮自动保存）：**

```bash
bcode
```

## 命令行参数

| 参数 | 说明 |
| --- | --- |
| `bcode "指令"` | One-shot：执行单条指令后保存退出（可含权限确认） |
| `bcode` | REPL：交互式多轮对话 |
| `bcode --resume` | REPL 并恢复上次会话 |
| `bcode --session <id>` | 恢复指定会话（配合`--resume`） |
| `bcode --plan "指令"` | Plan 模式：写 / 编辑 / shell 全部拦截，只读规划 |
| `bcode --yolo "指令"` | Bypass 模式：跳过 confirm（危险命令 deny 仍拦得住） |
| `bcode --auto "指令"` | Auto 模式：用分类器代替确认框 |
| `bcode --goal <条件> "指令"` | Auto 追目标：无人值守循环，直到条件达成 |
| `bcode --loop <秒> "指令"` | 定时重投：每隔 N 秒重复执行指令（Ctrl-C 停止） |
| `bcode --output-format json "指令"` | headless 输出结构化 JSON（结果/工具/用量），供 CI/脚本消费 |

`--output-format json` 示例输出：

```json
{
  "success": true,
  "session_id": "20260903-101500-ab",
  "model": "claude-sonnet-4-5-20250929",
  "instruction": "读取 package.json",
  "result": "该文件定义了……",
  "tools": [{ "name": "read_file", "input": { "file_path": "package.json" }, "output": "…" }],
  "usage": { "input_tokens": 1200, "output_tokens": 340, "calls": 2 },
  "error": null
}
```

退出时会打印恢复命令，例如：

```
想恢复本次会话，执行:
  bcode --resume --session <id>
```

## 交互界面（TTY）

TTY 下使用 [OpenTUI](https://github.com/anomalyco/opentui) 渲染：思考过程、工具调用块、Markdown 回复、权限确认、斜杠菜单均为声明式 UI。

**斜杠命令（输入 `/` 可唤起补全菜单，菜单超长时随选中项滚动）：**

| 命令 | 说明 |
| --- | --- |
| `/clear` | 清空当前对话历史（并重置"本轮自动审批"标记） |
| `/help` | 显示命令与快捷键帮助 |
| `/cost` | 本次会话 token 用量与估算成本 |
| `/model [名字]` | 查看 / 运行时切换模型 |
| `/compact` | 立即压缩上下文（摘要旧消息） |
| `/rewind` | 回退本次会话已改动的文件（检查点还原） |
| `/todos` | 查看模型自管的任务清单 |
| `/plan` | 切换 Plan（只读）模式 |
| `/yolo` | 切换 Bypass 模式 |
| `/auto` | 切换 Auto 模式（分类器管控写/shell） |
| `/default` | 切换回默认模式 |
| `/skills` | 技能面板：空格启用/禁用（禁用的不发给模型） |
| `/mcp` | MCP 面板：空格启用/禁用，`R` 重连 |
| `/export [路径]` | 导出当前会话为 markdown（默认 `./bcode-<id>.md`） |
| `/remember <事实>` | 保存一条长期记忆 |
| `exit` / `quit` | 退出 |

**快捷键：**

-   `Esc`：硬中断当前对话——立即取消在飞的模型请求、终止 `run_shell` 子进程，回到输入等待新指令（可继续输入）
-   `Ctrl+O`：切换工具输出面板（回看本轮全部工具/子 agent 的真实输出）
-   `Shift+Tab`：循环切换模式（default → plan → auto → bypass）
-   `↑` / `↓`：输入历史导航（输入框为空时）
-   `Ctrl+V` / `Cmd+V`：粘贴图片（存为 `[image #N]`）；纯文本粘贴由括号粘贴模式自动处理
-   **拖选 + `Ctrl+Shift+C`**：复制选中的文本（跨 SSH 也有效，走 OSC52）
-   `Ctrl+C`：第一次提示、2 秒内再按一次退出

非 TTY（管道 / CI / 脚本）下自动退化为 readline 交互，语义保持一致；权限确认只消费 `y/n` 行。

> **关于历史与滚动**：历史渲染在应用内的 `<scrollbox>` 里（原生视口裁剪 + 粘性贴底）， 鼠标滚轮直接可用。
> 
> **退出后终端不会保留本次历史**——OpenTUI 用备用屏全屏渲染，退出即销毁。 三种方式把内容带走：
> 
> -   退出时自动补打最近 3 轮对话
> -   `/export [路径]` 导出完整会话为 markdown
> -   `bcode --resume` 重新进入会话
> 
> 拖选用 `Ctrl+Shift+C` 复制（不是 Cmd+C：macOS 上它是终端自己的快捷键， 传不到应用；只有 Kitty / WezTerm 这类实现 Kitty 协议的终端才能收到）。

## 安装与分发

```bash
npm install -g @bysking/b-code
bcode
```

**无需安装 Node 或 Bun** —— 发布版是 `bun build --compile` 出的单文件可执行程序， Bun 运行时已嵌入。

### 支持平台

| 平台 | 包名 | 说明 |
| --- | --- | --- |
| macOS (Apple Silicon) | `@bysking/b-code-darwin-arm64` |  |
| macOS (Intel) | `@bysking/b-code-darwin-x64` |  |
| Linux (glibc) | `@bysking/b-code-linux-x64` | Ubuntu/Debian/CentOS 等 |
| Windows (x64) | `@bysking/b-code-win32-x64` |  |

npm 通过 `os`/`cpu` 字段自动只装匹配的平台包，用户只下载自己那份（~75MB）。

Alpine 等 musl 发行版暂未分发：`scripts/pack-platform.js` 已能生成 `linux-x64-musl` 变体，但需要先在主包 `optionalDependencies`、`bin/bcode.js` 和 CI 矩阵里一并登记才会生效。

### 渲染引擎

基于 [OpenTUI](https://github.com/anomalyco/opentui)（Zig 原生核心），按它的 最佳实践直接写原生组件——**没有兼容层**：

```tsx
<box flexDirection="column" borderStyle="rounded">
  <text fg="#7aa2f7" attributes={1}>标题</text>
  <scrollbox stickyScroll viewportCulling>
    <markdown content={text} syntaxStyle={style} />
  </scrollbox>
</box>
```

| 能力 | 用的原生组件 |
| --- | --- |
| 会话流滚动 | `<scrollbox>`（视口裁剪 + 粘性贴底 + 鼠标滚轮） |
| 文本输入 | `<input>`（受控 value、原生光标/选区/undo、Enter 提交） |
| Markdown | `<markdown>`（tree-sitter 解析 + 代码高亮） |
| 布局 | flexbox（Yoga） |
| 键盘 | `useKeyboard`（`e.name` 直接判断） |

**注意 `jsxImportSource`**：`tsconfig.json` 配了 `"jsxImportSource": "@opentui/react"`， 所以 `<box>` / `<text>` 这些是 OpenTUI 的原生标签，不是 React 组件包装。

**vs 之前的 ink 版**：删掉了手写虚拟滚动、滚轮 SGR 解析、输入框光标管理、 markdown 的 marked 管线（约 1500 行）。这些 OpenTUI 全都原生提供。

## 调试日志

```bash
BCODE_DEBUG_CONSOLE=1 bun src/index.ts
```

打开 OpenTUI 的 console overlay（浮层显示 `console.log`）。 默认关闭——浮层会遮挡 UI。业务日志不受影响：它们经 `setLogSink` 收进 `Ctrl+O` 面板的"日志"页。

### 测试

```bash
bun test
```

**必须用 Bun 跑**：OpenTUI 的原生 FFI 只在 Bun 运行时可用（Node 26 实测也不行）。 测试用 OpenTUI 的 `createTestRenderer`，辅助封装见 `test/helpers/otui-test.ts`。

### 构建

```bash
bun run build                   # 当前平台可执行文件 → dist/bcode（~75MB）
node scripts/pack-platform.js   # 打成可发布的平台包 → dist-pkg/<platform>/
bun run build:all-check         # 查看各平台构建前置条件
```

**各平台必须原生编译**：OpenTUI 的动态 import 让打包器把所有平台的 `@opentui/core-<platform>` 都当必需依赖，而这些包带 `os`/`cpu` 字段， npm 只允许装当前平台的 → 交叉编译会因缺包失败。全平台发布由 `.github/workflows/release.yml` 的 CI 矩阵完成。

### 发布

```bash
# 1. 改 package.json 的 version，并把 optionalDependencies 的 4 行平台包版本同步
# 2. CHANGELOG 里把 [Unreleased] 移到新版本小节
# 3. 打 tag 触发 CI（test → build 矩阵 → 平台包 → 主包）
git tag v3.0.0 && git push origin v3.0.0
```

也可以在 Actions 页面**手动触发**（`workflow_dispatch`，选 `main` 分支），勾 `dry_run` 可先只跑构建与校验、不发布。

CI 用 Bun 跑（`bun install --frozen-lockfile` / `bun test` / `node build-bun.js`）， **不是 pnpm** —— OpenTUI 的原生 FFI 只在 Bun 运行时可用。

发布走 **npm Trusted Publishing (OIDC)**，不用长期 token。前提是 npm CLI ≥ 11.5.1、 不给 `setup-node` 传 `registry-url`，以及**5 个包各配一次 Trusted Publisher**。 完整机制、配置步骤与排错表见 **[docs/RELEASING.md](https://npmcn.com/package/%40bysking/b-code/docs/RELEASING.md)**。

> 4 个平台包已发布 `1.0.0` 占位版本（只含 README，无二进制）。这是为了绕开 「OIDC 无法发布尚不存在的包」的限制——包存在后才能配置 Trusted Publishing。 主包 `optionalDependencies` 指向的版本与占位版本不同，用户不会装到它。

**主包只是启动器**（`bin/bcode.js`，~3KB，零依赖），真正的二进制在 4 个平台包里。 所以 `dependencies` 现在是空的：源码里用到的库都已移入 `devDependencies`，只参与 编译期打包、不随主包分发。改 `package.json` 的 version 时漏改平台包版本，npm 对 optionalDependencies 的解析失败是静默的，用户会装成功却跑不起来——`scripts/check-version.js` （已挂到 `prepublishOnly` 和 CI）会拦下这种漂移，同时校验平台清单在 `optionalDependencies` / `bin/bcode.js` / `lib/index.js` / `scripts/pack-platform.js` 四处是否一致。

## 权限与模式

四种模式：`default` / `plan` / `bypass` / `auto`。

权限判定三态：**allow（放行）/ deny（拦截）/ confirm（询问）**，遵循三个原则：

1.  **deny 优先** —— 危险命令在任何模式（含 `--yolo`）下都拦得住；
2.  **fail-closed** —— 未声明模式的工具默认 confirm，不默认放行；
3.  **plan 只读由权限层强制** —— 不靠提示词"求"模型别动。

以下危险命令直接 deny（连 `--yolo` 也绕不过）：

```
rm -rf / git reset --hard / sudo / mkfs
> /dev/ 设备写入 / dd（命令名）/ kill（命令名）/ reboot / shutdown
```

> `kill`/`dd` 等短词按**命令边界**匹配（命令串开头或 `;` `&` `|` 之后）， 因此 `npm run kill-port`、`git add .`、`ls dd-utils` 这类合法命令不会被误杀。

**敏感命令**（如 `git push`）默认需确认，但可授权后**持久化免问**：在确认框选择 批准（Yes / 本轮会话自动审批通过）后，该次授权写入 `{B_CODE_HOME}/settings.json` 的 `permissions.allow`，下次启动依然生效（无需重复批准）。持久化键按语义取值—— shell 按命令整串、文件类按 `工具:路径`（不按内容），避免"一次批准 = 永久放行整个工具"。

### 各模式的实际边界

|  | plan | default | auto | bypass |
| --- | --- | --- | --- | --- |
| `read` 工具 | ✅ 放行 | ✅ 放行 | ✅ 放行 | ✅ 放行 |
| `write` / `shell` | ⛔ 拦截 | ❓ 确认 | 🤖 分类器裁决 | ✅ 放行 |
| `external`（MCP） | ⛔ 拦截 | ❓ 确认 | ❓ **确认** | ✅ 放行 |
| 危险命令（`rm -rf` 等） | ⛔ 拦截 | ⛔ 拦截 | ⛔ 拦截 | ⛔ **拦截** |
| 敏感命令（`git push`） | ⛔ 拦截 | ❓ 确认 | ❓ **确认** | ❓ **确认** |

两个容易被误解的点：

-   **bypass 不是"什么都放行"**：危险命令仍被 deny（写死在权限层，任何模式绕不过）； `git push` 这类敏感命令即使 bypass 也仍要人工确认。bypass 跳过的是**普通确认框**。
-   **auto 模式不自动放行 MCP 工具**：auto 的分类器只裁决 `write` / `shell` 两类。 MCP 是 `external`，分类器对它的输入（JSON 参数）几乎没有判断力—— 把 `mcp__jira__delete_issue` 交给它，与 `get_issue` 看不出区别，等于盲目放行。 这是刻意的 fail-closed。

### 让 MCP 工具免确认的两条路

1.  **在 `mcp.json` 里声明只读**（推荐给纯读 server）：
    
    ```json
    { "mcpServers": { "docs": { "command": "npx", "args": ["-y", "@x/docs"], "mode": "read" } } }
    ```
    
    该 server 所有工具按 `read` 处理：plan 模式放行、任何模式都免确认。
    
2.  **确认一次，授权整个 server**：在确认框选批准后，MCP 工具的持久化键折叠为 `mcp__<server>__*` 写入白名单——同一个 server 的其他工具不再问（包括 server 升级后新增的工具）。别的 server 不受影响。
    

## 技能（Skills）

把常用提示词包装成 `/name 参数` 命令。技能支持两种形态，技能名 = 文件名 / 目录名：

**平铺文件** `{name}.md` —— 单文件即技能：

```markdown
---
name: commit
description: 用规范格式提交代码
user-invocable: true
---

按以下规范提交：$ARGUMENTS
```

**技能目录** `{name}/SKILL.md` —— 对齐 Claude 生态，目录名即技能名，描述与正文读目录下的 `SKILL.md`（或小写 `skill.md`），目录里的其他文件（reference、模板等）作为技能资源：

```
.claude/skills/
├── commit.md                      # 平铺形态
└── changelog-generator/
    ├── SKILL.md                   # 目录形态：描述 + 正文
    └── templates/                 # 技能资源，不参与解析
```

两种形态的差异：

|  | 平铺文件 | 技能目录 |
| --- | --- | --- |
| 技能名 | 文件名（去 `.md`） | 目录名 |
| `user-invocable` | 需显式写 `true` | 默认可调用，写 `false` 关闭 |
| 同名冲突 | 同目录内平铺优先 | — |

**调用参数透传**：`/技能名 参数1 参数2` 的参数会填进技能正文，技能里调用的工具因此能拿到它们。

| 占位符 | 含义 |
| --- | --- |
| `$ARGUMENTS` | 全部参数（原始字符串） |
| `$1` `$2` … | 第 n 个参数（越界替换为空） |

参数按空白切分，双引号可包裹含空格的多词参数：`/merge "feature/login fix" main`。

```
# .claude/skills/merge/SKILL.md
把分支 $1 合并到 $2，完整请求: $ARGUMENTS
```

**正文里一个占位符都没写时，参数会以 `[调用参数] …` 追加到末尾**——避免技能作者忘了写 `$ARGUMENTS` 导致参数被静默丢弃（技能里的工具就拿不到分支名、路径这类必需值了）。

技能调用优先于普通对话（内置命令如 `/clear` 精确匹配，始终优先）：`/commit 修复登录 bug` → 命中 `commit` 技能并填入参数。

frontmatter 的 `description` 支持块标量多行写法（`>-` 折叠成一行、`|` 保留换行），与 Claude 生态 SKILL.md 兼容。

**搜索链（越靠前优先级越高，同名技能前者生效）：**

1.  `{cwd}/.claude/skills` —— 项目级
2.  `$B_CODE_SKILLS_DIR` —— 显式覆盖（CI / 多环境）
3.  `$B_CODE_HOME/skills` —— 用户级，随数据根迁移
4.  `~/.claude/skills` —— 兼容既有 Claude 生态的兜底

**启用/禁用：** `/skills` 打开交互面板，`↑↓` 选择、`空格` 启停、`Esc` 关闭。 禁用的技能**不进 system prompt**（省 token，模型也不会主动推荐），但手动 `/commit` 依然照常执行——语义是"不主动推给模型"，不是封死。 状态存在 `{B_CODE_HOME}/settings.json` 的 `disabled.skills`（全局生效，跨项目持久）。

## 记忆（Memory）

跨会话长期记忆。模型通过 `save_memory` 工具主动沉淀（经用户确认后落盘），也可以在 REPL 里用 `/remember` 手动保存。

-   **存储**：`{B_CODE_HOME}/projects/{sha256(cwd)前16位}/memory/*.md`
-   **召回**：关键词重叠打分，纯确定性、不调模型；top3 注入 system prompt 末尾
-   **隔离**：同一目录的工作区各自独立记忆

## MCP

基于官方 [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) 接入， 协议细节（JSON-RPC 编解码、版本协商、错误码、超时、session）由 SDK 保证。

**配置搜索链（env 最高优先，同名 server 后者胜）：**

1.  `$B_CODE_MCP_CONFIG` —— 显式覆盖
2.  `{cwd}/.claude/mcp.json` —— 项目级
3.  `{B_CODE_HOME}/mcp.json` —— 用户级

### 两种传输

**本地子进程（stdio）** —— `command` / `args` / `env`：

```json
{
  "mcpServers": {
    "docs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }
  }
}
```

**远程端点（Streamable HTTP）** —— `url` / `headers`：

```json
{
  "mcpServers": {
    "sentry": {
      "url": "https://mcp.sentry.dev/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}
```

同时写了 `command` 和 `url` 时按本地子进程处理。

### 权限模式

每个工具的权限按三级判定（优先级从高到低）：

1.  **server 级 `mode: "read"`** —— 整片声明信任，该 server 所有工具按只读放行
2.  **工具自身的 `annotations.readOnlyHint`** —— MCP 规范的语义标注，可信，自动按只读处理
3.  **缺省 fail-closed** —— `external`，任何写入都需要确认

```json
{ "mcpServers": { "docs": { "command": "npx", "args": ["..."], "mode": "read" } } }
```

`annotations.destructiveHint` 为真的工具会在描述里标 `⚠️ destructive`，让模型自己谨慎。

**确认一次 = 授权整个 server**：在确认框选批准后，白名单写入 `mcp__<server>__*`， 该 server 的其他工具（包括 server 升级后新增的）不再询问。别的 server 不受影响。

### 启用/禁用与重连

`/mcp` 打开交互面板：`↑↓` 选择、`空格` 启停、`R` 重连、`Esc` 关闭。

-   **禁用** = 该 server 的工具从模型可见的 `toolsSchema` 摘掉（不花 token）；连接保持， 重新启用瞬时生效。与技能不同，MCP 没有"手动调用"通道，所以禁用即模型不可见。
-   **重连（`R`）** = 重新建立传输 → 重新握手 → 重新注册工具。用于进程崩了、远程端点 换了 token、或配置文件改了想立刻生效。失败时该 server 的工具会被完全摘除 （不留指向死连接的 handler）。
-   状态存在 `{B_CODE_HOME}/settings.json` 的 `disabled.mcpServers`（全局生效）。

**子进程 stderr 不会污染终端**：传输层把 server 的 stderr 收进日志系统 （`Ctrl+O` 的"日志"页可查），而不是直接继承终端——否则 server 随手一行输出就会 打乱 TUI 画面。

**资源（resources）**：server 若声明 `resources` 能力并返回资源列表，b-code 会把它们 聚合为一个只读工具 `mcp__<server>__read_resource`（参数 `uri`），模型可按 URI 读取 `resources/read` 的内容；不支持资源的 server 自动跳过，不影响工具发现。

### 动态工具与通知

-   **工具热更新**：server 发 `notifications/tools/list_changed` 时，b-code 会重新拉取 工具列表并自动重注册——**不需要手动按 `R` 重连**。用于 server 按需解锁功能的场景。
-   **资源订阅**：server 声明 `resources.subscribe` 时可订阅某 URI，内容变更时收到 `notifications/resources/updated` 推送。

### 反向调用（server → client）

MCP 允许 server 请求客户端代做它自己做不到的事。b-code 默认支持两项：

| 能力 | 作用 | 是否默认开启 |
| --- | --- | --- |
| `roots` | 告诉 server 工作区根目录 | ✅（就用当前工作目录） |
| `sampling` | server 借用宿主模型跑一次补全 | ✅（用当前配置的模型） |
| `elicitation` | server 弹表单问用户 | ❌ 刻意不声明 |

**为什么 sampling 是安全的**：server 没有 LLM 凭证，借我们的模型是规范内的设计； 调用走本 agent 的模型通道，但**不写入会话历史**（旁路调用，不污染对话上下文）。

**为什么不开 elicitation**：那等于让 server 绕过 b-code 的交互与权限体系直接弹窗， 既可能打断用户正在做的事，也会绕过权限确认。等有明确需求再说。

原则是**注入才声明**：不注入宿主能力就不向 server 声明该 capability， server 会据此自行降级，而不是发一个永远没人处理的请求然后超时。

## 任务清单（TodoWrite）

模型可调用 `todo_write` 工具维护一份**结构化任务清单**（`pending` / `in_progress` / `completed`）， 多步任务里据此自我跟踪进度；底部固定面板展示清单与完成度（如 `任务清单 2/5`），跨会话存续。

-   存储：`{B_CODE_HOME}/projects/{sha256(cwd)前16}/todo.json`（按项目隔离）
-   查看：`/todos`；该工具只写自身数据目录，**免权限确认**

> 与工具调用面板（"正在跑什么"）不同，这份清单描述\*\*"要做什么、做到哪了"\*\*。

## 回退（/rewind）

`write_file` / `edit_file` 执行前会自动记录文件前像（检查点），`/rewind` 按逆序还原， 把工程恢复到本次会话改动前（新建的文件会被删除）。回退是**破坏性操作**，会先经确认框确认。

## 生命周期钩子（Hooks）

在 `settings.json` 的 `hooks` 字段配置外部命令，在关键节点自动执行（协议对齐 Claude Code）：

```json
{
  "hooks": {
    "UserPromptSubmit": [{ "command": "node ./hooks/lint-prompt.mjs" }],
    "PreToolUse": [{ "matcher": "^write_|^edit_", "command": "node ./hooks/guard.mjs", "timeoutMs": 10000 }],
    "PostToolUse": [{ "matcher": "^run_shell$", "command": "node ./hooks/notify.mjs" }]
  }
}
```

| 事件 | 时机 | 可否拦截 |
| --- | --- | --- |
| `UserPromptSubmit` | 用户提交、发给模型之前 | ⚠️ 退出码 2 → 原因作为 `[hook notice]` 追加进 prompt |
| `PreToolUse` | 工具执行前（权限通过后） | ✅ 退出码 2 或 stdout 输出 `{"decision":"block","reason":"…"}` → 拦截 |
| `PostToolUse` | 工具执行后 | – stdout 作为 `[PostToolUse hook]` 追加到结果 |

-   事件 JSON 经 **stdin** 传入，`hook_event_name` 区分事件；环境变量 `B_CODE_HOOK_EVENT` 同样可用
-   `matcher` 为工具名正则（仅 Pre/PostToolUse 有意义；缺省匹配全部）
-   命令超时（缺省 60s）、异常、非 2 非 0 退出码一律 **fail-open**（不阻断主流程）

## 配置

### settings.json

配置文件位于 `{B_CODE_HOME}/settings.json`（`B_CODE_CONFIG` 可覆盖路径），复制 `settings.example.json` 后按需填写。

**合并原则：真实环境变量优先，配置只是缺省值** —— 已 export 的键不会被覆盖。

| 字段 | 说明 |
| --- | --- |
| `provider` | `"anthropic"` 或 `"openai"`（缺省按 endpoint 智能判断） |
| `apiKey` | 对应 provider 的密钥 |
| `baseUrl` | 对应 provider 的端点（支持 OpenAI 兼容端点） |
| `model` | 覆盖默认模型名（等价`B_CODE_MODEL`） |
| `env` | `{ KEY: value }` 注入环境变量 |
| `permissions` | `{ "allow": ["…"] }` 持久化白名单（授权"记住不再问"后自动写入） |
| `hooks` | 生命周期钩子（见「生命周期钩子」章节） |

### 环境变量

| 变量 | 说明 |
| --- | --- |
| `B_CODE_HOME` | 数据根目录（必须绝对路径；缺省`~/.b-code`） |
| `B_CODE_CONFIG` | 配置文件路径覆盖 |
| `B_CODE_MODEL` | 模型名覆盖 |
| `B_CODE_MAX_TOKENS` | 单次输出上限 token（缺省 4096） |
| `B_CODE_THINKING` | 正整数时开启 extended thinking（预算 token） |
| `B_CODE_HTTP_TIMEOUT` | OpenAI 兼容后端流式空闲超时 ms（缺省 120000） |
| `B_CODE_SHELL_TIMEOUT` | `run_shell` 命令超时 ms（缺省 30000） |
| `B_CODE_SKILLS_DIR` | 技能目录覆盖 |
| `B_CODE_MCP_CONFIG` | MCP 配置文件覆盖 |
| `B_CODE_LOG_LEVEL` | 日志级别：`debug` / `info` / `warn` / `error` |
| `B_CODE_LOG_FILE` | `true` 时输出日志到文件 |
| `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` | 对应 provider 的密钥 |
| `ANTHROPIC_BASE_URL` / `OPENAI_BASE_URL` | 对应 provider 的端点 |

## 数据目录

启动时自动创建（对齐 Claude Code 的约定目录）：

```
{B_CODE_HOME}/
├── sessions/     # 会话持久化
├── logs/         # 调试日志
├── projects/     # 跨项目记忆 + 任务清单（按项目哈希隔离）
├── skills/       # 用户级技能
├── plans/        # Plan 文件
├── settings.json # 全局配置（含持久化白名单 / hooks）
├── session.json  # 最近一次会话
└── mcp.json      # 用户级 MCP 配置
```

## 开发

依赖 Bun ≥ 1.3.14（OpenTUI 原生 FFI 只支持 Bun 运行时）。

```bash
bun install        # 安装依赖
bun run dev        # 开发运行（直跑 TS 源码）
bun run typecheck  # 类型检查
bun test           # 单元测试
bun run build      # 编译单文件可执行程序 → dist/bcode（当前平台）
./dist/bcode       # 验证产物
```

发布前 `prepublishOnly` 会自动跑类型检查与版本一致性校验（详见「[构建](https://npmcn.com/package/%40bysking/b-code/#readme-%E6%9E%84%E5%BB%BA)」）； 实际构建由 `.github/workflows/release.yml` 的 CI 矩阵在各平台原生完成 （OpenTUI 的跨平台原生包无法在单机上交叉编译）。

## License

MIT

## 常见问题

### @bysking/b-code 是什么？

从零构建的编码助手 — 你自己的 B-Code，运行在终端里（要求 Node\.js \>= 24, 推荐\>=26\.2\.0）

### 如何安装 @bysking/b-code？

在项目目录运行 npm install @bysking/b-code，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 bcode，可以用 npx bcode 直接运行。

### @bysking/b-code 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/bysking\_\_b-code 是否存在。

### @bysking/b-code 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @bysking/b-code 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=24。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @bysking/b-code 可以商用吗？

@bysking/b-code 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @bysking/b-code 的下载量有多少？

根据 npm 官方下载统计，@bysking/b-code 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,978 次，日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @bysking/b-code 还在维护吗？

最新版本 3\.4\.4 发布于 2026/11/07（1 天前）；至今共发布 28 个版本，其中过去 12 个月发布了 28 个；首次发布于 2026/08/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

