Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions PLANS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Plans

This file tracks multi-step implementation plans for repository work. Keep
entries concise and update them when a task changes scope.

## VS Code Slash Commands And ACP Runtime

Owner: project-lead
Status: active

Acceptance gates:
- Slash command catalog includes canonical commands, aliases, and argument
hints from the agent.
- Commands with subcommands expose keyboard-selectable first-level options.
- `/mcp enable`, `/mcp disable`, and `/mcp reconnect` expose configured server
names as second-level options when known.
- ACP/headless slash command execution completes without relying on terminal
Ink effects.
- Verification includes typecheck, Biome lint, unit tests, extension smoke, and
ACP smoke.

Stop conditions:
- All verification commands pass.
- No known slash-command execution path remains stuck in pending state.
- Any remaining limitation has a concrete owner and test plan.
7 changes: 6 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.13/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down Expand Up @@ -81,6 +81,11 @@
"enabled": false
}
},
"css": {
"parser": {
"tailwindDirectives": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
Expand Down
17 changes: 15 additions & 2 deletions build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DEFAULT_BUILD_FEATURES } from './scripts/defines.ts'
const outdir = 'dist'

// Step 1: Clean output directory
const { rmSync } = await import('fs')
const { existsSync, rmSync } = await import('fs')
rmSync(outdir, { recursive: true, force: true })

// Collect FEATURE_* env vars → Bun.build features
Expand Down Expand Up @@ -80,7 +80,20 @@ const vendorDir = join(outdir, 'vendor', 'audio-capture')
await cp('vendor/audio-capture', vendorDir, { recursive: true })
console.log(`Copied vendor/audio-capture/ → ${vendorDir}/`)

// Step 5: Generate cli-bun and cli-node executable entry points
// Step 5: Copy postinstall-managed ripgrep vendor binary when present.
// If it is absent, runtime falls back to PATH rg so Glob/Grep still work.
const ripgrepSourceDir = join('src', 'utils', 'vendor', 'ripgrep')
if (existsSync(ripgrepSourceDir)) {
const ripgrepVendorDir = join(outdir, 'vendor', 'ripgrep')
await cp(ripgrepSourceDir, ripgrepVendorDir, { recursive: true })
console.log(`Copied ${ripgrepSourceDir}/ → ${ripgrepVendorDir}/`)
} else {
console.warn(
`Skipped ripgrep vendor copy: ${ripgrepSourceDir}/ does not exist`,
)
}

// Step 6: Generate cli-bun and cli-node executable entry points
const cliBun = join(outdir, 'cli-bun.js')
const cliNode = join(outdir, 'cli-node.js')

Expand Down
1,060 changes: 241 additions & 819 deletions bun.lock

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions codex-slash-bug-trace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
| Hypothesis | Verdict | Evidence |
| --- | --- | --- |
| CSP/nonce blocks webview script | Rejected | `packages/vscode-extension/src/ChatViewProvider.ts:48-52` enables scripts and allows `dist`; `:603-617` creates a nonce and uses the same nonce on `dist/webview.js`. `packages/vscode-extension/dist/webview.js` exists. Seeing "No matching command" also means React mounted. |
| `acquireVsCodeApi` singleton throws | Rejected | `webview/hooks/useVSCodeAPI.ts:10-14` calls it once at module scope; `rg` shows only `useACP.ts:36,260` imports/uses the hook. |
| `isFromExtension` rejects valid messages | Rejected | `webview/lib/protocol.ts:86-92` accepts any object whose string `type` starts with `ext:`; it is not strict-equal to one literal. |
| Wrong prop name into PromptInput | Rejected | `App.tsx:113-119` passes `availableCommands`; `PromptInput.tsx:30-36` destructures it; `:299-303` passes it as `commands` to `CommandMenu`. |
| CommandMenu keydown masks empty list | Rejected | `CommandMenu.tsx:41-61` listens only to `keydown` and only when visible plus non-empty filtered results; it cannot block `window.message`. |
| `makeClient()` returns stale clients | Rejected | `ACPClient.ts:184` creates one `ClientSideConnection`; SDK `acp.js:467-538` calls `toClient(this)` once and stores that `client`. |
| `ndJsonStream` direction flipped | Rejected | SDK `stream.d.ts:20-24` wants writable output then readable input. `ACPClient.ts:180-182` passes child stdin writable, then child stdout readable. Names are confusing; order is correct. |

Final root cause: the real break is a readiness race where extension-host messages can be dropped because the webview HTML is assigned before the host receive listener is registered, and extension-to-webview sends are fire-and-forget with no ready queue.

Evidence: `ChatViewProvider.ts:46-55` sets `webview.html` before `onDidReceiveMessage`; the webview posts `ext:webview_ready` immediately after adding its own listener in `useACP.ts:279-299`. Command replay only starts if that ready message reaches `handleWebviewMessage` (`ChatViewProvider.ts:170-207`, `:585-599`). Meanwhile direct command pushes are one-shot (`:489-498`) and `postToWebview` ignores the returned thenable/ready state (`:576-577`). If `ext:webview_ready` or the one-shot `available_commands_update` lands during that gap, the reducer never sees commands, leaving `CommandMenu` with `commands.length === 0` (`CommandMenu.tsx:22-26`, `:70-80`).

Minimal patch suggestion: register `webview.onDidReceiveMessage` before assigning `webview.html`, add `private webviewReady = false`, set it true on `ext:webview_ready`, and make `postToWebview` queue `ext:available_commands`/state replay messages until ready, flushing on ready. Also await/log `webview.postMessage(...)` false results.
171 changes: 171 additions & 0 deletions docs/features/vscode-extension-installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# VS Code 插件安装指南

本文面向需要安装 `CCB - Claude Code Best` VS Code 插件的用户。

插件本身是 VS Code 侧边栏 UI;实际 agent 由本机的 CCB/Claude Code Best CLI 进程提供。安装插件前,建议先确认 CLI 可以在当前机器运行。

## 安装前准备

1. 安装 VS Code `1.85.0` 或更高版本。
2. 安装并构建本项目 CLI,或准备一个可执行的 CCB CLI 路径。
3. 在终端中确认 CLI 可运行:

```powershell
ccb --version
```

如果系统没有 `ccb` 命令,也可以在插件设置里手动配置 `ccb.cliPath` 指向 CLI 可执行文件。

## 方式一:安装 VSIX 包

如果你拿到的是发布者提供的 `.vsix` 文件,这是推荐给普通用户的安装方式。

### VS Code 界面安装

1. 打开 VS Code。
2. 打开 Extensions 视图。
3. 点击右上角 `...`。
4. 选择 `Install from VSIX...`。
5. 选择发布者提供的 `.vsix` 文件。
6. 完全退出 VS Code 后重新打开。

### 命令行安装

Windows PowerShell:

```powershell
code --install-extension .\ccb-vscode-0.3.0.vsix --force
```

macOS/Linux:

```bash
code --install-extension ./ccb-vscode-0.3.0.vsix --force
```

安装后重新打开 VS Code,左侧 Activity Bar 应出现 `CCB` 图标。

## 方式二:从源码安装到本机 VS Code

这是开发者或内测用户使用的方式。它会把 `packages/vscode-extension` 链接到本机 VS Code 扩展目录。

在仓库根目录先构建 CLI:

```powershell
bun run build
```

然后构建并安装 VS Code 插件。

Windows:

```powershell
cd packages\vscode-extension
bun run install-local:win
```

macOS/Linux:

```bash
cd packages/vscode-extension
bun run install-local
```

安装完成后必须完全退出 VS Code,再重新打开。只执行 `Reload Window` 不一定能更新扩展宿主进程中的旧代码。

## 配置 CLI 路径

插件默认使用:

```text
ccb.cliPath = auto
```

`auto` 会按以下优先级探测 CLI:

1. 当前仓库构建产物。
2. 开发入口。
3. `PATH` 中的 `ccb` / `claude-code-best` 命令。

如果自动探测失败,在 VS Code 设置中搜索 `CCB: Cli Path`,填入明确路径。

示例:

```json
{
"ccb.cliPath": "E:\\Source_code\\Claude-code-bast-vscode-extension\\dist\\cli-node.js"
}
```

## 基础验证

安装后按以下步骤确认插件可用:

1. 打开一个项目文件夹。
2. 点击左侧 `CCB` 图标。
3. 输入 `/help`,确认能返回斜杠菜单说明。
4. 输入 `/login`,确认能看到登录 provider 选项。
5. 输入 `/mcp`,确认能列出 MCP servers。
6. 如果需要 Chrome MCP,输入:

```text
/mcp tools claude-in-chrome
```

正常情况下应能看到 `tabs_context_mcp` 等 Chrome MCP 工具。

## 发布包不包含源码

发布 VSIX 时使用 `packages/vscode-extension/.vscodeignore` 控制包内容。

当前发布包只包含:

```text
package.json
resources/icon.svg
dist/webview.js
dist/extension.js
```

不会包含:

```text
src/
webview/
scripts/
node_modules/
tsconfig.json
esbuild.config.mjs
*.map
```

发布前可在 `packages/vscode-extension` 下运行:

```powershell
npx @vscode/vsce ls --no-dependencies
```

确认 VSIX 内容仍然只有 manifest、资源和编译产物。

## 卸载

VS Code 界面卸载:

1. 打开 Extensions。
2. 搜索 `CCB - Claude Code Best`。
3. 点击 Uninstall。
4. 重启 VS Code。

命令行卸载:

```powershell
code --uninstall-extension claude-code-best.ccb-vscode
```

如果使用源码本地安装脚本,Windows 下扩展目录通常是:

```text
C:\Users\<用户名>\.vscode\extensions\claude-code-best.ccb-vscode-0.3.0
```

删除该目录或 junction 后重启 VS Code 即可。
Loading
Loading