Skip to content
Merged
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
203 changes: 203 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

git-ai is a local code understanding tool that builds a semantic layer for codebases using advanced RAG techniques. It combines vector search (LanceDB) with graph-based analysis (CozoDB) to enable AI Agents to deeply understand code structure and relationships beyond simple text search.

**Key Design Principle**: Indices travel with code in Git repos—checkout, branch, or tag any version and the semantic index is immediately available without rebuilding.

## Development Commands

```bash
# Build
npm run build # Compile TypeScript to dist/

# Development run
npm run start -- --help # Run directly with ts-node
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: 开发命令语法可能不正确

npm run start -- --help 这种写法会将 --help 作为参数传递给 npm run,而不是直接传递给 ts-node 执行的程序。这可能不是预期的行为。

建议: 如果要查看 CLI 帮助信息,建议使用 npm run build 然后 node dist/bin/git-ai.js --help,或者确认 start 脚本的实际用途

Suggested change
npm run start -- --help # Run directly with ts-node
# Development run
npm run start # 如果 start 脚本配置正确的话
# 或者直接
node dist/bin/git-ai.js --help


# Testing
npm test # Full test suite (build + E2E)
npm run test:cli # CLI-specific tests
npm run test:parser # Parser verification

# Global install for local testing
npm i -g .
```

**Important**: After building, test with the compiled CLI to verify packaging:
```bash
node dist/bin/git-ai.js --help
```

## Architecture Overview

### Three-Layer Architecture

```
CLI Layer (src/cli/)
Core Layer (src/core/)
Data Layer (LanceDB + CozoDB)
```

**CLI Layer** (`src/cli/`):
- **Commands**: Commander.js command definitions in `cli/commands/`
- **Handlers**: Business logic in `cli/handlers/` (one per command type)
- **Schemas**: Zod validation schemas in `cli/schemas/`
- **Types**: CLI-specific types and the `executeHandler` wrapper in `cli/types.ts`

**Core Layer** (`src/core/`):
- **indexer.ts / indexerIncremental.ts**: Parallel indexing with worker pools
- **lancedb.ts**: Vector database (SQ8-quantized embeddings)
- **cozo.ts / astGraph.ts**: Graph database for AST relationships
- **parser.ts**: Tree-sitter based multi-language parsing
- **embedding.ts**: ONNX-based semantic embeddings
- **search.ts**: Multi-strategy retrieval (vector + graph + hybrid)
- **repoMap.ts**: PageRank-based importance scoring

### Data Flow

**Indexing**: Source files → Tree-sitter AST → Embeddings + Symbol extraction → LanceDB (chunks) + CozoDB (refs)

**Search**: Query → Classification → Multi-strategy retrieval → Reranking → Results

### Standard CLI Output Format

All CLI commands output JSON for agent readability:

**Success**:
```json
{
"ok": true,
"command": "semantic",
"repoRoot": "/path/to/repo",
"timestamp": "2024-01-01T00:00:00Z",
"duration_ms": 123,
"data": { ... }
}
```

**Error**:
```json
{
"ok": false,
"reason": "index_not_found",
"message": "No semantic index found",
"command": "semantic",
"hint": "Run 'git-ai ai index --overwrite' to create an index"
}
```

See `src/cli/types.ts` for `CLIResult`, `CLIError`, `ErrorReasons`, and `ErrorHints`.

Comment on lines +67 to +95
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc section specifies that all CLI success responses include timestamp and duration_ms, but the current handler implementations (e.g., src/cli/handlers/queryFilesHandlers.ts) don’t appear to include these fields in their returned JSON—only in logs. Either update the implementation to match this documented output contract, or adjust the examples/claims here so they reflect actual CLI output.

Copilot uses AI. Check for mistakes.
## Key Files by Purpose

### Entry Points
- `bin/git-ai.ts`: Main CLI—proxies to git for non-AI commands, registers `ai` command
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: 入口文件路径可能不正确

文档中提到 bin/git-ai.ts 是主 CLI 入口,但根据项目结构(src/cli/),入口文件更可能在 src/bin/git-ai.ts 或其他位置。需要确认实际路径。

建议: 确认 CLI 入口文件的实际路径并更新文档

Suggested change
- `bin/git-ai.ts`: Main CLI—proxies to git for non-AI commands, registers `ai` command
- `src/bin/git-ai.ts`: CLI 入口

- `src/commands/ai.ts`: AI command registry (all `git-ai ai *` subcommands)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: AI 命令注册路径可能不正确

文档提到 src/commands/ai.ts 是 AI 命令注册位置,但根据架构概述,CLI 命令应该在 src/cli/ 目录下。路径可能不准确。

