Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e514d36
docs:知识库飞轮系统设计roadmap文档
Jun 5, 2026
7455087
feat: phase 1 - agents support, multi-index search, recall subagent &…
Jun 7, 2026
941553f
docs: update roadmap文档
m0Nst3r873 Jun 8, 2026
7e9c7de
feat(search): P1.4 domain inference + search weighting
m0Nst3r873 Jun 8, 2026
16f7ae0
test(validation): add Phase 1 E2E suite and acceptance report
m0Nst3r873 Jun 8, 2026
b2aef31
docs: update roadmap — add P4.6 learning promotion mechanism
m0Nst3r873 Jun 8, 2026
f7dfaad
Merge pull request #1 from m0Nst3r873/worktree-feature+p1.4-domain-in…
m0Nst3r873 Jun 8, 2026
4ef5a07
docs(validation): update phase1 report to reflect E2E bug fix
m0Nst3r873 Jun 8, 2026
b4e4db6
docs(validation): add runtime evidence appendix to phase1 report
m0Nst3r873 Jun 8, 2026
a8a6310
feat(search): query-aware domain weights + IDF scoring (v4 index)
m0Nst3r873 Jun 8, 2026
f95fe7c
feat(import): add teamai import command — Phase 0 cold-start + P4.4 M…
m0Nst3r873 Jun 9, 2026
fec7ced
Merge pull request #2 from m0Nst3r873/worktree-feature+phase0-p44-import
m0Nst3r873 Jun 9, 2026
e791d8b
fix(import): support claude-internal CLI + gh REST API fallback + rea…
m0Nst3r873 Jun 9, 2026
779c4cb
Merge pull request #3 from m0Nst3r873/worktree-feature+phase0-p44-import
m0Nst3r873 Jun 9, 2026
c9eb178
fix(codebase): require file-path prefix in module descriptions for ag…
m0Nst3r873 Jun 9, 2026
336b600
feat(codebase): upgrade workspace + MR prompts to A1-level documentat…
m0Nst3r873 Jun 9, 2026
d76f4a8
docs(validation): replace A1+A4 codebase docs with real teamai-cli ge…
m0Nst3r873 Jun 9, 2026
588ddf0
feat(mr-hint): add SessionStart hook to hint AI about unimported merg…
m0Nst3r873 Jun 10, 2026
d508520
feat(mr-hint): add GitHub REST API fallback when gh CLI unavailable
m0Nst3r873 Jun 10, 2026
2cbc278
docs(validation): update public acceptance report for P4.4 mr-hint tr…
m0Nst3r873 Jun 10, 2026
771a875
feat(ai-client): support login shell PATH + extend CLI candidates
m0Nst3r873 Jun 10, 2026
c1e5e13
docs(validation): update A4 with real before/after codebase demo
m0Nst3r873 Jun 10, 2026
bfba491
Merge pull request #4 from m0Nst3r873/worktree-feature+p4-4-mr-hint
m0Nst3r873 Jun 10, 2026
b4bbb11
fix(providers): add TGit REST API fallback + multi-shell CLI detection
m0Nst3r873 Jun 10, 2026
29da3ee
docs: 验收文档typo更正
m0Nst3r873 Jun 10, 2026
0f58dfc
fix(ai-client): multi-CLI compat + shell injection hardening
m0Nst3r873 Jun 10, 2026
a166ebd
feat(codebase): align with llm-wiki — frontmatter / index / lint / mu…
m0Nst3r873 Jun 10, 2026
a456f9a
Merge pull request #5 from m0Nst3r873/worktree-codebase-llm-wiki-opti…
m0Nst3r873 Jun 10, 2026
d2fca83
feat(search): codebase-index.md high-weight + skip codebase.md
m0Nst3r873 Jun 10, 2026
ff331c2
docs(validation): refresh A1/A4 with llm-wiki-optimized codebase output
m0Nst3r873 Jun 10, 2026
3161efb
docs(validation): replace codebase-after full content with before/aft…
m0Nst3r873 Jun 10, 2026
1777051
docs(roadmap): add Phase 6 — Phase 5 hardening
m0Nst3r873 Jun 11, 2026
888aa5e
feat(import): Phase 5 — team-level codebase aggregation
m0Nst3r873 Jun 11, 2026
8ce2d96
Merge pull request #6 from m0Nst3r873/feature/team-codebase-phase5
m0Nst3r873 Jun 11, 2026
4651a7c
feat(agents): multi-CLI subagent sync + security hardening
m0Nst3r873 Jun 11, 2026
28cacd8
Merge pull request #7 from m0Nst3r873/worktree-feature+multi-cli-suba…
m0Nst3r873 Jun 11, 2026
2580f1e
feat: Phase 6 — Phase 5 hardening pass
m0Nst3r873 Jun 11, 2026
8ab73b7
Merge pull request #8 from m0Nst3r873/feature/team-codebase-phase6
m0Nst3r873 Jun 11, 2026
6e435aa
chore: stop tracking local drafts (roadmap, validation, .codebuddy)
m0Nst3r873 Jun 11, 2026
044e86e
docs(readme): trim subagent phase notes and add Phase 5/6 commands
m0Nst3r873 Jun 11, 2026
bad5cdd
fix(p5-p6): address audit findings — 2 blockers, 1 major, 5 medium
m0Nst3r873 Jun 11, 2026
f533ebc
Merge pull request #9 from m0Nst3r873/worktree-fix-p5-p6-audit
m0Nst3r873 Jun 11, 2026
7a74f92
fix(test): add missing `type` field to recall.test.ts SearchIndexEntr…
m0Nst3r873 Jun 11, 2026
8325e88
fix(test): resolve cross-platform path assertion failures in review-c…
m0Nst3r873 Jun 12, 2026
68f5850
Merge remote-tracking branch 'upstream/main'
m0Nst3r873 Jun 15, 2026
aa869d9
feat(contribute-check): Phase 2 知识库空白感知 + git commit 降权
m0Nst3r873 Jun 15, 2026
c828c44
Merge pull request #10 from m0Nst3r873/worktree-phase2-contribute-check
m0Nst3r873 Jun 15, 2026
2fb0143
chore: MVP 发布前清理——移除 --limit 死选项,import 完成后提示 push
m0Nst3r873 Jun 15, 2026
2ff41ea
chore: AI 调用超时从 2min 调整为 12min
m0Nst3r873 Jun 15, 2026
f1df9ef
fix(test): codebase-lint scaffold 使用 tmpdir 作为 source 路径
m0Nst3r873 Jun 15, 2026
8872c60
fix: 修复 MVP 6 个功能闭环问题
m0Nst3r873 Jun 15, 2026
c73f743
feat(tgit): 支持工蜂 group ID 直接用于 --from-org + fallback 策略
m0Nst3r873 Jun 16, 2026
7fcf5ae
feat: 部署 teamai-recall 规则到所有工具 rules/ 目录
m0Nst3r873 Jun 16, 2026
bedaf29
fix: 修复 import --from-org 产物路径、domain 映射和 AI 废话问题
Jun 16, 2026
3550651
feat: recall rules 明确团队知识库必须通过检索 subagent 访问
Jun 16, 2026
a4ad3c1
feat: recall rules 约束 agent 调用顺序 + codebase docs 搜索放宽
Jun 16, 2026
139ffdc
fix: 统一 user/project scope 索引路径与 hook 注入
Jun 16, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ docs/superpowers/
docs/designs/auto-update.md
docs/designs/ci-pipeline.md
docs/designs/knowledge-feed.md
docs/codebase.md
docs/llm-wiki.md
roadmap_jael.md
validation/
12 changes: 8 additions & 4 deletions agents/teamai-recall.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ upstream API"). Treat this as your query.

