jfox-cli 0.7.0__tar.gz → 0.7.1__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.
Files changed (160) hide show
  1. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/CHANGELOG.md +7 -0
  2. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/PKG-INFO +1 -1
  3. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/__init__.py +1 -1
  4. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/model_downloader.py +75 -18
  5. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/pyproject.toml +1 -1
  6. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_model_downloader.py +24 -0
  7. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/uv.lock +1 -1
  8. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.claude/settings.local.json +0 -0
  9. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.claude/skills/ci/SKILL.md +0 -0
  10. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.claude/skills/release/SKILL.md +0 -0
  11. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.claude/skills/release/release_helper.py +0 -0
  12. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.githooks/pre-push +0 -0
  13. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.github/workflows/integration-test.yml +0 -0
  14. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.github/workflows/publish.yml +0 -0
  15. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.gitignore +0 -0
  16. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/.python-version +0 -0
  17. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/AGENTS.md +0 -0
  18. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/CLAUDE.md +0 -0
  19. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/DEVELOPMENT_PLAN.md +0 -0
  20. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/README.md +0 -0
  21. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/SESSION.md +0 -0
  22. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/SESSION_SUMMARY.md +0 -0
  23. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/installation.md +0 -0
  24. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
  25. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
  26. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
  27. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
  28. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
  29. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
  30. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
  31. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
  32. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
  33. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
  34. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
  35. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
  36. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
  37. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
  38. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
  39. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
  40. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
  41. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
  42. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
  43. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
  44. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
  45. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
  46. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
  47. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
  48. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
  49. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
  50. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
  51. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-04-29-daemon-stop-fix.md +0 -0
  52. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-05-03-jfox-check.md +0 -0
  53. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md +0 -0
  54. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-05-03-log-level-fix.md +0 -0
  55. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/plans/2026-05-04-list-notes-index.md +0 -0
  56. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
  57. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
  58. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
  59. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
  60. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
  61. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
  62. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
  63. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
  64. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
  65. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
  66. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md +0 -0
  67. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md +0 -0
  68. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-05-03-jfox-check-design.md +0 -0
  69. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-05-03-list-notes-skip-summary-design.md +0 -0
  70. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-05-03-log-level-fix-design.md +0 -0
  71. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md +0 -0
  72. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/docs/troubleshooting.md +0 -0
  73. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jessica-jones-static-cable.md +0 -0
  74. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/__main__.py +0 -0
  75. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/bm25_index.py +0 -0
  76. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/cli.py +0 -0
  77. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/config.py +0 -0
  78. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/daemon/__init__.py +0 -0
  79. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/daemon/__main__.py +0 -0
  80. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/daemon/client.py +0 -0
  81. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/daemon/process.py +0 -0
  82. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/daemon/server.py +0 -0
  83. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/embedding_backend.py +0 -0
  84. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/formatters.py +0 -0
  85. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/git_extractor.py +0 -0
  86. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/global_config.py +0 -0
  87. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/graph.py +0 -0
  88. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/indexer.py +0 -0
  89. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/kb_manager.py +0 -0
  90. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/models.py +0 -0
  91. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/note.py +0 -0
  92. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/note_index.py +0 -0
  93. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/performance.py +0 -0
  94. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/search_engine.py +0 -0
  95. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/template.py +0 -0
  96. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/template_cli.py +0 -0
  97. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/jfox/vector_store.py +0 -0
  98. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/pytest.ini +0 -0
  99. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/run_full_test.ps1 +0 -0
  100. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/scripts/download-model-intranet.sh +0 -0
  101. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/README.md +0 -0
  102. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/claude-code/jfox-common/SKILL.md +0 -0
  103. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/claude-code/jfox-ingest/SKILL.md +0 -0
  104. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/claude-code/jfox-organize/SKILL.md +0 -0
  105. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/claude-code/jfox-search/SKILL.md +0 -0
  106. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/claude-code/jfox-session-summary/SKILL.md +0 -0
  107. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
  108. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
  109. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
  110. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
  111. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -0
  112. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/COVERAGE_PLAN.md +0 -0
  113. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/MIGRATION.md +0 -0
  114. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/TESTS.md +0 -0
  115. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/conftest.py +0 -0
  116. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/integration/__init__.py +0 -0
  117. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/integration/test_backlinks.py +0 -0
  118. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/integration/test_model_download.py +0 -0
  119. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/integration/test_tag_filter_cli.py +0 -0
  120. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/performance/__init__.py +0 -0
  121. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/performance/test_performance.py +0 -0
  122. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_advanced_features.py +0 -0
  123. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_cli_format.py +0 -0
  124. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_config_set_unit.py +0 -0
  125. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_config_unit.py +0 -0
  126. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_core_workflow.py +0 -0
  127. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_embedding_device.py +0 -0
  128. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_hybrid_search.py +0 -0
  129. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_integration.py +0 -0
  130. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_kb_current.py +0 -0
  131. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/test_suggest_links.py +0 -0
  132. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/__init__.py +0 -0
  133. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_bm25_batch.py +0 -0
  134. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_check.py +0 -0
  135. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_daemon_process.py +0 -0
  136. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_edit.py +0 -0
  137. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_format_unify.py +0 -0
  138. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_formatters.py +0 -0
  139. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_git_extractor.py +0 -0
  140. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_global_config.py +0 -0
  141. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_index_kb_param.py +0 -0
  142. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
  143. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_indexer_verify.py +0 -0
  144. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_kb_manager.py +0 -0
  145. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_lazy_import.py +0 -0
  146. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_list_notes_skip.py +0 -0
  147. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_logging_config.py +0 -0
  148. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_note_index.py +0 -0
  149. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_release_helper.py +0 -0
  150. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_show.py +0 -0
  151. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_tag_filter.py +0 -0
  152. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_template.py +0 -0
  153. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_template_cli.py +0 -0
  154. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_use_kb_env_var.py +0 -0
  155. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/unit/test_vector_store_clear.py +0 -0
  156. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/utils/__init__.py +0 -0
  157. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/utils/assertions.py +0 -0
  158. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/utils/jfox_cli.py +0 -0
  159. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/utils/note_generator.py +0 -0
  160. {jfox_cli-0.7.0 → jfox_cli-0.7.1}/tests/utils/temp_kb.py +0 -0
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to jfox-cli will be documented in this file.
4
4
 