建议: 确认 AI 命令注册的实际路径,可能是 src/cli/commands/ai.ts 或类似位置

Suggested change
- `src/commands/ai.ts`: AI command registry (all `git-ai ai *` subcommands)
- `src/cli/commands/ai.ts`: AI 命令注册


### Indexing System
- `src/core/indexer.ts`: Parallel indexing with HNSW vector index
- `src/core/indexerIncremental.ts`: Smart rebuild strategies
- `src/core/parser.ts`: Multi-language Tree-sitter adapters
- `src/core/embedding.ts`: ONNX runtime for local embeddings
- `src/core/lancedb.ts`: LanceDB management (chunks table)
- `src/core/sq8.ts`: Vector quantization for storage efficiency
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined INFO: 文件路径重复提及

sq8.ts 在架构概述中未提及,但在关键文件列表中出现了。虽然列在 LanceDB 相关的文件中,但建议与架构部分保持一致。

建议: 在架构概述的数据层部分提及 sq8.ts,或者在关键文件列表中移除(如果它不是直接相关的)

Suggested change
- `src/core/sq8.ts`: Vector quantization for storage efficiency
# 在 L44 后添加:
Data Layer (LanceDB + CozoDB + SQ8 quantization)


### Search & Retrieval
- `src/core/search.ts`: Query classification and multi-strategy routing
- `src/core/symbolSearch.ts`: Symbol-based search functionality
- `src/core/astGraphQuery.ts`: Graph-based call relationship queries

### Graph Database
- `src/core/cozo.ts`: CozoDB interface (refs table)
- `src/core/astGraph.ts`: AST graph construction

### Repository Management
- `src/core/git.ts`: Git repository handling
- `src/core/workspace.ts`: Workspace path resolution
- `src/core/manifest.ts`: Index versioning and compatibility checking
- `src/core/indexCheck.ts`: Index validation

### Archive & Distribution
- `src/core/archive.ts`: Pack/unpack index archives (.git-ai/lancedb.tar.gz)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: archive.ts 路径可能不正确

文档提到 src/core/archive.ts,但根据 MCP 服务器部分的 src/mcp/ 结构,archive 更可能位于 src/archive/ 或类似位置。

建议: 确认 archive 模块的实际位置并更新文档

Suggested change
- `src/core/archive.ts`: Pack/unpack index archives (.git-ai/lancedb.tar.gz)
- `src/archive/index.ts`: Pack/unpack index archives

- `src/core/lfs.ts`: Git LFS integration for index storage

### MCP Server
- `src/mcp/server.ts`: MCP server implementation (stdio + HTTP modes)
- `src/mcp/handlers/`: MCP tool implementations
- `src/mcp/tools/`: MCP tool registry

## MCP Integration

The MCP Server enables AI Agents to query git-ai indices. All MCP tools require a `path` parameter to specify the target repository—no implicit repository selection for atomic operation.

**Two modes**:
- **stdio mode** (default): Single-agent connection
- **HTTP mode** (`--http`): Multiple concurrent agents with session management

## Language Support

Supported languages are in `src/core/parser.ts`:
- TypeScript/JavaScript (`.ts`, `.tsx`, `.js`, `.jsx`)
- Java (`.java`)
- Python (`.py`)
- Go (`.go`)
- Rust (`.rs`)
- C (`.c`, `.h`)
- Markdown (`.md`, `.mdx`)
- YAML (`.yml`, `.yaml`)

Each language has a separate LanceDB table with its own HNSW index.

## File Filtering

Indexing respects three filter mechanisms (priority order):
1. `.aiignore` - Highest priority, explicit exclusions
2. `.git-ai/include.txt` - Force-include overrides `.gitignore`
3. `.gitignore` - Standard Git ignore patterns

Pattern syntax: `**` (any dirs), `*` (any chars), `directory/` (entire dir)

## Testing

Tests are located in `test/` with multiple formats (`.test.mjs`, `.test.ts`, `.test.js`).

Run single tests with Node's native test runner:
```bash
node --test test/cliCommands.test.js
```

## Native Dependencies

This project uses native modules that may need build tools:
- `@lancedb/lancedb` - Vector database (platform-specific prebuilt binaries)
- `cozo-node` - Graph database
- `onnxruntime-node` - ONNX runtime
- `tree-sitter-*` - Language parsers

If native builds fail, ensure:
- Node.js >= 18
- Build tools installed (Windows: Visual Studio Build Tools, Linux: build-essential)

## Common Tasks

