footprinter-cli 1.0.0rc3__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/PKG-INFO +66 -25
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/README.md +64 -22
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/__init__.py +10 -0
- footprinter_cli-1.0.1/footprinter/cli/doctor.py +247 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/mcp_setup.py +59 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/setup.py +160 -65
- footprinter_cli-1.0.1/footprinter/cli/uninstall.py +179 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/browser_indexer.py +14 -2
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/file_scanner.py +38 -8
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/orchestrator.py +5 -1
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/processing.py +24 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/registry.py +1 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/PKG-INFO +66 -25
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/SOURCES.txt +2 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/pyproject.toml +3 -4
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_package_init.py +4 -1
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/LICENSE +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/access.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/db.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/entities.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/search.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/semantic.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/server.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/api/status.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/config.example.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/context_patterns.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/extensions.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/filename_patterns.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/mime_mappings.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/salesforce_rules.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/bundled/patterns/security_patterns.yaml +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/__main__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/_common.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/_policy_helpers.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/_prompt.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/api_cmd.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/connect.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/data.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/delete.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/ingest.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/mcp_cmd.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/search.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/search_cmd.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/status.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/status_cmd.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/upsert.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/vectorize_cmd.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/cli/view.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/connectors/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/connectors/config_utils.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/browser.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/chats.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/clients.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/emails.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/files.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/folders.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/messages.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/policies.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/projects.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/search.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/sql_utils.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/status.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/db/uploads.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/browser.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/chat.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/ingest.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/local_files.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/local_folders.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/adapters/protocol.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/chat_dedup.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/chat_indexer.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/chat_parsers/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/chat_parsers/chatgpt_parser.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/chat_parsers/claude_parser.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/cli.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/content_extractors.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/database.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/db/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/db/connector_schema.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/db/migration.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/db/schema.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/db/security.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/file_indexer.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/folder_indexer.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/full_content_extractor.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/pipe_runner.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/run_record.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/ingest/status.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/__main__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/db.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/errors.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/extraction.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/server.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/navigation.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/read.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/search.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/semantic.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/mcp/tools/status.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/paths.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/permissions.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/semantic/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/semantic/chunking.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/semantic/embeddings.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/semantic/hybrid_search.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/semantic/vector_store.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/access_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/chat_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/client_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/content_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/email_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/file_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/folder_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/includes.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/ingest_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/project_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/roles.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/search_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/semantic_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/status_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/services/visit_service.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/source_registry.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/__init__.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/hash_utils.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/logging_config.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/mime.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/text.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/utils/time.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter/visibility.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/dependency_links.txt +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/entry_points.txt +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/requires.txt +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/footprinter_cli.egg-info/top_level.txt +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/setup.cfg +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_access_control_bypasses.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_access_control_docs.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_access_recalculate.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_build_status_filter.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_bundled.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_e2e_install.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_e2e_pipeline.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_edit_recalculate.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_examples.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_files_rename.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_files_surface.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_inherit_resolution.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_logging.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_no_project_root.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_paths_no_test_marker.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_pip_install_e2e.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_prompt_safety.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_resolver.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_security_layer.py +0 -0
- {footprinter_cli-1.0.0rc3 → footprinter_cli-1.0.1}/tests/test_security_permissions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: footprinter-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: A local context layer for your files, browser history, chats, and email — searchable, user-owned, MCP-served.
|
|
5
5
|
Author: SwellCity Group
|
|
6
6
|
License: MIT
|
|
@@ -8,9 +8,8 @@ Project-URL: Homepage, https://github.com/swellcitygroup/footprinter
|
|
|
8
8
|
Project-URL: Repository, https://github.com/swellcitygroup/footprinter
|
|
9
9
|
Project-URL: Issues, https://github.com/swellcitygroup/footprinter/issues
|
|
10
10
|
Project-URL: Documentation, https://github.com/swellcitygroup/footprinter/blob/main/README.md
|
|
11
|
-
Project-URL: Changelog, https://github.com/swellcitygroup/footprinter/blob/main/CHANGELOG.md
|
|
12
11
|
Keywords: indexer,mcp,metadata,model-context-protocol,file-indexing,sqlite,context-engineering,personal-information-management
|
|
13
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
13
|
Classifier: Environment :: Console
|
|
15
14
|
Classifier: Intended Audience :: Developers
|
|
16
15
|
Classifier: Intended Audience :: End Users/Desktop
|
|
@@ -58,18 +57,62 @@ Requires-Dist: httpx<1.0,>=0.27.0; extra == "dev"
|
|
|
58
57
|
|
|
59
58
|
Your work lives across a filesystem, a browser, an inbox, a chat history, and whatever other tools you reach for. Footprinter indexes those sources into a single local store, organizes them into the projects and groupings *you* define, and serves the result to AI agents through a governed access layer. You control what the agent can see. Everything stays on your machine.
|
|
60
59
|
|
|
60
|
+
## Prerequisites
|
|
61
|
+
|
|
62
|
+
- **Python 3.11 or newer.** Stock macOS ships with Python 3.9, which won't work — install a newer Python from [python.org](https://www.python.org/downloads/) (recommended) or via `brew install python@3.11`.
|
|
63
|
+
- **macOS 13+** or **Linux**.
|
|
64
|
+
- **Full Disk Access on macOS** for browser history indexing. Grant it to your terminal app under *System Settings → Privacy & Security → Full Disk Access*. `fp setup` will guide you through this when needed.
|
|
65
|
+
|
|
61
66
|
## Install
|
|
62
67
|
|
|
68
|
+
The fastest path on a clean machine is the install script — it ensures Python 3.11+ is present and installs `footprinter-cli`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Base install (CLI + MCP + HTTP API)
|
|
72
|
+
curl -fsSL https://raw.githubusercontent.com/swellcitygroup/footprinter/main/scripts/release/install.sh | bash
|
|
73
|
+
|
|
74
|
+
# Full install (adds semantic search + document parsing)
|
|
75
|
+
curl -fsSL https://raw.githubusercontent.com/swellcitygroup/footprinter/main/scripts/release/install-full.sh | bash
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If you prefer to manage the install yourself, use **pipx** (recommended) — modern macOS Python ships PEP 668 enabled, which blocks bare `pip install`:
|
|
79
|
+
|
|
63
80
|
```bash
|
|
64
|
-
|
|
81
|
+
brew install pipx
|
|
82
|
+
pipx ensurepath # then restart your terminal
|
|
83
|
+
pipx install footprinter-cli
|
|
84
|
+
pipx install 'footprinter-cli[full]' # with semantic + parse
|
|
65
85
|
```
|
|
66
86
|
|
|
67
|
-
|
|
87
|
+
Inside an existing venv, `pip` works as expected:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
./venv/bin/pip install footprinter-cli
|
|
91
|
+
./venv/bin/pip install 'footprinter-cli[full]'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The base install includes the indexing pipeline, CLI, MCP server, HTTP API, and token encryption. Optional extras add more:
|
|
95
|
+
|
|
96
|
+
| Extra | What it adds |
|
|
97
|
+
|-------|-------------|
|
|
98
|
+
| `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
|
|
99
|
+
| `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
|
|
100
|
+
| `[full]` | All optional extras (semantic + parse) |
|
|
101
|
+
|
|
102
|
+
> **Privacy note:** The `[semantic]` extra installs ChromaDB. Footprinter initializes
|
|
103
|
+
> the ChromaDB client with `anonymized_telemetry=False`, so no telemetry is sent
|
|
104
|
+
> regardless of which version pip resolves. ChromaDB also removed product telemetry
|
|
105
|
+
> entirely in version 1.5.4. See
|
|
106
|
+
> [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss) for details.
|
|
107
|
+
|
|
108
|
+
### Uninstall
|
|
109
|
+
|
|
110
|
+
`fp uninstall` cleans up the MCP entry and user data first, then run the appropriate package uninstall:
|
|
68
111
|
|
|
69
112
|
```bash
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
pip
|
|
113
|
+
fp uninstall # remove MCP entry + user data
|
|
114
|
+
pipx uninstall footprinter-cli # if you installed via pipx
|
|
115
|
+
./venv/bin/pip uninstall footprinter-cli # if you installed inside a venv
|
|
73
116
|
```
|
|
74
117
|
|
|
75
118
|
## Quick Start
|
|
@@ -81,16 +124,22 @@ fp status # See what's indexed
|
|
|
81
124
|
fp search "meeting notes" # Find things
|
|
82
125
|
```
|
|
83
126
|
|
|
84
|
-
|
|
127
|
+
A few first-run notes:
|
|
128
|
+
|
|
129
|
+
- The first ingest is implicitly full; subsequent runs are incremental. If you change exclusions or add directories after the first run, re-run with `fp ingest --full` so previously skipped files get picked up.
|
|
130
|
+
- With `[semantic]` or `[full]`, the **first ingest downloads ~80MB** of ONNX embedding model weights. It's a one-time cost — subsequent ingests are fast.
|
|
131
|
+
- Keep the directories you want indexed **outside `~/Downloads`** — the default exclusion list skips it.
|
|
85
132
|
|
|
86
133
|
## Connect to Claude Desktop
|
|
87
134
|
|
|
88
135
|
Footprinter includes an MCP server that gives Claude Desktop (or any MCP client) structured access to your indexed data:
|
|
89
136
|
|
|
90
137
|
```bash
|
|
91
|
-
fp setup mcp # Configure MCP for Claude Desktop
|
|
138
|
+
fp setup mcp --claude # Configure MCP for Claude Desktop
|
|
92
139
|
```
|
|
93
140
|
|
|
141
|
+
After running this, **fully quit Claude Desktop (Cmd+Q) and relaunch** before the Footprinter tools appear in the conversation tools list. A simple window close isn't enough — the app keeps running in the menu bar.
|
|
142
|
+
|
|
94
143
|
Once configured, Claude can search your files, browse projects, and find related conversations — through natural language.
|
|
95
144
|
|
|
96
145
|
## What It Indexes
|
|
@@ -104,6 +153,8 @@ Once configured, Claude can search your files, browse projects, and find related
|
|
|
104
153
|
| **Documents** | PDF, Word, Excel, PowerPoint content (with `[parse]` extra) |
|
|
105
154
|
| **Semantic embeddings** | Conceptual similarity across all sources (with `[semantic]` extra) |
|
|
106
155
|
|
|
156
|
+
What lands in the database — and when — is controlled by the **content storage tier** you opt into. By default, Footprinter only indexes metadata; it does not read your file content until you explicitly enable it. See [Content Storage](https://github.com/swellcitygroup/footprinter/blob/main/reference/content-storage.md) for the full breakdown.
|
|
157
|
+
|
|
107
158
|
Additional sources are available through [connector plugins](#connectors).
|
|
108
159
|
|
|
109
160
|
## CLI Commands
|
|
@@ -124,6 +175,8 @@ All commands use the `fp` entry point.
|
|
|
124
175
|
| `fp data` | Export data, generate templates, or import metadata corrections |
|
|
125
176
|
| `fp delete` | Soft-delete a record |
|
|
126
177
|
| `fp vectorize` | Manage per-record vectorization control |
|
|
178
|
+
| `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
|
|
179
|
+
| `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
|
|
127
180
|
|
|
128
181
|
Run `fp <command> --help` for full usage.
|
|
129
182
|
|
|
@@ -145,23 +198,10 @@ Single-process CLI with optional MCP server. SQLite database. No containers, no
|
|
|
145
198
|
|
|
146
199
|
Sources are scanned into SQLite with bidirectional links connecting local files to remote backups via content hash matching. Embeddings are generated at ingest time for semantic search. The MCP server exposes indexed data with two-layer access control (visibility + permissions) — you decide what agents can see.
|
|
147
200
|
|
|
148
|
-
## Optional Extras
|
|
149
|
-
|
|
150
|
-
| Extra | What it adds |
|
|
151
|
-
|-------|-------------|
|
|
152
|
-
| `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
|
|
153
|
-
| `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
|
|
154
|
-
| `[full]` | All optional extras (semantic + parse) |
|
|
155
|
-
|
|
156
|
-
> **Privacy note:** The `[semantic]` extra installs ChromaDB, which bundles PostHog analytics.
|
|
157
|
-
> ChromaDB collects anonymous usage telemetry by default. Set `ANONYMIZED_TELEMETRY=False`
|
|
158
|
-
> in your environment to disable it. See
|
|
159
|
-
> [ChromaDB telemetry docs](https://docs.trychroma.com/docs/overview/telemetry) for details.
|
|
160
|
-
|
|
161
201
|
## Requirements
|
|
162
202
|
|
|
163
203
|
- Python 3.11+
|
|
164
|
-
- macOS or Linux
|
|
204
|
+
- macOS 13+ or Linux
|
|
165
205
|
- Full Disk Access on macOS (for browser history)
|
|
166
206
|
|
|
167
207
|
## Documentation
|
|
@@ -169,6 +209,7 @@ Sources are scanned into SQLite with bidirectional links connecting local files
|
|
|
169
209
|
- [Interfaces](https://github.com/swellcitygroup/footprinter/blob/main/reference/interfaces.md) — CLI commands, MCP tools, Python API
|
|
170
210
|
- [Data Model](https://github.com/swellcitygroup/footprinter/blob/main/reference/data-model.md) — database schema
|
|
171
211
|
- [Pipeline](https://github.com/swellcitygroup/footprinter/blob/main/reference/pipeline.md) — indexing stages and configuration
|
|
212
|
+
- [Content Storage](https://github.com/swellcitygroup/footprinter/blob/main/reference/content-storage.md) — metadata vs. snippet vs. full-content tiers
|
|
172
213
|
- [Access Control](https://github.com/swellcitygroup/footprinter/blob/main/reference/mcp-access-control.md) — MCP security model
|
|
173
214
|
|
|
174
215
|
## Contributing
|
|
@@ -189,7 +230,7 @@ python3 -m venv venv
|
|
|
189
230
|
### Running tests
|
|
190
231
|
|
|
191
232
|
```bash
|
|
192
|
-
pytest tests/ -v --tb=short
|
|
233
|
+
./venv/bin/pytest tests/ -v --tb=short
|
|
193
234
|
```
|
|
194
235
|
|
|
195
236
|
### Code style
|
|
@@ -6,18 +6,62 @@
|
|
|
6
6
|
|
|
7
7
|
Your work lives across a filesystem, a browser, an inbox, a chat history, and whatever other tools you reach for. Footprinter indexes those sources into a single local store, organizes them into the projects and groupings *you* define, and serves the result to AI agents through a governed access layer. You control what the agent can see. Everything stays on your machine.
|
|
8
8
|
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- **Python 3.11 or newer.** Stock macOS ships with Python 3.9, which won't work — install a newer Python from [python.org](https://www.python.org/downloads/) (recommended) or via `brew install python@3.11`.
|
|
12
|
+
- **macOS 13+** or **Linux**.
|
|
13
|
+
- **Full Disk Access on macOS** for browser history indexing. Grant it to your terminal app under *System Settings → Privacy & Security → Full Disk Access*. `fp setup` will guide you through this when needed.
|
|
14
|
+
|
|
9
15
|
## Install
|
|
10
16
|
|
|
17
|
+
The fastest path on a clean machine is the install script — it ensures Python 3.11+ is present and installs `footprinter-cli`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Base install (CLI + MCP + HTTP API)
|
|
21
|
+
curl -fsSL https://raw.githubusercontent.com/swellcitygroup/footprinter/main/scripts/release/install.sh | bash
|
|
22
|
+
|
|
23
|
+
# Full install (adds semantic search + document parsing)
|
|
24
|
+
curl -fsSL https://raw.githubusercontent.com/swellcitygroup/footprinter/main/scripts/release/install-full.sh | bash
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If you prefer to manage the install yourself, use **pipx** (recommended) — modern macOS Python ships PEP 668 enabled, which blocks bare `pip install`:
|
|
28
|
+
|
|
11
29
|
```bash
|
|
12
|
-
|
|
30
|
+
brew install pipx
|
|
31
|
+
pipx ensurepath # then restart your terminal
|
|
32
|
+
pipx install footprinter-cli
|
|
33
|
+
pipx install 'footprinter-cli[full]' # with semantic + parse
|
|
13
34
|
```
|
|
14
35
|
|
|
15
|
-
|
|
36
|
+
Inside an existing venv, `pip` works as expected:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
./venv/bin/pip install footprinter-cli
|
|
40
|
+
./venv/bin/pip install 'footprinter-cli[full]'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The base install includes the indexing pipeline, CLI, MCP server, HTTP API, and token encryption. Optional extras add more:
|
|
44
|
+
|
|
45
|
+
| Extra | What it adds |
|
|
46
|
+
|-------|-------------|
|
|
47
|
+
| `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
|
|
48
|
+
| `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
|
|
49
|
+
| `[full]` | All optional extras (semantic + parse) |
|
|
50
|
+
|
|
51
|
+
> **Privacy note:** The `[semantic]` extra installs ChromaDB. Footprinter initializes
|
|
52
|
+
> the ChromaDB client with `anonymized_telemetry=False`, so no telemetry is sent
|
|
53
|
+
> regardless of which version pip resolves. ChromaDB also removed product telemetry
|
|
54
|
+
> entirely in version 1.5.4. See
|
|
55
|
+
> [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss) for details.
|
|
56
|
+
|
|
57
|
+
### Uninstall
|
|
58
|
+
|
|
59
|
+
`fp uninstall` cleans up the MCP entry and user data first, then run the appropriate package uninstall:
|
|
16
60
|
|
|
17
61
|
```bash
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
pip
|
|
62
|
+
fp uninstall # remove MCP entry + user data
|
|
63
|
+
pipx uninstall footprinter-cli # if you installed via pipx
|
|
64
|
+
./venv/bin/pip uninstall footprinter-cli # if you installed inside a venv
|
|
21
65
|
```
|
|
22
66
|
|
|
23
67
|
## Quick Start
|
|
@@ -29,16 +73,22 @@ fp status # See what's indexed
|
|
|
29
73
|
fp search "meeting notes" # Find things
|
|
30
74
|
```
|
|
31
75
|
|
|
32
|
-
|
|
76
|
+
A few first-run notes:
|
|
77
|
+
|
|
78
|
+
- The first ingest is implicitly full; subsequent runs are incremental. If you change exclusions or add directories after the first run, re-run with `fp ingest --full` so previously skipped files get picked up.
|
|
79
|
+
- With `[semantic]` or `[full]`, the **first ingest downloads ~80MB** of ONNX embedding model weights. It's a one-time cost — subsequent ingests are fast.
|
|
80
|
+
- Keep the directories you want indexed **outside `~/Downloads`** — the default exclusion list skips it.
|
|
33
81
|
|
|
34
82
|
## Connect to Claude Desktop
|
|
35
83
|
|
|
36
84
|
Footprinter includes an MCP server that gives Claude Desktop (or any MCP client) structured access to your indexed data:
|
|
37
85
|
|
|
38
86
|
```bash
|
|
39
|
-
fp setup mcp # Configure MCP for Claude Desktop
|
|
87
|
+
fp setup mcp --claude # Configure MCP for Claude Desktop
|
|
40
88
|
```
|
|
41
89
|
|
|
90
|
+
After running this, **fully quit Claude Desktop (Cmd+Q) and relaunch** before the Footprinter tools appear in the conversation tools list. A simple window close isn't enough — the app keeps running in the menu bar.
|
|
91
|
+
|
|
42
92
|
Once configured, Claude can search your files, browse projects, and find related conversations — through natural language.
|
|
43
93
|
|
|
44
94
|
## What It Indexes
|
|
@@ -52,6 +102,8 @@ Once configured, Claude can search your files, browse projects, and find related
|
|
|
52
102
|
| **Documents** | PDF, Word, Excel, PowerPoint content (with `[parse]` extra) |
|
|
53
103
|
| **Semantic embeddings** | Conceptual similarity across all sources (with `[semantic]` extra) |
|
|
54
104
|
|
|
105
|
+
What lands in the database — and when — is controlled by the **content storage tier** you opt into. By default, Footprinter only indexes metadata; it does not read your file content until you explicitly enable it. See [Content Storage](https://github.com/swellcitygroup/footprinter/blob/main/reference/content-storage.md) for the full breakdown.
|
|
106
|
+
|
|
55
107
|
Additional sources are available through [connector plugins](#connectors).
|
|
56
108
|
|
|
57
109
|
## CLI Commands
|
|
@@ -72,6 +124,8 @@ All commands use the `fp` entry point.
|
|
|
72
124
|
| `fp data` | Export data, generate templates, or import metadata corrections |
|
|
73
125
|
| `fp delete` | Soft-delete a record |
|
|
74
126
|
| `fp vectorize` | Manage per-record vectorization control |
|
|
127
|
+
| `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
|
|
128
|
+
| `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
|
|
75
129
|
|
|
76
130
|
Run `fp <command> --help` for full usage.
|
|
77
131
|
|
|
@@ -93,23 +147,10 @@ Single-process CLI with optional MCP server. SQLite database. No containers, no
|
|
|
93
147
|
|
|
94
148
|
Sources are scanned into SQLite with bidirectional links connecting local files to remote backups via content hash matching. Embeddings are generated at ingest time for semantic search. The MCP server exposes indexed data with two-layer access control (visibility + permissions) — you decide what agents can see.
|
|
95
149
|
|
|
96
|
-
## Optional Extras
|
|
97
|
-
|
|
98
|
-
| Extra | What it adds |
|
|
99
|
-
|-------|-------------|
|
|
100
|
-
| `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
|
|
101
|
-
| `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
|
|
102
|
-
| `[full]` | All optional extras (semantic + parse) |
|
|
103
|
-
|
|
104
|
-
> **Privacy note:** The `[semantic]` extra installs ChromaDB, which bundles PostHog analytics.
|
|
105
|
-
> ChromaDB collects anonymous usage telemetry by default. Set `ANONYMIZED_TELEMETRY=False`
|
|
106
|
-
> in your environment to disable it. See
|
|
107
|
-
> [ChromaDB telemetry docs](https://docs.trychroma.com/docs/overview/telemetry) for details.
|
|
108
|
-
|
|
109
150
|
## Requirements
|
|
110
151
|
|
|
111
152
|
- Python 3.11+
|
|
112
|
-
- macOS or Linux
|
|
153
|
+
- macOS 13+ or Linux
|
|
113
154
|
- Full Disk Access on macOS (for browser history)
|
|
114
155
|
|
|
115
156
|
## Documentation
|
|
@@ -117,6 +158,7 @@ Sources are scanned into SQLite with bidirectional links connecting local files
|
|
|
117
158
|
- [Interfaces](https://github.com/swellcitygroup/footprinter/blob/main/reference/interfaces.md) — CLI commands, MCP tools, Python API
|
|
118
159
|
- [Data Model](https://github.com/swellcitygroup/footprinter/blob/main/reference/data-model.md) — database schema
|
|
119
160
|
- [Pipeline](https://github.com/swellcitygroup/footprinter/blob/main/reference/pipeline.md) — indexing stages and configuration
|
|
161
|
+
- [Content Storage](https://github.com/swellcitygroup/footprinter/blob/main/reference/content-storage.md) — metadata vs. snippet vs. full-content tiers
|
|
120
162
|
- [Access Control](https://github.com/swellcitygroup/footprinter/blob/main/reference/mcp-access-control.md) — MCP security model
|
|
121
163
|
|
|
122
164
|
## Contributing
|
|
@@ -137,7 +179,7 @@ python3 -m venv venv
|
|
|
137
179
|
### Running tests
|
|
138
180
|
|
|
139
181
|
```bash
|
|
140
|
-
pytest tests/ -v --tb=short
|
|
182
|
+
./venv/bin/pytest tests/ -v --tb=short
|
|
141
183
|
```
|
|
142
184
|
|
|
143
185
|
### Code style
|
|
@@ -63,6 +63,12 @@ def main(argv=None) -> None:
|
|
|
63
63
|
" fp api Start the HTTP API server\n"
|
|
64
64
|
" fp mcp check ~/Work/file Check access resolution for a path\n"
|
|
65
65
|
"\n"
|
|
66
|
+
"diagnostics:\n"
|
|
67
|
+
" fp doctor Check installation health\n"
|
|
68
|
+
"\n"
|
|
69
|
+
"cleanup:\n"
|
|
70
|
+
" fp uninstall Remove Footprinter (MCP entry, data, package)\n"
|
|
71
|
+
"\n"
|
|
66
72
|
"tip: use 'fp <command> --help' for details on any command."
|
|
67
73
|
),
|
|
68
74
|
formatter_class=FORMATTER,
|
|
@@ -80,11 +86,13 @@ def main(argv=None) -> None:
|
|
|
80
86
|
connect,
|
|
81
87
|
data,
|
|
82
88
|
delete,
|
|
89
|
+
doctor,
|
|
83
90
|
ingest,
|
|
84
91
|
mcp_cmd,
|
|
85
92
|
search_cmd,
|
|
86
93
|
setup,
|
|
87
94
|
status_cmd,
|
|
95
|
+
uninstall,
|
|
88
96
|
upsert,
|
|
89
97
|
vectorize_cmd,
|
|
90
98
|
view,
|
|
@@ -103,6 +111,8 @@ def main(argv=None) -> None:
|
|
|
103
111
|
data,
|
|
104
112
|
delete,
|
|
105
113
|
vectorize_cmd,
|
|
114
|
+
uninstall,
|
|
115
|
+
doctor,
|
|
106
116
|
]:
|
|
107
117
|
mod.register(subparsers)
|
|
108
118
|
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""fp doctor — post-install health check command.
|
|
2
|
+
|
|
3
|
+
Diagnostic checks for installation and environment issues.
|
|
4
|
+
Like ``brew doctor`` or ``gh auth status`` — reports problems,
|
|
5
|
+
doesn't fix them.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import importlib.util
|
|
9
|
+
import json
|
|
10
|
+
import platform
|
|
11
|
+
import shutil
|
|
12
|
+
import sqlite3
|
|
13
|
+
import sys
|
|
14
|
+
from dataclasses import asdict, dataclass
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from footprinter.cli._common import FORMATTER, add_json_flag, console, output_json
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Check:
|
|
22
|
+
"""Result of a single diagnostic check."""
|
|
23
|
+
|
|
24
|
+
name: str
|
|
25
|
+
status: str # OK, WARN, FAIL
|
|
26
|
+
message: str = ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _get_python_version() -> tuple:
|
|
30
|
+
return sys.version_info[:3]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _find_spec(name: str):
|
|
34
|
+
try:
|
|
35
|
+
return importlib.util.find_spec(name)
|
|
36
|
+
except (ModuleNotFoundError, ValueError):
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _probe_fda() -> bool:
|
|
41
|
+
"""Return True if Safari History.db is readable (macOS FDA check)."""
|
|
42
|
+
safari_db = Path.home() / "Library" / "Safari" / "History.db"
|
|
43
|
+
if not safari_db.exists():
|
|
44
|
+
return True # no Safari DB means nothing to check
|
|
45
|
+
try:
|
|
46
|
+
with sqlite3.connect(f"file:{safari_db}?mode=ro", uri=True) as conn:
|
|
47
|
+
conn.execute("SELECT count(*) FROM sqlite_master")
|
|
48
|
+
return True
|
|
49
|
+
except Exception:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _check_python_version() -> Check:
|
|
54
|
+
major, minor, micro = _get_python_version()
|
|
55
|
+
if (major, minor) >= (3, 11):
|
|
56
|
+
return Check("python_version", "OK", f"Python {major}.{minor}.{micro}")
|
|
57
|
+
return Check(
|
|
58
|
+
"python_version",
|
|
59
|
+
"FAIL",
|
|
60
|
+
f"Python {major}.{minor}.{micro} — requires 3.11 or later",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _check_platform() -> Check:
|
|
65
|
+
system = platform.system()
|
|
66
|
+
machine = platform.machine()
|
|
67
|
+
return Check("platform", "OK", f"{system} ({machine})")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _check_config() -> Check:
|
|
71
|
+
from footprinter.paths import get_config_path
|
|
72
|
+
|
|
73
|
+
config_path = get_config_path()
|
|
74
|
+
if not config_path.exists():
|
|
75
|
+
return Check(
|
|
76
|
+
"config",
|
|
77
|
+
"WARN",
|
|
78
|
+
f"No config at {config_path} — run 'fp setup' to create one",
|
|
79
|
+
)
|
|
80
|
+
try:
|
|
81
|
+
import yaml
|
|
82
|
+
|
|
83
|
+
with open(config_path) as f:
|
|
84
|
+
yaml.safe_load(f)
|
|
85
|
+
return Check("config", "OK", str(config_path))
|
|
86
|
+
except Exception as e:
|
|
87
|
+
return Check("config", "FAIL", f"Config at {config_path} is not valid YAML: {e}")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _check_database() -> Check:
|
|
91
|
+
from footprinter.paths import get_db_path
|
|
92
|
+
|
|
93
|
+
db_path = get_db_path()
|
|
94
|
+
if not db_path.exists():
|
|
95
|
+
return Check(
|
|
96
|
+
"database",
|
|
97
|
+
"WARN",
|
|
98
|
+
f"No database at {db_path} — run 'fp ingest' to create one",
|
|
99
|
+
)
|
|
100
|
+
try:
|
|
101
|
+
with sqlite3.connect(f"file:{db_path}?mode=ro", uri=True) as conn:
|
|
102
|
+
conn.execute("SELECT count(*) FROM sqlite_master")
|
|
103
|
+
return Check("database", "OK", str(db_path))
|
|
104
|
+
except Exception as e:
|
|
105
|
+
return Check("database", "FAIL", f"Database at {db_path} is not readable: {e}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _check_fda() -> Check:
|
|
109
|
+
if platform.system() != "Darwin":
|
|
110
|
+
return Check("fda", "OK", "Not macOS — Full Disk Access not applicable")
|
|
111
|
+
if _probe_fda():
|
|
112
|
+
return Check("fda", "OK", "Safari History.db is readable")
|
|
113
|
+
return Check(
|
|
114
|
+
"fda",
|
|
115
|
+
"WARN",
|
|
116
|
+
"Cannot read Safari History.db — grant Full Disk Access to your terminal in System Settings > Privacy & Security",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _check_semantic_deps() -> Check:
|
|
121
|
+
missing = []
|
|
122
|
+
for mod in ("chromadb", "sentence_transformers"):
|
|
123
|
+
if _find_spec(mod) is None:
|
|
124
|
+
missing.append(mod)
|
|
125
|
+
if not missing:
|
|
126
|
+
return Check("semantic_deps", "OK", "chromadb and sentence_transformers available")
|
|
127
|
+
return Check(
|
|
128
|
+
"semantic_deps",
|
|
129
|
+
"WARN",
|
|
130
|
+
f"Optional semantic search dependencies not installed: {', '.join(missing)} — install with: pipx install --force 'footprinter-cli[full]'",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _check_parse_deps() -> Check:
|
|
135
|
+
missing = []
|
|
136
|
+
for mod in ("docx", "pdfplumber"):
|
|
137
|
+
if _find_spec(mod) is None:
|
|
138
|
+
missing.append(mod)
|
|
139
|
+
if not missing:
|
|
140
|
+
return Check("parse_deps", "OK", "Document parsing dependencies available")
|
|
141
|
+
return Check(
|
|
142
|
+
"parse_deps",
|
|
143
|
+
"WARN",
|
|
144
|
+
f"Optional parsing dependencies not installed: {', '.join(missing)} — install with: pipx install --force 'footprinter-cli[full]'",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _check_mcp_config() -> Check:
|
|
149
|
+
if platform.system() == "Darwin":
|
|
150
|
+
config_path = (
|
|
151
|
+
Path.home()
|
|
152
|
+
/ "Library"
|
|
153
|
+
/ "Application Support"
|
|
154
|
+
/ "Claude"
|
|
155
|
+
/ "claude_desktop_config.json"
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
config_dir = Path.home() / ".config" / "Claude"
|
|
159
|
+
config_path = config_dir / "claude_desktop_config.json"
|
|
160
|
+
|
|
161
|
+
if not config_path.exists():
|
|
162
|
+
return Check("mcp_config", "OK", "No Claude Desktop config found (optional)")
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
with open(config_path) as f:
|
|
166
|
+
data = json.load(f)
|
|
167
|
+
servers = data.get("mcpServers", {})
|
|
168
|
+
if "footprinter" not in servers:
|
|
169
|
+
return Check("mcp_config", "OK", "Claude Desktop config exists but no footprinter entry (optional)")
|
|
170
|
+
|
|
171
|
+
entry = servers["footprinter"]
|
|
172
|
+
command = entry.get("command", "")
|
|
173
|
+
if command:
|
|
174
|
+
resolved = Path(command).exists() if Path(command).is_absolute() else shutil.which(command)
|
|
175
|
+
if not resolved:
|
|
176
|
+
return Check(
|
|
177
|
+
"mcp_config",
|
|
178
|
+
"WARN",
|
|
179
|
+
f"MCP command not found: {command}",
|
|
180
|
+
)
|
|
181
|
+
return Check("mcp_config", "OK", "footprinter MCP server configured in Claude Desktop")
|
|
182
|
+
except Exception as e:
|
|
183
|
+
return Check("mcp_config", "WARN", f"Could not read Claude Desktop config: {e}")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def run_checks() -> list[Check]:
|
|
187
|
+
"""Run all diagnostic checks and return the results."""
|
|
188
|
+
return [
|
|
189
|
+
_check_python_version(),
|
|
190
|
+
_check_platform(),
|
|
191
|
+
_check_config(),
|
|
192
|
+
_check_database(),
|
|
193
|
+
_check_fda(),
|
|
194
|
+
_check_semantic_deps(),
|
|
195
|
+
_check_parse_deps(),
|
|
196
|
+
_check_mcp_config(),
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def register(subparsers) -> None:
|
|
201
|
+
"""Register ``fp doctor`` on the CLI router."""
|
|
202
|
+
parser = subparsers.add_parser(
|
|
203
|
+
"doctor",
|
|
204
|
+
help="Check installation health",
|
|
205
|
+
description=(
|
|
206
|
+
"Run diagnostic checks on your Footprinter installation.\n"
|
|
207
|
+
"Reports environment, configuration, and dependency status.\n"
|
|
208
|
+
"Diagnostic only — does not modify anything."
|
|
209
|
+
),
|
|
210
|
+
epilog=(
|
|
211
|
+
"examples:\n"
|
|
212
|
+
" fp doctor Run all health checks\n"
|
|
213
|
+
" fp doctor --json Machine-readable output"
|
|
214
|
+
),
|
|
215
|
+
formatter_class=FORMATTER,
|
|
216
|
+
)
|
|
217
|
+
add_json_flag(parser)
|
|
218
|
+
parser.set_defaults(func=_handle)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _handle(args) -> None:
|
|
222
|
+
checks = run_checks()
|
|
223
|
+
|
|
224
|
+
if getattr(args, "json", False):
|
|
225
|
+
output_json([asdict(c) for c in checks])
|
|
226
|
+
else:
|
|
227
|
+
from rich.table import Table
|
|
228
|
+
|
|
229
|
+
table = Table(show_header=False, box=None, pad_edge=False)
|
|
230
|
+
table.add_column("check", style="bold")
|
|
231
|
+
table.add_column("status", width=6)
|
|
232
|
+
table.add_column("message")
|
|
233
|
+
|
|
234
|
+
for c in checks:
|
|
235
|
+
if c.status == "OK":
|
|
236
|
+
status_cell = f"[green]{c.status}[/green]"
|
|
237
|
+
elif c.status == "WARN":
|
|
238
|
+
status_cell = f"[yellow]{c.status}[/yellow]"
|
|
239
|
+
else:
|
|
240
|
+
status_cell = f"[red]{c.status}[/red]"
|
|
241
|
+
table.add_row(c.name, status_cell, c.message)
|
|
242
|
+
|
|
243
|
+
console.print(table)
|
|
244
|
+
|
|
245
|
+
has_fail = any(c.status == "FAIL" for c in checks)
|
|
246
|
+
if has_fail:
|
|
247
|
+
sys.exit(1)
|
|
@@ -275,6 +275,65 @@ def write_config(snippet: dict, config_path: Path = None, dry_run: bool = False)
|
|
|
275
275
|
return True
|
|
276
276
|
|
|
277
277
|
|
|
278
|
+
def unregister_mcp_server(config_path: Path = None, dry_run: bool = False) -> bool:
|
|
279
|
+
"""Remove the footprinter entry from the Claude Desktop MCP config.
|
|
280
|
+
|
|
281
|
+
Mirrors :func:`write_config` — backs up the existing file before mutating.
|
|
282
|
+
Idempotent: missing file or missing entry both return True without error.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
config_path: Override config path (default: auto-detected).
|
|
286
|
+
dry_run: If True, report intent without writing.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
True on success (including no-op cases — missing file, missing
|
|
290
|
+
``mcpServers`` key, or no footprinter entry). False when the
|
|
291
|
+
platform is unsupported (no config path) or the config file
|
|
292
|
+
exists but cannot be parsed as JSON.
|
|
293
|
+
"""
|
|
294
|
+
path = config_path or detect_config_path()
|
|
295
|
+
|
|
296
|
+
if path is None:
|
|
297
|
+
console.print("[yellow]Unsupported platform — cannot detect MCP config path.[/yellow]")
|
|
298
|
+
return False
|
|
299
|
+
|
|
300
|
+
if not path.exists():
|
|
301
|
+
console.print(f" [dim]No MCP config at {path} — nothing to remove.[/dim]")
|
|
302
|
+
return True
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
with open(path, "r") as f:
|
|
306
|
+
existing = json.load(f)
|
|
307
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
308
|
+
console.print(f"[red]Cannot read existing config:[/red] {e}")
|
|
309
|
+
return False
|
|
310
|
+
|
|
311
|
+
# Hand-edited configs may have ``"mcpServers": null`` — coerce to {}.
|
|
312
|
+
servers = existing.get("mcpServers") or {}
|
|
313
|
+
if "footprinter" not in servers:
|
|
314
|
+
console.print(f" [dim]No footprinter entry in {path}.[/dim]")
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
if dry_run:
|
|
318
|
+
console.print(f"[dim]Would remove footprinter from:[/dim] {path}")
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
|
322
|
+
backup = path.with_suffix(f".backup_{timestamp}.json")
|
|
323
|
+
shutil.copy2(path, backup)
|
|
324
|
+
console.print(f" Backed up to [dim]{backup}[/dim]")
|
|
325
|
+
|
|
326
|
+
del servers["footprinter"]
|
|
327
|
+
existing["mcpServers"] = servers
|
|
328
|
+
|
|
329
|
+
with open(path, "w") as f:
|
|
330
|
+
json.dump(existing, f, indent=2)
|
|
331
|
+
f.write("\n")
|
|
332
|
+
|
|
333
|
+
console.print(f" Removed footprinter from [bold]{path}[/bold]")
|
|
334
|
+
return True
|
|
335
|
+
|
|
336
|
+
|
|
278
337
|
def print_client_paths():
|
|
279
338
|
"""Render a table of known MCP clients and their config locations."""
|
|
280
339
|
table = Table(title="MCP Client Config Paths", show_header=True)
|