jfox-cli 0.7.2__tar.gz → 0.8.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.8.0/.claude-plugin/marketplace.json +20 -0
- jfox_cli-0.8.0/.claude-plugin/plugin.json +22 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/AGENTS.md +111 -34
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/CHANGELOG.md +11 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/PKG-INFO +1 -1
- jfox_cli-0.8.0/commands/jfox-common.md +6 -0
- jfox_cli-0.8.0/commands/jfox-ingest.md +6 -0
- jfox_cli-0.8.0/commands/jfox-organize.md +6 -0
- jfox_cli-0.8.0/commands/jfox-search.md +6 -0
- jfox_cli-0.8.0/commands/jfox-session-summary.md +6 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/__init__.py +1 -1
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/cli.py +44 -16
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/config.py +1 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/kb_manager.py +2 -2
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/models.py +10 -1
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/note.py +2 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/template.py +21 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/template_cli.py +1 -1
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/pyproject.toml +1 -1
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/claude-code/jfox-session-summary/SKILL.md +8 -5
- jfox_cli-0.8.0/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +122 -0
- jfox_cli-0.8.0/tests/unit/test_session_note.py +231 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/uv.lock +1 -1
- jfox_cli-0.7.2/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -122
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.claude/settings.local.json +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.claude/skills/ci/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.claude/skills/release/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.claude/skills/release/release_helper.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.githooks/pre-push +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.github/workflows/integration-test.yml +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.github/workflows/publish.yml +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.gitignore +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/.python-version +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/CLAUDE.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/DEVELOPMENT_PLAN.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/README.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/SESSION.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/SESSION_SUMMARY.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/installation.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-04-29-daemon-stop-fix.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-05-03-jfox-check.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-05-03-log-level-fix.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/plans/2026-05-04-list-notes-index.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-05-03-jfox-check-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-05-03-list-notes-skip-summary-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-05-03-log-level-fix-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/docs/troubleshooting.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jessica-jones-static-cable.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/__main__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/bm25_index.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/daemon/__init__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/daemon/__main__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/daemon/client.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/daemon/process.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/daemon/server.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/embedding_backend.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/formatters.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/git_extractor.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/global_config.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/graph.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/indexer.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/model_downloader.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/note_index.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/performance.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/search_engine.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/jfox/vector_store.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/pytest.ini +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/run_full_test.ps1 +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/scripts/download-model-intranet.sh +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/README.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/claude-code/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/claude-code/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/claude-code/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/claude-code/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/COVERAGE_PLAN.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/MIGRATION.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/TESTS.md +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/conftest.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/integration/__init__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/integration/test_backlinks.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/integration/test_model_download.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/integration/test_tag_filter_cli.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/performance/__init__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/performance/test_performance.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_advanced_features.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_cli_format.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_config_set_unit.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_config_unit.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_core_workflow.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_embedding_device.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_hybrid_search.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_integration.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_kb_current.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/test_suggest_links.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/__init__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_atomic_write.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_bm25_batch.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_check.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_content_file.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_daemon_process.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_edit.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_format_unify.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_formatters.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_git_extractor.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_global_config.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_index_kb_param.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_indexer_verify.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_kb_manager.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_lazy_import.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_list_notes_skip.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_logging_config.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_model_downloader.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_note_index.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_release_helper.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_show.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_tag_filter.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_template.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_template_cli.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_use_kb_env_var.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/unit/test_vector_store_clear.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/utils/__init__.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/utils/assertions.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/utils/jfox_cli.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/utils/note_generator.py +0 -0
- {jfox_cli-0.7.2 → jfox_cli-0.8.0}/tests/utils/temp_kb.py +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jfox-skills",
|
|
3
|
+
"id": "jfox-skills",
|
|
4
|
+
"owner": { "name": "zhuxixi" },
|
|
5
|
+
"metadata": {
|
|
6
|
+
"description": "JFox Zettelkasten 知识管理工具的 Claude Code 集成",
|
|
7
|
+
"version": "0.1.0"
|
|
8
|
+
},
|
|
9
|
+
"plugins": [
|
|
10
|
+
{
|
|
11
|
+
"name": "jfox",
|
|
12
|
+
"source": "./",
|
|
13
|
+
"description": "JFox 知识管理 CLI 的 Claude Code 集成——搜索、导入、整理、会话总结",
|
|
14
|
+
"version": "0.1.0",
|
|
15
|
+
"author": { "name": "zhuxixi" },
|
|
16
|
+
"keywords": ["zettelkasten", "knowledge-management"],
|
|
17
|
+
"category": "workflow"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jfox",
|
|
3
|
+
"description": "JFox 知识管理 CLI 的 Claude Code 集成——搜索、导入、整理、会话总结",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": { "name": "zhuxixi" },
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": ["zettelkasten", "knowledge-management", "cli"],
|
|
8
|
+
"skills": [
|
|
9
|
+
"./skills-recommend/claude-code/jfox-common",
|
|
10
|
+
"./skills-recommend/claude-code/jfox-ingest",
|
|
11
|
+
"./skills-recommend/claude-code/jfox-organize",
|
|
12
|
+
"./skills-recommend/claude-code/jfox-search",
|
|
13
|
+
"./skills-recommend/claude-code/jfox-session-summary"
|
|
14
|
+
],
|
|
15
|
+
"commands": [
|
|
16
|
+
"./commands/jfox-common",
|
|
17
|
+
"./commands/jfox-ingest",
|
|
18
|
+
"./commands/jfox-organize",
|
|
19
|
+
"./commands/jfox-search",
|
|
20
|
+
"./commands/jfox-session-summary"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -38,21 +38,25 @@ jfox/
|
|
|
38
38
|
├── jfox/ # 主包
|
|
39
39
|
│ ├── __init__.py
|
|
40
40
|
│ ├── __main__.py # 入口点
|
|
41
|
-
│ ├── cli.py # CLI
|
|
41
|
+
│ ├── cli.py # CLI 主程序(所有命令,~2900 行)
|
|
42
42
|
│ ├── models.py # 数据模型(Note, NoteType)
|
|
43
43
|
│ ├── config.py # 配置管理(ZKConfig, use_kb)
|
|
44
44
|
│ ├── global_config.py # 全局配置管理(多知识库)
|
|
45
45
|
│ ├── note.py # 笔记 CRUD 操作
|
|
46
46
|
│ ├── kb_manager.py # 知识库管理器
|
|
47
|
-
│ ├── embedding_backend.py #
|
|
47
|
+
│ ├── embedding_backend.py # 嵌入模型后端(支持 daemon 代理)
|
|
48
|
+
│ ├── daemon/ # Embedding 模型 HTTP 守护进程
|
|
48
49
|
│ ├── vector_store.py # ChromaDB 向量存储
|
|
49
50
|
│ ├── bm25_index.py # BM25 关键词索引
|
|
50
51
|
│ ├── search_engine.py # 混合搜索引擎(RRF 融合)
|
|
51
52
|
│ ├── graph.py # 知识图谱(NetworkX)
|
|
52
|
-
│ ├── indexer.py #
|
|
53
|
+
│ ├── indexer.py # 文件监控和增量索引
|
|
53
54
|
│ ├── formatters.py # 多格式输出(JSON/CSV/YAML/Tree)
|
|
54
55
|
│ ├── template.py # 模板系统
|
|
55
56
|
│ ├── template_cli.py # 模板 CLI 子命令
|
|
57
|
+
│ ├── git_extractor.py # Git 仓库数据提取器(ingest 功能)
|
|
58
|
+
│ ├── model_downloader.py # 嵌入模型下载与缓存管理
|
|
59
|
+
│ ├── note_index.py # 笔记索引管理(文件名↔ID 映射)
|
|
56
60
|
│ └── performance.py # 性能优化工具
|
|
57
61
|
├── tests/ # 测试目录
|
|
58
62
|
│ ├── conftest.py # pytest 配置和 fixtures
|
|
@@ -81,30 +85,32 @@ jfox/
|
|
|
81
85
|
### 安装开发环境
|
|
82
86
|
|
|
83
87
|
```bash
|
|
84
|
-
#
|
|
85
|
-
python -m venv .venv
|
|
86
|
-
source .venv/bin/activate # Linux/Mac
|
|
87
|
-
.venv\Scripts\activate # Windows
|
|
88
|
-
|
|
89
|
-
# 开发模式安装
|
|
88
|
+
# 安装(使用 uv,推荐)
|
|
90
89
|
uv sync --extra dev
|
|
90
|
+
|
|
91
|
+
# 安装(legacy pip fallback)
|
|
92
|
+
pip install -e ".[dev]"
|
|
91
93
|
```
|
|
92
94
|
|
|
93
95
|
### 运行测试
|
|
94
96
|
|
|
95
97
|
```bash
|
|
96
98
|
# 运行所有测试
|
|
97
|
-
pytest tests/ -v
|
|
99
|
+
uv run pytest tests/ -v
|
|
98
100
|
|
|
99
101
|
# 运行特定测试文件
|
|
100
|
-
pytest tests/test_core_workflow.py -v
|
|
102
|
+
uv run pytest tests/test_core_workflow.py -v
|
|
101
103
|
|
|
102
104
|
# 运行带标记的测试
|
|
103
|
-
pytest tests/ -m "not slow"
|
|
104
|
-
pytest tests/ -m "
|
|
105
|
+
uv run pytest tests/ -m "not slow" # 排除慢测试
|
|
106
|
+
uv run pytest tests/ -m "not embedding and not slow" # 快速测试(不加载模型)
|
|
107
|
+
uv run pytest tests/ -m "integration" # 仅运行集成测试
|
|
105
108
|
|
|
106
109
|
# 保留测试数据(用于调试)
|
|
107
|
-
pytest tests/ --keep-data
|
|
110
|
+
uv run pytest tests/ --keep-data
|
|
111
|
+
|
|
112
|
+
# 覆盖率
|
|
113
|
+
uv run pytest tests/ --cov=jfox --cov-report=html
|
|
108
114
|
|
|
109
115
|
# Windows 全量测试(清理 + 测试)
|
|
110
116
|
.\run_full_test.ps1
|
|
@@ -117,21 +123,21 @@ pytest tests/ --keep-data
|
|
|
117
123
|
|
|
118
124
|
```bash
|
|
119
125
|
# 使用 black 格式化
|
|
120
|
-
black jfox/ tests/
|
|
126
|
+
uv run black jfox/ tests/
|
|
121
127
|
|
|
122
128
|
# 使用 ruff 检查
|
|
123
|
-
ruff check jfox/ tests/
|
|
129
|
+
uv run ruff check jfox/ tests/
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
###
|
|
132
|
+
### 构建和验证
|
|
127
133
|
|
|
128
134
|
```bash
|
|
129
|
-
#
|
|
130
|
-
|
|
135
|
+
# 构建
|
|
136
|
+
uv build
|
|
131
137
|
|
|
132
|
-
#
|
|
133
|
-
jfox --help
|
|
134
|
-
jfox --version
|
|
138
|
+
# 验证 CLI
|
|
139
|
+
uv run jfox --help
|
|
140
|
+
uv run jfox --version
|
|
135
141
|
```
|
|
136
142
|
|
|
137
143
|
## 代码组织
|
|
@@ -140,16 +146,21 @@ jfox --version
|
|
|
140
146
|
|
|
141
147
|
| 模块 | 职责 |
|
|
142
148
|
|------|------|
|
|
143
|
-
| `cli.py` | 所有 CLI 命令定义和实现(~
|
|
149
|
+
| `cli.py` | 所有 CLI 命令定义和实现(~2900 行) |
|
|
144
150
|
| `models.py` | Note 数据类、NoteType 枚举、Markdown 序列化/反序列化 |
|
|
145
151
|
| `config.py` | ZKConfig 配置类、use_kb 上下文管理器(多知识库切换) |
|
|
146
152
|
| `global_config.py` | GlobalConfigManager,管理 ~/.zk_config.json |
|
|
147
153
|
| `note.py` | 笔记 CRUD:create_note, save_note, load_note, delete_note |
|
|
148
154
|
| `kb_manager.py` | KnowledgeBaseManager,知识库生命周期管理 |
|
|
149
|
-
| `search_engine.py` | HybridSearchEngine,支持 HYBRID/SEMANTIC/KEYWORD
|
|
155
|
+
| `search_engine.py` | HybridSearchEngine,支持 HYBRID/SEMANTIC/KEYWORD 模式,RRF 融合 |
|
|
150
156
|
| `bm25_index.py` | BM25Index,本地文件存储的关键词索引 |
|
|
151
157
|
| `vector_store.py` | VectorStore,ChromaDB 封装 |
|
|
152
158
|
| `graph.py` | KnowledgeGraph,NetworkX 图分析和可视化 |
|
|
159
|
+
| `git_extractor.py` | Git 仓库数据提取器(ingest 功能) |
|
|
160
|
+
| `model_downloader.py` | 嵌入模型下载与缓存管理 |
|
|
161
|
+
| `note_index.py` | 笔记索引管理(文件名↔ID 映射) |
|
|
162
|
+
| `indexer.py` | 文件监控(watchdog)+ 增量索引 |
|
|
163
|
+
| `daemon/` | Embedding 模型 HTTP 守护进程(server/client/process) |
|
|
153
164
|
|
|
154
165
|
### 笔记类型
|
|
155
166
|
|
|
@@ -158,8 +169,14 @@ class NoteType(Enum):
|
|
|
158
169
|
FLEETING = "fleeting" # 闪念笔记 - 快速捕捉
|
|
159
170
|
LITERATURE = "literature" # 文献笔记 - 读书笔记
|
|
160
171
|
PERMANENT = "permanent" # 永久笔记 - 整理后的知识
|
|
172
|
+
SESSION = "session" # AI Agent 会话记录
|
|
161
173
|
```
|
|
162
174
|
|
|
175
|
+
各类型文件名格式:
|
|
176
|
+
- `fleeting`: `YYYYMMDD-HHMMSS.md`
|
|
177
|
+
- `literature`: `YYYYMMDDHHMMSS-{slug}.md`
|
|
178
|
+
- `permanent`: `YYYYMMDDHHMMSS-{slug}.md`
|
|
179
|
+
|
|
163
180
|
### 笔记文件格式
|
|
164
181
|
|
|
165
182
|
每个笔记是一个 Markdown 文件,包含 YAML frontmatter:
|
|
@@ -174,6 +191,7 @@ updated: '2026-03-21T01:15:28'
|
|
|
174
191
|
tags: [tag1, tag2]
|
|
175
192
|
links: ['20260321011546'] # 正向链接
|
|
176
193
|
backlinks: ['20260321011550'] # 反向链接(自动生成)
|
|
194
|
+
topic: null # 会话主题(仅 session 类型)
|
|
177
195
|
---
|
|
178
196
|
|
|
179
197
|
# 笔记标题
|
|
@@ -184,8 +202,8 @@ backlinks: ['20260321011550'] # 反向链接(自动生成)
|
|
|
184
202
|
### 多知识库支持
|
|
185
203
|
|
|
186
204
|
- 全局配置存储在 `~/.zk_config.json`
|
|
187
|
-
- 默认知识库路径:`~/.zettelkasten
|
|
188
|
-
- 命名知识库路径:`~/.zettelkasten
|
|
205
|
+
- 默认知识库路径:`~/.zettelkasten/default/`
|
|
206
|
+
- 命名知识库路径:`~/.zettelkasten/<name>/`
|
|
189
207
|
- 使用 `use_kb()` 上下文管理器临时切换知识库
|
|
190
208
|
|
|
191
209
|
## 代码风格指南
|
|
@@ -224,6 +242,13 @@ backlinks: ['20260321011550'] # 反向链接(自动生成)
|
|
|
224
242
|
2. **集成测试**: 测试完整工作流
|
|
225
243
|
3. **性能测试**: 标记为 `@pytest.mark.performance`
|
|
226
244
|
|
|
245
|
+
### 测试目录结构
|
|
246
|
+
|
|
247
|
+
- `tests/unit/` — 纯逻辑单元测试(约 25 个文件)
|
|
248
|
+
- `tests/integration/` — 跨模块集成测试
|
|
249
|
+
- `tests/performance/` — 性能基准测试
|
|
250
|
+
- 根级遗留:`test_config_unit.py`、`test_config_set_unit.py`(与 unit 目录中测试内容不同)
|
|
251
|
+
|
|
227
252
|
### 测试工具
|
|
228
253
|
|
|
229
254
|
- **临时知识库**: `tests/utils/temp_kb.py`
|
|
@@ -235,34 +260,49 @@ backlinks: ['20260321011550'] # 反向链接(自动生成)
|
|
|
235
260
|
```python
|
|
236
261
|
# conftest.py 中定义的主要 fixtures
|
|
237
262
|
|
|
238
|
-
def test_example(temp_kb, cli, generator):
|
|
263
|
+
def test_example(temp_kb, cli, cli_fast, generator, mock_embedding_backend):
|
|
239
264
|
"""
|
|
240
265
|
temp_kb: 临时知识库路径
|
|
241
266
|
cli: 已初始化的 ZKCLI 实例
|
|
267
|
+
cli_fast: ZKCLI with mocked embeddings(快速,不加载模型)
|
|
242
268
|
generator: NoteGenerator 数据生成器
|
|
269
|
+
mock_embedding_backend: mock 嵌入后端
|
|
243
270
|
"""
|
|
244
271
|
pass
|
|
245
272
|
```
|
|
246
273
|
|
|
274
|
+
### 测试标记(Markers)
|
|
275
|
+
|
|
276
|
+
| 标记 | 含义 |
|
|
277
|
+
|------|------|
|
|
278
|
+
| `slow` | 慢测试 |
|
|
279
|
+
| `performance` | 性能基准 |
|
|
280
|
+
| `integration` | 集成测试 |
|
|
281
|
+
| `embedding` | 涉及模型加载 |
|
|
282
|
+
| `workflow` | 工作流测试 |
|
|
283
|
+
| `bulk` | 批量操作测试 |
|
|
284
|
+
|
|
285
|
+
### 测试运行规则
|
|
286
|
+
|
|
287
|
+
- **全量/集成测试(~50min)不要自主运行**,提供命令让用户手动执行
|
|
288
|
+
- **快速单元测试(几秒内)可以自主运行**,如单个模块的纯逻辑测试,不涉及 embedding 或 ChromaDB
|
|
289
|
+
- `pytest.ini` 配置:`timeout=120`、`--strict-markers`、`-ra`
|
|
290
|
+
- 测试以单进程运行,避免 ChromaDB/模型加载冲突
|
|
291
|
+
|
|
247
292
|
### 编写新测试的模板
|
|
248
293
|
|
|
249
294
|
```python
|
|
250
295
|
# tests/test_feature.py
|
|
251
296
|
|
|
252
297
|
import pytest
|
|
253
|
-
from tests.utils.temp_kb import temp_knowledge_base
|
|
254
|
-
from tests.utils.jfox_cli import ZKCLI
|
|
255
298
|
|
|
256
299
|
|
|
257
300
|
class TestFeatureName:
|
|
258
301
|
"""测试功能名称"""
|
|
259
302
|
|
|
260
|
-
def test_basic_functionality(self, temp_kb):
|
|
303
|
+
def test_basic_functionality(self, temp_kb, cli):
|
|
261
304
|
"""测试基本功能"""
|
|
262
|
-
|
|
263
|
-
cli.init()
|
|
264
|
-
|
|
265
|
-
# 测试代码
|
|
305
|
+
# 使用 fixture 自动初始化的临时知识库和 CLI 实例
|
|
266
306
|
result = cli.add("测试内容", title="测试笔记")
|
|
267
307
|
|
|
268
308
|
assert result.success
|
|
@@ -343,6 +383,37 @@ def new_command(
|
|
|
343
383
|
| 图谱构建 | <1s (1000笔记) |
|
|
344
384
|
| 文件监控 | 实时 (<1s 延迟) |
|
|
345
385
|
|
|
386
|
+
## CI(GitHub Actions)
|
|
387
|
+
|
|
388
|
+
`.github/workflows/integration-test.yml` 包含四个 job:
|
|
389
|
+
|
|
390
|
+
- **Fast**(PR/push 触发):`not embedding and not slow`,Python 3.11,Ubuntu + Windows
|
|
391
|
+
- **Core**(main 分支推送):Core workflow 测试,使用真实 embedding,Python 3.10 + 3.12
|
|
392
|
+
- **Full**(手动触发):所有测试、所有 OS、所有 Python 版本
|
|
393
|
+
- **Coverage**(Fast 完成后):运行覆盖率,上传 HTML/XML 产物
|
|
394
|
+
|
|
395
|
+
**Release** 工作流(`.github/workflows/publish.yml`):在 GitHub Release 发布时自动推送到 PyPI。
|
|
396
|
+
|
|
397
|
+
## Windows 注意事项
|
|
398
|
+
|
|
399
|
+
- `robocopy` 参数会被 bash 误解析,应使用 `cmd.exe /c "robocopy source dest /E"`
|
|
400
|
+
- 设置 `PYTHONUTF8=1` 和 `chcp 65001` 避免编码问题
|
|
401
|
+
- HuggingFace 国内镜像:`export HF_ENDPOINT=https://hf-mirror.com`
|
|
402
|
+
|
|
403
|
+
## 分支规则
|
|
404
|
+
|
|
405
|
+
- **main 是保护分支**,不能直接 commit 或 push
|
|
406
|
+
- 所有改动必须通过**新分支 + PR** 合入
|
|
407
|
+
|
|
408
|
+
## 发版规则
|
|
409
|
+
|
|
410
|
+
- 发版时必须同时修改三处版本号:
|
|
411
|
+
1. `pyproject.toml`
|
|
412
|
+
2. `jfox/__init__.py`
|
|
413
|
+
3. `uv.lock`
|
|
414
|
+
- 操作顺序:先改 `pyproject.toml` 和 `__init__.py`,再跑 `uv lock` 更新 lock 文件
|
|
415
|
+
- (曾有 #88 遗漏 `__init__.py` 的教训)
|
|
416
|
+
|
|
346
417
|
## 相关资源
|
|
347
418
|
|
|
348
419
|
- **详细 CLI 文档**: `README.md`
|
|
@@ -384,6 +455,12 @@ class OutputFormatter:
|
|
|
384
455
|
# 4. 添加测试
|
|
385
456
|
```
|
|
386
457
|
|
|
458
|
+
## 常见陷阱(Gotchas)
|
|
459
|
+
|
|
460
|
+
- `pytest.ini` 的 `addopts` 已包含 `-v`,手动再加 `-v` 是冗余的
|
|
461
|
+
- 测试目录重组已基本完成,根级 `test_config_unit.py` 和 `test_config_set_unit.py` 与 `tests/unit/` 中对应文件测试内容不同,不是重复
|
|
462
|
+
- `jfox show <id_or_title>` 复用 `find_note_id_by_title_or_id` 定位笔记,只读输出完整 Markdown
|
|
463
|
+
|
|
387
464
|
---
|
|
388
465
|
|
|
389
466
|
## Session History
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to jfox-cli will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.8.0] - 2026-05-10
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
- add Claude Code plugin packaging for jfox skills (#209) (#210)
|
|
9
|
+
- 新增 session 笔记类型,专存 AI Agent 会话记录 (#202)
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
- sync AGENTS.md with CLAUDE.md and current codebase (#208)
|
|
13
|
+
|
|
14
|
+
[0.8.0]: https://github.com/zhuxixi/jfox/compare/v0.7.2...v0.8.0
|
|
15
|
+
|
|
5
16
|
## [0.7.2] - 2026-05-07
|
|
6
17
|
|
|
7
18
|
### Fixes
|
|
@@ -292,6 +292,7 @@ def _add_note_impl(
|
|
|
292
292
|
source: Optional[str],
|
|
293
293
|
output_format: str,
|
|
294
294
|
template: Optional[str] = None,
|
|
295
|
+
topic: Optional[str] = None,
|
|
295
296
|
):
|
|
296
297
|
"""添加笔记的内部实现"""
|
|
297
298
|
# 如果指定了模板,使用模板渲染
|
|
@@ -305,6 +306,7 @@ def _add_note_impl(
|
|
|
305
306
|
"title": title or "",
|
|
306
307
|
"content": content,
|
|
307
308
|
"source": source or "",
|
|
309
|
+
"topic": topic or "",
|
|
308
310
|
}
|
|
309
311
|
|
|
310
312
|
# 渲染模板
|
|
@@ -331,7 +333,13 @@ def _add_note_impl(
|
|
|
331
333
|
try:
|
|
332
334
|
nt = NoteType(note_type.lower())
|
|
333
335
|
except ValueError:
|
|
334
|
-
raise ValueError(
|
|
336
|
+
raise ValueError(
|
|
337
|
+
f"Invalid note type: {note_type}. Use: fleeting, literature, permanent, session"
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# session 类型必须提供 --topic
|
|
341
|
+
if nt == NoteType.SESSION and not topic:
|
|
342
|
+
raise ValueError("--type session 需要 --topic 参数")
|
|
335
343
|
|
|
336
344
|
# 从内容中提取维基链接
|
|
337
345
|
wiki_links = extract_wiki_links(content)
|
|
@@ -353,6 +361,7 @@ def _add_note_impl(
|
|
|
353
361
|
tags=tags or [],
|
|
354
362
|
links=resolved_links,
|
|
355
363
|
source=source,
|
|
364
|
+
topic=topic,
|
|
356
365
|
)
|
|
357
366
|
|
|
358
367
|
# 保存笔记
|
|
@@ -410,7 +419,7 @@ def add(
|
|
|
410
419
|
content: Optional[str] = typer.Argument(None, help="笔记内容(支持 [[笔记标题]] 格式链接)"),
|
|
411
420
|
title: Optional[str] = typer.Option(None, "--title", "-t", help="笔记标题"),
|
|
412
421
|
note_type: str = typer.Option(
|
|
413
|
-
"fleeting", "--type", help="笔记类型 (fleeting/literature/permanent)"
|
|
422
|
+
"fleeting", "--type", help="笔记类型 (fleeting/literature/permanent/session)"
|
|
414
423
|
),
|
|
415
424
|
tags: Optional[List[str]] = typer.Option(None, "--tag", help="标签(可多次使用)"),
|
|
416
425
|
source: Optional[str] = typer.Option(None, "--source", "-s", help="来源(文献笔记)"),
|
|
@@ -420,6 +429,7 @@ def add(
|
|
|
420
429
|
content_file: Optional[str] = typer.Option(
|
|
421
430
|
None, "--content-file", help="从文件读取内容(用 - 表示 stdin)"
|
|
422
431
|
),
|
|
432
|
+
topic: Optional[str] = typer.Option(None, "--topic", help="会话主题(session 类型必填)"),
|
|
423
433
|
kb: Optional[str] = typer.Option(None, "--kb", "-k", help="目标知识库名称"),
|
|
424
434
|
output_format: str = typer.Option("table", "--format", "-f", help="输出格式: json, table"),
|
|
425
435
|
json_output: bool = typer.Option(
|
|
@@ -447,7 +457,7 @@ def add(
|
|
|
447
457
|
from .config import use_kb
|
|
448
458
|
|
|
449
459
|
with use_kb(kb):
|
|
450
|
-
_add_note_impl(content, title, note_type, tags, source, output_format, template)
|
|
460
|
+
_add_note_impl(content, title, note_type, tags, source, output_format, template, topic)
|
|
451
461
|
|
|
452
462
|
except typer.Exit:
|
|
453
463
|
raise
|
|
@@ -783,7 +793,9 @@ def _list_impl(
|
|
|
783
793
|
try:
|
|
784
794
|
nt = NoteType(note_type.lower())
|
|
785
795
|
except ValueError:
|
|
786
|
-
raise ValueError(
|
|
796
|
+
raise ValueError(
|
|
797
|
+
f"Invalid note type: {note_type}. Use: fleeting, literature, permanent, session"
|
|
798
|
+
)
|
|
787
799
|
|
|
788
800
|
notes = note.list_notes(note_type=nt, tags=tags, limit=limit)
|
|
789
801
|
data = [n.to_dict() for n in notes]
|
|
@@ -1195,6 +1207,7 @@ def _edit_impl(
|
|
|
1195
1207
|
note_type: Optional[str],
|
|
1196
1208
|
source: Optional[str],
|
|
1197
1209
|
output_format: str,
|
|
1210
|
+
topic: Optional[str] = None,
|
|
1198
1211
|
):
|
|
1199
1212
|
"""编辑笔记的内部实现"""
|
|
1200
1213
|
# 验证:--content 和 --content-file 互斥
|
|
@@ -1206,10 +1219,10 @@ def _edit_impl(
|
|
|
1206
1219
|
content = _read_content_file(content_file)
|
|
1207
1220
|
|
|
1208
1221
|
# 验证:至少指定一个编辑字段
|
|
1209
|
-
if all(v is None for v in [content, title, tags, note_type, source]):
|
|
1222
|
+
if all(v is None for v in [content, title, tags, note_type, source, topic]):
|
|
1210
1223
|
raise ValueError(
|
|
1211
1224
|
"至少指定一个要编辑的字段 "
|
|
1212
|
-
"(--content, --content-file, --title, --tags, --type, --source)"
|
|
1225
|
+
"(--content, --content-file, --title, --tags, --type, --source, --topic)"
|
|
1213
1226
|
)
|
|
1214
1227
|
|
|
1215
1228
|
# 加载笔记
|
|
@@ -1234,9 +1247,15 @@ def _edit_impl(
|
|
|
1234
1247
|
new_type = NoteType(note_type.lower())
|
|
1235
1248
|
except ValueError:
|
|
1236
1249
|
raise ValueError(
|
|
1237
|
-
f"Invalid note type: {note_type}. Use: fleeting, literature, permanent"
|
|
1250
|
+
f"Invalid note type: {note_type}. Use: fleeting, literature, permanent, session"
|
|
1238
1251
|
)
|
|
1239
1252
|
n.type = new_type
|
|
1253
|
+
# 改为 session 类型时,笔记必须已有 topic 或通过 --topic 设置
|
|
1254
|
+
if new_type == NoteType.SESSION and not n.topic and not topic:
|
|
1255
|
+
raise ValueError("改为 session 类型时需要 --topic 参数")
|
|
1256
|
+
|
|
1257
|
+
if topic is not None:
|
|
1258
|
+
n.topic = topic
|
|
1240
1259
|
|
|
1241
1260
|
# 如果内容被更新,解析 wiki links
|
|
1242
1261
|
if content is not None:
|
|
@@ -1333,9 +1352,10 @@ def edit(
|
|
|
1333
1352
|
title: Optional[str] = typer.Option(None, "--title", "-t", help="新标题"),
|
|
1334
1353
|
tags: Optional[List[str]] = typer.Option(None, "--tag", help="新标签(替换全部)"),
|
|
1335
1354
|
note_type: Optional[str] = typer.Option(
|
|
1336
|
-
None, "--type", help="新类型 (fleeting/literature/permanent)"
|
|
1355
|
+
None, "--type", help="新类型 (fleeting/literature/permanent/session)"
|
|
1337
1356
|
),
|
|
1338
1357
|
source: Optional[str] = typer.Option(None, "--source", "-s", help="新来源"),
|
|
1358
|
+
topic: Optional[str] = typer.Option(None, "--topic", help="会话主题(session 类型)"),
|
|
1339
1359
|
kb: Optional[str] = typer.Option(None, "--kb", "-k", help="目标知识库名称"),
|
|
1340
1360
|
output_format: str = typer.Option("table", "--format", "-f", help="输出格式: json, table"),
|
|
1341
1361
|
json_output: bool = typer.Option(
|
|
@@ -1352,7 +1372,7 @@ def edit(
|
|
|
1352
1372
|
|
|
1353
1373
|
with use_kb(kb):
|
|
1354
1374
|
_edit_impl(
|
|
1355
|
-
note_id, content, content_file, title, tags, note_type, source, output_format
|
|
1375
|
+
note_id, content, content_file, title, tags, note_type, source, output_format, topic
|
|
1356
1376
|
)
|
|
1357
1377
|
except typer.Exit:
|
|
1358
1378
|
raise
|
|
@@ -1684,28 +1704,36 @@ def _inbox_impl(
|
|
|
1684
1704
|
from .note_index import get_note_index
|
|
1685
1705
|
|
|
1686
1706
|
idx = get_note_index()
|
|
1687
|
-
|
|
1707
|
+
# 查询 fleeting 和 session 类型笔记(不传 limit,合并后再截断)
|
|
1708
|
+
fleeting_notes = idx.list_meta(note_type=NoteType.FLEETING)
|
|
1709
|
+
session_notes = idx.list_meta(note_type=NoteType.SESSION)
|
|
1710
|
+
all_notes = fleeting_notes + session_notes
|
|
1711
|
+
# Sort by created descending
|
|
1712
|
+
all_notes.sort(key=lambda m: m.created or "", reverse=True)
|
|
1713
|
+
all_notes = all_notes[:limit]
|
|
1688
1714
|
|
|
1689
1715
|
result = {
|
|
1690
|
-
"total": len(
|
|
1716
|
+
"total": len(all_notes),
|
|
1691
1717
|
"notes": [
|
|
1692
1718
|
{
|
|
1693
1719
|
"id": m.id,
|
|
1694
1720
|
"title": m.title,
|
|
1721
|
+
"type": m.type.value,
|
|
1695
1722
|
"created": m.created,
|
|
1696
1723
|
"filepath": m.filepath if m.filepath else None,
|
|
1697
1724
|
}
|
|
1698
|
-
for m in
|
|
1725
|
+
for m in all_notes
|
|
1699
1726
|
],
|
|
1700
1727
|
}
|
|
1701
1728
|
|
|
1702
1729
|
if output_format == "json":
|
|
1703
1730
|
print(output_json(result))
|
|
1704
1731
|
else:
|
|
1705
|
-
console.print(f"[bold]
|
|
1706
|
-
for m in
|
|
1732
|
+
console.print(f"[bold]Inbox ({len(all_notes)}):[/bold]\n")
|
|
1733
|
+
for m in all_notes:
|
|
1707
1734
|
time_str = m.created[11:16] if m.created and len(m.created) >= 16 else ""
|
|
1708
|
-
|
|
1735
|
+
type_badge = {"fleeting": "fl", "session": "se"}.get(m.type.value, "??")
|
|
1736
|
+
console.print(f"- [{time_str}] [{type_badge}] {m.title}")
|
|
1709
1737
|
|
|
1710
1738
|
|
|
1711
1739
|
def _suggest_links_impl(
|
|
@@ -1795,7 +1823,7 @@ def inbox(
|
|
|
1795
1823
|
False, "--json", help="JSON 输出(快捷方式,等同于 --format json)"
|
|
1796
1824
|
),
|
|
1797
1825
|
):
|
|
1798
|
-
"""
|
|
1826
|
+
"""查看临时笔记和会话记录 (Fleeting + Session Notes)"""
|
|
1799
1827
|
try:
|
|
1800
1828
|
# 处理 --json 快捷方式
|
|
1801
1829
|
if json_output:
|
|
@@ -249,12 +249,12 @@ class KnowledgeBaseManager:
|
|
|
249
249
|
|
|
250
250
|
# 统计笔记数量
|
|
251
251
|
total = 0
|
|
252
|
-
by_type = {"fleeting": 0, "literature": 0, "permanent": 0}
|
|
252
|
+
by_type = {"fleeting": 0, "literature": 0, "permanent": 0, "session": 0}
|
|
253
253
|
|
|
254
254
|
if path.exists():
|
|
255
255
|
notes_dir = path / "notes"
|
|
256
256
|
if notes_dir.exists():
|
|
257
|
-
for note_type in ["fleeting", "literature", "permanent"]:
|
|
257
|
+
for note_type in ["fleeting", "literature", "permanent", "session"]:
|
|
258
258
|
type_dir = notes_dir / note_type
|
|
259
259
|
if type_dir.exists():
|
|
260
260
|
count = len(list(type_dir.glob("*.md")))
|
|
@@ -16,6 +16,7 @@ class NoteType(Enum):
|
|
|
16
16
|
FLEETING = "fleeting" # 闪念笔记
|
|
17
17
|
LITERATURE = "literature" # 文献笔记
|
|
18
18
|
PERMANENT = "permanent" # 永久笔记
|
|
19
|
+
SESSION = "session" # AI Agent 会话记录
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
@dataclass
|
|
@@ -32,6 +33,7 @@ class Note:
|
|
|
32
33
|
links: List[str] = field(default_factory=list) # 正向链接
|
|
33
34
|
backlinks: List[str] = field(default_factory=list) # 反向链接
|
|
34
35
|
source: Optional[str] = None # 来源(文献笔记)
|
|
36
|
+
topic: Optional[str] = None # 会话主题(session 类型)
|
|
35
37
|
|
|
36
38
|
# 运行时字段(不持久化到 frontmatter)
|
|
37
39
|
embedding: Optional[List[float]] = None # 向量
|
|
@@ -48,9 +50,12 @@ class Note:
|
|
|
48
50
|
"""生成文件名"""
|
|
49
51
|
if self.type == NoteType.FLEETING:
|
|
50
52
|
return f"{self.id[:8]}-{self.id[8:]}.md"
|
|
53
|
+
elif self.type == NoteType.SESSION:
|
|
54
|
+
source = self.topic or self.title or "untitled"
|
|
55
|
+
slug = re.sub(r"[^\w\-]", "", source.lower().replace(" ", "-"))[:50]
|
|
56
|
+
return f"{self.id}-{slug}.md"
|
|
51
57
|
else:
|
|
52
58
|
slug = self.title.lower().replace(" ", "-")[:50]
|
|
53
|
-
# 移除特殊字符
|
|
54
59
|
slug = re.sub(r"[^\w\-]", "", slug)
|
|
55
60
|
return f"{self.id}-{slug}.md"
|
|
56
61
|
|
|
@@ -80,6 +85,8 @@ class Note:
|
|
|
80
85
|
}
|
|
81
86
|
if self.source:
|
|
82
87
|
frontmatter["source"] = self.source
|
|
88
|
+
if self.topic:
|
|
89
|
+
frontmatter["topic"] = self.topic
|
|
83
90
|
|
|
84
91
|
fm_yaml = yaml.dump(frontmatter, allow_unicode=True, sort_keys=False)
|
|
85
92
|
|
|
@@ -128,6 +135,7 @@ class Note:
|
|
|
128
135
|
links=fm.get("links", []),
|
|
129
136
|
backlinks=fm.get("backlinks", []),
|
|
130
137
|
source=fm.get("source"),
|
|
138
|
+
topic=fm.get("topic"),
|
|
131
139
|
)
|
|
132
140
|
|
|
133
141
|
def to_dict(self) -> Dict[str, Any]:
|
|
@@ -144,4 +152,5 @@ class Note:
|
|
|
144
152
|
"filepath": str(self.filepath),
|
|
145
153
|
"score": self.score,
|
|
146
154
|
"hop": self.hop,
|
|
155
|
+
"topic": self.topic,
|
|
147
156
|
}
|