**Add a new CLI command**:
1. Create handler in `src/cli/handlers/yourHandler.ts`
2. Create Zod schema in `src/cli/schemas/` (optional)
3. Register in `src/cli/registry.ts`
4. Add Commander command in `src/cli/commands/yourCommand.ts`
5. Register in `src/commands/ai.ts`

**Add language support**:
1. Add Tree-sitter grammar in `package.json` dependencies
2. Extend `src/core/parser.ts` with new language adapter
3. Test with `npm run test:parser`

**Add MCP tool**:
1. Create handler in `src/mcp/handlers/`
2. Register in `src/mcp/tools/`
3. Export from `src/mcp/server.ts`
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"build": "tsc",
"start": "ts-node bin/git-ai.ts",
"test": "npm run build && node dist/bin/git-ai.js ai index --overwrite && node --test test/*.test.mjs test/*.test.ts",
"test": "npm run build && node dist/bin/git-ai.js ai index --overwrite && node --test test/*.test.mjs test/*.test.ts test/*.test.js",
"test:cli": "bash test-cli.sh",
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm run test:cli is implemented via bash test-cli.sh, which will fail on Windows environments that don’t have bash available. Since this package declares win32 support in package.json, consider making the CLI test runner cross-platform (e.g., a small Node script) or integrating the CLI tests into the existing node --test ... invocation.

Suggested change
"test:cli": "bash test-cli.sh",
"test:cli": "node test-cli.js",

