jfox-cli 0.5.0__tar.gz → 0.6.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.5.0 → jfox_cli-0.6.0}/PKG-INFO +1 -1
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/__init__.py +1 -1
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/cli.py +37 -106
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/config.py +23 -2
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/daemon/process.py +38 -5
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/daemon/server.py +19 -1
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/template_cli.py +5 -23
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/pyproject.toml +1 -1
- jfox_cli-0.6.0/tests/unit/test_use_kb_env_var.py +94 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/uv.lock +1 -1
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.claude/settings.local.json +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.claude/skills/release/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.claude/skills/release/release_helper.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.githooks/pre-push +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.github/workflows/integration-test.yml +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.github/workflows/publish.yml +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.gitignore +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/.python-version +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/AGENTS.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/CHANGELOG.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/CLAUDE.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/DEVELOPMENT_PLAN.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/README.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/SESSION.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/SESSION_SUMMARY.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/installation.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/troubleshooting.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jessica-jones-static-cable.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/__main__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/bm25_index.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/daemon/__init__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/daemon/__main__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/daemon/client.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/embedding_backend.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/formatters.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/git_extractor.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/global_config.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/graph.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/indexer.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/kb_manager.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/model_downloader.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/models.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/note.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/performance.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/search_engine.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/template.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/jfox/vector_store.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/pytest.ini +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/run_full_test.ps1 +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/scripts/download-model-intranet.sh +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/README.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/COVERAGE_PLAN.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/MIGRATION.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/TESTS.md +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/conftest.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/integration/__init__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/integration/test_backlinks.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/integration/test_model_download.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/integration/test_tag_filter_cli.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/performance/__init__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/performance/test_performance.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_advanced_features.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_cli_format.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_config_set_unit.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_config_unit.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_core_workflow.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_embedding_device.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_hybrid_search.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_integration.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_kb_current.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/test_suggest_links.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/__init__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_bm25_batch.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_daemon_process.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_edit.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_format_unify.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_formatters.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_git_extractor.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_global_config.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_index_kb_param.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_indexer_verify.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_kb_manager.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_lazy_import.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_logging_config.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_model_downloader.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_release_helper.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_show.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_tag_filter.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_template.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_template_cli.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/unit/test_vector_store_clear.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/utils/__init__.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/utils/assertions.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/utils/jfox_cli.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/utils/note_generator.py +0 -0
- {jfox_cli-0.5.0 → jfox_cli-0.6.0}/tests/utils/temp_kb.py +0 -0
|
@@ -424,13 +424,9 @@ def add(
|
|
|
424
424
|
if not content:
|
|
425
425
|
raise ValueError("请提供笔记内容(位置参数或 --content-file)")
|
|
426
426
|
|
|
427
|
-
|
|
428
|
-
if kb:
|
|
429
|
-
from .config import use_kb
|
|
427
|
+
from .config import use_kb
|
|
430
428
|
|
|
431
|
-
|
|
432
|
-
_add_note_impl(content, title, note_type, tags, source, output_format, template)
|
|
433
|
-
else:
|
|
429
|
+
with use_kb(kb):
|
|
434
430
|
_add_note_impl(content, title, note_type, tags, source, output_format, template)
|
|
435
431
|
|
|
436
432
|
except typer.Exit:
|
|
@@ -561,13 +557,9 @@ def search(
|
|
|
561
557
|
if json_output:
|
|
562
558
|
output_format = "json"
|
|
563
559
|
|
|
564
|
-
|
|
565
|
-
if kb:
|
|
566
|
-
from .config import use_kb
|
|
560
|
+
from .config import use_kb
|
|
567
561
|
|
|
568
|
-
|
|
569
|
-
_search_impl(query, top, note_type, tags, search_mode, output_format)
|
|
570
|
-
else:
|
|
562
|
+
with use_kb(kb):
|
|
571
563
|
_search_impl(query, top, note_type, tags, search_mode, output_format)
|
|
572
564
|
|
|
573
565
|
except Exception as e:
|
|
@@ -746,13 +738,9 @@ def status(
|
|
|
746
738
|
):
|
|
747
739
|
"""查看知识库状态"""
|
|
748
740
|
try:
|
|
749
|
-
|
|
750
|
-
if kb:
|
|
751
|
-
from .config import use_kb
|
|
741
|
+
from .config import use_kb
|
|
752
742
|
|
|
753
|
-
|
|
754
|
-
_status_impl(output_format, json_output)
|
|
755
|
-
else:
|
|
743
|
+
with use_kb(kb):
|
|
756
744
|
_status_impl(output_format, json_output)
|
|
757
745
|
|
|
758
746
|
except Exception as e:
|
|
@@ -847,13 +835,9 @@ def list(
|
|
|
847
835
|
if json_output:
|
|
848
836
|
output_format = "json"
|
|
849
837
|
|
|
850
|
-
|
|
851
|
-
if kb:
|
|
852
|
-
from .config import use_kb
|
|
838
|
+
from .config import use_kb
|
|
853
839
|
|
|
854
|
-
|
|
855
|
-
_list_impl(note_type, tags, limit, output_format)
|
|
856
|
-
else:
|
|
840
|
+
with use_kb(kb):
|
|
857
841
|
_list_impl(note_type, tags, limit, output_format)
|
|
858
842
|
|
|
859
843
|
except Exception as e:
|
|
@@ -897,12 +881,9 @@ def show(
|
|
|
897
881
|
支持通过笔记 ID 或标题定位。
|
|
898
882
|
"""
|
|
899
883
|
try:
|
|
900
|
-
|
|
901
|
-
from .config import use_kb
|
|
884
|
+
from .config import use_kb
|
|
902
885
|
|
|
903
|
-
|
|
904
|
-
_show_impl(note_ref)
|
|
905
|
-
else:
|
|
886
|
+
with use_kb(kb):
|
|
906
887
|
_show_impl(note_ref)
|
|
907
888
|
|
|
908
889
|
except Exception as e:
|
|
@@ -1046,13 +1027,9 @@ def refs(
|
|
|
1046
1027
|
if json_output:
|
|
1047
1028
|
output_format = "json"
|
|
1048
1029
|
|
|
1049
|
-
|
|
1050
|
-
if kb:
|
|
1051
|
-
from .config import use_kb
|
|
1030
|
+
from .config import use_kb
|
|
1052
1031
|
|
|
1053
|
-
|
|
1054
|
-
_refs_impl(note_id, search, output_format, json_output)
|
|
1055
|
-
else:
|
|
1032
|
+
with use_kb(kb):
|
|
1056
1033
|
_refs_impl(note_id, search, output_format, json_output)
|
|
1057
1034
|
|
|
1058
1035
|
except Exception as e:
|
|
@@ -1125,13 +1102,9 @@ def delete(
|
|
|
1125
1102
|
if json_output:
|
|
1126
1103
|
output_format = "json"
|
|
1127
1104
|
|
|
1128
|
-
|
|
1129
|
-
if kb:
|
|
1130
|
-
from .config import use_kb
|
|
1105
|
+
from .config import use_kb
|
|
1131
1106
|
|
|
1132
|
-
|
|
1133
|
-
_delete_impl(note_id, force, output_format)
|
|
1134
|
-
else:
|
|
1107
|
+
with use_kb(kb):
|
|
1135
1108
|
_delete_impl(note_id, force, output_format)
|
|
1136
1109
|
|
|
1137
1110
|
except typer.Exit:
|
|
@@ -1331,14 +1304,9 @@ def edit(
|
|
|
1331
1304
|
if json_output:
|
|
1332
1305
|
output_format = "json"
|
|
1333
1306
|
|
|
1334
|
-
|
|
1335
|
-
from .config import use_kb
|
|
1307
|
+
from .config import use_kb
|
|
1336
1308
|
|
|
1337
|
-
|
|
1338
|
-
_edit_impl(
|
|
1339
|
-
note_id, content, content_file, title, tags, note_type, source, output_format
|
|
1340
|
-
)
|
|
1341
|
-
else:
|
|
1309
|
+
with use_kb(kb):
|
|
1342
1310
|
_edit_impl(
|
|
1343
1311
|
note_id, content, content_file, title, tags, note_type, source, output_format
|
|
1344
1312
|
)
|
|
@@ -1443,13 +1411,9 @@ def query(
|
|
|
1443
1411
|
):
|
|
1444
1412
|
"""语义搜索 + 知识图谱联合查询"""
|
|
1445
1413
|
try:
|
|
1446
|
-
|
|
1447
|
-
if kb:
|
|
1448
|
-
from .config import use_kb
|
|
1414
|
+
from .config import use_kb
|
|
1449
1415
|
|
|
1450
|
-
|
|
1451
|
-
_query_impl(query_str, top, graph_depth, json_output)
|
|
1452
|
-
else:
|
|
1416
|
+
with use_kb(kb):
|
|
1453
1417
|
_query_impl(query_str, top, graph_depth, json_output)
|
|
1454
1418
|
|
|
1455
1419
|
except Exception as e:
|
|
@@ -1579,13 +1543,9 @@ def graph(
|
|
|
1579
1543
|
if json_output:
|
|
1580
1544
|
output_format = "json"
|
|
1581
1545
|
|
|
1582
|
-
|
|
1583
|
-
if kb:
|
|
1584
|
-
from .config import use_kb
|
|
1546
|
+
from .config import use_kb
|
|
1585
1547
|
|
|
1586
|
-
|
|
1587
|
-
_graph_impl(note_id, depth, stats, orphans, output_format, json_output)
|
|
1588
|
-
else:
|
|
1548
|
+
with use_kb(kb):
|
|
1589
1549
|
_graph_impl(note_id, depth, stats, orphans, output_format, json_output)
|
|
1590
1550
|
|
|
1591
1551
|
except Exception as e:
|
|
@@ -1654,13 +1614,9 @@ def daily(
|
|
|
1654
1614
|
if json_output:
|
|
1655
1615
|
output_format = "json"
|
|
1656
1616
|
|
|
1657
|
-
|
|
1658
|
-
if kb:
|
|
1659
|
-
from .config import use_kb
|
|
1617
|
+
from .config import use_kb
|
|
1660
1618
|
|
|
1661
|
-
|
|
1662
|
-
_daily_impl(date, output_format, json_output)
|
|
1663
|
-
else:
|
|
1619
|
+
with use_kb(kb):
|
|
1664
1620
|
_daily_impl(date, output_format, json_output)
|
|
1665
1621
|
|
|
1666
1622
|
except Exception as e:
|
|
@@ -1766,13 +1722,9 @@ def suggest_links(
|
|
|
1766
1722
|
output_format = "json"
|
|
1767
1723
|
|
|
1768
1724
|
try:
|
|
1769
|
-
|
|
1770
|
-
if kb:
|
|
1771
|
-
from .config import use_kb
|
|
1725
|
+
from .config import use_kb
|
|
1772
1726
|
|
|
1773
|
-
|
|
1774
|
-
_suggest_links_impl(content, top_k, threshold, output_format, json_output)
|
|
1775
|
-
else:
|
|
1727
|
+
with use_kb(kb):
|
|
1776
1728
|
_suggest_links_impl(content, top_k, threshold, output_format, json_output)
|
|
1777
1729
|
|
|
1778
1730
|
except Exception as e:
|
|
@@ -1799,13 +1751,9 @@ def inbox(
|
|
|
1799
1751
|
if json_output:
|
|
1800
1752
|
output_format = "json"
|
|
1801
1753
|
|
|
1802
|
-
|
|
1803
|
-
if kb:
|
|
1804
|
-
from .config import use_kb
|
|
1754
|
+
from .config import use_kb
|
|
1805
1755
|
|
|
1806
|
-
|
|
1807
|
-
_inbox_impl(limit, output_format, json_output)
|
|
1808
|
-
else:
|
|
1756
|
+
with use_kb(kb):
|
|
1809
1757
|
_inbox_impl(limit, output_format, json_output)
|
|
1810
1758
|
|
|
1811
1759
|
except Exception as e:
|
|
@@ -1985,13 +1933,9 @@ def index(
|
|
|
1985
1933
|
if json_output:
|
|
1986
1934
|
output_format = "json"
|
|
1987
1935
|
|
|
1988
|
-
|
|
1989
|
-
if kb:
|
|
1990
|
-
from .config import use_kb
|
|
1936
|
+
from .config import use_kb
|
|
1991
1937
|
|
|
1992
|
-
|
|
1993
|
-
_index_impl(action, output_format)
|
|
1994
|
-
else:
|
|
1938
|
+
with use_kb(kb):
|
|
1995
1939
|
_index_impl(action, output_format)
|
|
1996
1940
|
|
|
1997
1941
|
except typer.Exit:
|
|
@@ -2453,15 +2397,9 @@ def ingest_log(
|
|
|
2453
2397
|
if json_output:
|
|
2454
2398
|
output_format = "json"
|
|
2455
2399
|
|
|
2456
|
-
|
|
2457
|
-
if kb:
|
|
2458
|
-
from .config import use_kb
|
|
2400
|
+
from .config import use_kb
|
|
2459
2401
|
|
|
2460
|
-
|
|
2461
|
-
_ingest_log_impl(
|
|
2462
|
-
repo_path, limit, note_type, batch_size, output_format, json_output
|
|
2463
|
-
)
|
|
2464
|
-
else:
|
|
2402
|
+
with use_kb(kb):
|
|
2465
2403
|
_ingest_log_impl(repo_path, limit, note_type, batch_size, output_format, json_output)
|
|
2466
2404
|
|
|
2467
2405
|
except ValueError as e:
|
|
@@ -2512,20 +2450,10 @@ def bulk_import(
|
|
|
2512
2450
|
|
|
2513
2451
|
console.print(f"[yellow]Importing {len(notes_data)} notes...[/yellow]")
|
|
2514
2452
|
|
|
2453
|
+
from .config import use_kb
|
|
2515
2454
|
from .performance import bulk_import_notes
|
|
2516
2455
|
|
|
2517
|
-
|
|
2518
|
-
if kb:
|
|
2519
|
-
from .config import use_kb
|
|
2520
|
-
|
|
2521
|
-
with use_kb(kb):
|
|
2522
|
-
result = bulk_import_notes(
|
|
2523
|
-
notes_data=notes_data,
|
|
2524
|
-
note_type=note_type,
|
|
2525
|
-
batch_size=batch_size,
|
|
2526
|
-
show_progress=not json_output,
|
|
2527
|
-
)
|
|
2528
|
-
else:
|
|
2456
|
+
with use_kb(kb):
|
|
2529
2457
|
result = bulk_import_notes(
|
|
2530
2458
|
notes_data=notes_data,
|
|
2531
2459
|
note_type=note_type,
|
|
@@ -2659,8 +2587,11 @@ def daemon(
|
|
|
2659
2587
|
console.print("[dim]Daemon 未运行[/dim]")
|
|
2660
2588
|
return
|
|
2661
2589
|
console.print("[yellow]正在停止 daemon...[/yellow]")
|
|
2662
|
-
stop_daemon()
|
|
2663
|
-
|
|
2590
|
+
if stop_daemon():
|
|
2591
|
+
console.print("[green]✓ Daemon 已停止[/green]")
|
|
2592
|
+
else:
|
|
2593
|
+
console.print("[red]✗ Daemon 停止失败,请手动终止进程[/red]")
|
|
2594
|
+
raise typer.Exit(1)
|
|
2664
2595
|
|
|
2665
2596
|
elif action == "status":
|
|
2666
2597
|
info = get_daemon_status()
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"""配置管理"""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from contextlib import contextmanager
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
8
9
|
import yaml
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
_console = Console(stderr=True)
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
def get_default_kb_path() -> Path:
|
|
@@ -148,15 +152,26 @@ def use_kb(kb_name: Optional[str] = None):
|
|
|
148
152
|
# 在这个上下文中,操作都在 work 知识库上
|
|
149
153
|
note = create_note(...)
|
|
150
154
|
|
|
155
|
+
优先级: --kb > JFOX_KB > 全局配置 default
|
|
156
|
+
当 kb_name 为 None 时,会先检查 JFOX_KB 环境变量,
|
|
157
|
+
若未设置则使用全局配置中的默认知识库。
|
|
158
|
+
|
|
151
159
|
Args:
|
|
152
160
|
kb_name: 知识库名称,None 表示使用当前默认知识库
|
|
153
161
|
|
|
154
162
|
Raises:
|
|
155
163
|
ValueError: 知识库不存在
|
|
156
164
|
"""
|
|
165
|
+
resolved_from_env = False
|
|
166
|
+
|
|
157
167
|
if not kb_name:
|
|
158
|
-
|
|
159
|
-
|
|
168
|
+
env_kb = os.environ.get("JFOX_KB", "").strip()
|
|
169
|
+
if env_kb:
|
|
170
|
+
kb_name = env_kb
|
|
171
|
+
resolved_from_env = True
|
|
172
|
+
else:
|
|
173
|
+
yield
|
|
174
|
+
return
|
|
160
175
|
|
|
161
176
|
from .kb_manager import get_kb_manager
|
|
162
177
|
|
|
@@ -182,6 +197,12 @@ def use_kb(kb_name: Optional[str] = None):
|
|
|
182
197
|
# 重置索引和搜索引擎(使用新的知识库路径)
|
|
183
198
|
_reset_singletons()
|
|
184
199
|
|
|
200
|
+
if resolved_from_env:
|
|
201
|
+
_console.print(
|
|
202
|
+
f"Using knowledge base '{kb_name}' (from JFOX_KB environment variable)",
|
|
203
|
+
style="dim",
|
|
204
|
+
)
|
|
205
|
+
|
|
185
206
|
yield
|
|
186
207
|
finally:
|
|
187
208
|
# 恢复原始配置
|
|
@@ -88,6 +88,19 @@ def _http_health_check(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> Op
|
|
|
88
88
|
return None
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def _http_shutdown(host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> bool:
|
|
92
|
+
"""请求 daemon 通过 /shutdown endpoint 自行停止"""
|
|
93
|
+
try:
|
|
94
|
+
import urllib.request
|
|
95
|
+
|
|
96
|
+
req = urllib.request.Request(f"http://{host}:{port}/shutdown", method="POST", data=b"")
|
|
97
|
+
with urllib.request.urlopen(req, timeout=3) as resp:
|
|
98
|
+
result = json.loads(resp.read().decode("utf-8"))
|
|
99
|
+
return result.get("status") == "shutting_down"
|
|
100
|
+
except (OSError, ValueError):
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
|
|
91
104
|
def is_daemon_running() -> bool:
|
|
92
105
|
"""检查 daemon 是否在运行(以 HTTP 健康检查为准)"""
|
|
93
106
|
# 先尝试 PID 文件记录的地址
|
|
@@ -276,11 +289,32 @@ def stop_daemon() -> bool:
|
|
|
276
289
|
port = data.get("port", DEFAULT_PORT)
|
|
277
290
|
|
|
278
291
|
# 先检查是否真的在跑
|
|
279
|
-
|
|
292
|
+
health = _http_health_check(host, port)
|
|
293
|
+
if health is None:
|
|
280
294
|
_remove_pid_file()
|
|
281
295
|
return True
|
|
282
296
|
|
|
283
|
-
#
|
|
297
|
+
# 1. 优先通过 HTTP /shutdown 让 daemon 自行退出
|
|
298
|
+
logger.info("正在通过 /shutdown 请求 daemon 停止...")
|
|
299
|
+
shutdown_ok = _http_shutdown(host, port)
|
|
300
|
+
|
|
301
|
+
if shutdown_ok:
|
|
302
|
+
# 等待 daemon 自行退出(最多 3 秒)
|
|
303
|
+
for _ in range(6):
|
|
304
|
+
if _http_health_check(host, port) is None:
|
|
305
|
+
_remove_pid_file()
|
|
306
|
+
logger.info("Daemon 已通过 /shutdown 停止")
|
|
307
|
+
return True
|
|
308
|
+
time.sleep(0.5)
|
|
309
|
+
|
|
310
|
+
# 2. /shutdown 失败或超时,从 /health 获取真实 PID 后尝试 taskkill/kill
|
|
311
|
+
if pid == 0:
|
|
312
|
+
health = _http_health_check(host, port)
|
|
313
|
+
if health:
|
|
314
|
+
pid = health.get("pid", 0)
|
|
315
|
+
if not isinstance(pid, int):
|
|
316
|
+
pid = 0
|
|
317
|
+
|
|
284
318
|
if pid > 0:
|
|
285
319
|
try:
|
|
286
320
|
if sys.platform == "win32":
|
|
@@ -294,7 +328,7 @@ def stop_daemon() -> bool:
|
|
|
294
328
|
except (OSError, subprocess.SubprocessError) as e:
|
|
295
329
|
logger.warning(f"停止 daemon 失败: {e}")
|
|
296
330
|
|
|
297
|
-
#
|
|
331
|
+
# 等待进程退出(最多 5 秒)
|
|
298
332
|
for _ in range(10):
|
|
299
333
|
if _http_health_check(host, port) is None:
|
|
300
334
|
_remove_pid_file()
|
|
@@ -302,9 +336,8 @@ def stop_daemon() -> bool:
|
|
|
302
336
|
return True
|
|
303
337
|
time.sleep(0.5)
|
|
304
338
|
|
|
305
|
-
# 超时未退出
|
|
339
|
+
# 超时未退出 — 不删 PID 文件,保留追踪信息
|
|
306
340
|
logger.warning(f"Daemon 停止超时 (PID: {pid})")
|
|
307
|
-
_remove_pid_file()
|
|
308
341
|
return False
|
|
309
342
|
|
|
310
343
|
|
|
@@ -19,6 +19,9 @@ logger = logging.getLogger(__name__)
|
|
|
19
19
|
# 全局 embedding 后端(模型加载后常驻内存)
|
|
20
20
|
_backend = None
|
|
21
21
|
|
|
22
|
+
# uvicorn Server 实例(用于 graceful shutdown)
|
|
23
|
+
_server = None
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
def _load_model():
|
|
24
27
|
"""启动时加载模型(标记为 daemon 进程,防止自引用)"""
|
|
@@ -76,6 +79,10 @@ class EncodeSingleRequest(BaseModel):
|
|
|
76
79
|
text: str
|
|
77
80
|
|
|
78
81
|
|
|
82
|
+
class ShutdownResponse(BaseModel):
|
|
83
|
+
status: str
|
|
84
|
+
|
|
85
|
+
|
|
79
86
|
class EncodeSingleResponse(BaseModel):
|
|
80
87
|
embedding: List[float]
|
|
81
88
|
dimension: int
|
|
@@ -98,6 +105,14 @@ def health():
|
|
|
98
105
|
)
|
|
99
106
|
|
|
100
107
|
|
|
108
|
+
@app.post("/shutdown", response_model=ShutdownResponse)
|
|
109
|
+
def shutdown():
|
|
110
|
+
"""请求 daemon 自行停止"""
|
|
111
|
+
if _server:
|
|
112
|
+
_server.should_exit = True
|
|
113
|
+
return ShutdownResponse(status="shutting_down")
|
|
114
|
+
|
|
115
|
+
|
|
101
116
|
@app.post("/encode", response_model=EncodeResponse)
|
|
102
117
|
def encode(req: EncodeRequest):
|
|
103
118
|
"""批量文本编码"""
|
|
@@ -133,7 +148,10 @@ def main():
|
|
|
133
148
|
|
|
134
149
|
import uvicorn
|
|
135
150
|
|
|
136
|
-
|
|
151
|
+
global _server
|
|
152
|
+
config = uvicorn.Config(app, host=args.host, port=args.port, log_level="warning")
|
|
153
|
+
_server = uvicorn.Server(config)
|
|
154
|
+
_server.run()
|
|
137
155
|
|
|
138
156
|
|
|
139
157
|
if __name__ == "__main__":
|
|
@@ -42,11 +42,7 @@ def list_templates(
|
|
|
42
42
|
if json_output:
|
|
43
43
|
output_format = "json"
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
with use_kb(kb):
|
|
47
|
-
manager = get_template_manager()
|
|
48
|
-
templates = manager.list_templates()
|
|
49
|
-
else:
|
|
45
|
+
with use_kb(kb):
|
|
50
46
|
manager = get_template_manager()
|
|
51
47
|
templates = manager.list_templates()
|
|
52
48
|
|
|
@@ -120,11 +116,7 @@ def show_template(
|
|
|
120
116
|
try:
|
|
121
117
|
from .config import use_kb
|
|
122
118
|
|
|
123
|
-
|
|
124
|
-
with use_kb(kb):
|
|
125
|
-
manager = get_template_manager()
|
|
126
|
-
template = manager.get_template(name)
|
|
127
|
-
else:
|
|
119
|
+
with use_kb(kb):
|
|
128
120
|
manager = get_template_manager()
|
|
129
121
|
template = manager.get_template(name)
|
|
130
122
|
|
|
@@ -183,10 +175,7 @@ def create_template(
|
|
|
183
175
|
try:
|
|
184
176
|
from .config import use_kb
|
|
185
177
|
|
|
186
|
-
|
|
187
|
-
with use_kb(kb):
|
|
188
|
-
manager = get_template_manager()
|
|
189
|
-
else:
|
|
178
|
+
with use_kb(kb):
|
|
190
179
|
manager = get_template_manager()
|
|
191
180
|
|
|
192
181
|
# Check if template exists
|
|
@@ -246,11 +235,7 @@ def edit_template(
|
|
|
246
235
|
try:
|
|
247
236
|
from .config import use_kb
|
|
248
237
|
|
|
249
|
-
|
|
250
|
-
with use_kb(kb):
|
|
251
|
-
manager = get_template_manager()
|
|
252
|
-
template = manager.get_template(name)
|
|
253
|
-
else:
|
|
238
|
+
with use_kb(kb):
|
|
254
239
|
manager = get_template_manager()
|
|
255
240
|
template = manager.get_template(name)
|
|
256
241
|
|
|
@@ -294,10 +279,7 @@ def remove_template(
|
|
|
294
279
|
try:
|
|
295
280
|
from .config import use_kb
|
|
296
281
|
|
|
297
|
-
|
|
298
|
-
with use_kb(kb):
|
|
299
|
-
manager = get_template_manager()
|
|
300
|
-
else:
|
|
282
|
+
with use_kb(kb):
|
|
301
283
|
manager = get_template_manager()
|
|
302
284
|
|
|
303
285
|
template = manager.get_template(name)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
测试类型: 单元测试
|
|
3
|
+
目标模块: jfox.config.use_kb
|
|
4
|
+
预估耗时: < 1秒
|
|
5
|
+
依赖要求: 无外部依赖,使用 mock
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
pytestmark = [pytest.mark.unit, pytest.mark.fast]
|
|
13
|
+
from unittest.mock import Mock, patch
|
|
14
|
+
|
|
15
|
+
from jfox.config import config, use_kb
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestUseKbEnvVar:
|
|
19
|
+
"""测试 use_kb() 对 JFOX_KB 环境变量的支持"""
|
|
20
|
+
|
|
21
|
+
def test_env_var_used_when_kb_arg_none(self):
|
|
22
|
+
"""当 kb_name 为 None 且 JFOX_KB 设置时,应切换到该知识库"""
|
|
23
|
+
with patch.dict(os.environ, {"JFOX_KB": "work"}):
|
|
24
|
+
with patch("jfox.config._reset_singletons"):
|
|
25
|
+
with patch("jfox.kb_manager.get_kb_manager") as mock_get_manager:
|
|
26
|
+
mock_manager = Mock()
|
|
27
|
+
mock_manager.config_manager.kb_exists.return_value = True
|
|
28
|
+
mock_manager.config_manager.get_kb_path.return_value = (
|
|
29
|
+
config.base_dir.parent / "work"
|
|
30
|
+
)
|
|
31
|
+
mock_get_manager.return_value = mock_manager
|
|
32
|
+
|
|
33
|
+
with use_kb(None) as _:
|
|
34
|
+
# 验证确实切换了知识库
|
|
35
|
+
mock_manager.config_manager.get_kb_path.assert_called_once_with("work")
|
|
36
|
+
|
|
37
|
+
def test_cli_arg_overrides_env_var(self):
|
|
38
|
+
"""当同时传入 kb_name 和设置 JFOX_KB 时,应优先使用传入的 kb_name"""
|
|
39
|
+
with patch.dict(os.environ, {"JFOX_KB": "work"}):
|
|
40
|
+
with patch("jfox.config._reset_singletons"):
|
|
41
|
+
with patch("jfox.kb_manager.get_kb_manager") as mock_get_manager:
|
|
42
|
+
mock_manager = Mock()
|
|
43
|
+
mock_manager.config_manager.kb_exists.return_value = True
|
|
44
|
+
mock_manager.config_manager.get_kb_path.return_value = (
|
|
45
|
+
config.base_dir.parent / "personal"
|
|
46
|
+
)
|
|
47
|
+
mock_get_manager.return_value = mock_manager
|
|
48
|
+
|
|
49
|
+
with use_kb("personal") as _:
|
|
50
|
+
# 验证使用的是传入的 "personal",而不是环境变量的 "work"
|
|
51
|
+
mock_manager.config_manager.get_kb_path.assert_called_once_with("personal")
|
|
52
|
+
|
|
53
|
+
def test_invalid_jfox_kb_raises_valueerror(self):
|
|
54
|
+
"""当 JFOX_KB 指向不存在的知识库时,应抛出 ValueError"""
|
|
55
|
+
with patch.dict(os.environ, {"JFOX_KB": "nonexistent"}):
|
|
56
|
+
with patch("jfox.config._reset_singletons"):
|
|
57
|
+
with patch("jfox.kb_manager.get_kb_manager") as mock_get_manager:
|
|
58
|
+
mock_manager = Mock()
|
|
59
|
+
mock_manager.config_manager.kb_exists.return_value = False
|
|
60
|
+
mock_get_manager.return_value = mock_manager
|
|
61
|
+
|
|
62
|
+
with pytest.raises(ValueError, match="Knowledge base 'nonexistent' not found"):
|
|
63
|
+
with use_kb(None):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
def test_no_env_var_falls_back_to_global_default(self):
|
|
67
|
+
"""当没有设置 JFOX_KB 且 kb_name 为 None 时,应直接使用当前默认知识库"""
|
|
68
|
+
with patch.dict(os.environ, {}, clear=False):
|
|
69
|
+
os.environ.pop("JFOX_KB", None)
|
|
70
|
+
with patch("jfox.kb_manager.get_kb_manager") as mock_get_manager:
|
|
71
|
+
# 不应调用 get_kb_manager,因为没有需要切换的知识库
|
|
72
|
+
original_base_dir = config.base_dir
|
|
73
|
+
|
|
74
|
+
with use_kb(None) as _:
|
|
75
|
+
# 验证没有尝试获取 kb_manager
|
|
76
|
+
mock_get_manager.assert_not_called()
|
|
77
|
+
# 验证配置没有被修改
|
|
78
|
+
assert config.base_dir == original_base_dir
|
|
79
|
+
|
|
80
|
+
def test_jfox_kb_with_whitespace_is_stripped(self):
|
|
81
|
+
"""JFOX_KB 值包含首尾空格时应被去除"""
|
|
82
|
+
with patch.dict(os.environ, {"JFOX_KB": " work "}):
|
|
83
|
+
with patch("jfox.config._reset_singletons"):
|
|
84
|
+
with patch("jfox.kb_manager.get_kb_manager") as mock_get_manager:
|
|
85
|
+
mock_manager = Mock()
|
|
86
|
+
mock_manager.config_manager.kb_exists.return_value = True
|
|
87
|
+
mock_manager.config_manager.get_kb_path.return_value = (
|
|
88
|
+
config.base_dir.parent / "work"
|
|
89
|
+
)
|
|
90
|
+
mock_get_manager.return_value = mock_manager
|
|
91
|
+
|
|
92
|
+
with use_kb(None) as _:
|
|
93
|
+
# 验证去除了空格后使用的是 "work"
|
|
94
|
+
mock_manager.config_manager.get_kb_path.assert_called_once_with("work")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md
RENAMED
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md
RENAMED
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/plans/2026-04-27-intranet-model-download.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md
RENAMED
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.5.0 → jfox_cli-0.6.0}/skills-recommend/claude-code/jfox-session-summary/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|