jfox-cli 0.7.1__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/CHANGELOG.md +11 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/CLAUDE.md +12 -7
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/PKG-INFO +1 -1
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/__init__.py +1 -1
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/cli.py +22 -2
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/note.py +35 -9
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/performance.py +3 -3
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/pyproject.toml +1 -1
- jfox_cli-0.7.2/tests/unit/test_atomic_write.py +165 -0
- jfox_cli-0.7.2/tests/unit/test_content_file.py +73 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/uv.lock +1 -1
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.claude/settings.local.json +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.claude/skills/ci/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.claude/skills/release/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.claude/skills/release/release_helper.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.githooks/pre-push +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.github/workflows/integration-test.yml +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.github/workflows/publish.yml +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.gitignore +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/.python-version +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/AGENTS.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/DEVELOPMENT_PLAN.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/README.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/SESSION.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/SESSION_SUMMARY.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/installation.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-add-content-file.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-ingest-log-command.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-ingest-skill-sync.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-sync-skills-with-cli.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-15-gpu-embedding.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-16-fix-windows-daemon-console-window.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-18-daemon-timeout-and-index-rebuild.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-22-release-skill.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-26-fix-daemon-deprecation-warnings.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-27-intranet-model-download.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-28-tag-filtering.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-29-daemon-stop-fix.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-05-03-jfox-check.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-05-03-log-level-fix.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-05-04-list-notes-index.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-14-show-command-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-15-gpu-embedding-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-15-session-summary-confirmation-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-21-release-skill-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-26-fix-daemon-deprecation-warnings-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-27-intranet-model-download-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-28-tag-filtering-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-05-03-jfox-check-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-05-03-list-notes-skip-summary-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-05-03-log-level-fix-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/troubleshooting.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jessica-jones-static-cable.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/__main__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/bm25_index.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/config.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/daemon/__init__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/daemon/__main__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/daemon/client.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/daemon/process.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/daemon/server.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/embedding_backend.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/formatters.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/git_extractor.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/global_config.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/graph.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/indexer.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/kb_manager.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/model_downloader.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/models.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/note_index.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/search_engine.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/template.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/template_cli.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/jfox/vector_store.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/pytest.ini +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/run_full_test.ps1 +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/scripts/download-model-intranet.sh +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/README.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/kimi-cli/jfox-common/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/kimi-cli/jfox-ingest/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/kimi-cli/jfox-organize/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/kimi-cli/jfox-search/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/kimi-cli/jfox-session-summary/SKILL.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/COVERAGE_PLAN.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/MIGRATION.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/TESTS.md +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/conftest.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/integration/__init__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/integration/test_backlinks.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/integration/test_model_download.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/integration/test_tag_filter_cli.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/performance/__init__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/performance/test_performance.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_advanced_features.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_cli_format.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_config_set_unit.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_config_unit.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_core_workflow.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_embedding_device.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_hybrid_search.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_integration.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_kb_current.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/test_suggest_links.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/__init__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_bm25_batch.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_check.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_daemon_process.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_edit.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_format_unify.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_formatters.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_git_extractor.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_global_config.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_index_kb_param.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_indexer_verify.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_kb_manager.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_lazy_import.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_list_notes_skip.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_logging_config.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_model_downloader.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_note_index.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_release_helper.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_show.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_tag_filter.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_template.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_template_cli.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_use_kb_env_var.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/unit/test_vector_store_clear.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/utils/__init__.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/utils/assertions.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/utils/jfox_cli.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/utils/note_generator.py +0 -0
- {jfox_cli-0.7.1 → jfox_cli-0.7.2}/tests/utils/temp_kb.py +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to jfox-cli will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.7.2] - 2026-05-07
|
|
6
|
+
|
|
7
|
+
### Fixes
|
|
8
|
+
- **note**: atomic write to prevent 0-byte note files (#201)
|
|
9
|
+
- strip frontmatter from --content-file input to prevent duplication (#200)
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
- update CLAUDE.md to reflect current codebase state (#203)
|
|
13
|
+
|
|
14
|
+
[0.7.2]: https://github.com/zhuxixi/jfox/compare/v0.7.1...v0.7.2
|
|
15
|
+
|
|
5
16
|
## [0.7.1] - 2026-05-05
|
|
6
17
|
|
|
7
18
|
### Fixes
|
|
@@ -56,18 +56,21 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
|
|
|
56
56
|
|
|
57
57
|
| Module | Role |
|
|
58
58
|
|--------|------|
|
|
59
|
-
| `cli.py` | All CLI commands (~
|
|
59
|
+
| `cli.py` | All CLI commands (~2900 lines). Commands follow pattern: `@app.command()` → `_xxx_impl()` helper for reuse |
|
|
60
60
|
| `config.py` | `ZKConfig` + `use_kb()` context manager for multi-KB switching |
|
|
61
61
|
| `global_config.py` | `GlobalConfigManager` managing `~/.zk_config.json` |
|
|
62
62
|
| `kb_manager.py` | Knowledge base lifecycle (create, rename, remove) |
|
|
63
63
|
| `formatters.py` | Output formats: JSON, CSV, YAML, Table, Paths |
|
|
64
|
+
| `git_extractor.py` | Git 仓库数据提取器(ingest 功能) |
|
|
65
|
+
| `model_downloader.py` | Embedding 模型下载与缓存管理 |
|
|
66
|
+
| `note_index.py` | 笔记索引管理(文件名↔ID 映射) |
|
|
64
67
|
| `indexer.py` | File monitoring (watchdog) + incremental indexing |
|
|
65
68
|
| `note.py` | Markdown file CRUD with YAML frontmatter |
|
|
66
69
|
| `models.py` | `Note` data model with frontmatter serialization |
|
|
67
70
|
| `search_engine.py` | `HybridSearchEngine` with `SearchMode` enum, RRF fusion |
|
|
68
71
|
| `bm25_index.py` | BM25 keyword search index |
|
|
69
72
|
| `embedding_backend.py` | Sentence-transformers embedding backend(支持 daemon 代理) |
|
|
70
|
-
| `daemon/` | Embedding 模型 HTTP
|
|
73
|
+
| `daemon/` | Embedding 模型 HTTP 守护进程 (`server.py`/`client.py`/`process.py`),`jfox daemon start/stop/status` |
|
|
71
74
|
| `vector_store.py` | ChromaDB vector store for semantic search |
|
|
72
75
|
| `graph.py` | NetworkX knowledge graph from links/backlinks |
|
|
73
76
|
| `template.py` / `template_cli.py` | Jinja2 template system for structured note creation |
|
|
@@ -107,11 +110,11 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
|
|
|
107
110
|
- **Model caching**: Session-level model cache in conftest.py to avoid 30-60s reload per test
|
|
108
111
|
- **Test markers**: `slow`, `performance`, `integration`, `embedding`, `workflow`, `bulk`
|
|
109
112
|
- **Run single-process** to avoid ChromaDB/model loading conflicts
|
|
110
|
-
- **Test directory reorganization
|
|
111
|
-
- `tests/unit/` — Pure logic unit tests (
|
|
112
|
-
- `tests/integration/` — Cross-module integration tests (backlinks)
|
|
113
|
+
- **Test directory reorganization mostly complete**:
|
|
114
|
+
- `tests/unit/` — Pure logic unit tests (25 files)
|
|
115
|
+
- `tests/integration/` — Cross-module integration tests (backlinks, tag filter, model download)
|
|
113
116
|
- `tests/performance/` — Performance benchmarks
|
|
114
|
-
- Root-level `
|
|
117
|
+
- Root-level `test_config_unit.py` and `test_config_set_unit.py` remain (no longer duplicated, test different things)
|
|
115
118
|
- **pytest.ini**: `timeout=120`, `--strict-markers`, `-ra` (show all test summary)
|
|
116
119
|
|
|
117
120
|
## CI (GitHub Actions)
|
|
@@ -122,6 +125,8 @@ Four jobs in `.github/workflows/integration-test.yml`:
|
|
|
122
125
|
- **Full** (manual): All tests, all OS, all Python versions
|
|
123
126
|
- **Coverage** (after fast): Runs coverage on fast tests, uploads HTML/XML artifacts
|
|
124
127
|
|
|
128
|
+
**Release** workflow in `.github/workflows/publish.yml`: publishes to PyPI on GitHub release publication.
|
|
129
|
+
|
|
125
130
|
## Windows Notes
|
|
126
131
|
|
|
127
132
|
- `robocopy` flags get misinterpreted by bash — use `cmd.exe /c "robocopy source dest /E"`
|
|
@@ -135,4 +140,4 @@ Four jobs in `.github/workflows/integration-test.yml`:
|
|
|
135
140
|
## Gotchas
|
|
136
141
|
|
|
137
142
|
- `pytest.ini` `addopts` includes `-v`, so `pytest tests/` already runs verbose — adding `-v` manually is redundant
|
|
138
|
-
- Test directory migration
|
|
143
|
+
- Test directory migration mostly complete; root-level `test_config_unit.py` and `test_config_set_unit.py` remain but test different things from `tests/unit/`
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
import re
|
|
5
6
|
import sys
|
|
6
7
|
import warnings
|
|
7
8
|
from datetime import datetime
|
|
@@ -1146,8 +1147,25 @@ def delete(
|
|
|
1146
1147
|
raise typer.Exit(1)
|
|
1147
1148
|
|
|
1148
1149
|
|
|
1150
|
+
def _strip_frontmatter(raw: str) -> str:
|
|
1151
|
+
"""如果内容包含 YAML frontmatter,则剥离 frontmatter 和标题行,只返回正文"""
|
|
1152
|
+
# 去除 UTF-8 BOM
|
|
1153
|
+
if raw.startswith(""):
|
|
1154
|
+
raw = raw[1:]
|
|
1155
|
+
match = re.match(r"^---\n.*?\n---\n+(.*)", raw, re.DOTALL)
|
|
1156
|
+
if not match:
|
|
1157
|
+
return raw
|
|
1158
|
+
body = match.group(1).strip()
|
|
1159
|
+
# 去除 jfox 生成的标题行(# 后跟空格和非空内容,空行结尾)
|
|
1160
|
+
body = re.sub(r"^#[ \t]+\S.*\n*", "", body).strip()
|
|
1161
|
+
return body
|
|
1162
|
+
|
|
1163
|
+
|
|
1149
1164
|
def _read_content_file(content_file: str) -> str:
|
|
1150
|
-
"""从文件或 stdin 读取内容(--content-file 共用逻辑)
|
|
1165
|
+
"""从文件或 stdin 读取内容(--content-file 共用逻辑)
|
|
1166
|
+
|
|
1167
|
+
如果文件包含 YAML frontmatter(如 jfox 笔记文件),自动剥离只保留正文。
|
|
1168
|
+
"""
|
|
1151
1169
|
if content_file == "-":
|
|
1152
1170
|
import sys
|
|
1153
1171
|
|
|
@@ -1159,12 +1177,14 @@ def _read_content_file(content_file: str) -> str:
|
|
|
1159
1177
|
if not p.is_file():
|
|
1160
1178
|
raise ValueError(f"路径不是文件: {content_file}")
|
|
1161
1179
|
try:
|
|
1162
|
-
|
|
1180
|
+
raw = p.read_text(encoding="utf-8")
|
|
1163
1181
|
except PermissionError:
|
|
1164
1182
|
raise ValueError(f"无权限读取文件: {content_file}")
|
|
1165
1183
|
except UnicodeDecodeError:
|
|
1166
1184
|
raise ValueError(f"文件编码错误(需要 UTF-8): {content_file}")
|
|
1167
1185
|
|
|
1186
|
+
return _strip_frontmatter(raw)
|
|
1187
|
+
|
|
1168
1188
|
|
|
1169
1189
|
def _edit_impl(
|
|
1170
1190
|
note_id: str,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""笔记 CRUD 操作"""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import os
|
|
5
|
+
import tempfile
|
|
4
6
|
from datetime import datetime
|
|
5
7
|
from pathlib import Path
|
|
6
8
|
from typing import Any, Dict, List, Optional
|
|
@@ -59,15 +61,41 @@ def create_note(
|
|
|
59
61
|
return note
|
|
60
62
|
|
|
61
63
|
|
|
64
|
+
def _atomic_write(filepath: Path, content: str) -> None:
|
|
65
|
+
"""原子写入:先写临时文件再原子替换,防止崩溃产生空文件"""
|
|
66
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
tmp_fd = -1
|
|
68
|
+
tmp_path = ""
|
|
69
|
+
try:
|
|
70
|
+
tmp_fd, tmp_path = tempfile.mkstemp(dir=filepath.parent, suffix=".tmp")
|
|
71
|
+
with os.fdopen(tmp_fd, "w", encoding="utf-8") as f:
|
|
72
|
+
tmp_fd = -1 # fd 已移交 fdopen 管理
|
|
73
|
+
f.write(content)
|
|
74
|
+
# 保留目标文件权限(如已存在)
|
|
75
|
+
if filepath.exists():
|
|
76
|
+
try:
|
|
77
|
+
os.chmod(tmp_path, filepath.stat().st_mode)
|
|
78
|
+
except OSError:
|
|
79
|
+
pass
|
|
80
|
+
os.replace(tmp_path, filepath)
|
|
81
|
+
except BaseException:
|
|
82
|
+
if tmp_fd >= 0:
|
|
83
|
+
try:
|
|
84
|
+
os.close(tmp_fd)
|
|
85
|
+
except OSError:
|
|
86
|
+
pass
|
|
87
|
+
if tmp_path:
|
|
88
|
+
try:
|
|
89
|
+
os.unlink(tmp_path)
|
|
90
|
+
except OSError:
|
|
91
|
+
pass
|
|
92
|
+
raise
|
|
93
|
+
|
|
94
|
+
|
|
62
95
|
def save_note(note: Note, add_to_index: bool = True) -> bool:
|
|
63
96
|
"""保存笔记到文件"""
|
|
64
97
|
try:
|
|
65
|
-
|
|
66
|
-
note.filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
-
|
|
68
|
-
# 写入文件
|
|
69
|
-
with open(note.filepath, "w", encoding="utf-8") as f:
|
|
70
|
-
f.write(note.to_markdown())
|
|
98
|
+
_atomic_write(note.filepath, note.to_markdown())
|
|
71
99
|
|
|
72
100
|
logger.info(f"Saved note to {note.filepath}")
|
|
73
101
|
|
|
@@ -265,9 +293,7 @@ def update_note(note_obj: Note, add_to_index: bool = True) -> bool:
|
|
|
265
293
|
note_obj.updated = datetime.now()
|
|
266
294
|
|
|
267
295
|
# 写入新文件(filepath 属性根据当前字段生成)
|
|
268
|
-
note_obj.filepath.
|
|
269
|
-
with open(note_obj.filepath, "w", encoding="utf-8") as f:
|
|
270
|
-
f.write(note_obj.to_markdown())
|
|
296
|
+
_atomic_write(note_obj.filepath, note_obj.to_markdown())
|
|
271
297
|
|
|
272
298
|
# 如果文件路径变了(标题修改导致重命名),删除旧文件
|
|
273
299
|
if old_filepath != note_obj.filepath and old_filepath.exists():
|
|
@@ -9,6 +9,8 @@ import time
|
|
|
9
9
|
from functools import wraps
|
|
10
10
|
from typing import Any, Callable, List, Optional
|
|
11
11
|
|
|
12
|
+
from .note import _atomic_write
|
|
13
|
+
|
|
12
14
|
logger = logging.getLogger(__name__)
|
|
13
15
|
|
|
14
16
|
|
|
@@ -237,9 +239,7 @@ def bulk_import_notes(
|
|
|
237
239
|
# 批量保存(不索引)
|
|
238
240
|
for note in notes:
|
|
239
241
|
try:
|
|
240
|
-
note.filepath.
|
|
241
|
-
with open(note.filepath, "w", encoding="utf-8") as f:
|
|
242
|
-
f.write(note.to_markdown())
|
|
242
|
+
_atomic_write(note.filepath, note.to_markdown())
|
|
243
243
|
imported += 1
|
|
244
244
|
except Exception as e:
|
|
245
245
|
logger.warning(f"Failed to save note: {e}")
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""
|
|
2
|
+
测试类型: 单元测试
|
|
3
|
+
目标模块: jfox.note (_atomic_write 函数)
|
|
4
|
+
预估耗时: < 1秒
|
|
5
|
+
依赖要求: 无外部依赖
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import tempfile
|
|
10
|
+
from unittest.mock import patch
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
pytestmark = [pytest.mark.unit, pytest.mark.fast]
|
|
15
|
+
|
|
16
|
+
from jfox.config import ZKConfig
|
|
17
|
+
from jfox.models import NoteType
|
|
18
|
+
from jfox.note import (
|
|
19
|
+
_atomic_write,
|
|
20
|
+
create_note,
|
|
21
|
+
find_note_file,
|
|
22
|
+
save_note,
|
|
23
|
+
update_note,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestAtomicWrite:
|
|
28
|
+
"""测试 _atomic_write 原子写入"""
|
|
29
|
+
|
|
30
|
+
def test_normal_write(self, tmp_path):
|
|
31
|
+
"""正常写入:文件内容正确"""
|
|
32
|
+
filepath = tmp_path / "test.md"
|
|
33
|
+
_atomic_write(filepath, "hello world")
|
|
34
|
+
assert filepath.read_text(encoding="utf-8") == "hello world"
|
|
35
|
+
|
|
36
|
+
def test_creates_parent_dir(self, tmp_path):
|
|
37
|
+
"""目标目录不存在时自动创建"""
|
|
38
|
+
filepath = tmp_path / "sub" / "dir" / "test.md"
|
|
39
|
+
_atomic_write(filepath, "content")
|
|
40
|
+
assert filepath.read_text(encoding="utf-8") == "content"
|
|
41
|
+
|
|
42
|
+
def test_overwrites_existing(self, tmp_path):
|
|
43
|
+
"""覆盖已有文件时内容正确"""
|
|
44
|
+
filepath = tmp_path / "test.md"
|
|
45
|
+
filepath.write_text("old content", encoding="utf-8")
|
|
46
|
+
_atomic_write(filepath, "new content")
|
|
47
|
+
assert filepath.read_text(encoding="utf-8") == "new content"
|
|
48
|
+
|
|
49
|
+
def test_no_tmp_file_on_write_failure(self, tmp_path):
|
|
50
|
+
"""写入失败时不留临时文件,原文件不受影响"""
|
|
51
|
+
filepath = tmp_path / "test.md"
|
|
52
|
+
filepath.write_text("original", encoding="utf-8")
|
|
53
|
+
|
|
54
|
+
# 模拟写入过程中异常
|
|
55
|
+
with patch("os.replace", side_effect=OSError("disk full")):
|
|
56
|
+
with pytest.raises(OSError, match="disk full"):
|
|
57
|
+
_atomic_write(filepath, "new content")
|
|
58
|
+
|
|
59
|
+
# 原文件不受影响
|
|
60
|
+
assert filepath.read_text(encoding="utf-8") == "original"
|
|
61
|
+
# 无 .tmp 残留
|
|
62
|
+
tmp_files = list(tmp_path.glob("*.tmp"))
|
|
63
|
+
assert len(tmp_files) == 0
|
|
64
|
+
|
|
65
|
+
def test_no_empty_file_on_crash(self, tmp_path):
|
|
66
|
+
"""崩溃后不会产生 0 字节目标文件"""
|
|
67
|
+
filepath = tmp_path / "test.md"
|
|
68
|
+
filepath.write_text("original", encoding="utf-8")
|
|
69
|
+
|
|
70
|
+
original_mkstemp = tempfile.mkstemp
|
|
71
|
+
|
|
72
|
+
def failing_mkstemp(**kwargs):
|
|
73
|
+
fd, path = original_mkstemp(**kwargs)
|
|
74
|
+
os.write(fd, b"partial")
|
|
75
|
+
os.close(fd)
|
|
76
|
+
raise KeyboardInterrupt
|
|
77
|
+
|
|
78
|
+
with patch("tempfile.mkstemp", side_effect=failing_mkstemp):
|
|
79
|
+
with pytest.raises(KeyboardInterrupt):
|
|
80
|
+
_atomic_write(filepath, "new content")
|
|
81
|
+
|
|
82
|
+
# 目标文件不受影响
|
|
83
|
+
assert filepath.read_text(encoding="utf-8") == "original"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TestUpdateNoteAtomic:
|
|
87
|
+
"""测试 update_note 使用原子写入"""
|
|
88
|
+
|
|
89
|
+
def _make_config(self, tmp_path):
|
|
90
|
+
cfg = ZKConfig(base_dir=tmp_path)
|
|
91
|
+
cfg.ensure_dirs()
|
|
92
|
+
return cfg
|
|
93
|
+
|
|
94
|
+
@patch("jfox.note.config")
|
|
95
|
+
@patch("jfox.config.config")
|
|
96
|
+
def test_update_note_no_zero_byte_on_failure(
|
|
97
|
+
self, mock_global_config, mock_note_config, tmp_path
|
|
98
|
+
):
|
|
99
|
+
"""update_note 写入失败时不留 0 字节文件"""
|
|
100
|
+
cfg = self._make_config(tmp_path)
|
|
101
|
+
mock_global_config.notes_dir = cfg.notes_dir
|
|
102
|
+
mock_note_config.notes_dir = cfg.notes_dir
|
|
103
|
+
|
|
104
|
+
n = create_note("original", title="Test", note_type=NoteType.PERMANENT)
|
|
105
|
+
save_note(n, add_to_index=False)
|
|
106
|
+
|
|
107
|
+
# 修改内容
|
|
108
|
+
n.content = "modified"
|
|
109
|
+
|
|
110
|
+
# 模拟 _atomic_write 失败
|
|
111
|
+
with patch("jfox.note._atomic_write", side_effect=RuntimeError("boom")):
|
|
112
|
+
result = update_note(n, add_to_index=False)
|
|
113
|
+
|
|
114
|
+
assert result is False
|
|
115
|
+
# 磁盘上原文件不变
|
|
116
|
+
old_file = find_note_file(cfg, n.id)
|
|
117
|
+
assert old_file is not None
|
|
118
|
+
assert "original" in old_file.read_text(encoding="utf-8")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TestSaveNoteAtomic:
|
|
122
|
+
"""测试 save_note 使用原子写入"""
|
|
123
|
+
|
|
124
|
+
def _make_config(self, tmp_path):
|
|
125
|
+
cfg = ZKConfig(base_dir=tmp_path)
|
|
126
|
+
cfg.ensure_dirs()
|
|
127
|
+
return cfg
|
|
128
|
+
|
|
129
|
+
@patch("jfox.note.config")
|
|
130
|
+
def test_save_note_uses_atomic_write(self, mock_config, tmp_path):
|
|
131
|
+
"""save_note 应通过 _atomic_write 写入"""
|
|
132
|
+
cfg = self._make_config(tmp_path)
|
|
133
|
+
mock_config.notes_dir = cfg.notes_dir
|
|
134
|
+
|
|
135
|
+
n = create_note("test content", title="Test", note_type=NoteType.FLEETING)
|
|
136
|
+
|
|
137
|
+
with patch("jfox.note._atomic_write", wraps=_atomic_write) as mock_aw:
|
|
138
|
+
save_note(n, add_to_index=False)
|
|
139
|
+
mock_aw.assert_called_once()
|
|
140
|
+
|
|
141
|
+
# 验证文件内容正确
|
|
142
|
+
assert n.filepath.exists()
|
|
143
|
+
content = n.filepath.read_text(encoding="utf-8")
|
|
144
|
+
assert "test content" in content
|
|
145
|
+
|
|
146
|
+
@patch("jfox.note.config")
|
|
147
|
+
def test_save_note_no_zero_byte_on_failure(self, mock_config, tmp_path):
|
|
148
|
+
"""save_note 写入失败时不留 0 字节文件"""
|
|
149
|
+
cfg = self._make_config(tmp_path)
|
|
150
|
+
mock_config.notes_dir = cfg.notes_dir
|
|
151
|
+
|
|
152
|
+
n = create_note("content", title="Test", note_type=NoteType.FLEETING)
|
|
153
|
+
n.set_filepath(cfg.notes_dir / "fleeting" / "test.md")
|
|
154
|
+
|
|
155
|
+
# 先创建一个有内容的文件
|
|
156
|
+
n.filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
157
|
+
n.filepath.write_text("original content", encoding="utf-8")
|
|
158
|
+
|
|
159
|
+
# 模拟 _atomic_write 失败
|
|
160
|
+
with patch("jfox.note._atomic_write", side_effect=RuntimeError("boom")):
|
|
161
|
+
result = save_note(n, add_to_index=False)
|
|
162
|
+
|
|
163
|
+
assert result is False
|
|
164
|
+
# 原文件不受影响(不会被截断为 0 字节)
|
|
165
|
+
assert n.filepath.read_text(encoding="utf-8") == "original content"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""测试 _read_content_file 对含 frontmatter 文件的处理"""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import tempfile
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from jfox.cli import _read_content_file
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestReadContentFile:
|
|
12
|
+
"""_read_content_file 的单元测试"""
|
|
13
|
+
|
|
14
|
+
def test_plain_content_unchanged(self):
|
|
15
|
+
"""纯文本内容应原样返回"""
|
|
16
|
+
with tempfile.NamedTemporaryFile(
|
|
17
|
+
mode="w", suffix=".md", delete=False, encoding="utf-8"
|
|
18
|
+
) as f:
|
|
19
|
+
f.write("Hello world")
|
|
20
|
+
f.flush()
|
|
21
|
+
result = _read_content_file(f.name)
|
|
22
|
+
assert result == "Hello world"
|
|
23
|
+
|
|
24
|
+
def test_content_with_frontmatter_stripped(self):
|
|
25
|
+
"""含 frontmatter 的文件应只返回正文"""
|
|
26
|
+
raw = "---\nid: '123'\ntitle: test\n---\n\n# test\n\nBody text\n"
|
|
27
|
+
with tempfile.NamedTemporaryFile(
|
|
28
|
+
mode="w", suffix=".md", delete=False, encoding="utf-8"
|
|
29
|
+
) as f:
|
|
30
|
+
f.write(raw)
|
|
31
|
+
f.flush()
|
|
32
|
+
result = _read_content_file(f.name)
|
|
33
|
+
assert "---" not in result
|
|
34
|
+
assert "Body text" in result
|
|
35
|
+
|
|
36
|
+
def test_content_with_frontmatter_no_title(self):
|
|
37
|
+
"""含 frontmatter 但无标题行的文件"""
|
|
38
|
+
raw = "---\nid: '123'\ntitle: test\n---\n\nJust body text\n"
|
|
39
|
+
with tempfile.NamedTemporaryFile(
|
|
40
|
+
mode="w", suffix=".md", delete=False, encoding="utf-8"
|
|
41
|
+
) as f:
|
|
42
|
+
f.write(raw)
|
|
43
|
+
f.flush()
|
|
44
|
+
result = _read_content_file(f.name)
|
|
45
|
+
assert "---" not in result
|
|
46
|
+
assert "Just body text" in result
|
|
47
|
+
|
|
48
|
+
def test_stdin_passthrough(self):
|
|
49
|
+
"""stdin 模式('-')不应做处理"""
|
|
50
|
+
import sys
|
|
51
|
+
|
|
52
|
+
old_stdin = sys.stdin
|
|
53
|
+
try:
|
|
54
|
+
sys.stdin = io.StringIO("---\nid: x\n---\nbody")
|
|
55
|
+
result = _read_content_file("-")
|
|
56
|
+
finally:
|
|
57
|
+
sys.stdin = old_stdin
|
|
58
|
+
assert "---" in result
|
|
59
|
+
|
|
60
|
+
def test_file_not_found(self):
|
|
61
|
+
"""不存在的文件应抛异常"""
|
|
62
|
+
with pytest.raises(ValueError, match="文件不存在"):
|
|
63
|
+
_read_content_file("/nonexistent/file.md")
|
|
64
|
+
|
|
65
|
+
def test_bom_file_stripped(self):
|
|
66
|
+
"""含 UTF-8 BOM 的 frontmatter 文件应正确剥离"""
|
|
67
|
+
raw = "---\nid: '123'\ntitle: test\n---\n\nBody with BOM\n"
|
|
68
|
+
with tempfile.NamedTemporaryFile(mode="wb", suffix=".md", delete=False) as f:
|
|
69
|
+
f.write(raw.encode("utf-8-sig"))
|
|
70
|
+
f.flush()
|
|
71
|
+
result = _read_content_file(f.name)
|
|
72
|
+
assert "---" not in result
|
|
73
|
+
assert "Body with BOM" in result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md
RENAMED
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-bulk-import-vectorstore-init.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-13-suppress-third-party-logging.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-14-sync-docs-daemon-show.md
RENAMED
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-15-make-daemon-deps-required.md
RENAMED
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-15-session-summary-confirmation.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-04-27-intranet-model-download.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/plans/2026-05-03-list-notes-skip-summary.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md
RENAMED
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-29-daemon-stop-fix-design.md
RENAMED
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-04-30-jfox-kb-env-var-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/docs/superpowers/specs/2026-05-04-list-notes-index-design.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{jfox_cli-0.7.1 → jfox_cli-0.7.2}/skills-recommend/claude-code/jfox-session-summary/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|