jfox-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jfox_cli-0.1.0/.githooks/pre-push +22 -0
- jfox_cli-0.1.0/.github/workflows/integration-test.yml +215 -0
- jfox_cli-0.1.0/.github/workflows/publish.yml +26 -0
- jfox_cli-0.1.0/.gitignore +33 -0
- jfox_cli-0.1.0/.python-version +1 -0
- jfox_cli-0.1.0/AGENTS.md +399 -0
- jfox_cli-0.1.0/CLAUDE.md +131 -0
- jfox_cli-0.1.0/DEVELOPMENT_PLAN.md +467 -0
- jfox_cli-0.1.0/PKG-INFO +637 -0
- jfox_cli-0.1.0/README.md +600 -0
- jfox_cli-0.1.0/SESSION.md +100 -0
- jfox_cli-0.1.0/SESSION_SUMMARY.md +308 -0
- jfox_cli-0.1.0/docs/superpowers/specs/2026-04-03-bugfixes-design.md +34 -0
- jfox_cli-0.1.0/jessica-jones-static-cable.md +761 -0
- jfox_cli-0.1.0/jfox/__init__.py +5 -0
- jfox_cli-0.1.0/jfox/__main__.py +6 -0
- jfox_cli-0.1.0/jfox/bm25_index.py +388 -0
- jfox_cli-0.1.0/jfox/cli.py +1895 -0
- jfox_cli-0.1.0/jfox/config.py +180 -0
- jfox_cli-0.1.0/jfox/embedding_backend.py +65 -0
- jfox_cli-0.1.0/jfox/formatters.py +305 -0
- jfox_cli-0.1.0/jfox/global_config.py +281 -0
- jfox_cli-0.1.0/jfox/graph.py +331 -0
- jfox_cli-0.1.0/jfox/indexer.py +366 -0
- jfox_cli-0.1.0/jfox/kb_manager.py +316 -0
- jfox_cli-0.1.0/jfox/models.py +144 -0
- jfox_cli-0.1.0/jfox/note.py +464 -0
- jfox_cli-0.1.0/jfox/performance.py +408 -0
- jfox_cli-0.1.0/jfox/search_engine.py +237 -0
- jfox_cli-0.1.0/jfox/template.py +301 -0
- jfox_cli-0.1.0/jfox/template_cli.py +327 -0
- jfox_cli-0.1.0/jfox/vector_store.py +200 -0
- jfox_cli-0.1.0/pyproject.toml +69 -0
- jfox_cli-0.1.0/pytest.ini +33 -0
- jfox_cli-0.1.0/run_full_test.ps1 +214 -0
- jfox_cli-0.1.0/skill/evals/evals.json +185 -0
- jfox_cli-0.1.0/skill/knowledge-base-notes/SKILL.md +278 -0
- jfox_cli-0.1.0/skill/knowledge-base-workspace/SKILL.md +242 -0
- jfox_cli-0.1.0/tests/COVERAGE_PLAN.md +455 -0
- jfox_cli-0.1.0/tests/MIGRATION.md +171 -0
- jfox_cli-0.1.0/tests/TESTS.md +342 -0
- jfox_cli-0.1.0/tests/conftest.py +295 -0
- jfox_cli-0.1.0/tests/integration/__init__.py +0 -0
- jfox_cli-0.1.0/tests/integration/test_backlinks.py +154 -0
- jfox_cli-0.1.0/tests/performance/__init__.py +0 -0
- jfox_cli-0.1.0/tests/performance/test_performance.py +317 -0
- jfox_cli-0.1.0/tests/test_advanced_features.py +180 -0
- jfox_cli-0.1.0/tests/test_cli_format.py +313 -0
- jfox_cli-0.1.0/tests/test_config_unit.py +243 -0
- jfox_cli-0.1.0/tests/test_core_workflow.py +565 -0
- jfox_cli-0.1.0/tests/test_hybrid_search.py +273 -0
- jfox_cli-0.1.0/tests/test_integration.py +56 -0
- jfox_cli-0.1.0/tests/test_kb_current.py +109 -0
- jfox_cli-0.1.0/tests/test_suggest_links.py +125 -0
- jfox_cli-0.1.0/tests/unit/__init__.py +0 -0
- jfox_cli-0.1.0/tests/unit/test_formatters.py +294 -0
- jfox_cli-0.1.0/tests/unit/test_global_config.py +513 -0
- jfox_cli-0.1.0/tests/unit/test_kb_manager.py +478 -0
- jfox_cli-0.1.0/tests/unit/test_template.py +156 -0
- jfox_cli-0.1.0/tests/unit/test_template_cli.py +605 -0
- jfox_cli-0.1.0/tests/utils/__init__.py +1 -0
- jfox_cli-0.1.0/tests/utils/assertions.py +177 -0
- jfox_cli-0.1.0/tests/utils/jfox_cli.py +404 -0
- jfox_cli-0.1.0/tests/utils/note_generator.py +344 -0
- jfox_cli-0.1.0/tests/utils/temp_kb.py +140 -0
- jfox_cli-0.1.0/uv.lock +3579 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# JFox pre-push hook: push 前自动跑快速单元测试
|
|
3
|
+
# 只跑不涉及 embedding/ChromaDB 的单元测试,几秒内完成
|
|
4
|
+
# 如果需要跳过(紧急情况),使用: git push --no-verify
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo "[pre-push] Running fast unit tests..."
|
|
9
|
+
|
|
10
|
+
# 只跑非 embedding 非 slow 的测试,排除已知的 template_cli 失败
|
|
11
|
+
python -m pytest tests/unit/ -m "not embedding and not slow" \
|
|
12
|
+
--timeout=30 -q --tb=short --no-header \
|
|
13
|
+
--ignore=tests/unit/test_template_cli.py 2>&1
|
|
14
|
+
|
|
15
|
+
if [ $? -ne 0 ]; then
|
|
16
|
+
echo ""
|
|
17
|
+
echo "[pre-push] FAILED! Fix tests before pushing."
|
|
18
|
+
echo "[pre-push] Skip with: git push --no-verify"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
echo "[pre-push] All tests passed. Pushing..."
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
name: Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, develop ]
|
|
6
|
+
paths:
|
|
7
|
+
- 'jfox/**'
|
|
8
|
+
- 'tests/**'
|
|
9
|
+
- 'pyproject.toml'
|
|
10
|
+
- '.github/workflows/integration-test.yml'
|
|
11
|
+
pull_request:
|
|
12
|
+
branches: [ main, develop ]
|
|
13
|
+
paths:
|
|
14
|
+
- 'jfox/**'
|
|
15
|
+
- 'tests/**'
|
|
16
|
+
- 'pyproject.toml'
|
|
17
|
+
# 允许手动触发
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
test_type:
|
|
21
|
+
description: 'Test type to run'
|
|
22
|
+
required: true
|
|
23
|
+
default: 'fast'
|
|
24
|
+
type: choice
|
|
25
|
+
options:
|
|
26
|
+
- fast # 快速测试(跳过 embedding)
|
|
27
|
+
- full # 全量测试
|
|
28
|
+
- core # 核心测试
|
|
29
|
+
|
|
30
|
+
env:
|
|
31
|
+
# 设置 UTF-8 编码,避免 Windows 上的编码错误
|
|
32
|
+
PYTHONIOENCODING: utf-8
|
|
33
|
+
PYTHONUTF8: 1
|
|
34
|
+
|
|
35
|
+
jobs:
|
|
36
|
+
# ============ 快速测试(PR 和 push 触发)============
|
|
37
|
+
test-fast:
|
|
38
|
+
runs-on: ${{ matrix.os }}
|
|
39
|
+
if: github.event_name != 'workflow_dispatch' || github.event.inputs.test_type == 'fast'
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
os: [ubuntu-latest, windows-latest]
|
|
44
|
+
python-version: ['3.11']
|
|
45
|
+
|
|
46
|
+
steps:
|
|
47
|
+
- name: Checkout code
|
|
48
|
+
uses: actions/checkout@v4
|
|
49
|
+
|
|
50
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
51
|
+
uses: actions/setup-python@v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: ${{ matrix.python-version }}
|
|
54
|
+
|
|
55
|
+
- uses: astral-sh/setup-uv@v4
|
|
56
|
+
with:
|
|
57
|
+
version: "latest"
|
|
58
|
+
enable-cache: true
|
|
59
|
+
|
|
60
|
+
- name: Install dependencies
|
|
61
|
+
run: uv sync --extra dev
|
|
62
|
+
|
|
63
|
+
- name: Run fast tests (no embedding)
|
|
64
|
+
run: |
|
|
65
|
+
# 运行非 embedding 测试(单进程避免知识库冲突)
|
|
66
|
+
uv run pytest tests/ -m "not embedding and not slow" --timeout=180 -v --tb=short
|
|
67
|
+
timeout-minutes: ${{ matrix.os == 'windows-latest' && 50 || 20 }}
|
|
68
|
+
env:
|
|
69
|
+
PYTHONIOENCODING: utf-8
|
|
70
|
+
PYTHONUTF8: 1
|
|
71
|
+
|
|
72
|
+
- name: Upload test results
|
|
73
|
+
if: always()
|
|
74
|
+
uses: actions/upload-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: test-results-fast-${{ matrix.os }}-py${{ matrix.python-version }}
|
|
77
|
+
path: |
|
|
78
|
+
.pytest_cache/
|
|
79
|
+
htmlcov/
|
|
80
|
+
|
|
81
|
+
# ============ 核心测试(带 embedding,但只跑核心)============
|
|
82
|
+
test-core:
|
|
83
|
+
runs-on: ${{ matrix.os }}
|
|
84
|
+
if: github.ref == 'refs/heads/main' || github.event.inputs.test_type == 'core' || github.event.inputs.test_type == 'full'
|
|
85
|
+
strategy:
|
|
86
|
+
fail-fast: false
|
|
87
|
+
matrix:
|
|
88
|
+
os: [ubuntu-latest, windows-latest]
|
|
89
|
+
python-version: ['3.10', '3.12']
|
|
90
|
+
|
|
91
|
+
steps:
|
|
92
|
+
- name: Checkout code
|
|
93
|
+
uses: actions/checkout@v4
|
|
94
|
+
|
|
95
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
96
|
+
uses: actions/setup-python@v5
|
|
97
|
+
with:
|
|
98
|
+
python-version: ${{ matrix.python-version }}
|
|
99
|
+
|
|
100
|
+
- uses: astral-sh/setup-uv@v4
|
|
101
|
+
with:
|
|
102
|
+
version: "latest"
|
|
103
|
+
enable-cache: true
|
|
104
|
+
|
|
105
|
+
- name: Cache model
|
|
106
|
+
uses: actions/cache@v4
|
|
107
|
+
with:
|
|
108
|
+
path: ~/.cache/torch/sentence_transformers
|
|
109
|
+
key: ${{ runner.os }}-sentence-transformers-all-MiniLM-L6-v2
|
|
110
|
+
|
|
111
|
+
- name: Install dependencies
|
|
112
|
+
run: uv sync --extra dev
|
|
113
|
+
|
|
114
|
+
- name: Run core tests
|
|
115
|
+
run: |
|
|
116
|
+
# 只跑核心工作流测试,单进程避免模型加载冲突
|
|
117
|
+
uv run pytest tests/test_core_workflow.py tests/test_integration.py -v --timeout=400 --tb=short
|
|
118
|
+
timeout-minutes: ${{ matrix.os == 'windows-latest' && 50 || 25 }}
|
|
119
|
+
env:
|
|
120
|
+
PYTHONIOENCODING: utf-8
|
|
121
|
+
PYTHONUTF8: 1
|
|
122
|
+
|
|
123
|
+
- name: Upload test results
|
|
124
|
+
if: always()
|
|
125
|
+
uses: actions/upload-artifact@v4
|
|
126
|
+
with:
|
|
127
|
+
name: test-results-core-${{ matrix.os }}-py${{ matrix.python-version }}
|
|
128
|
+
path: |
|
|
129
|
+
.pytest_cache/
|
|
130
|
+
|
|
131
|
+
# ============ 全量测试(仅 main 分支或手动触发)============
|
|
132
|
+
test-full:
|
|
133
|
+
runs-on: ${{ matrix.os }}
|
|
134
|
+
if: github.event.inputs.test_type == 'full'
|
|
135
|
+
strategy:
|
|
136
|
+
fail-fast: false
|
|
137
|
+
matrix:
|
|
138
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
139
|
+
python-version: ['3.10', '3.11', '3.12']
|
|
140
|
+
|
|
141
|
+
steps:
|
|
142
|
+
- name: Checkout code
|
|
143
|
+
uses: actions/checkout@v4
|
|
144
|
+
|
|
145
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
146
|
+
uses: actions/setup-python@v5
|
|
147
|
+
with:
|
|
148
|
+
python-version: ${{ matrix.python-version }}
|
|
149
|
+
|
|
150
|
+
- uses: astral-sh/setup-uv@v4
|
|
151
|
+
with:
|
|
152
|
+
version: "latest"
|
|
153
|
+
enable-cache: true
|
|
154
|
+
|
|
155
|
+
- name: Cache model
|
|
156
|
+
uses: actions/cache@v4
|
|
157
|
+
with:
|
|
158
|
+
path: ~/.cache/torch/sentence_transformers
|
|
159
|
+
key: ${{ runner.os }}-sentence-transformers-all-MiniLM-L6-v2
|
|
160
|
+
|
|
161
|
+
- name: Install dependencies
|
|
162
|
+
run: uv sync --extra dev
|
|
163
|
+
|
|
164
|
+
- name: Run full test suite
|
|
165
|
+
run: |
|
|
166
|
+
# 全量测试,单进程(避免模型加载问题)
|
|
167
|
+
uv run pytest tests/ -v --timeout=600 --tb=short
|
|
168
|
+
timeout-minutes: 60
|
|
169
|
+
env:
|
|
170
|
+
PYTHONIOENCODING: utf-8
|
|
171
|
+
PYTHONUTF8: 1
|
|
172
|
+
|
|
173
|
+
- name: Upload test results
|
|
174
|
+
if: always()
|
|
175
|
+
uses: actions/upload-artifact@v4
|
|
176
|
+
with:
|
|
177
|
+
name: test-results-full-${{ matrix.os }}-py${{ matrix.python-version }}
|
|
178
|
+
path: |
|
|
179
|
+
.pytest_cache/
|
|
180
|
+
|
|
181
|
+
# ============ 覆盖率报告汇总 ============
|
|
182
|
+
coverage:
|
|
183
|
+
runs-on: ubuntu-latest
|
|
184
|
+
needs: [test-fast]
|
|
185
|
+
if: always() && needs.test-fast.result == 'success'
|
|
186
|
+
|
|
187
|
+
steps:
|
|
188
|
+
- name: Checkout code
|
|
189
|
+
uses: actions/checkout@v4
|
|
190
|
+
|
|
191
|
+
- name: Set up Python
|
|
192
|
+
uses: actions/setup-python@v5
|
|
193
|
+
with:
|
|
194
|
+
python-version: '3.11'
|
|
195
|
+
|
|
196
|
+
- uses: astral-sh/setup-uv@v4
|
|
197
|
+
with:
|
|
198
|
+
version: "latest"
|
|
199
|
+
enable-cache: true
|
|
200
|
+
|
|
201
|
+
- name: Install dependencies
|
|
202
|
+
run: uv sync --extra dev
|
|
203
|
+
|
|
204
|
+
- name: Run coverage
|
|
205
|
+
run: |
|
|
206
|
+
uv run pytest tests/ -m "not embedding and not slow" --cov=jfox --cov-report=xml --cov-report=html -v --timeout=300
|
|
207
|
+
timeout-minutes: 25
|
|
208
|
+
|
|
209
|
+
- name: Upload coverage report
|
|
210
|
+
uses: actions/upload-artifact@v4
|
|
211
|
+
with:
|
|
212
|
+
name: coverage-report
|
|
213
|
+
path: |
|
|
214
|
+
htmlcov/
|
|
215
|
+
coverage.xml
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
pypi-publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout code
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: astral-sh/setup-uv@v4
|
|
19
|
+
with:
|
|
20
|
+
version: "latest"
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: uv build
|
|
24
|
+
|
|
25
|
+
- name: Publish to PyPI
|
|
26
|
+
run: uv publish
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Worktrees directory
|
|
2
|
+
.worktrees/
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.so
|
|
9
|
+
.Python
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
venv/
|
|
16
|
+
.venv/
|
|
17
|
+
env/
|
|
18
|
+
ENV/
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
25
|
+
|
|
26
|
+
# Testing
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
jfox_cli-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# AGENTS.md - JFox 项目指南
|
|
2
|
+
|
|
3
|
+
> 本文档面向 AI 编程助手。项目语言:中文(注释和文档主要使用中文)
|
|
4
|
+
|
|
5
|
+
## 项目概述
|
|
6
|
+
|
|
7
|
+
**JFox** 是一个基于 Zettelkasten(卡片盒)方法的命令行知识管理工具。
|
|
8
|
+
|
|
9
|
+
- **项目定位**: 本地优先的个人知识库软件
|
|
10
|
+
- **核心价值**: 通过双向链接、语义搜索和知识图谱,帮助用户构建可生长的知识网络
|
|
11
|
+
- **技术特点**: 纯 CPU 运行,无需 GPU/NPU,数据完全本地存储
|
|
12
|
+
|
|
13
|
+
### 为什么叫 JFox?
|
|
14
|
+
- **J** - 创始人名字 "Jiefeng" 的首字母
|
|
15
|
+
- **Fox** - 谐音 "Box"(盒子),呼应卡片盒本质;狐狸象征聪明、机敏
|
|
16
|
+
|
|
17
|
+
## 技术栈
|
|
18
|
+
|
|
19
|
+
| 类别 | 技术 |
|
|
20
|
+
|------|------|
|
|
21
|
+
| 语言 | Python >= 3.10 |
|
|
22
|
+
| CLI 框架 | Typer >= 0.12.0 |
|
|
23
|
+
| 终端美化 | Rich >= 13.0.0 |
|
|
24
|
+
| 文本嵌入 | sentence-transformers >= 3.0 (all-MiniLM-L6-v2) |
|
|
25
|
+
| 向量数据库 | ChromaDB >= 0.5.0 |
|
|
26
|
+
| 知识图谱 | NetworkX >= 3.0 |
|
|
27
|
+
| 文件监控 | Watchdog >= 3.0 |
|
|
28
|
+
| 配置管理 | PyYAML >= 6.0, Pydantic >= 2.0 |
|
|
29
|
+
| 模板引擎 | Jinja2 >= 3.1.0 |
|
|
30
|
+
|
|
31
|
+
## 项目结构
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
jfox/
|
|
35
|
+
├── pyproject.toml # Python 项目配置
|
|
36
|
+
├── README.md # 详细文档(中文)
|
|
37
|
+
├── run_full_test.ps1 # 全量测试脚本(PowerShell)
|
|
38
|
+
├── jfox/ # 主包
|
|
39
|
+
│ ├── __init__.py
|
|
40
|
+
│ ├── __main__.py # 入口点
|
|
41
|
+
│ ├── cli.py # CLI 主程序(所有命令)
|
|
42
|
+
│ ├── models.py # 数据模型(Note, NoteType)
|
|
43
|
+
│ ├── config.py # 配置管理(ZKConfig, use_kb)
|
|
44
|
+
│ ├── global_config.py # 全局配置管理(多知识库)
|
|
45
|
+
│ ├── note.py # 笔记 CRUD 操作
|
|
46
|
+
│ ├── kb_manager.py # 知识库管理器
|
|
47
|
+
│ ├── embedding_backend.py # 嵌入模型后端
|
|
48
|
+
│ ├── vector_store.py # ChromaDB 向量存储
|
|
49
|
+
│ ├── bm25_index.py # BM25 关键词索引
|
|
50
|
+
│ ├── search_engine.py # 混合搜索引擎(RRF 融合)
|
|
51
|
+
│ ├── graph.py # 知识图谱(NetworkX)
|
|
52
|
+
│ ├── indexer.py # 文件监控和索引
|
|
53
|
+
│ ├── formatters.py # 多格式输出(JSON/CSV/YAML/Tree)
|
|
54
|
+
│ ├── template.py # 模板系统
|
|
55
|
+
│ ├── template_cli.py # 模板 CLI 子命令
|
|
56
|
+
│ └── performance.py # 性能优化工具
|
|
57
|
+
├── tests/ # 测试目录
|
|
58
|
+
│ ├── conftest.py # pytest 配置和 fixtures
|
|
59
|
+
│ ├── test_core_workflow.py
|
|
60
|
+
│ ├── test_integration.py
|
|
61
|
+
│ ├── test_hybrid_search.py
|
|
62
|
+
│ ├── test_backlinks.py
|
|
63
|
+
│ ├── test_formatters.py
|
|
64
|
+
│ ├── test_suggest_links.py
|
|
65
|
+
│ ├── test_kb_current.py
|
|
66
|
+
│ ├── test_template.py
|
|
67
|
+
│ └── utils/ # 测试工具
|
|
68
|
+
│ ├── temp_kb.py # 临时知识库管理
|
|
69
|
+
│ ├── jfox_cli.py # CLI 命令封装
|
|
70
|
+
│ └── note_generator.py # 测试数据生成
|
|
71
|
+
├── skill/ # Kimi Skill 定义
|
|
72
|
+
│ ├── knowledge-base-notes/SKILL.md # 笔记管理 Skill
|
|
73
|
+
│ └── knowledge-base-workspace/SKILL.md # 知识库工作空间 Skill
|
|
74
|
+
├── DEVELOPMENT_PLAN.md # 开发计划与验收标准
|
|
75
|
+
├── SESSION_SUMMARY.md # 会话历史记录
|
|
76
|
+
└── AGENTS.md # 本文档
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 构建和测试命令
|
|
80
|
+
|
|
81
|
+
### 安装开发环境
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 创建虚拟环境(推荐)
|
|
85
|
+
python -m venv .venv
|
|
86
|
+
source .venv/bin/activate # Linux/Mac
|
|
87
|
+
.venv\Scripts\activate # Windows
|
|
88
|
+
|
|
89
|
+
# 开发模式安装
|
|
90
|
+
uv sync --extra dev
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 运行测试
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# 运行所有测试
|
|
97
|
+
pytest tests/ -v
|
|
98
|
+
|
|
99
|
+
# 运行特定测试文件
|
|
100
|
+
pytest tests/test_core_workflow.py -v
|
|
101
|
+
|
|
102
|
+
# 运行带标记的测试
|
|
103
|
+
pytest tests/ -m "not slow" # 排除慢测试
|
|
104
|
+
pytest tests/ -m "integration" # 仅运行集成测试
|
|
105
|
+
|
|
106
|
+
# 保留测试数据(用于调试)
|
|
107
|
+
pytest tests/ --keep-data
|
|
108
|
+
|
|
109
|
+
# Windows 全量测试(清理 + 测试)
|
|
110
|
+
.\run_full_test.ps1
|
|
111
|
+
|
|
112
|
+
# 保留数据运行测试
|
|
113
|
+
.\run_full_test.ps1 -KeepData
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 代码格式化
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# 使用 black 格式化
|
|
120
|
+
black jfox/ tests/
|
|
121
|
+
|
|
122
|
+
# 使用 ruff 检查
|
|
123
|
+
ruff check jfox/ tests/
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 本地安装和验证
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 安装到本地
|
|
130
|
+
pip install -e .
|
|
131
|
+
|
|
132
|
+
# 验证安装
|
|
133
|
+
jfox --help
|
|
134
|
+
jfox --version
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 代码组织
|
|
138
|
+
|
|
139
|
+
### 核心模块职责
|
|
140
|
+
|
|
141
|
+
| 模块 | 职责 |
|
|
142
|
+
|------|------|
|
|
143
|
+
| `cli.py` | 所有 CLI 命令定义和实现(~1000 行) |
|
|
144
|
+
| `models.py` | Note 数据类、NoteType 枚举、Markdown 序列化/反序列化 |
|
|
145
|
+
| `config.py` | ZKConfig 配置类、use_kb 上下文管理器(多知识库切换) |
|
|
146
|
+
| `global_config.py` | GlobalConfigManager,管理 ~/.zk_config.json |
|
|
147
|
+
| `note.py` | 笔记 CRUD:create_note, save_note, load_note, delete_note |
|
|
148
|
+
| `kb_manager.py` | KnowledgeBaseManager,知识库生命周期管理 |
|
|
149
|
+
| `search_engine.py` | HybridSearchEngine,支持 HYBRID/SEMANTIC/KEYWORD 模式 |
|
|
150
|
+
| `bm25_index.py` | BM25Index,本地文件存储的关键词索引 |
|
|
151
|
+
| `vector_store.py` | VectorStore,ChromaDB 封装 |
|
|
152
|
+
| `graph.py` | KnowledgeGraph,NetworkX 图分析和可视化 |
|
|
153
|
+
|
|
154
|
+
### 笔记类型
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
class NoteType(Enum):
|
|
158
|
+
FLEETING = "fleeting" # 闪念笔记 - 快速捕捉
|
|
159
|
+
LITERATURE = "literature" # 文献笔记 - 读书笔记
|
|
160
|
+
PERMANENT = "permanent" # 永久笔记 - 整理后的知识
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 笔记文件格式
|
|
164
|
+
|
|
165
|
+
每个笔记是一个 Markdown 文件,包含 YAML frontmatter:
|
|
166
|
+
|
|
167
|
+
```markdown
|
|
168
|
+
---
|
|
169
|
+
id: '20260321011528'
|
|
170
|
+
title: 笔记标题
|
|
171
|
+
type: permanent
|
|
172
|
+
created: '2026-03-21T01:15:28'
|
|
173
|
+
updated: '2026-03-21T01:15:28'
|
|
174
|
+
tags: [tag1, tag2]
|
|
175
|
+
links: ['20260321011546'] # 正向链接
|
|
176
|
+
backlinks: ['20260321011550'] # 反向链接(自动生成)
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
# 笔记标题
|
|
180
|
+
|
|
181
|
+
笔记内容,支持 [[其他笔记标题]] 双向链接语法
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 多知识库支持
|
|
185
|
+
|
|
186
|
+
- 全局配置存储在 `~/.zk_config.json`
|
|
187
|
+
- 默认知识库路径:`~/.zettelkasten`
|
|
188
|
+
- 命名知识库路径:`~/.zettelkasten-{name}`
|
|
189
|
+
- 使用 `use_kb()` 上下文管理器临时切换知识库
|
|
190
|
+
|
|
191
|
+
## 代码风格指南
|
|
192
|
+
|
|
193
|
+
### Python 代码规范
|
|
194
|
+
|
|
195
|
+
- **行长度**: 100 字符(pyproject.toml 中配置)
|
|
196
|
+
- **格式化**: black
|
|
197
|
+
- **检查**: ruff
|
|
198
|
+
- **类型注解**: 鼓励使用,特别是公共 API
|
|
199
|
+
|
|
200
|
+
### 命名规范
|
|
201
|
+
|
|
202
|
+
- **类名**: PascalCase(如 `KnowledgeGraph`, `NoteType`)
|
|
203
|
+
- **函数/方法**: snake_case(如 `create_note`, `search_notes`)
|
|
204
|
+
- **常量**: UPPER_SNAKE_CASE
|
|
205
|
+
- **私有成员**: 下划线前缀(如 `_note_cache`)
|
|
206
|
+
|
|
207
|
+
### 注释规范
|
|
208
|
+
|
|
209
|
+
- 使用中文注释(与项目文档保持一致)
|
|
210
|
+
- 模块和类需要文档字符串
|
|
211
|
+
- 复杂函数需要参数和返回值说明
|
|
212
|
+
|
|
213
|
+
### 错误处理
|
|
214
|
+
|
|
215
|
+
- 使用 try-except 捕获具体异常
|
|
216
|
+
- 记录错误日志(logging)
|
|
217
|
+
- CLI 命令返回结构化错误(JSON 格式)
|
|
218
|
+
|
|
219
|
+
## 测试策略
|
|
220
|
+
|
|
221
|
+
### 测试类型
|
|
222
|
+
|
|
223
|
+
1. **单元测试**: 测试单个函数/方法
|
|
224
|
+
2. **集成测试**: 测试完整工作流
|
|
225
|
+
3. **性能测试**: 标记为 `@pytest.mark.performance`
|
|
226
|
+
|
|
227
|
+
### 测试工具
|
|
228
|
+
|
|
229
|
+
- **临时知识库**: `tests/utils/temp_kb.py`
|
|
230
|
+
- **CLI 封装**: `tests/utils/jfox_cli.py`
|
|
231
|
+
- **数据生成**: `tests/utils/note_generator.py`
|
|
232
|
+
|
|
233
|
+
### 测试 Fixture
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# conftest.py 中定义的主要 fixtures
|
|
237
|
+
|
|
238
|
+
def test_example(temp_kb, cli, generator):
|
|
239
|
+
"""
|
|
240
|
+
temp_kb: 临时知识库路径
|
|
241
|
+
cli: 已初始化的 ZKCLI 实例
|
|
242
|
+
generator: NoteGenerator 数据生成器
|
|
243
|
+
"""
|
|
244
|
+
pass
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 编写新测试的模板
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
# tests/test_feature.py
|
|
251
|
+
|
|
252
|
+
import pytest
|
|
253
|
+
from tests.utils.temp_kb import temp_knowledge_base
|
|
254
|
+
from tests.utils.jfox_cli import ZKCLI
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestFeatureName:
|
|
258
|
+
"""测试功能名称"""
|
|
259
|
+
|
|
260
|
+
def test_basic_functionality(self, temp_kb):
|
|
261
|
+
"""测试基本功能"""
|
|
262
|
+
cli = ZKCLI(temp_kb)
|
|
263
|
+
cli.init()
|
|
264
|
+
|
|
265
|
+
# 测试代码
|
|
266
|
+
result = cli.add("测试内容", title="测试笔记")
|
|
267
|
+
|
|
268
|
+
assert result.success
|
|
269
|
+
assert "test" in result.stdout.lower()
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## 开发约定
|
|
273
|
+
|
|
274
|
+
### 添加新 CLI 命令
|
|
275
|
+
|
|
276
|
+
1. 在 `cli.py` 中定义命令函数
|
|
277
|
+
2. 使用 `@app.command()` 装饰器
|
|
278
|
+
3. 提供 `--format json` 输出支持
|
|
279
|
+
4. 添加 `--kb` 参数支持多知识库
|
|
280
|
+
5. 实现内部 `_xxx_impl()` 函数便于复用
|
|
281
|
+
|
|
282
|
+
模板:
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
@app.command()
|
|
286
|
+
def new_command(
|
|
287
|
+
arg: str = typer.Argument(..., help="参数说明"),
|
|
288
|
+
kb: Optional[str] = typer.Option(None, "--kb", "-k", help="目标知识库"),
|
|
289
|
+
output_format: str = typer.Option("table", "--format", "-f", help="输出格式"),
|
|
290
|
+
):
|
|
291
|
+
"""命令说明"""
|
|
292
|
+
try:
|
|
293
|
+
if kb:
|
|
294
|
+
from .config import use_kb
|
|
295
|
+
with use_kb(kb):
|
|
296
|
+
_new_command_impl(arg, output_format)
|
|
297
|
+
else:
|
|
298
|
+
_new_command_impl(arg, output_format)
|
|
299
|
+
except Exception as e:
|
|
300
|
+
# 错误处理...
|
|
301
|
+
raise typer.Exit(1)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 添加新搜索模式
|
|
305
|
+
|
|
306
|
+
1. 在 `search_engine.py` 的 `SearchMode` 枚举中添加模式
|
|
307
|
+
2. 在 `HybridSearchEngine.search()` 中实现逻辑
|
|
308
|
+
3. 更新 CLI 的 `--mode` 参数帮助文本
|
|
309
|
+
|
|
310
|
+
### 修改数据模型
|
|
311
|
+
|
|
312
|
+
1. 更新 `models.py` 中的 `Note` 类
|
|
313
|
+
2. 更新 `to_markdown()` 和 `from_markdown()` 方法
|
|
314
|
+
3. 考虑向后兼容性
|
|
315
|
+
4. 更新相关测试
|
|
316
|
+
|
|
317
|
+
## 安全注意事项
|
|
318
|
+
|
|
319
|
+
### 路径安全
|
|
320
|
+
|
|
321
|
+
- 使用 `Path.expanduser().resolve()` 处理用户输入路径
|
|
322
|
+
- 避免路径遍历攻击
|
|
323
|
+
|
|
324
|
+
### 命令注入
|
|
325
|
+
|
|
326
|
+
- 使用 Typer 的参数解析,避免直接拼接 shell 命令
|
|
327
|
+
- 用户输入内容应转义后再写入文件
|
|
328
|
+
|
|
329
|
+
### 数据安全
|
|
330
|
+
|
|
331
|
+
- 所有数据存储在用户主目录下(`~/.zettelkasten*`)
|
|
332
|
+
- 不会上传数据到远程服务器
|
|
333
|
+
- 向量数据库(ChromaDB)完全本地运行
|
|
334
|
+
|
|
335
|
+
## 性能基准
|
|
336
|
+
|
|
337
|
+
在 Intel Core Ultra 7 258V 上的性能指标:
|
|
338
|
+
|
|
339
|
+
| 操作 | 耗时 |
|
|
340
|
+
|------|------|
|
|
341
|
+
| 嵌入生成 | ~1.6ms/文本 |
|
|
342
|
+
| 语义搜索 | <100ms |
|
|
343
|
+
| 图谱构建 | <1s (1000笔记) |
|
|
344
|
+
| 文件监控 | 实时 (<1s 延迟) |
|
|
345
|
+
|
|
346
|
+
## 相关资源
|
|
347
|
+
|
|
348
|
+
- **详细 CLI 文档**: `README.md`
|
|
349
|
+
- **开发计划**: `DEVELOPMENT_PLAN.md`
|
|
350
|
+
- **会话历史**: `SESSION_SUMMARY.md`
|
|
351
|
+
- **Kimi Skills**: `skill/` 目录
|
|
352
|
+
|
|
353
|
+
## 常见任务速查
|
|
354
|
+
|
|
355
|
+
### 添加一个新的笔记命令
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
# 1. 在 cli.py 中添加命令
|
|
359
|
+
@app.command()
|
|
360
|
+
def my_command(...):
|
|
361
|
+
...
|
|
362
|
+
|
|
363
|
+
# 2. 确保支持 --kb 参数
|
|
364
|
+
# 3. 添加测试到 tests/test_my_command.py
|
|
365
|
+
# 4. 更新 README.md 文档
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 添加新的输出格式
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
# 在 formatters.py 中添加
|
|
372
|
+
class OutputFormatter:
|
|
373
|
+
@staticmethod
|
|
374
|
+
def to_new_format(data: List[Dict]) -> str:
|
|
375
|
+
...
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 添加新的搜索后端
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
# 1. 创建新模块(如 new_index.py)
|
|
382
|
+
# 2. 实现索引类
|
|
383
|
+
# 3. 在 search_engine.py 中集成
|
|
384
|
+
# 4. 添加测试
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Session History
|
|
390
|
+
|
|
391
|
+
📋 **完整会话历史**: [SESSION.md](./SESSION.md)
|
|
392
|
+
|
|
393
|
+
> 最近3个 session 摘要:
|
|
394
|
+
> - **Session 2** (2026-03-25): 修复 Windows Unicode 编码问题,改进 list table 格式
|
|
395
|
+
> - **Session 1** (2026-03-25): 通过 `/init` 命令生成 AGENTS.md 项目指南
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
*本文档最后更新: 2026-03-26*
|