mirror of
https://github.com/Tencent/teamai-cli.git
synced 2026-10-02 03:14:40 +08:00
fix(codebase): point builtin wiki skill at teamai extract
Phase 0 of team-wiki-codebase instructed agents to run a standalone team-wiki CLI that is not shipped with teamai. Use the existing `teamai codebase --extract` path, unhide it in --help, drop the dead GRAPH-CAPABILITIES.md link, and skip later team-wiki-only steps with an English note that no extra plugin is required. Related: #360
This commit is contained in:
@@ -226,6 +226,7 @@ Matched: conflict | Missing: port
|
||||
```bash
|
||||
teamai import --from-repo https://github.com/org/repo
|
||||
teamai import --from-org myorg # batch import all repos
|
||||
teamai codebase --extract /path/to/repo # local extract into teamwiki/
|
||||
teamai codebase --lint # health check
|
||||
```
|
||||
|
||||
@@ -267,6 +268,7 @@ Insight into how the team actually uses its AI tools, and a starting point for t
|
||||
| `teamai recall promote [learningId]` | Promote a high-confidence learning to formal knowledge (skills/rules/docs) |
|
||||
| `teamai recall maintenance` | Maintain knowledge base health: prune low-confidence learnings, writeback confidence scores, flag stale entries |
|
||||
| `teamai import` | Import knowledge (`--dir`, `--from-repo`, `--from-org`, `--from-repo-list`, `--from-mr`) |
|
||||
| `teamai codebase --extract [path]` | Extract code facts and build the local graph under `teamwiki/` |
|
||||
| `teamai codebase --lint` | Knowledge graph health check |
|
||||
| `teamai ci extract-mr --url <url>` | CI: extract knowledge from MR, post comments, write after merge |
|
||||
| `teamai members` | List team members |
|
||||
|
||||
@@ -226,6 +226,7 @@ Matched: conflict | Missing: port
|
||||
```bash
|
||||
teamai import --from-repo https://github.com/org/repo
|
||||
teamai import --from-org myorg # 批量导入所有仓库
|
||||
teamai codebase --extract /path/to/repo # 本地提取到 teamwiki/
|
||||
teamai codebase --lint # 健康检查
|
||||
```
|
||||
|
||||
@@ -267,6 +268,7 @@ WASM 解析器是纯 JavaScript 依赖,无需任何原生编译工具链。若
|
||||
| `teamai recall promote [learningId]` | 将高置信度 learning 晋升为正式知识(skills/rules/docs) |
|
||||
| `teamai recall maintenance` | 维护知识库健康:清理低置信度 learnings、回写置信度、标记过时条目 |
|
||||
| `teamai import` | 导入知识(`--dir`、`--from-repo`、`--from-org`、`--from-repo-list`、`--from-mr`) |
|
||||
| `teamai codebase --extract [path]` | 提取代码事实并在 `teamwiki/` 下构建本地图谱 |
|
||||
| `teamai codebase --lint` | 知识图谱健康检查 |
|
||||
| `teamai ci extract-mr --url <url>` | CI:从 MR 提取知识、发评论、合并后写入 |
|
||||
| `teamai members` | 查看团队成员 |
|
||||
|
||||
@@ -1071,6 +1071,9 @@ The graph stores components, interfaces, configs, and cross-repo dependencies. `
|
||||
Dependency edges are extracted by two parallel tracks: a WASM tree-sitter **AST track** (TypeScript/JavaScript, Python, Go) that resolves imports, calls, and TS `implements` clauses to precise file-to-file edges (`code-ast`), and a regex **heuristic track** (all languages, `code-heuristic`) that also covers languages the AST track does not. AST results win on overlap. The AST parser needs no native toolchain; on load failure, extraction falls back to heuristics and records an `AST_UNAVAILABLE` gap. Set `TEAMAI_SKIP_AST=1` to force heuristic-only extraction.
|
||||
|
||||
```bash
|
||||
# Extract code facts and the graph from a local repo (writes <repo>/teamwiki/)
|
||||
teamai codebase --extract /path/to/repo --project my-service
|
||||
|
||||
# Graph health check
|
||||
teamai codebase --lint
|
||||
```
|
||||
|
||||
@@ -1059,6 +1059,9 @@ teamai import --from-repo https://github.com/org/repo --skip-enrich
|
||||
依赖边由两条并行轨道提取:WASM tree-sitter **AST 轨**(TypeScript/JavaScript、Python、Go),将 import、调用、以及 TS `implements` 子句解析为精确的文件到文件边(`code-ast`);以及正则 **启发式轨**(所有语言,`code-heuristic`),同时覆盖 AST 轨未支持的语言。重叠时 AST 结果优先。AST 解析器无需原生编译工具链;加载失败时提取会降级到启发式并记录一条 `AST_UNAVAILABLE` gap。设置 `TEAMAI_SKIP_AST=1` 可强制仅用启发式提取。
|
||||
|
||||
```bash
|
||||
# 从本地仓库提取代码事实与图谱(写入 <repo>/teamwiki/)
|
||||
teamai codebase --extract /path/to/repo --project my-service
|
||||
|
||||
# 图谱健康检查
|
||||
teamai codebase --lint
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# team-wiki-codebase — 大型代码库 AI 认知工程
|
||||
|
||||
> Team Wiki 插件内置 skill:方法论、脚本与 Agent 规范均随 `team-wiki install` / `upgrade` 部署到项目的 `.codebuddy/`、`.cursor/` 等目录。
|
||||
> TeamAI builtin skill:方法论、脚本与 Agent 规范随 `teamai pull` / `teamai init` 部署到项目的 `.codebuddy/`、`.cursor/` 等目录。TeamAI does not ship a separate team-wiki CLI. No extra plugin is required.
|
||||
|
||||
## 为什么需要这个 skill
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
- 每条组件关系有置信度标注(`EXTRACTED` / `INFERRED` / `AMBIGUOUS`)
|
||||
- 每次生成后有准确性统计,超标自动警告
|
||||
- AI 读知识库而非读源码,**约 1/50 的 token 消耗**获得全局架构认知
|
||||
- Phase 0 可用 `team-wiki compile code --extract ast,heuristic` 生成可证据化的结构边(TS/JS/Python/Go)
|
||||
- Phase 0 可用 `teamai codebase --extract` 生成可证据化的结构边(TS/JS/Python/Go AST + 多语言 heuristic)
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
├── XX_{项目名}产品规则速查表.md
|
||||
├── XX_{项目名}业务开发规范SOP.md
|
||||
├── {反模式/RPC契约/排障记录} × N
|
||||
├── _manifest.json ← 机器可读 manifest(供 team-wiki compile 快路径)
|
||||
├── _manifest.json ← 机器可读 manifest(供后续图谱合并)
|
||||
└── graph/ ← Graph RAG 图谱文档集
|
||||
├── G1 组件依赖关系矩阵
|
||||
├── G2 调用链路全景 + 状态机
|
||||
|
||||
@@ -6,7 +6,7 @@ description: |
|
||||
|
||||
适用场景:项目有 10+ 仓库或微服务,AI 直接读代码无法全局理解、回答不准确、token 开销大。
|
||||
|
||||
产出:组件设计文档 × N + 架构总览 + 桥梁文档 + Graph RAG 图谱(G1~G9) + _manifest.json + team-wiki 编译产物。
|
||||
产出:组件设计文档 × N + 架构总览 + 桥梁文档 + Graph RAG 图谱(G1~G9) + _manifest.json + teamai extract graph (teamwiki/)。
|
||||
|
||||
Trigger: team-wiki-codebase, code-to-knowledge, 代码知识库, 架构分析, 架构逆向
|
||||
Prerequisites: 可访问的源码目录(支持多仓库);本 skill 目录下 `references/` 与 `scripts/`
|
||||
@@ -14,8 +14,8 @@ description: |
|
||||
|
||||
# team-wiki-codebase — 大型代码库 AI 认知工程
|
||||
|
||||
> 方法论与脚本位于本 skill 的 `references/`、`scripts/`(`team-wiki upgrade` 后出现在 `.cursor/skills/team-wiki-codebase/` 或 `.codebuddy/skills/team-wiki-codebase/`)。人类可读概览见 [README.md](./README.md)。
|
||||
> 图谱 CLI 能力见 [GRAPH-CAPABILITIES.md](../GRAPH-CAPABILITIES.md)。
|
||||
> 方法论与脚本位于本 skill 的 `references/`、`scripts/`(`teamai pull` 后出现在 `.cursor/skills/team-wiki-codebase/` 或 `.codebuddy/skills/team-wiki-codebase/`)。人类可读概览见 [README.md](./README.md)。
|
||||
> Phase 0 结构基线使用 `teamai codebase --extract`。TeamAI does not ship a separate team-wiki CLI. No extra plugin is required.
|
||||
|
||||
**解决什么问题**:大型项目(10+ 仓库、数十微服务、迭代多年)让 AI 无法全局理解——上下文窗口装不下所有代码,组件关系散落各处,业务规则隐藏在深层调用链中。直接让 AI 读代码,既慢(海量 token)又不准(缺乏全局视角)。
|
||||
|
||||
@@ -300,22 +300,17 @@ FOR repo in repos:
|
||||
|
||||
**Step 0D:CLI 结构基线(每个代码仓库,推荐)**
|
||||
|
||||
在 K1 深读之前,用 Team Wiki CLI 生成可证据化的 import/call 结构边(Python/Go/TS 等,`code-ast`)并与 regex 基线合并(`code-heuristic`):
|
||||
在 K1 深读之前,用 TeamAI 提取可证据化的 import/call 结构边(Python/Go/TS 等,`code-ast`)并与 regex 基线合并(`code-heuristic`):
|
||||
|
||||
```bash
|
||||
# 对每个 repo(<wiki_root> 通常为项目下的 .teamwiki 或 .wiki)
|
||||
team-wiki compile code <repo_abs_path> <wiki_root> \
|
||||
--project <project_slug> \
|
||||
--extract ast,heuristic \
|
||||
--write
|
||||
|
||||
# 预览 AST 统计(不写盘)
|
||||
team-wiki compile code <repo> <wiki> --extract ast --dry-run
|
||||
# For each repo. Writes <repo>/teamwiki/ (evidence pages + .indices/graph-index.json).
|
||||
# Existing flags only: --extract [path], optional --project <slug>, optional --incremental.
|
||||
teamai codebase --extract <repo_abs_path> --project <project_slug>
|
||||
```
|
||||
|
||||
- 输出:`code/<project>/` 下 index/component/relation 等页;`graph/<project>-graph-index.json`(结构边草案)。
|
||||
- K1/K2/K3 写 `_manifest.json` 的 `edges[]` 时:**优先引用** compile 的 `code-ast` 边 + `evidenceRefs`(`path:line`),Agent 推断标 `INFERRED`/`AMBIGUOUS`。
|
||||
- K3 完成后写入 wiki 图:`team-wiki compile code <output_dir> <wiki_root> --extract ast,heuristic --write`(有 `_manifest.json` 时走 manifest 快路径 merge `graph-index.json`)。
|
||||
- Output: `teamwiki/evidence/code/<project>/` pages; `teamwiki/.indices/graph-index.json` (structural edges).
|
||||
- K1/K2/K3 写 `_manifest.json` 的 `edges[]` 时:**优先引用** extract 的 `code-ast` 边 + `evidenceRefs`(`path:line`),Agent 推断标 `INFERRED`/`AMBIGUOUS`。
|
||||
- After Phase K3, skip any extra graph compile / merge step that is not a `teamai` command. TeamAI does not ship a separate team-wiki CLI. Continue with this skill using `teamai` and the files under this skill directory. No extra plugin is required.
|
||||
|
||||
写入初始 progress.json(current_phase: "phase0_done"),进入 **Phase K1**。
|
||||
|
||||
@@ -889,16 +884,16 @@ _review/ ← 过程文件(不入知识库)
|
||||
|
||||
---
|
||||
|
||||
## 与 Team Wiki CLI 的配合(必读)
|
||||
## 与 TeamAI CLI 的配合(必读)
|
||||
|
||||
| 阶段 | 命令 / 路径 |
|
||||
|------|-------------|
|
||||
| Phase 0 结构基线 | `team-wiki compile code <repo> <wiki> --extract ast,heuristic --write` |
|
||||
| K3 后编译进 wiki | `team-wiki compile code <knowledge_output> <wiki> --write`(检测 `_manifest.json` → manifest 快路径) |
|
||||
| 产品文档入图 | `team-wiki compile docs <docs> <wiki> --extract structure,entity --write` |
|
||||
| 产品↔代码桥接 | `team-wiki reconcile <wiki> --write` |
|
||||
| 一键刷新 | `team-wiki refresh <wiki> --repo <repo> [--docs <docs>] --extract-code ast,heuristic --write` |
|
||||
| 质量评估 | `team-wiki evaluate <wiki>`(含 `graph.structuralEdgeRatio` 等) |
|
||||
| Phase 0 结构基线 | `teamai codebase --extract <repo> --project <slug>`(writes `<repo>/teamwiki/`) |
|
||||
| K3 后编译进 wiki | Skip. TeamAI does not ship a separate team-wiki CLI. Continue with this skill using `teamai` and the files under this skill directory. No extra plugin is required. |
|
||||
| 产品文档入图 | Skip. Same English note as above. |
|
||||
| 产品↔代码桥接 | Skip. Same English note as above. |
|
||||
| 一键刷新 | Use `teamai codebase --extract --incremental` when updating a repo already extracted. Do not look for another CLI. |
|
||||
| 质量评估 | Use `scripts/validate_kb.py` and `teamai codebase --lint` on `teamwiki/`. Skip any extra evaluate binary. |
|
||||
|
||||
**路径约定**(本 skill 安装后):
|
||||
|
||||
@@ -906,4 +901,4 @@ _review/ ← 过程文件(不入知识库)
|
||||
- Agent:`references/agents/kb-doc-generator.md`、`references/agents/graph-rag-agent.md`
|
||||
- 脚本:`scripts/scan_repo.py`、`scripts/validate_kb.py`
|
||||
|
||||
所有流程在本 skill(`references/`、`scripts/`)与 `team-wiki` CLI 内完成。
|
||||
所有流程在本 skill(`references/`、`scripts/`)与 `teamai` CLI 内完成。No extra plugin is required.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
**边类型**: `[CALLS]`(同步RPC/HTTP) / `[PUBLISHES]`(异步MQ) / `[CONSUMES]`(MQ消费) / `[READS]`(DB读) / `[WRITES]`(DB写) / `[CONFIGURES]`(配置驱动) / `[MAPS_TO]`(产品→代码)
|
||||
|
||||
**构建方法**(按可用性排序):
|
||||
1. **`team-wiki compile code --extract ast,heuristic --write`** — Tree-sitter 结构边(**TS/JS/Python/Go** 等)+ 多语言 heuristic 事实页
|
||||
1. **`teamai codebase --extract`** — Tree-sitter 结构边(**TS/JS/Python/Go** 等)+ 多语言 heuristic 事实页(writes `teamwiki/`)
|
||||
2. Grep + Read(Agent K1/K2)— 补充动态路由、配置驱动调用
|
||||
3. 解析编排配置 → 模块→命令映射
|
||||
4. 解析 Proto/IDL/DDL → 数据结构和表关系(结构化文件,可精确解析)
|
||||
@@ -39,7 +39,7 @@
|
||||
6. API 映射 → 外部 API 名称 → 内部 Handler 入口
|
||||
|
||||
> `code-ast` 对相对 import 可产出 `DEPENDS_ON` 边;包级/动态调用仍可能遗漏,标 `[UNVERIFIED]` 或 `AMBIGUOUS`。
|
||||
> 能力 ID 与边优先级见插件内 `GRAPH-CAPABILITIES.md`。
|
||||
> AST 结果优先于 heuristic。There is no separate capabilities doc in this package; use `teamai codebase --extract` output under `teamwiki/`.
|
||||
|
||||
## 输入源优先级
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { describe, it, expect, beforeAll } from 'vitest';
|
||||
import { spawn } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
||||
const CLI = path.join(ROOT, 'dist', 'index.js');
|
||||
|
||||
interface RunResult {
|
||||
code: number | null;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
output: string;
|
||||
}
|
||||
|
||||
function runCLI(args: string[], cwd: string = ROOT): Promise<RunResult> {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn('node', [CLI, ...args], {
|
||||
env: { ...process.env, FORCE_COLOR: '0' },
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
cwd,
|
||||
});
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
child.stdout.on('data', (d: Buffer) => { stdout += d.toString(); });
|
||||
child.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
child.stdin.end();
|
||||
child.on('close', (code) => {
|
||||
resolve({ code, stdout, stderr, output: stdout + stderr });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('teamai codebase extract CLI (issue #360 slice 1)', () => {
|
||||
beforeAll(() => {
|
||||
if (!fs.existsSync(CLI)) {
|
||||
throw new Error(`CLI binary not found at ${CLI}. Run "npm run build" first.`);
|
||||
}
|
||||
});
|
||||
|
||||
it('lists --extract on teamai codebase --help', async () => {
|
||||
const result = await runCLI(['codebase', '--help']);
|
||||
expect(result.code).toBe(0);
|
||||
expect(result.stdout).toContain('--extract');
|
||||
});
|
||||
|
||||
it('extracts a tiny local repo into teamwiki graph output', async () => {
|
||||
const fixture = fs.mkdtempSync(path.join(os.tmpdir(), 'teamai-extract-360-'));
|
||||
try {
|
||||
const srcDir = path.join(fixture, 'src');
|
||||
fs.mkdirSync(srcDir);
|
||||
fs.writeFileSync(
|
||||
path.join(srcDir, 'greet.ts'),
|
||||
'export function greet(name: string): string {\n return `hello ${name}`;\n}\n',
|
||||
);
|
||||
|
||||
const result = await runCLI(
|
||||
['codebase', '--extract', fixture, '--project', 'slice360', '--json', '--max-files', '10'],
|
||||
fixture,
|
||||
);
|
||||
expect(result.code, result.output).toBe(0);
|
||||
|
||||
const graphPath = path.join(fixture, 'teamwiki', '.indices', 'graph-index.json');
|
||||
expect(fs.existsSync(graphPath), result.output).toBe(true);
|
||||
const graph = JSON.parse(fs.readFileSync(graphPath, 'utf8')) as {
|
||||
nodes?: unknown[];
|
||||
edges?: unknown[];
|
||||
};
|
||||
const artifactCount = (graph.nodes?.length ?? 0) + (graph.edges?.length ?? 0);
|
||||
expect(artifactCount).toBeGreaterThan(0);
|
||||
|
||||
const evidenceDir = path.join(fixture, 'teamwiki', 'evidence', 'code', 'slice360');
|
||||
expect(fs.existsSync(evidenceDir)).toBe(true);
|
||||
} finally {
|
||||
fs.rmSync(fixture, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
const SKILL_DIR = path.join(ROOT, 'skills', 'team-wiki-codebase');
|
||||
|
||||
const SKILL_FILES = [
|
||||
path.join(SKILL_DIR, 'SKILL.md'),
|
||||
path.join(SKILL_DIR, 'README.md'),
|
||||
path.join(SKILL_DIR, 'references', 'methodology', 'phase0-collection.md'),
|
||||
] as const;
|
||||
|
||||
const FORBIDDEN_REQUIRED_COMMANDS = [
|
||||
'team-wiki compile code',
|
||||
'team-wiki reconcile',
|
||||
'team-wiki evaluate',
|
||||
'team-wiki compile docs',
|
||||
'team-wiki refresh',
|
||||
] as const;
|
||||
|
||||
describe('team-wiki-codebase builtin skill (issue #360 slice 1)', () => {
|
||||
it('ships the packaged skill files', () => {
|
||||
for (const file of SKILL_FILES) {
|
||||
expect(fs.existsSync(file), file).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('tells Phase 0 to run teamai codebase --extract', () => {
|
||||
for (const file of SKILL_FILES) {
|
||||
const text = fs.readFileSync(file, 'utf8');
|
||||
expect(text, file).toContain('teamai codebase --extract');
|
||||
}
|
||||
});
|
||||
|
||||
it('does not point at GRAPH-CAPABILITIES.md', () => {
|
||||
for (const file of SKILL_FILES) {
|
||||
const text = fs.readFileSync(file, 'utf8');
|
||||
expect(text, file).not.toContain('GRAPH-CAPABILITIES.md');
|
||||
}
|
||||
});
|
||||
|
||||
it('does not require standalone team-wiki CLI commands', () => {
|
||||
for (const file of SKILL_FILES) {
|
||||
const text = fs.readFileSync(file, 'utf8');
|
||||
for (const cmd of FORBIDDEN_REQUIRED_COMMANDS) {
|
||||
expect(text, `${file} must not require ${cmd}`).not.toContain(cmd);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -873,7 +873,7 @@ program
|
||||
program
|
||||
.command('codebase')
|
||||
.description('Inspect and maintain team-codebase outputs')
|
||||
.addOption(new Option('--extract [path]', 'Extract code knowledge and build graph from source').hideHelp())
|
||||
.option('--extract [path]', 'Extract code knowledge and build graph from source')
|
||||
.addOption(new Option('--incremental', 'Only re-extract changed files (requires prior manifest)').hideHelp())
|
||||
.addOption(new Option('--project <name>', 'Project slug for extract output (default: directory name)').hideHelp())
|
||||
.addOption(new Option('--max-files <n>', 'Max source files to scan (default: 200)').hideHelp())
|
||||
|
||||
Reference in New Issue
Block a user