jfox-cli 1.7.2__tar.gz → 1.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.
Files changed (404) hide show
  1. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.gitignore +1 -0
  2. jfox_cli-1.8.0/.pi-lens.json +5 -0
  3. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/CHANGELOG.md +14 -0
  4. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/CLAUDE.md +2 -1
  5. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/PKG-INFO +2 -2
  6. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/README.md +1 -1
  7. jfox_cli-1.8.0/docs/superpowers/plans/2026-08-21-index-verify-legacy-filenames.md +480 -0
  8. jfox_cli-1.8.0/docs/superpowers/plans/2026-08-21-moc-density-diagnose.md +524 -0
  9. jfox_cli-1.8.0/docs/superpowers/specs/2026-08-21-index-verify-legacy-filenames-design.md +100 -0
  10. jfox_cli-1.8.0/docs/superpowers/specs/2026-08-21-moc-density-diagnose-design.md +186 -0
  11. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/__init__.py +1 -1
  12. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bm25_index.py +36 -8
  13. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/cli.py +37 -8
  14. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/indexer.py +35 -43
  15. jfox_cli-1.8.0/jfox/moc/__init__.py +52 -0
  16. jfox_cli-1.8.0/jfox/moc/cli.py +235 -0
  17. jfox_cli-1.8.0/jfox/moc/cluster.py +415 -0
  18. jfox_cli-1.8.0/jfox/vector_store.py +502 -0
  19. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/pyproject.toml +1 -1
  20. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_advanced_features.py +5 -0
  21. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_bm25_concurrency.py +18 -0
  22. jfox_cli-1.8.0/tests/unit/test_indexer_verify.py +159 -0
  23. jfox_cli-1.8.0/tests/unit/test_moc_cli.py +298 -0
  24. jfox_cli-1.8.0/tests/unit/test_moc_cluster.py +564 -0
  25. jfox_cli-1.8.0/tests/unit/test_vector_store_embeddings.py +447 -0
  26. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/uv.lock +1 -1
  27. jfox_cli-1.7.2/jfox/vector_store.py +0 -291
  28. jfox_cli-1.7.2/tests/unit/test_indexer_verify.py +0 -53
  29. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/ci/SKILL.md +0 -0
  30. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release/SKILL.md +0 -0
  31. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release/release_helper.py +0 -0
  32. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-all/SKILL.md +0 -0
  33. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-all/release_all_helper.py +0 -0
  34. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-cc-plugin/SKILL.md +0 -0
  35. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-cc-plugin/release_cc_plugin_helper.py +0 -0
  36. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-kimi-plugin/SKILL.md +0 -0
  37. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-kimi-plugin/release_kimi_plugin_helper.py +0 -0
  38. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude-plugin/marketplace.json +0 -0
  39. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.githooks/pre-push +0 -0
  40. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  41. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  42. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/docs_improvement.yml +0 -0
  43. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  44. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  45. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/workflows/integration-test.yml +0 -0
  46. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/workflows/publish.yml +0 -0
  47. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.python-version +0 -0
  48. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/AGENTS.md +0 -0
  49. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/DEVELOPMENT_PLAN.md +0 -0
  50. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/SESSION.md +0 -0
  51. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/SESSION_SUMMARY.md +0 -0
  52. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/claude-code-plugin-guide.md +0 -0
  53. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/installation.md +0 -0
  54. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/nightly-test.md +0 -0
  55. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
  56. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
  57. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
  58. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
  59. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
  60. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
  61. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
  62. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
  63. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
  64. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
  65. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
  66. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
  67. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
  68. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
  69. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
  70. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
  71. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
  72. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
  73. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
  74. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
  75. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
  76. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
  77. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
  78. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
  79. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
  80. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
  81. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
  82. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-29-daemon-stop-fix.md +0 -0
  83. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-jfox-check.md +0 -0
  84. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md +0 -0
  85. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-log-level-fix.md +0 -0
  86. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-04-list-notes-index.md +0 -0
  87. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-06-atomic-write.md +0 -0
  88. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-09-session-note-type.md +0 -0
  89. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-10-jfox-plugin.md +0 -0
  90. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-19-fix-last-used-never.md +0 -0
  91. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-20-modelscope-migration.md +0 -0
  92. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-02-todo-note-type.md +0 -0
  93. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-16-kimi-code-auto-summary.md +0 -0
  94. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-17-index-rebuild-backlinks.md +0 -0
  95. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-17-using-jfox-skill.md +0 -0
  96. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-18-self-update-command.md +0 -0
  97. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-21-fragment-capture.md +0 -0
  98. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-21-gem-synthesis.md +0 -0
  99. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-25-gem-synth-throttle-ledger.md +0 -0
  100. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-08-auto-summary-schedule-window.md +0 -0
  101. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-08-candidate-promote.md +0 -0
  102. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-gem-synth-dedup.md +0 -0
  103. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-release-cc-plugin-skill.md +0 -0
  104. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-session-summary-streamline.md +0 -0
  105. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-show-json.md +0 -0
  106. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-17-fix-candidate-dual-h1.md +0 -0
  107. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-18-dedup-lifecycle-decouple.md +0 -0
  108. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-19-promote-skill-three-modes.md +0 -0
  109. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-25-bookshelf.md +0 -0
  110. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-25-gem-synth-dedup-incremental-merge.md +0 -0
  111. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-26-kb-backup-restore.md +0 -0
  112. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-26-promote-skill-clear-reports-rewrite.md +0 -0
  113. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-27-release-all.md +0 -0
  114. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-28-bookshelf-flat-bundle.md +0 -0
  115. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-28-nightly-fulltest.md +0 -0
  116. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-07-session-to-permanent-cc-kimi.md +0 -0
  117. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-11-permanent-note-template.md +0 -0
  118. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-12-noteindex-frontmatter-limit-drop.md +0 -0
  119. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-15-delete-backlinks-cleanup.md +0 -0
  120. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-16-bm25-concurrent-write-race.md +0 -0
  121. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
  122. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
  123. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
  124. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
  125. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
  126. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
  127. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
  128. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
  129. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
  130. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
  131. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md +0 -0
  132. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md +0 -0
  133. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-jfox-check-design.md +0 -0
  134. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-list-notes-skip-summary-design.md +0 -0
  135. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-log-level-fix-design.md +0 -0
  136. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md +0 -0
  137. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-06-atomic-write-design.md +0 -0
  138. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-09-jfox-plugin-design.md +0 -0
  139. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-09-session-note-type-design.md +0 -0
  140. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-20-modelscope-migration-design.md +0 -0
  141. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-02-todo-note-type-design.md +0 -0
  142. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-16-kimi-code-auto-summary-design.md +0 -0
  143. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-17-index-rebuild-backlinks-design.md +0 -0
  144. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-17-using-jfox-skill-design.md +0 -0
  145. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-18-archive-soft-delete-design.md +0 -0
  146. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-18-self-update-command-design.md +0 -0
  147. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-21-fragment-capture-design.md +0 -0
  148. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-21-gem-synthesis-design.md +0 -0
  149. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-25-gem-synth-throttle-ledger-design.md +0 -0
  150. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-08-candidate-promote-design.md +0 -0
  151. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-gem-synth-dedup-design.md +0 -0
  152. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-release-cc-plugin-skill-design.md +0 -0
  153. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-session-summary-streamline-design.md +0 -0
  154. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-show-json-design.md +0 -0
  155. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-18-dedup-lifecycle-decouple-design.md +0 -0
  156. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-19-promote-skill-three-modes-design.md +0 -0
  157. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-25-bookshelf-design.md +0 -0
  158. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-25-gem-synth-dedup-incremental-merge-design.md +0 -0
  159. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-26-kb-backup-restore-design.md +0 -0
  160. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-26-promote-skill-clear-reports-rewrite-design.md +0 -0
  161. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-27-release-all-orchestration-design.md +0 -0
  162. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-28-bookshelf-flat-bundle-design.md +0 -0
  163. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-28-nightly-fulltest-design.md +0 -0
  164. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-07-session-to-permanent-cc-kimi-design.md +0 -0
  165. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-11-permanent-note-template-design.md +0 -0
  166. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-12-noteindex-frontmatter-limit-drop-design.md +0 -0
  167. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-15-delete-backlinks-cleanup-design.md +0 -0
  168. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-16-bm25-concurrent-write-race-design.md +0 -0
  169. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-20-bm25-clear-orphan-followup-design.md +0 -0
  170. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/troubleshooting.md +0 -0
  171. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jessica-jones-static-cable.md +0 -0
  172. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/__main__.py +0 -0
  173. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/__init__.py +0 -0
  174. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/cli.py +0 -0
  175. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/extractor.py +0 -0
  176. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/kimi_source.py +0 -0
  177. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/ledger.py +0 -0
  178. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/loop.py +0 -0
  179. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/runner.py +0 -0
  180. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/scanner.py +0 -0
  181. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/schedule.py +0 -0
  182. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/sources.py +0 -0
  183. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/__init__.py +0 -0
  184. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/cli.py +0 -0
  185. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/loop.py +0 -0
  186. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/manager.py +0 -0
  187. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/schedule.py +0 -0
  188. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/__init__.py +0 -0
  189. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/cli.py +0 -0
  190. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/meta.py +0 -0
  191. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/store.py +0 -0
  192. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/config.py +0 -0
  193. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/__init__.py +0 -0
  194. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/__main__.py +0 -0
  195. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/client.py +0 -0
  196. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/process.py +0 -0
  197. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/server.py +0 -0
  198. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/embedding_backend.py +0 -0
  199. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/formatters.py +0 -0
  200. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/__init__.py +0 -0
  201. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/cli.py +0 -0
  202. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/detector.py +0 -0
  203. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/internal_sources.py +0 -0
  204. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/service.py +0 -0
  205. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/store.py +0 -0
  206. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/__init__.py +0 -0
  207. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/anchors.py +0 -0
  208. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/cli.py +0 -0
  209. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/dedup.py +0 -0
  210. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/grounding.py +0 -0
  211. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/lifecycle.py +0 -0
  212. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/llm.py +0 -0
  213. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/loop.py +0 -0
  214. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/paths.py +0 -0
  215. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/store.py +0 -0
  216. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/synthesizer.py +0 -0
  217. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/transcript.py +0 -0
  218. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/git_extractor.py +0 -0
  219. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/global_config.py +0 -0
  220. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/graph.py +0 -0
  221. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/kb_manager.py +0 -0
  222. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/model_downloader.py +0 -0
  223. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/models.py +0 -0
  224. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/note.py +0 -0
  225. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/note_index.py +0 -0
  226. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/performance.py +0 -0
  227. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/search_engine.py +0 -0
  228. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/template.py +0 -0
  229. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/template_cli.py +0 -0
  230. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/utils.py +0 -0
  231. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/package.json +0 -0
  232. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/.claude-plugin/plugin.json +0 -0
  233. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/hooks/fragment-capture.sh +0 -0
  234. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/hooks/hooks.json +0 -0
  235. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/bookshelf/SKILL.md +0 -0
  236. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/ingest/SKILL.md +0 -0
  237. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/manage/SKILL.md +0 -0
  238. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/organize/SKILL.md +0 -0
  239. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/promote/SKILL.md +0 -0
  240. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/search/SKILL.md +0 -0
  241. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/session-summary/SKILL.md +0 -0
  242. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/session-to-permanent/SKILL.md +0 -0
  243. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/using-jfox/SKILL.md +0 -0
  244. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/README.md +0 -0
  245. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/kimi.plugin.json +0 -0
  246. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-admin/SKILL.md +0 -0
  247. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-auto-summary/SKILL.md +0 -0
  248. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-ingest/SKILL.md +0 -0
  249. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-manage/SKILL.md +0 -0
  250. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-organize/SKILL.md +0 -0
  251. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-promote/SKILL.md +0 -0
  252. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-search/SKILL.md +0 -0
  253. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-session-summary/SKILL.md +0 -0
  254. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-session-to-permanent/SKILL.md +0 -0
  255. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-template/SKILL.md +0 -0
  256. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/using-jfox/SKILL.md +0 -0
  257. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/pytest.ini +0 -0
  258. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/run_full_test.ps1 +0 -0
  259. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/download-model-intranet.sh +0 -0
  260. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/nightly_test.sh +0 -0
  261. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/nightly_test_helpers.py +0 -0
  262. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/README.md +0 -0
  263. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
  264. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
  265. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
  266. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
  267. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -0
  268. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-bookshelf/SKILL.md +0 -0
  269. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-ci/SKILL.md +0 -0
  270. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-common/SKILL.md +0 -0
  271. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-ingest/SKILL.md +0 -0
  272. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-organize/SKILL.md +0 -0
  273. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-overview/SKILL.md +0 -0
  274. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-promote/SKILL.md +0 -0
  275. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release/SKILL.md +0 -0
  276. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-all/SKILL.md +0 -0
  277. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-cc-plugin/SKILL.md +0 -0
  278. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-kimi-plugin/SKILL.md +0 -0
  279. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-search/SKILL.md +0 -0
  280. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-session-summary/SKILL.md +0 -0
  281. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-session-to-permanent/SKILL.md +0 -0
  282. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/COVERAGE_PLAN.md +0 -0
  283. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/MIGRATION.md +0 -0
  284. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/TESTS.md +0 -0
  285. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/conftest.py +0 -0
  286. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/__init__.py +0 -0
  287. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_auto_summary_kimi.py +0 -0
  288. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_backlinks.py +0 -0
  289. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_candidate_promote_flow.py +0 -0
  290. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_fragment_capture_flow.py +0 -0
  291. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_gem_synth_flow.py +0 -0
  292. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_index_rebuild_backlinks.py +0 -0
  293. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_model_download.py +0 -0
  294. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_tag_filter_cli.py +0 -0
  295. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/performance/__init__.py +0 -0
  296. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/performance/test_performance.py +0 -0
  297. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_cli_format.py +0 -0
  298. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_config_set_unit.py +0 -0
  299. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_config_unit.py +0 -0
  300. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_core_workflow.py +0 -0
  301. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_embedding_device.py +0 -0
  302. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_hybrid_search.py +0 -0
  303. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_integration.py +0 -0
  304. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_kb_current.py +0 -0
  305. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_suggest_links.py +0 -0
  306. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/__init__.py +0 -0
  307. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/__init__.py +0 -0
  308. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/conftest.py +0 -0
  309. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_cli.py +0 -0
  310. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_meta.py +0 -0
  311. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_store.py +0 -0
  312. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/conftest.py +0 -0
  313. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_add_backfill_links.py +0 -0
  314. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_archive.py +0 -0
  315. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_atomic_write.py +0 -0
  316. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_cli.py +0 -0
  317. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_config_sources.py +0 -0
  318. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_defaults.py +0 -0
  319. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_extractor.py +0 -0
  320. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_ledger.py +0 -0
  321. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_loop.py +0 -0
  322. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_runner.py +0 -0
  323. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_scanner.py +0 -0
  324. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_schedule.py +0 -0
  325. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_status.py +0 -0
  326. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_backup.py +0 -0
  327. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_bm25_batch.py +0 -0
  328. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_check.py +0 -0
  329. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_content_file.py +0 -0
  330. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_daemon_cli.py +0 -0
  331. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_daemon_process.py +0 -0
  332. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_delete_backlink_cleanup.py +0 -0
  333. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_edit.py +0 -0
  334. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_embedding_local_load.py +0 -0
  335. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_format_unify.py +0 -0
  336. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_formatters.py +0 -0
  337. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_cli.py +0 -0
  338. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_config.py +0 -0
  339. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_detector.py +0 -0
  340. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_hook.py +0 -0
  341. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_internal_sources.py +0 -0
  342. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_service.py +0 -0
  343. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_store.py +0 -0
  344. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_anchors.py +0 -0
  345. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_backfill.py +0 -0
  346. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_cli.py +0 -0
  347. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_config.py +0 -0
  348. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_config_dedup.py +0 -0
  349. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_dedup.py +0 -0
  350. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_grounding.py +0 -0
  351. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_lifecycle.py +0 -0
  352. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_llm.py +0 -0
  353. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_loop.py +0 -0
  354. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_store.py +0 -0
  355. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_store_duplicate.py +0 -0
  356. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_synthesizer.py +0 -0
  357. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_transcript.py +0 -0
  358. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_git_extractor.py +0 -0
  359. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_global_config.py +0 -0
  360. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_index_kb_param.py +0 -0
  361. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
  362. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kb_manager.py +0 -0
  363. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_extractor.py +0 -0
  364. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_plugin_skills.py +0 -0
  365. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_scanner.py +0 -0
  366. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_lazy_import.py +0 -0
  367. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_ledger_migration.py +0 -0
  368. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_list_notes_skip.py +0 -0
  369. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_logging_config.py +0 -0
  370. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_model_downloader.py +0 -0
  371. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_nightly_test_helpers.py +0 -0
  372. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_candidate_fields.py +0 -0
  373. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_candidate_filename.py +0 -0
  374. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_dedup_sync.py +0 -0
  375. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_index.py +0 -0
  376. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_lifecycle_hooks.py +0 -0
  377. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_promote.py +0 -0
  378. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_type_candidate.py +0 -0
  379. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_rebuild_backlinks_impl.py +0 -0
  380. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_all_helper.py +0 -0
  381. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_cc_plugin_helper.py +0 -0
  382. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_helper.py +0 -0
  383. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_helper_verify.py +0 -0
  384. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_kimi_plugin_helper.py +0 -0
  385. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_runner_multi_source.py +0 -0
  386. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_scanner_list.py +0 -0
  387. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_file_source.py +0 -0
  388. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_note.py +0 -0
  389. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_source.py +0 -0
  390. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_show.py +0 -0
  391. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_synthesizer_dedup.py +0 -0
  392. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_system_prompt_sections.py +0 -0
  393. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_tag_filter.py +0 -0
  394. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_template.py +0 -0
  395. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_template_cli.py +0 -0
  396. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_update.py +0 -0
  397. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_use_kb_env_var.py +0 -0
  398. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_using_jfox_skill.py +0 -0
  399. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_vector_store_clear.py +0 -0
  400. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/__init__.py +0 -0
  401. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/assertions.py +0 -0
  402. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/jfox_cli.py +0 -0
  403. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/note_generator.py +0 -0
  404. {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/temp_kb.py +0 -0
@@ -48,6 +48,7 @@ cache/
48
48
  .pi/
49
49
 
50
50
  # Temporary analysis files
51
+ /.superpowers/*.md
51
52
  analysis_report.md
52
53
  kimi-export-*.md
53
54
  review_body*.md
@@ -0,0 +1,5 @@
1
+ {
2
+ "format": {
3
+ "enabled": false
4
+ }
5
+ }
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to jfox-cli will be documented in this file.
4
4
 
5
+ ## [1.8.0] - 2026-08-22
6
+
7
+ ### Features
8
+ - add MOC density diagnose command (#410)
9
+
10
+ ### Fixes
11
+ - **index**: verify 以 frontmatter 真实 ID 对账向量库,修复 legacy 文件名误报 orphan (#407) (#408)
12
+
13
+ ### Changes
14
+ - 项目级 .pi-lens.json 关闭自动格式化,与 CI black 对齐 (#409)
15
+ - **claude.md**: 记 BM25 并发写乐观并发控制与引擎 stale 检查语义(#391/#396) (#400)
16
+
17
+ [1.8.0]: https://github.com/zhuxixi/jfox/compare/v1.7.2...v1.8.0
18
+
5
19
  ## [1.7.2] - 2026-08-21
6
20
 
7
21
  ### Fixes
@@ -68,7 +68,7 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
68
68
  | `note.py` | Markdown file CRUD with YAML frontmatter |
69
69
  | `models.py` | `Note` data model with frontmatter serialization |
70
70
  | `search_engine.py` | `HybridSearchEngine` with `SearchMode` enum, RRF fusion |
71
- | `bm25_index.py` | BM25 keyword search index |
71
+ | `bm25_index.py` | BM25 keyword search index;写路径 filelock + 原子写 + `write_version` 乐观并发控制,多进程并发写安全(#391/#396) |
72
72
  | `embedding_backend.py` | Sentence-transformers embedding backend(支持 daemon 代理) |
73
73
  | `daemon/` | Embedding 模型 HTTP 守护进程 (`server.py`/`client.py`/`process.py`),`jfox daemon start/stop/status` |
74
74
  | `fragment/` | 碎片采集:detector 分类 + store SQLite(WAL) + service 编排 |
@@ -180,3 +180,4 @@ JFox ships as a Claude Code plugin. Two-tier structure:
180
180
  - 生命周期订阅模块的重依赖(numpy 等)必须 lazy import 进回调体,不能顶层 import——`jfox/__init__.py` 每次启动都 import 订阅模块,顶层会令 `--version`/`search` 等不相关命令多付 ~70-100ms eager 加载。参考 `gem_synth/lifecycle.py`
181
181
  - `rich` Console 输出机器解析的 JSON 时须 `soft_wrap=True`:默认按 80 列硬折行,会把长字符串(如 Windows 绝对路径)在 JSON 字符串内部断行,`json.loads` 报 Invalid control character(Ubuntu 路径短不触发,只在 Windows CI 挂,#336)。参考 `bookshelf/cli.py` `_emit_json`
182
182
  - `delete_note`/`promote_note` 增量同步各 target 的 backlinks(#388 起对称):单 target 写盘失败仅 warning 不中断;悬空/不对称残留用 `jfox index rebuild --backlinks` 全量重算兜底
183
+ - `HybridSearchEngine` 构造时仅对自取的 BM25 单例做一次 stale 检查并 reload(磁盘被其他进程写过则刷新快照);显式传入的 `bm25_index` 实例归调用方所有、不隐式 reload——长驻进程须自行周期重建引擎或调 `check_stale_and_reload`(#391)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: jfox-cli
3
- Version: 1.7.2
3
+ Version: 1.8.0
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
@@ -338,7 +338,7 @@ jfox query "Luhmann's methodology" --depth 2
338
338
  |---------|-------------|
339
339
  | `jfox index status` | Show index health |
340
340
  | `jfox index rebuild` | Rebuild vector + BM25 indexes |
341
- | `jfox index verify` | Cross-check files vs indexed entries |
341
+ | `jfox index verify` | Cross-check note files vs vector store entries by frontmatter IDs |
342
342
 
343
343
  ### Templates
344
344
 
@@ -297,7 +297,7 @@ jfox query "Luhmann's methodology" --depth 2
297
297
  |---------|-------------|
298
298
  | `jfox index status` | Show index health |
299
299
  | `jfox index rebuild` | Rebuild vector + BM25 indexes |
300
- | `jfox index verify` | Cross-check files vs indexed entries |
300
+ | `jfox index verify` | Cross-check note files vs vector store entries by frontmatter IDs |
301
301
 
302
302
  ### Templates
303
303
 
@@ -0,0 +1,480 @@
1
+ # index verify 改用 frontmatter 真实 ID 对账 Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** `jfox index verify` 以 frontmatter `id` 字段(而非文件名)与向量库对账,消除 legacy `14位时间戳-6位微秒-slug` 文件名导致的 orphan 误报。
6
+
7
+ **Architecture:** `Indexer.verify_index()` 复用 `jfox/note_index.py::_parse_frontmatter_only()` 逐文件取真实 ID,与 `vector_store.get_all_ids()` 做差集;unreadable 文件与重复 ID 单独报告;CLI 输出标注验证对象为 VectorStore。删除已无调用者的 `_extract_note_id_from_filename`。
8
+
9
+ **Tech Stack:** Python 3.10+, pytest, Typer/Rich(不引入新依赖)。
10
+
11
+ ## Global Constraints
12
+
13
+ - verify 必须保持不加载 embedding 模型(秒级只读路径);改动不碰 `VectorStore.add_note` 等写入路径。
14
+ - 返回 dict 保留键 `total_files` / `total_indexed` / `missing_from_index` / `orphaned_in_index` / `healthy`(`tests/unit/test_index_kb_param.py` 断言 `healthy` 存在,向后兼容)。
15
+ - `healthy` 语义 = missing 与 orphaned 均为空;unreadable/duplicate 不影响 healthy(文件层问题,repair 修不了)。
16
+ - 中文注释与现有代码风格一致(jfox 项目注释用中文);行宽 100。
17
+ - 所有文件操作在 worktree 内(`/home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames/`),禁止触碰主 checkout。
18
+
19
+ ---
20
+
21
+ ### Task 1: verify_index 数据源替换 + 删除旧解析函数(`jfox/indexer.py`)
22
+
23
+ **Files:**
24
+ - Modify: `jfox/indexer.py:30-50`(删除 `_extract_note_id_from_filename`)、`jfox/indexer.py:315-346`(重写 `verify_index`)、`jfox/indexer.py:11`(删 `import re`)
25
+ - Test: `tests/unit/test_indexer_verify.py`(整体重写)
26
+
27
+ **Interfaces:**
28
+ - Produces: `Indexer.verify_index() -> Dict[str, Any]`,键:
29
+ - `total_files: int` — 扫描到的 md 文件总数(含 unreadable)
30
+ - `valid_files: int` — 有有效 frontmatter id 的文件数(含重复)
31
+ - `unique_ids: int` — 去重后的文件 ID 数
32
+ - `total_indexed: int` — 向量库 ID 数
33
+ - `unreadable_files: List[str]` — frontmatter 读不了/无 id 的文件绝对路径
34
+ - `duplicate_ids: List[Dict[str, Any]]` — `[{"id": str, "files": [str]}]`,同 id 多文件,按 id 排序
35
+ - `missing_from_index: List[str]` — 文件有、向量库无(sorted)
36
+ - `orphaned_in_index: List[str]` — 向量库有、文件无(sorted)
37
+ - `healthy: bool`
38
+ - `checked: str` — 恒为 `"vector_store"`
39
+ - notes_dir 不存在时:`{"error": "Notes directory not found"}`(保持现状)
40
+ - Consumes: `jfox.note_index._parse_frontmatter_only(filepath) -> Optional[dict]`(返回 None 表示解析失败)
41
+
42
+ - [ ] **Step 1: 写失败测试(重写 `tests/unit/test_indexer_verify.py`)**
43
+
44
+ ```python
45
+ """
46
+ 测试 indexer.verify_index 以 frontmatter 真实 ID 对账
47
+
48
+ Issue #407: legacy 文件名(14位时间戳-6位微秒-slug)无法从文件名解析 ID,
49
+ 导致 candidate/legacy permanent 全部误报 orphaned。
50
+ """
51
+
52
+ import pytest
53
+
54
+ from jfox.config import ZKConfig
55
+ from jfox.indexer import Indexer
56
+
57
+
58
+ class FakeVectorStore:
59
+ """verify_index 只调用 get_all_ids();假对象避开 ChromaDB/embedding 依赖"""
60
+
61
+ def __init__(self, ids):
62
+ self._ids = list(ids)
63
+
64
+ def get_all_ids(self):
65
+ return list(self._ids)
66
+
67
+
68
+ @pytest.fixture
69
+ def indexer(tmp_path):
70
+ """构造 notes 目录 + FakeVectorStore + Indexer"""
71
+ cfg = ZKConfig(base_dir=tmp_path)
72
+ cfg.ensure_dirs()
73
+ return Indexer(cfg, FakeVectorStore([]))
74
+
75
+
76
+ def write_note(notes_dir, relpath, note_id, title="Test"):
77
+ """手写含 frontmatter 的 md 文件,返回路径"""
78
+ p = notes_dir / relpath
79
+ p.parent.mkdir(parents=True, exist_ok=True)
80
+ p.write_text(
81
+ f"---\nid: {note_id}\ntitle: {title}\ntype: permanent\n"
82
+ "created: '2026-01-01T00:00:00'\n---\n\n# {title}\n\nbody\n",
83
+ encoding="utf-8",
84
+ )
85
+ return p
86
+
87
+
88
+ class TestLegacyFilenameReconciliation:
89
+ """legacy 14位-6位-slug 文件名不再误报(#407 核心)"""
90
+
91
+ def test_legacy_candidate_filename(self, indexer):
92
+ notes_dir = indexer.config.notes_dir
93
+ nid = "20260628004828-286060"
94
+ write_note(notes_dir, f"candidate/{nid}-jfox-embedding-daemon.md", nid)
95
+ indexer.vector_store = FakeVectorStore([nid])
96
+
97
+ result = indexer.verify_index()
98
+ assert result["missing_from_index"] == []
99
+ assert result["orphaned_in_index"] == []
100
+ assert result["healthy"] is True
101
+
102
+ def test_legacy_permanent_filename(self, indexer):
103
+ notes_dir = indexer.config.notes_dir
104
+ nid = "20260708002136-108471"
105
+ write_note(notes_dir, f"permanent/{nid}-cc-plugin-版本号.md", nid)
106
+ indexer.vector_store = FakeVectorStore([nid])
107
+
108
+ result = indexer.verify_index()
109
+ assert result["healthy"] is True
110
+ assert result["unique_ids"] == 1
111
+ assert result["valid_files"] == 1
112
+
113
+ def test_current_formats_still_reconcile(self, indexer):
114
+ """18位-slug / fleeting 8-10 / session 18位 回归"""
115
+ notes_dir = indexer.config.notes_dir
116
+ write_note(notes_dir, "permanent/202604120150293323-some-slug.md", "202604120150293323")
117
+ write_note(notes_dir, "fleeting/20260412-0150293323.md", "202604120150293323")
118
+ write_note(notes_dir, "session/202604120150293399-session-a.md", "202604120150293399")
119
+ indexer.vector_store = FakeVectorStore(
120
+ ["202604120150293323", "202604120150293399"]
121
+ )
122
+
123
+ result = indexer.verify_index()
124
+ assert result["healthy"] is True
125
+ assert result["unique_ids"] == 2
126
+ assert result["total_files"] == 3
127
+
128
+
129
+ class TestUnreadableAndDuplicate:
130
+ """unreadable / duplicate 单独报告,不混入 missing/orphaned"""
131
+
132
+ def test_unreadable_file_reported_separately(self, indexer):
133
+ notes_dir = indexer.config.notes_dir
134
+ good_id = "202604120150293323"
135
+ write_note(notes_dir, "permanent/good.md", good_id)
136
+ broken = notes_dir / "permanent" / "broken.md"
137
+ broken.parent.mkdir(parents=True, exist_ok=True)
138
+ broken.write_text("# no frontmatter here\n\njust body\n", encoding="utf-8")
139
+ indexer.vector_store = FakeVectorStore([good_id])
140
+
141
+ result = indexer.verify_index()
142
+ assert result["unreadable_files"] == [str(broken)]
143
+ assert result["missing_from_index"] == []
144
+ assert result["orphaned_in_index"] == []
145
+ assert result["total_files"] == 2
146
+ assert result["valid_files"] == 1
147
+
148
+ def test_frontmatter_without_id_is_unreadable(self, indexer):
149
+ notes_dir = indexer.config.notes_dir
150
+ p = notes_dir / "permanent" / "no-id.md"
151
+ p.parent.mkdir(parents=True, exist_ok=True)
152
+ p.write_text("---\ntitle: No Id\ntype: permanent\n---\n\nbody\n", encoding="utf-8")
153
+
154
+ result = indexer.verify_index()
155
+ assert result["unreadable_files"] == [str(p)]
156
+ assert result["healthy"] is True # 对账无差集
157
+
158
+ def test_duplicate_id_reported(self, indexer):
159
+ notes_dir = indexer.config.notes_dir
160
+ nid = "20260711104217-263635"
161
+ f1 = write_note(notes_dir, f"permanent/{nid}-没爆就别修.md", nid, title="A")
162
+ f2 = write_note(notes_dir, f"permanent/{nid}-代码审查务实原则.md", nid, title="B")
163
+ indexer.vector_store = FakeVectorStore([nid])
164
+
165
+ result = indexer.verify_index()
166
+ assert len(result["duplicate_ids"]) == 1
167
+ assert result["duplicate_ids"][0]["id"] == nid
168
+ assert set(result["duplicate_ids"][0]["files"]) == {str(f1), str(f2)}
169
+ assert result["missing_from_index"] == []
170
+ assert result["orphaned_in_index"] == []
171
+ assert result["unique_ids"] == 1
172
+ assert result["valid_files"] == 2
173
+
174
+
175
+ class TestTrueDiff:
176
+ """missing / orphaned 真值判定"""
177
+
178
+ def test_missing_and_orphaned(self, indexer):
179
+ notes_dir = indexer.config.notes_dir
180
+ file_only = "202604120150293323"
181
+ index_only = "202604120150293999"
182
+ write_note(notes_dir, "permanent/file-only.md", file_only)
183
+ indexer.vector_store = FakeVectorStore([index_only])
184
+
185
+ result = indexer.verify_index()
186
+ assert result["missing_from_index"] == [file_only]
187
+ assert result["orphaned_in_index"] == [index_only]
188
+ assert result["healthy"] is False
189
+ assert result["checked"] == "vector_store"
190
+
191
+ def test_empty_notes_dir(self, indexer):
192
+ result = indexer.verify_index()
193
+ assert result["total_files"] == 0
194
+ assert result["healthy"] is True
195
+
196
+ def test_missing_notes_dir(self, tmp_path):
197
+ import shutil
198
+
199
+ cfg = ZKConfig(base_dir=tmp_path)
200
+ cfg.ensure_dirs()
201
+ shutil.rmtree(cfg.notes_dir)
202
+ idx = Indexer(cfg, FakeVectorStore([]))
203
+ result = idx.verify_index()
204
+ assert result == {"error": "Notes directory not found"}
205
+ ```
206
+
207
+ - [ ] **Step 2: 运行测试确认失败**
208
+
209
+ ```bash
210
+ cd /home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames
211
+ uv run pytest tests/unit/test_indexer_verify.py -v
212
+ ```
213
+
214
+ Expected: FAIL(`test_legacy_candidate_filename` 报 orphaned 误报;`test_missing_notes_dir` 因新键不存在而断言差异——旧实现返回旧结构;旧版测试文件整体被替换)
215
+
216
+ - [ ] **Step 3: 实现(修改 `jfox/indexer.py`)**
217
+
218
+ 删除 `_extract_note_id_from_filename` 函数(30-50 行)与 `import re`(第 11 行,该文件 `re` 仅此函数使用)。
219
+
220
+ 重写 `verify_index`(315-346 行):
221
+
222
+ ```python
223
+ def verify_index(self) -> Dict[str, any]:
224
+ """
225
+ Verify the vector store against note files, reconciling by frontmatter
226
+ note IDs. Filename format is irrelevant — legacy `14位时间戳-6位微秒-slug`
227
+ files reconcile correctly as long as their frontmatter `id` matches.
228
+
229
+ Returns:
230
+ Dict with verification results (see unit tests for the contract).
231
+ """
232
+ from .note_index import _parse_frontmatter_only
233
+
234
+ notes_dir = Path(self.config.notes_dir)
235
+ if not notes_dir.exists():
236
+ return {"error": "Notes directory not found"}
237
+
238
+ # 按 frontmatter 真实 id 收集文件(文件名格式无关)
239
+ note_files = list(notes_dir.rglob("*.md"))
240
+ id_to_files: Dict[str, List[str]] = {}
241
+ unreadable_files: List[str] = []
242
+ for f in note_files:
243
+ fm = _parse_frontmatter_only(f)
244
+ if fm is None or not fm.get("id"):
245
+ unreadable_files.append(str(f))
246
+ continue
247
+ note_id = str(fm["id"])
248
+ id_to_files.setdefault(note_id, []).append(str(f))
249
+
250
+ duplicate_ids = [
251
+ {"id": nid, "files": paths}
252
+ for nid, paths in sorted(id_to_files.items())
253
+ if len(paths) > 1
254
+ ]
255
+ file_ids = set(id_to_files)
256
+
257
+ indexed_ids = set(self.vector_store.get_all_ids())
258
+ missing_from_index = sorted(file_ids - indexed_ids)
259
+ orphaned_in_index = sorted(indexed_ids - file_ids)
260
+
261
+ return {
262
+ "total_files": len(note_files),
263
+ "valid_files": sum(len(v) for v in id_to_files.values()),
264
+ "unique_ids": len(file_ids),
265
+ "total_indexed": len(indexed_ids),
266
+ "unreadable_files": unreadable_files,
267
+ "duplicate_ids": duplicate_ids,
268
+ "missing_from_index": missing_from_index,
269
+ "orphaned_in_index": orphaned_in_index,
270
+ "healthy": not missing_from_index and not orphaned_in_index,
271
+ "checked": "vector_store",
272
+ }
273
+ ```
274
+
275
+ - [ ] **Step 4: 运行测试确认通过**
276
+
277
+ ```bash
278
+ cd /home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames
279
+ uv run pytest tests/unit/test_indexer_verify.py -v
280
+ ```
281
+
282
+ Expected: PASS(全部新用例)
283
+
284
+ - [ ] **Step 5: Commit**
285
+
286
+ ```bash
287
+ git add tests/unit/test_indexer_verify.py jfox/indexer.py
288
+ git commit -m "fix(index): verify 以 frontmatter 真实 ID 对账向量库,修复 legacy 文件名误报 orphan (#407)"
289
+ ```
290
+
291
+ ---
292
+
293
+ ### Task 2: CLI verify 分支输出更新(`jfox/cli.py`)
294
+
295
+ **Files:**
296
+ - Modify: `jfox/cli.py:2425-2457`(verify 分支)
297
+
298
+ **Interfaces:**
299
+ - Consumes: Task 1 的 `verify_index()` 返回结构(含 `error` / `checked` / `unreadable_files` / `duplicate_ids`)
300
+ - Produces: 无(CLI 终端输出)
301
+
302
+ - [ ] **Step 1: 修改 verify 分支(`jfox/cli.py:2425-2457`)**
303
+
304
+ ```python
305
+ elif action == "verify":
306
+ verification = indexer.verify_index()
307
+
308
+ result = verification
309
+
310
+ if output_format == "json":
311
+ print(output_json(result))
312
+ else:
313
+ if verification.get("error"):
314
+ console.print(f"[red]✗[/red] {verification['error']}")
315
+ raise typer.Exit(1)
316
+
317
+ console.print(
318
+ "[bold]Vector Store Verification[/bold] "
319
+ "[dim](BM25 not covered — see `jfox index bm25-status`)[/dim]"
320
+ )
321
+ if verification["healthy"]:
322
+ console.print("[green]✓[/green] Vector index is healthy")
323
+ else:
324
+ console.print("[yellow]⚠[/yellow] Vector index has issues")
325
+
326
+ console.print(f" Files: {verification['total_files']}")
327
+ console.print(f" Valid IDs: {verification['unique_ids']}")
328
+ console.print(f" Indexed: {verification['total_indexed']}")
329
+
330
+ if verification["unreadable_files"]:
331
+ console.print(
332
+ f"\n[yellow]Unreadable files "
333
+ f"({len(verification['unreadable_files'])}):[/yellow]"
334
+ )
335
+ for p in verification["unreadable_files"][:5]:
336
+ console.print(f" - {p}")
337
+
338
+ if verification["duplicate_ids"]:
339
+ console.print(
340
+ f"\n[yellow]Duplicate IDs "
341
+ f"({len(verification['duplicate_ids'])}):[/yellow]"
342
+ )
343
+ for d in verification["duplicate_ids"][:5]:
344
+ console.print(f" - {d['id']}")
345
+
346
+ if verification["missing_from_index"]:
347
+ console.print(
348
+ f"\n[yellow]Missing from index "
349
+ f"({len(verification['missing_from_index'])}):[/yellow]"
350
+ )
351
+ for nid in verification["missing_from_index"][:5]:
352
+ console.print(f" - {nid}")
353
+
354
+ if verification["orphaned_in_index"]:
355
+ console.print(
356
+ f"\n[yellow]Orphaned in index "
357
+ f"({len(verification['orphaned_in_index'])}):[/yellow]"
358
+ )
359
+ for nid in verification["orphaned_in_index"][:5]:
360
+ console.print(f" - {nid}")
361
+ ```
362
+
363
+ - [ ] **Step 2: 运行 CLI 相关测试**
364
+
365
+ ```bash
366
+ cd /home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames
367
+ uv run pytest tests/unit/test_index_kb_param.py -v
368
+ uv run pytest tests/unit/test_indexer_verify.py -v
369
+ ```
370
+
371
+ Expected: PASS(`test_index_kb_param.py` 断言 `healthy` in data,新结构兼容)
372
+
373
+ - [ ] **Step 3: Commit**
374
+
375
+ ```bash
376
+ git add jfox/cli.py
377
+ git commit -m "fix(cli): index verify 输出标注 VectorStore 并单独报告 unreadable/duplicate (#407)"
378
+ ```
379
+
380
+ ---
381
+
382
+ ### Task 3: 集成测试断言更新(`tests/test_advanced_features.py`)
383
+
384
+ **Files:**
385
+ - Modify: `tests/test_advanced_features.py:133-135`(test_indexer 的 verify 断言)、`tests/test_advanced_features.py:189-225`(test_verify_index_matches_filenames_to_ids)
386
+
387
+ **Interfaces:**
388
+ - Consumes: Task 1 的返回结构
389
+
390
+ - [ ] **Step 1: 更新断言**
391
+
392
+ `test_indexer`(~134 行):
393
+
394
+ ```python
395
+ # 测试 verify_index
396
+ verification = indexer.verify_index()
397
+ assert verification["total_files"] == 1
398
+ assert verification["unique_ids"] == 1
399
+ assert verification["checked"] == "vector_store"
400
+ assert verification["healthy"] is True
401
+ ```
402
+
403
+ `test_verify_index_matches_filenames_to_ids` 末尾(~216-222 行)追加:
404
+
405
+ ```python
406
+ assert result["missing_from_index"] == []
407
+ assert result["orphaned_in_index"] == []
408
+ assert result["unreadable_files"] == []
409
+ assert result["checked"] == "vector_store"
410
+ ```
411
+
412
+ (原断言 `result["healthy"] is True` 保留不变——新实现下依然通过,证明向后兼容。)
413
+
414
+ - [ ] **Step 2: 运行测试**
415
+
416
+ ```bash
417
+ cd /home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames
418
+ uv run pytest tests/test_advanced_features.py -v
419
+ ```
420
+
421
+ Expected: PASS
422
+
423
+ - [ ] **Step 3: 全量快速测试回归**
424
+
425
+ ```bash
426
+ cd /home/elling/git-repo/github/jfox/.pi/worktrees/issue-407-index-verify-legacy-filenames
427
+ uv run pytest tests/ -m "not embedding and not slow" -q
428
+ ```
429
+
430
+ Expected: PASS(若出现与本改动无关的既有失败,记录并在 commit message 注明,不顺手修)
431
+
432
+ - [ ] **Step 4: Commit**
433
+
434
+ ```bash
435
+ git add tests/test_advanced_features.py
436
+ git commit -m "test(index): verify 集成测试断言对齐 frontmatter 对账结构 (#407)"
437
+ ```
438
+
439
+ ---
440
+
441
+ ### Task 4: 文档文案(`README.md`)
442
+
443
+ **Files:**
444
+ - Modify: `README.md:300`
445
+
446
+ - [ ] **Step 1: 更新表格行**
447
+
448
+ `README.md:300` 原文:
449
+
450
+ ```markdown
451
+ | `jfox index verify` | Cross-check files vs indexed entries |
452
+ ```
453
+
454
+ 改为:
455
+
456
+ ```markdown
457
+ | `jfox index verify` | Cross-check note files vs vector store entries by frontmatter IDs |
458
+ ```
459
+
460
+ - [ ] **Step 2: Commit**
461
+
462
+ ```bash
463
+ git add README.md
464
+ git commit -m "docs: index verify 表格描述标注 vector store 与 frontmatter ID 对账 (#407)"
465
+ ```
466
+
467
+ ---
468
+
469
+ ## Self-Review
470
+
471
+ **1. Spec coverage:**
472
+ - 四种文件格式对账 → Task 1 `test_current_formats_still_reconcile` + `test_legacy_*`
473
+ - candidate 不再误报 → Task 1 legacy 用例(candidate 目录)
474
+ - missing/orphan 与 frontmatter 对账一致 → Task 1 `TestTrueDiff`(调研 R3 实测同口径)
475
+ - 输出区分 vector/BM25 → Task 2 `checked` 字段 + 标题;Task 4 文档
476
+ - 回归测试 legacy/unreadable/duplicate → Task 1 `TestLegacyFilenameReconciliation` + `TestUnreadableAndDuplicate`
477
+
478
+ **2. Placeholder scan:** 无 TBD/占位符;所有代码块为完整内容。
479
+
480
+ **3. Type consistency:** `verify_index` 返回键在 Task 1 Interface 定义、Task 2 CLI 与 Task 3 测试消费一致;`FakeVectorStore.get_all_ids()` 签名与 `VectorStore.get_all_ids()` 一致。