Copilot uses AI. Check for mistakes.
"test:parser": "ts-node test/verify_parsing.ts"
},
"files": [
Expand Down
12 changes: 9 additions & 3 deletions src/cli/handlers/queryFilesHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type { SearchFilesInput } from '../schemas/queryFilesSchemas';
import {
isCLIError,
buildRepoMapAttachment,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 NIT: 未使用的导入可安全移除

filterWorkspaceRowsByLang 导入被移除。如果该函数确实不再使用,这是合理的清理。但建议确认此函数在其他地方是否仍有引用,避免意外删除仍在使用的代码。

建议: 已正确移除。如果 filterWorkspaceRowsByLang 函数在其他文件中也不再使用,建议一并删除该函数定义以保持代码整洁。

filterWorkspaceRowsByLang,
} from './sharedHelpers';

function escapeQuotes(s: string): string {
Expand Down Expand Up @@ -249,11 +248,18 @@ export async function handleSearchFiles(input: SearchFilesInput): Promise<CLIRes

const repoMap = input.withRepoMap ? await buildRepoMapAttachment(ctx.repoRoot, input) : undefined;

const files = rows.map(r => ({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 SUGGESTION: String() 强制转换可能导致意外的类型行为

使用 String(r.file || '') 将字段强制转换为字符串可能掩盖潜在的数据类型问题。如果原始 r.file 是数字或其他类型,这种转换会导致类型信息丢失。

建议: 建议先验证原始数据的类型,或使用类型守卫确保数据符合预期格式后再进行转换。如果确定字段始终是字符串类型,可考虑使用类型断言。

Suggested change
const files = rows.map(r => ({
// 方案1:保持原类型(如果原始数据已是正确类型)
const files = rows.map(r => ({
path: r.file ?? '',
symbol: r.symbol ?? '',
kind: r.kind ?? '',
lang: r.lang ?? '',
}));
// 方案2:添加类型验证
const files = rows.map(r => ({
path: typeof r.file === 'string' ? r.file : String(r.file ?? ''),
symbol: typeof r.symbol === 'string' ? r.symbol : String(r.symbol ?? ''),
kind: typeof r.kind === 'string' ? r.kind : String(r.kind ?? ''),
lang: typeof r.lang === 'string' ? r.lang : String(r.lang ?? ''),
}));

path: String(r.file || ''),
symbol: String(r.symbol || ''),
kind: String(r.kind || ''),
lang: String(r.lang || ''),
}));

return success({
repoRoot: ctx.repoRoot,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 SUGGESTION: count 计算可简化为直接使用 rows.length

新代码先创建 files 数组再用 files.length 计算数量,这在逻辑上正确,但 rows.length 在转换前后值相同,可直接使用以减少一次数组遍历。

建议: 使用 rows.length 代替 files.length,避免不必要的遍历:

return success({
repoRoot: ctx.repoRoot,
count: rows.length, // 直接使用 rows.length
files,
lang: input.lang,
...(repoMap ? { repo_map: repoMap } : {}),
});

Suggested change
repoRoot: ctx.repoRoot,
return success({
repoRoot: ctx.repoRoot,
count: rows.length,
files,
lang: input.lang,
...(repoMap ? { repo_map: repoMap } : {}),
});

count: rows.length,
count: files.length,
lang: input.lang,
rows,
files,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: API 响应字段名变更影响向后兼容性

返回字段从 rows 变更为 files,这可能破坏依赖原字段名的现有客户端或集成。根据语义上下文,此文件被多个测试文件引用,字段名变更会导致测试失败或需要大量修改。

建议: 如果需要保持向后兼容性,考虑同时保留 rowsfiles 两个字段,或者使用版本化 API。如果这是内部使用,请确保调用方已同步更新。

Suggested change
files,
return success({
repoRoot: ctx.repoRoot,
count: files.length,
rows: files, // 保留 rows 以保持兼容
files, // 同时提供新字段
lang: input.lang,
...(repoMap ? { repo_map: repoMap } : {}),
});

...(repoMap ? { repo_map: repoMap } : {}),
Comment on lines 259 to 263

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize workspace query-files payload to files

This branch now returns files, but handleSearchFiles still returns rows when inferWorkspaceRoot(repoRoot) is true (return success({ ...res, rows, ... }) in the workspace path), so the response schema depends on repo type. In manifest workspaces, clients that adopted the new files[].path contract will break even though the same command was called; both branches should emit the same top-level shape (files/count) to keep the CLI API consistent.

Useful? React with 👍 / 👎.

});
Comment on lines 258 to 264
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handler logs duration_ms, and the PR description/CLAUDE.md describe timestamps + duration being included in all CLI JSON outputs, but the returned success({...}) payload here doesn’t include timestamp or duration_ms. If the standardized output format is part of this PR, add those fields to the returned JSON (or ensure a shared wrapper injects them consistently).

Copilot uses AI. Check for mistakes.
} catch (e) {
Expand Down
8 changes: 4 additions & 4 deletions src/core/lfs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { spawnSync } from 'child_process';

function runGit(args: string[], cwd: string) {
const res = spawnSync('git', args, { cwd, stdio: 'inherit' });
function runGit(args: string[], cwd: string, silent: boolean = false) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: 函数签名变更未同步更新文档或类型定义

runGit 函数的签名从 2 个参数变为 3 个参数。虽然添加了默认参数使其向后兼容,但这个变更可能影响其他调用方。

建议: 确保所有调用 runGit 的地方都已检查,特别是如果有其他文件调用此函数。

Suggested change
function runGit(args: string[], cwd: string, silent: boolean = false) {
// 当前实现已通过默认参数保持向后兼容,但建议添加 JSDoc 说明 silent 参数的用途
/**
* @param args - git 命令参数
* @param cwd - 工作目录
* @param silent - 是否静默执行(不输出到 stdio)
*/

const res = spawnSync('git', args, { cwd, stdio: silent ? 'ignore' : 'inherit' });
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed`);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: silent 模式下错误信息丢失

当 silent=true 时,spawnSync 的 stderr 输出被忽略。如果 git 命令失败,用户看不到任何错误原因,只能收到一个模糊的错误消息。这会使调试变得困难。

建议: 在抛出错误时,包含 res.error 和 res.stderr 的信息,以便在 silent 模式下也能提供有意义的错误诊断

Suggested change
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed`);
if (res.status !== 0) {
const msg = res.error?.message || res.stderr?.toString() || '';
throw new Error(`git ${args.join(' ')} failed: ${msg}`);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 SUGGESTION: 未检查 res.error 字段

spawnSync 返回的 res.error 字段(当 spawn 本身失败时,如命令不存在)没有被检查。如果 git 不在 PATH 中,res.status 可能为 null,而错误信息丢失。

建议: 在检查 status 之前先检查 res.error

Suggested change
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed`);
if (res.error) throw new Error(`git spawn failed: ${res.error.message}`);
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed`);

Comment on lines +4 to 5
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When silent is true, spawnSync uses stdio: 'ignore', so any git error output is discarded. If the command fails, the thrown error (git ... failed) provides no stderr/stdout context, which makes diagnosing LFS tracking failures difficult. Consider using stdio: 'pipe' (or at least capturing stderr) in silent mode and include the captured output in the thrown error message while still suppressing normal console noise.

Suggested change
const res = spawnSync('git', args, { cwd, stdio: silent ? 'ignore' : 'inherit' });
if (res.status !== 0) throw new Error(`git ${args.join(' ')} failed`);
const res = spawnSync('git', args, { cwd, stdio: silent ? 'pipe' : 'inherit' });
if (res.status !== 0) {
let details = '';
if (res.stdout) {
const stdout = res.stdout.toString().trim();
if (stdout) details += `\nstdout:\n${stdout}`;
}
if (res.stderr) {
const stderr = res.stderr.toString().trim();
if (stderr) details += `\nstderr:\n${stderr}`;
}
throw new Error(`git ${args.join(' ')} failed${details}`);
}

Copilot uses AI. Check for mistakes.
}

Expand All @@ -18,7 +18,7 @@ export function isGitLfsInstalled(cwd: string): boolean {

export function ensureLfsTracking(cwd: string, pattern: string): { tracked: boolean } {
if (!isGitLfsInstalled(cwd)) return { tracked: false };
runGit(['lfs', 'track', pattern], cwd);
runGit(['add', '.gitattributes'], cwd);
runGit(['lfs', 'track', pattern], cwd, true);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 SUGGESTION: 静默模式可能影响调试体验

ensureLfsTracking 现在静默执行 git lfs track 和 git add 命令。如果操作失败,用户将看不到任何错误输出,只能看到抛出的异常。

建议: 考虑在静默模式下也记录日志,或者提供 verbose 参数让调用方控制输出。

Suggested change
runGit(['lfs', 'track', pattern], cwd, true);
// 可选改进:添加日志记录
runGit(['lfs', 'track', pattern], cwd, true);
// console.debug(`LFS: Tracking pattern ${pattern}`);

runGit(['add', '.gitattributes'], cwd, true);
return { tracked: true };
}
7 changes: 7 additions & 0 deletions test-cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
if [ -f test/cliCommands.test.js ]; then
npm run build && node --test test/cliCommands.test.js
else
echo "cliCommands.test.js not found (skipping CLI tests)"
exit 0
fi
7 changes: 3 additions & 4 deletions test/e2e.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,9 @@ test('git-ai works in Spring Boot and Vue repos', async () => {
runOk('node', [CLI, 'ai', 'agent', 'install'], repo);
assert.ok(runOk('node', [CLI, 'ai', 'agent', 'install', '--overwrite'], repo).status === 0);
{
const skill = await fs.readFile(path.join(repo, '.agents', 'skills', 'git-ai-mcp', 'SKILL.md'), 'utf-8');
const rule = await fs.readFile(path.join(repo, '.agents', 'rules', 'git-ai-mcp', 'RULE.md'), 'utf-8');
assert.ok(skill.includes('git-ai-mcp'));
assert.ok(rule.includes('git-ai-mcp'));
// git-ai-code-search has SKILL.md but no RULE.md, so only check SKILL
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: 测试覆盖范围缩小

原始代码同时验证 SKILL.md 和 RULE.md 两个文件是否存在且包含正确内容,修改后仅验证 SKILL.md。如果 git-ai-code-search 应该同时具有 SKILL 和 RULE 组件,则测试验证不完整。

建议: 确认 git-ai-code-search 确实不需要 RULE.md 文件。如果确实不需要,建议添加注释说明这是预期行为而非遗漏。如果未来可能需要 RULE,建议保留原始断言或添加明确的 TODO 注释

Suggested change
// git-ai-code-search has SKILL.md but no RULE.md, so only check SKILL
// 确认 git-ai-code-search 确实不需要 RULE.md
// TODO: 如果未来添加 RULE.md,需要恢复 RULE 断言
const skill = await fs.readFile(...)

const skill = await fs.readFile(path.join(repo, '.agents', 'skills', 'git-ai-code-search', 'SKILL.md'), 'utf-8');
assert.ok(skill.includes('git-ai-code-search'), 'git-ai-code-search skill should be installed');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 SUGGESTION: 文件读取缺少错误处理

fs.readFile 调用没有 try-catch 包裹,如果文件不存在或读取失败,测试会抛出未处理的 Promise 拒绝而非清晰的断言失败

建议: 使用 try-catch 或断言库的 error expectation 处理可能的文件读取错误

Suggested change
assert.ok(skill.includes('git-ai-code-search'), 'git-ai-code-search skill should be installed');
try {
const skill = await fs.readFile(path.join(repo, '.agents', 'skills', 'git-ai-code-search', 'SKILL.md'), 'utf-8');
assert.ok(skill.includes('git-ai-code-search'), 'git-ai-code-search skill should be installed');
} catch (err) {
assert.fail(`Failed to read SKILL.md: ${err.message}`);
}

}
runOk('git', ['add', '.git-ai/meta.json', '.git-ai/lancedb.tar.gz'], repo);
runOk('git', ['commit', '-m', 'add git-ai index'], repo);
Expand Down
Loading
Loading