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.
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.gitignore +1 -0
- jfox_cli-1.8.0/.pi-lens.json +5 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/CHANGELOG.md +14 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/CLAUDE.md +2 -1
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/PKG-INFO +2 -2
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/README.md +1 -1
- jfox_cli-1.8.0/docs/superpowers/plans/2026-08-21-index-verify-legacy-filenames.md +480 -0
- jfox_cli-1.8.0/docs/superpowers/plans/2026-08-21-moc-density-diagnose.md +524 -0
- jfox_cli-1.8.0/docs/superpowers/specs/2026-08-21-index-verify-legacy-filenames-design.md +100 -0
- jfox_cli-1.8.0/docs/superpowers/specs/2026-08-21-moc-density-diagnose-design.md +186 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/__init__.py +1 -1
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bm25_index.py +36 -8
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/cli.py +37 -8
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/indexer.py +35 -43
- jfox_cli-1.8.0/jfox/moc/__init__.py +52 -0
- jfox_cli-1.8.0/jfox/moc/cli.py +235 -0
- jfox_cli-1.8.0/jfox/moc/cluster.py +415 -0
- jfox_cli-1.8.0/jfox/vector_store.py +502 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/pyproject.toml +1 -1
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_advanced_features.py +5 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_bm25_concurrency.py +18 -0
- jfox_cli-1.8.0/tests/unit/test_indexer_verify.py +159 -0
- jfox_cli-1.8.0/tests/unit/test_moc_cli.py +298 -0
- jfox_cli-1.8.0/tests/unit/test_moc_cluster.py +564 -0
- jfox_cli-1.8.0/tests/unit/test_vector_store_embeddings.py +447 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/uv.lock +1 -1
- jfox_cli-1.7.2/jfox/vector_store.py +0 -291
- jfox_cli-1.7.2/tests/unit/test_indexer_verify.py +0 -53
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/ci/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release/release_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-all/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-all/release_all_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-cc-plugin/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-cc-plugin/release_cc_plugin_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-kimi-plugin/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude/skills/release-kimi-plugin/release_kimi_plugin_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.claude-plugin/marketplace.json +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.githooks/pre-push +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/docs_improvement.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/workflows/integration-test.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.github/workflows/publish.yml +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/.python-version +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/AGENTS.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/DEVELOPMENT_PLAN.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/SESSION.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/SESSION_SUMMARY.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/claude-code-plugin-guide.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/installation.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/nightly-test.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
- {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
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-04-29-daemon-stop-fix.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-jfox-check.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-03-log-level-fix.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-04-list-notes-index.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-06-atomic-write.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-09-session-note-type.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-10-jfox-plugin.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-19-fix-last-used-never.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-05-20-modelscope-migration.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-02-todo-note-type.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-16-kimi-code-auto-summary.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-17-index-rebuild-backlinks.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-17-using-jfox-skill.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-18-self-update-command.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-21-fragment-capture.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-21-gem-synthesis.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-06-25-gem-synth-throttle-ledger.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-08-auto-summary-schedule-window.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-08-candidate-promote.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-gem-synth-dedup.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-release-cc-plugin-skill.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-session-summary-streamline.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-12-show-json.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-17-fix-candidate-dual-h1.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-18-dedup-lifecycle-decouple.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-19-promote-skill-three-modes.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-25-bookshelf.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-25-gem-synth-dedup-incremental-merge.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-26-kb-backup-restore.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-26-promote-skill-clear-reports-rewrite.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-27-release-all.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-28-bookshelf-flat-bundle.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-07-28-nightly-fulltest.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-07-session-to-permanent-cc-kimi.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-11-permanent-note-template.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-12-noteindex-frontmatter-limit-drop.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-15-delete-backlinks-cleanup.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/plans/2026-08-16-bm25-concurrent-write-race.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-jfox-check-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-list-notes-skip-summary-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-03-log-level-fix-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-06-atomic-write-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-09-jfox-plugin-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-09-session-note-type-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-05-20-modelscope-migration-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-02-todo-note-type-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-16-kimi-code-auto-summary-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-17-index-rebuild-backlinks-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-17-using-jfox-skill-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-18-archive-soft-delete-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-18-self-update-command-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-21-fragment-capture-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-21-gem-synthesis-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-06-25-gem-synth-throttle-ledger-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-08-candidate-promote-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-gem-synth-dedup-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-release-cc-plugin-skill-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-session-summary-streamline-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-12-show-json-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-18-dedup-lifecycle-decouple-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-19-promote-skill-three-modes-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-25-bookshelf-design.md +0 -0
- {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
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-26-kb-backup-restore-design.md +0 -0
- {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
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-27-release-all-orchestration-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-28-bookshelf-flat-bundle-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-07-28-nightly-fulltest-design.md +0 -0
- {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
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-11-permanent-note-template-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-12-noteindex-frontmatter-limit-drop-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-15-delete-backlinks-cleanup-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-16-bm25-concurrent-write-race-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/superpowers/specs/2026-08-20-bm25-clear-orphan-followup-design.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/docs/troubleshooting.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jessica-jones-static-cable.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/__main__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/extractor.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/kimi_source.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/ledger.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/loop.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/runner.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/scanner.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/schedule.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/auto_summary/sources.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/loop.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/manager.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/backup/schedule.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/meta.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/bookshelf/store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/__main__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/client.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/process.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/daemon/server.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/embedding_backend.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/formatters.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/detector.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/internal_sources.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/service.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/fragment/store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/anchors.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/dedup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/grounding.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/lifecycle.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/llm.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/loop.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/paths.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/synthesizer.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/gem_synth/transcript.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/git_extractor.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/global_config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/graph.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/kb_manager.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/model_downloader.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/models.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/note.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/note_index.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/performance.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/search_engine.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/template.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/template_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/jfox/utils.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/package.json +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/.claude-plugin/plugin.json +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/hooks/fragment-capture.sh +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/hooks/hooks.json +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/bookshelf/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/ingest/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/manage/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/organize/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/promote/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/search/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/session-summary/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/session-to-permanent/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/cc-plugin/skills/using-jfox/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/README.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/kimi.plugin.json +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-admin/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-auto-summary/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-manage/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-organize/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-promote/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-search/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-session-to-permanent/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/jfox-template/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/packages/kimi-plugin/skills/using-jfox/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/pytest.ini +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/run_full_test.ps1 +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/download-model-intranet.sh +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/nightly_test.sh +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/scripts/nightly_test_helpers.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/README.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-bookshelf/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-ci/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-common/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-organize/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-overview/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-promote/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-all/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-cc-plugin/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-release-kimi-plugin/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-search/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/skills-recommend/pi/jfox-session-to-permanent/SKILL.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/COVERAGE_PLAN.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/MIGRATION.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/TESTS.md +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/conftest.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_auto_summary_kimi.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_backlinks.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_candidate_promote_flow.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_fragment_capture_flow.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_gem_synth_flow.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_index_rebuild_backlinks.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_model_download.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/integration/test_tag_filter_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/performance/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/performance/test_performance.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_cli_format.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_config_set_unit.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_config_unit.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_core_workflow.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_embedding_device.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_hybrid_search.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_integration.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_kb_current.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/test_suggest_links.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/conftest.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_meta.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/bookshelf/test_store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/conftest.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_add_backfill_links.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_archive.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_atomic_write.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_config_sources.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_defaults.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_extractor.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_ledger.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_loop.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_runner.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_scanner.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_schedule.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_auto_summary_status.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_backup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_bm25_batch.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_check.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_content_file.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_daemon_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_daemon_process.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_delete_backlink_cleanup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_edit.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_embedding_local_load.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_format_unify.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_formatters.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_detector.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_hook.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_internal_sources.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_service.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_fragment_store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_anchors.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_backfill.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_config_dedup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_dedup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_grounding.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_lifecycle.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_llm.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_loop.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_store.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_store_duplicate.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_synthesizer.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_gem_synth_transcript.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_git_extractor.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_global_config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_index_kb_param.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kb_manager.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_extractor.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_plugin_skills.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_kimi_scanner.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_lazy_import.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_ledger_migration.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_list_notes_skip.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_logging_config.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_model_downloader.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_nightly_test_helpers.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_candidate_fields.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_candidate_filename.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_dedup_sync.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_index.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_lifecycle_hooks.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_promote.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_note_type_candidate.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_rebuild_backlinks_impl.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_all_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_cc_plugin_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_helper_verify.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_release_kimi_plugin_helper.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_runner_multi_source.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_scanner_list.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_file_source.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_note.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_session_source.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_show.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_synthesizer_dedup.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_system_prompt_sections.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_tag_filter.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_template.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_template_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_update.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_use_kb_env_var.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_using_jfox_skill.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/unit/test_vector_store_clear.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/__init__.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/assertions.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/jfox_cli.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/note_generator.py +0 -0
- {jfox_cli-1.7.2 → jfox_cli-1.8.0}/tests/utils/temp_kb.py +0 -0
|
@@ -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.
|
|
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
|
|
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
|
|
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()` 一致。
|