### Step 1 — Read the codebase manifest (optional but preferred)

If `~/.teamai/docs/codebase.md` exists, read it first. It lists the team's
repositories and their purposes. Extract a one-sentence repo-list summary
to prepend to your final output. If the file does not exist, **silently
skip** this step — never error out.
If `~/.teamai/docs/codebase.md` OR `docs/team-codebase/index.md` (in the
current project) exists, read it first. It lists the team's repositories
and their purposes. Extract a one-sentence repo-list summary to prepend to
your final output. If neither file exists, **silently skip** this step —
never error out.

> Note: `teamai recall` already indexes team-codebase documents
> (repos/*.md), so Step 3 will return codebase knowledge matches directly.

### Step 2 — Extract keywords from the task description

Expand Down
132 changes: 132 additions & 0 deletions src/__tests__/auto-recall-quality.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { readRecallQuality } from '../auto-recall.js';

function makeTmpDir(): string {
return fs.mkdtempSync(path.join(os.tmpdir(), 'teamai-recall-quality-test-'));
}

describe('readRecallQuality', () => {
let tmpDir: string;
const originalHome = process.env.HOME;

beforeEach(() => {
tmpDir = makeTmpDir();
process.env.HOME = tmpDir;
});

afterEach(() => {
process.env.HOME = originalHome;
fs.rmSync(tmpDir, { recursive: true, force: true });
});

it('returns null when no cache exists', () => {
const result = readRecallQuality('nonexistent-session');
expect(result).toBeNull();
});

it('returns null when cache has zero hit and miss counts', () => {
const sessionId = 'zero-counts-session';
const sessionsDir = path.join(tmpDir, '.teamai', 'sessions');
fs.mkdirSync(sessionsDir, { recursive: true });
fs.writeFileSync(
path.join(sessionsDir, `${sessionId}-recall-cache.json`),
JSON.stringify({
queries: [],
count: 0,
updatedAt: new Date().toISOString(),
topScore: 0,
hitCount: 0,
missCount: 0,
}),
'utf-8',
);

const result = readRecallQuality(sessionId);
expect(result).toBeNull();
});

it('returns quality data when hitCount > 0', () => {
const sessionId = 'hit-session';
const sessionsDir = path.join(tmpDir, '.teamai', 'sessions');
fs.mkdirSync(sessionsDir, { recursive: true });
fs.writeFileSync(
path.join(sessionsDir, `${sessionId}-recall-cache.json`),
JSON.stringify({
queries: ['test'],
count: 1,
updatedAt: new Date().toISOString(),
topScore: 12.5,
hitCount: 2,
missCount: 1,
}),
'utf-8',
);

const result = readRecallQuality(sessionId);
expect(result).toEqual({ topScore: 12.5, hitCount: 2, missCount: 1 });
});

it('returns quality data when missCount > 0 and hitCount is 0', () => {
const sessionId = 'miss-only-session';
const sessionsDir = path.join(tmpDir, '.teamai', 'sessions');
fs.mkdirSync(sessionsDir, { recursive: true });
fs.writeFileSync(
path.join(sessionsDir, `${sessionId}-recall-cache.json`),
JSON.stringify({
queries: ['q1'],
count: 1,
updatedAt: new Date().toISOString(),
topScore: 0,
hitCount: 0,
missCount: 3,
}),
'utf-8',
);

const result = readRecallQuality(sessionId);
expect(result).toEqual({ topScore: 0, hitCount: 0, missCount: 3 });
});

it('handles legacy cache format (missing quality fields) gracefully', () => {
const sessionId = 'legacy-session';
const sessionsDir = path.join(tmpDir, '.teamai', 'sessions');
fs.mkdirSync(sessionsDir, { recursive: true });
fs.writeFileSync(
path.join(sessionsDir, `${sessionId}-recall-cache.json`),
JSON.stringify({
queries: ['old'],
count: 2,
updatedAt: new Date().toISOString(),
}),
'utf-8',
);

const result = readRecallQuality(sessionId);
expect(result).toBeNull();
});

it('returns null for expired cache (TTL exceeded)', () => {
const sessionId = 'expired-session';
const sessionsDir = path.join(tmpDir, '.teamai', 'sessions');
fs.mkdirSync(sessionsDir, { recursive: true });
const expiredAt = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString();
fs.writeFileSync(
path.join(sessionsDir, `${sessionId}-recall-cache.json`),
JSON.stringify({
queries: ['q1'],
count: 1,
updatedAt: expiredAt,
topScore: 8.0,
hitCount: 1,
missCount: 0,
}),
'utf-8',
);

const result = readRecallQuality(sessionId);
expect(result).toBeNull();
});
});
16 changes: 8 additions & 8 deletions src/__tests__/builtin-rules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ describe('builtin-rules', () => {
});

describe('deployBuiltinRules', () => {
it('should clean up legacy teamai-recall.md files', async () => {
// Arrange: create tool rules directories with legacy rule
it('should deploy teamai-recall.md rule to tool rules directory', async () => {
const claudeRulesDir = path.join(tmpDir, '.claude', 'rules');
fs.mkdirSync(claudeRulesDir, { recursive: true });
fs.writeFileSync(path.join(claudeRulesDir, 'teamai-recall.md'), 'old recall rule', 'utf-8');

const teamConfig = {
toolPaths: {
Expand All @@ -42,12 +40,14 @@ describe('builtin-rules', () => {
},
} as any;

// Act
const { deployBuiltinRules } = await import('../builtin-rules.js');
await deployBuiltinRules(teamConfig);

// Assert: legacy file is removed
expect(fs.existsSync(path.join(claudeRulesDir, 'teamai-recall.md'))).toBe(false);
const deployed = path.join(claudeRulesDir, 'teamai-recall.md');
expect(fs.existsSync(deployed)).toBe(true);
const content = fs.readFileSync(deployed, 'utf-8');
expect(content).toContain('Team Knowledge Recall');
expect(content).toContain('teamai recall');
});

it('should skip tool directories that do not exist (tool not installed)', async () => {
Expand Down Expand Up @@ -103,9 +103,9 @@ describe('builtin-rules', () => {
});

describe('BUILTIN_RULE_NAMES', () => {
it('should be empty (no built-in rules deployed after recall rule removal)', async () => {
it('should contain teamai-recall', async () => {
const { BUILTIN_RULE_NAMES } = await import('../builtin-rules.js');
expect(BUILTIN_RULE_NAMES.size).toBe(0);
expect(BUILTIN_RULE_NAMES.has('teamai-recall')).toBe(true);
});
});
});
2 changes: 1 addition & 1 deletion src/__tests__/codebase-lint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async function scaffold(opts: ScaffoldOptions): Promise<void> {
const fm = {
title: 'Codebase 概览',
lastUpdated: isoAgo(1),
source: path.join(os.homedir(), '.teamai', 'cache', 'repos', 'placeholder'),
source: opts.cwd,
generator: 'teamai-cli',
schemaVersion: 1,
...(opts.repoFrontmatter ?? {}),
Expand Down
Loading
Loading