5
+ ## [0.7.1] - 2026-05-05
6
+
7
+ ### Fixes
8
+ - dynamically detect model weight file format
9
+
10
+ [0.7.1]: https://github.com/zhuxixi/jfox/compare/v0.7.0...v0.7.1
11
+
5
12
  ## [0.7.0] - 2026-05-05
6
13
 
7
14
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jfox-cli
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: JFox - Zettelkasten 知识管理 CLI 工具
5
5
  Project-URL: Homepage, https://github.com/zhuxixi/jfox
6
6
  Project-URL: Repository, https://github.com/zhuxixi/jfox
@@ -1,5 +1,5 @@
1
1
  """JFox - Zettelkasten 知识管理工具"""
2
2
 
3
- __version__ = "0.7.0"
3
+ __version__ = "0.7.1"
4
4
  __author__ = "User"
5
5
  __email__ = "user@example.com"
@@ -18,9 +18,14 @@ _HF_MIRROR = "https://hf-mirror.com"
18
18
  _TIMEOUT_HF_HUB = 60
19
19
  _TIMEOUT_CURL = 120
20
20
 
21
- # 需要下载的文件列表(按重要性排序)
22
- _REQUIRED_FILES = [
21
+ # 权重文件候选列表(按优先级排序:safetensors 优先,PyTorch 回退)
22
+ _WEIGHT_FILE_CANDIDATES = [
23
23
  "model.safetensors",
24
+ "pytorch_model.bin",
25
+ ]
26
+
27
+ # 非权重必需文件列表
28
+ _REQUIRED_FILES = [
24
29
  "config.json",
25
30
  "tokenizer.json",
26
31
  "tokenizer_config.json",
@@ -89,12 +94,13 @@ class ModelDownloader:
89
94
  snapshots_dir = self._model_cache / "snapshots"
90
95
  if not snapshots_dir.exists():
91
96
  return False
92
- # 检查至少有一个 snapshot 且包含 model.safetensors
97
+ # 检查至少有一个 snapshot 且包含权重文件
93
98
  try:
94
99
  for snapshot in snapshots_dir.iterdir():
95
100
  if snapshot.is_dir():
96
- if (snapshot / "model.safetensors").exists():
97
- return True
101
+ for candidate in _WEIGHT_FILE_CANDIDATES:
102
+ if (snapshot / candidate).exists():
103
+ return True
98
104
  except OSError:
99
105
  logger.warning(f"无法遍历缓存目录: {snapshots_dir}")
100
106
  return False
@@ -113,15 +119,29 @@ class ModelDownloader:
113
119
  env_backup = os.environ.get("HF_ENDPOINT")
114
120
  os.environ["HF_ENDPOINT"] = endpoint
115
121
 
116
- # 下载核心文件
117
- hf_hub_download(
118
- repo_id=self.model_name,
119
- filename="model.safetensors",
120
- cache_dir=str(self._hf_hub_cache),
121
- local_files_only=False,
122
- )
122
+ # 按优先级尝试下载权重文件
123
+ weight_downloaded = False
124
+ for candidate in _WEIGHT_FILE_CANDIDATES:
125
+ try:
126
+ hf_hub_download(
127
+ repo_id=self.model_name,
128
+ filename=candidate,
129
+ cache_dir=str(self._hf_hub_cache),
130
+ local_files_only=False,
131
+ )
132
+ weight_downloaded = True
133
+ logger.debug(f"权重文件 {candidate} 下载成功")
134
+ break
135
+ except Exception as e:
136
+ logger.debug(f"权重文件 {candidate} 尝试失败 ({e}),尝试下一个")
137
+ continue
138
+
139
+ if not weight_downloaded:
140
+ logger.warning("所有权重文件候选均下载失败")
141
+ return False
142
+
123
143
  # 尝试下载其他必要文件(不失败)
124
- for fname in _REQUIRED_FILES[1:]:
144
+ for fname in _REQUIRED_FILES:
125
145
  try:
126
146
  hf_hub_download(
127
147
  repo_id=self.model_name,
@@ -159,6 +179,46 @@ class ModelDownloader:
159
179
  tmp_path = Path(tmpdir)
160
180
  downloaded = []
161
181
 
182
+ # 按优先级尝试下载权重文件
183
+ weight_downloaded = False
184
+ for candidate in _WEIGHT_FILE_CANDIDATES:
185
+ url = f"{base_url}/{candidate}"
186
+ dest = tmp_path / candidate
187
+ logger.info(f"试用权重文件 {candidate}...")
188
+ try:
189
+ result = subprocess.run(
190
+ [
191
+ "curl",
192
+ "-L",
193
+ "-f",
194
+ "-s",
195
+ "-S",
196
+ "--connect-timeout",
197
+ "10",
198
+ "--max-time",
199
+ str(_TIMEOUT_CURL),
200
+ "-o",
201
+ str(dest),
202
+ url,
203
+ ],
204
+ capture_output=True,
205
+ text=True,
206
+ timeout=_TIMEOUT_CURL + 5,
207
+ )
208
+ if result.returncode == 0 and dest.exists() and dest.stat().st_size > 0:
209
+ downloaded.append(candidate)
210
+ weight_downloaded = True
211
+ break
212
+ else:
213
+ logger.debug(f"{candidate} 下载失败或为空,跳过")
214
+ except (OSError, subprocess.TimeoutExpired) as e:
215
+ logger.debug(f"{candidate} 下载异常: {e}")
216
+
217
+ if not weight_downloaded:
218
+ logger.error("所有权重文件候选下载失败,步骤 3 未完成")
219
+ return False
220
+
221
+ # 下载非权重必需文件
162
222
  for fname in _REQUIRED_FILES:
163
223
  url = f"{base_url}/{fname}"
164
224
  dest = tmp_path / fname
@@ -190,10 +250,6 @@ class ModelDownloader:
190
250
  except (OSError, subprocess.TimeoutExpired) as e:
191
251
  logger.debug(f"{fname} 下载异常: {e}")
192
252
 
193
- if "model.safetensors" not in downloaded:
194
- logger.error("model.safetensors 下载失败,步骤 3 未完成")
195
- return False
196
-
197
253
  # 按 HF 缓存目录结构放置
198
254
  import hashlib
199
255
 
@@ -215,10 +271,11 @@ class ModelDownloader:
215
271
 
216
272
  def get_manual_instructions(self) -> str:
217
273
  """获取手动下载说明"""
274
+ candidates = " / ".join(_WEIGHT_FILE_CANDIDATES)
218
275
  return (
219
276
  f"自动下载失败。请手动下载模型:\n"
220
277
  f" 1. 访问 {_HF_MIRROR}/{self.model_name}\n"
221
- f" 2. 下载 model.safetensors 和 config.json\n"
278
+ f" 2. 下载权重文件({candidates})和 config.json\n"
222
279
  f" 3. 放置到 {self._model_cache}/snapshots/\n"
223
280
  f" 或运行: bash scripts/download-model-intranet.sh"
224
281
  )
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "jfox-cli"
7
- version = "0.7.0"
7
+ version = "0.7.1"
8
8
  description = "JFox - Zettelkasten 知识管理 CLI 工具"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -101,6 +101,30 @@ class TestModelDownloader:
101
101
  result = downloader._try_curl_download()
102
102
  assert result is False
103
103
 
104
+ def test_check_cached_with_pytorch_bin(self, downloader):
105
+ """pytorch_model.bin 格式的缓存也能正常识别"""
106
+ snapshot = downloader._model_cache / "snapshots" / "abc123"
107
+ snapshot.mkdir(parents=True)
108
+ (snapshot / "pytorch_model.bin").write_text("fake")
109
+ assert downloader._check_cached() is True
110
+
111
+ def test_try_hf_hub_download_fallback_to_pytorch(self, downloader):
112
+ """model.safetensors 不存在时回退到 pytorch_model.bin"""
113
+ call_count = 0
114
+
115
+ def hf_hub_side_effect(*args, **kwargs):
116
+ nonlocal call_count
117
+ call_count += 1
118
+ if call_count == 1: # model.safetensors 失败
119
+ raise Exception("not found")
120
+ # pytorch_model.bin + 其他文件均成功
121
+ return str(downloader._model_cache / "snapshots" / "abc")
122
+
123
+ with patch("huggingface_hub.hf_hub_download") as mock_download:
124
+ mock_download.side_effect = hf_hub_side_effect
125
+ result = downloader._try_hf_hub_download()
126
+ assert result is True
127
+
104
128
  def test_cleanup_partial(self, downloader):
105
129
  """验证部分下载残留被清理(通过 TemporaryDirectory 自动实现)"""
106
130
  with patch("jfox.model_downloader.shutil.which", return_value="curl"):
@@ -867,7 +867,7 @@ wheels = [
867
867
 
868
868
  [[package]]
869
869
  name = "jfox-cli"
870
- version = "0.7.0"
870
+ version = "0.7.1"
871
871
  source = { editable = "." }
872
872
  dependencies = [
873
873
  { name = "chromadb" },
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