footprinter-cli 1.0.4__tar.gz → 1.1.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.
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/PKG-INFO +17 -11
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/README.md +16 -10
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/access_stamper.py +44 -22
- footprinter_cli-1.1.0/footprinter/api/__init__.py +19 -0
- footprinter_cli-1.1.0/footprinter/api/__main__.py +5 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/entities.py +0 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/server.py +43 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/bundled/config.example.yaml +27 -13
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/__init__.py +24 -16
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/_common.py +98 -41
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/_policy_helpers.py +345 -170
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/_vectorize_stage.py +49 -9
- footprinter_cli-1.1.0/footprinter/cli/add.py +817 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/delete.py +4 -4
- footprinter_cli-1.1.0/footprinter/cli/diagnostics.py +149 -0
- footprinter_cli-1.1.0/footprinter/cli/doctor.py +624 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/ingest.py +23 -326
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/mcp_setup.py +44 -116
- footprinter_cli-1.1.0/footprinter/cli/permission_cmd.py +800 -0
- footprinter_cli-1.1.0/footprinter/cli/search.py +224 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/setup.py +58 -396
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/status.py +93 -396
- footprinter_cli-1.1.0/footprinter/cli/update.py +886 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/view.py +221 -7
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/browser.py +32 -12
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/chats.py +29 -8
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/clients.py +68 -29
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/emails.py +14 -8
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/files.py +70 -66
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/folders.py +113 -20
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/messages.py +18 -9
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/policies.py +11 -9
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/projects.py +75 -130
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/search.py +44 -31
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/status.py +62 -15
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db_base.py +18 -7
- footprinter_cli-1.1.0/footprinter/ingest/adapters/chat.py +120 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/local_files.py +1 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/local_folders.py +16 -8
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/protocol.py +1 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/chat_indexer.py +34 -87
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/chat_parsers/__init__.py +2 -1
- footprinter_cli-1.1.0/footprinter/ingest/chat_parsers/claude_code_parser.py +165 -0
- footprinter_cli-1.1.0/footprinter/ingest/database.py +73 -0
- footprinter_cli-1.1.0/footprinter/ingest/db/ddl.py +858 -0
- footprinter_cli-1.1.0/footprinter/ingest/db/fts.py +417 -0
- footprinter_cli-1.1.0/footprinter/ingest/db/schema.py +13 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/file_indexer.py +15 -13
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/file_scanner.py +4 -4
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/folder_indexer.py +3 -3
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/orchestrator.py +2 -7
- footprinter_cli-1.1.0/footprinter/ingest/processing.py +526 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/scan_summary.py +1 -1
- footprinter_cli-1.1.0/footprinter/ingest/status.py +133 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/vector_ops.py +132 -67
- footprinter_cli-1.1.0/footprinter/mcp/db.py +72 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/resources/context.py +13 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/resources/discoverability.py +1 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/server.py +2 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/navigation.py +0 -8
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/read.py +15 -9
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/search.py +67 -20
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/paths.py +0 -3
- footprinter_cli-1.1.0/footprinter/permissions.py +292 -0
- footprinter_cli-1.1.0/footprinter/policy_resolver.py +411 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/semantic/chunking.py +18 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/semantic/embeddings.py +1 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/semantic/hybrid_search.py +3 -5
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/semantic/vector_store.py +13 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/access_service.py +22 -17
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/chat_service.py +4 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/client_service.py +46 -19
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/folder_service.py +11 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/ingest_service.py +1 -1
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/project_service.py +23 -36
- footprinter_cli-1.1.0/footprinter/services/search_service.py +445 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/semantic_service.py +10 -10
- footprinter_cli-1.1.0/footprinter/services/status_service.py +333 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/visit_service.py +5 -1
- footprinter_cli-1.1.0/footprinter/utils/sqlite_errors.py +58 -0
- footprinter_cli-1.1.0/footprinter/visibility.py +330 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter_cli.egg-info/PKG-INFO +17 -11
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter_cli.egg-info/SOURCES.txt +18 -12
- footprinter_cli-1.1.0/footprinter_cli.egg-info/entry_points.txt +4 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/pyproject.toml +5 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_access_control_bypasses.py +7 -7
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_access_control_docs.py +44 -6
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_access_recalculate.py +146 -146
- footprinter_cli-1.1.0/tests/test_access_source_provenance.py +263 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_bundled.py +19 -26
- footprinter_cli-1.1.0/tests/test_config_limits.py +186 -0
- footprinter_cli-1.1.0/tests/test_conftest_config.py +25 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_db_base.py +38 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_e2e_install.py +48 -65
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_edit_recalculate.py +16 -16
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_files_surface.py +3 -3
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_inherit_resolution.py +13 -13
- footprinter_cli-1.1.0/tests/test_no_issue_ids.py +61 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_pip_install_e2e.py +4 -6
- footprinter_cli-1.1.0/tests/test_policy_resolver.py +435 -0
- footprinter_cli-1.1.0/tests/test_qa_dispatch.py +149 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_resolver.py +17 -10
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_security_layer.py +91 -88
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_security_permissions.py +25 -25
- footprinter_cli-1.1.0/tests/test_verify_install.py +136 -0
- footprinter_cli-1.0.4/footprinter/api/__init__.py +0 -4
- footprinter_cli-1.0.4/footprinter/bundled/patterns/context_patterns.yaml +0 -18
- footprinter_cli-1.0.4/footprinter/bundled/patterns/extensions.yaml +0 -283
- footprinter_cli-1.0.4/footprinter/bundled/patterns/filename_patterns.yaml +0 -61
- footprinter_cli-1.0.4/footprinter/bundled/patterns/mime_mappings.yaml +0 -68
- footprinter_cli-1.0.4/footprinter/bundled/patterns/salesforce_rules.yaml +0 -84
- footprinter_cli-1.0.4/footprinter/bundled/patterns/security_patterns.yaml +0 -27
- footprinter_cli-1.0.4/footprinter/cli/api_cmd.py +0 -61
- footprinter_cli-1.0.4/footprinter/cli/data.py +0 -879
- footprinter_cli-1.0.4/footprinter/cli/doctor.py +0 -251
- footprinter_cli-1.0.4/footprinter/cli/mcp_cmd.py +0 -469
- footprinter_cli-1.0.4/footprinter/cli/search.py +0 -451
- footprinter_cli-1.0.4/footprinter/cli/upsert.py +0 -1087
- footprinter_cli-1.0.4/footprinter/cli/vectorize.py +0 -215
- footprinter_cli-1.0.4/footprinter/ingest/adapters/chat.py +0 -57
- footprinter_cli-1.0.4/footprinter/ingest/database.py +0 -36
- footprinter_cli-1.0.4/footprinter/ingest/db/schema.py +0 -1048
- footprinter_cli-1.0.4/footprinter/ingest/processing.py +0 -327
- footprinter_cli-1.0.4/footprinter/ingest/status.py +0 -347
- footprinter_cli-1.0.4/footprinter/mcp/db.py +0 -34
- footprinter_cli-1.0.4/footprinter/permissions.py +0 -1160
- footprinter_cli-1.0.4/footprinter/services/search_service.py +0 -161
- footprinter_cli-1.0.4/footprinter/services/status_service.py +0 -18
- footprinter_cli-1.0.4/footprinter/visibility.py +0 -1310
- footprinter_cli-1.0.4/footprinter_cli.egg-info/entry_points.txt +0 -2
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/LICENSE +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/db.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/search.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/semantic.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/api/status.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/bundled/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/__main__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/_prompt.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/connect.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/cli/uninstall.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/connectors/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/connectors/config_utils.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/protocols.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/sql_utils.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/db/uploads.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/browser.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/adapters/ingest.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/browser_indexer.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/chat_parsers/chatgpt_parser.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/chat_parsers/claude_parser.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/content_extractors.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/db/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/db/connector_schema.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/full_content_extractor.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/pipe_runner.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/registry.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/ingest/run_record.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/__main__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/errors.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/resources/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/semantic.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/mcp/tools/status.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/semantic/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/content_service.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/email_service.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/file_service.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/includes.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/services/roles.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/source_registry.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/__init__.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/exceptions.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/extraction.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/hash_utils.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/logging_config.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/mime.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/paths.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/text.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter/utils/time.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter_cli.egg-info/dependency_links.txt +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter_cli.egg-info/requires.txt +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/footprinter_cli.egg-info/top_level.txt +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/setup.cfg +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_build_status_filter.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_e2e_pipeline.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_examples.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_files_rename.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_logging.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_no_project_root.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_package_init.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_paths_no_test_marker.py +0 -0
- {footprinter_cli-1.0.4 → footprinter_cli-1.1.0}/tests/test_prompt_safety.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.1.0
|
|
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
|
|
@@ -59,6 +59,12 @@ Requires-Dist: httpx<1.0,>=0.27.0; extra == "dev"
|
|
|
59
59
|
|
|
60
60
|
**A local context layer for your files, browser history, chats, and email — searchable, user-owned, and served to AI agents through [MCP](https://modelcontextprotocol.io/).**
|
|
61
61
|
|
|
62
|
+
> ⚠️ **Install with `pipx`, not `pip`.** `pipx` puts the `fp` command on your PATH automatically; bare `pip` often doesn't — which leaves you with `fp: command not found` even though the install succeeded.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pipx install footprinter-cli
|
|
66
|
+
```
|
|
67
|
+
|
|
62
68
|
Your work lives across filesystems, browsers, inboxes, chat histories, and other tools. 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.
|
|
63
69
|
|
|
64
70
|
## Install
|
|
@@ -75,7 +81,7 @@ Or install with **pipx** directly:
|
|
|
75
81
|
pipx install footprinter-cli
|
|
76
82
|
```
|
|
77
83
|
|
|
78
|
-
Either method
|
|
84
|
+
Either method installs three commands: `fp` (the CLI and indexing pipeline), `fp-mcp` (the MCP server for AI agents), and `fp-api` (the HTTP API). Optional extras add more:
|
|
79
85
|
|
|
80
86
|
| Extra | What it adds |
|
|
81
87
|
|-------|-------------|
|
|
@@ -100,6 +106,8 @@ To install with extras: use the [full install script](https://raw.githubusercont
|
|
|
100
106
|
|
|
101
107
|
**ChromaDB telemetry:** Footprinter sets `anonymized_telemetry=False`. ChromaDB also removed product telemetry in v1.5.4. See [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss).
|
|
102
108
|
|
|
109
|
+
**Apple Silicon (Rosetta):** If `fp doctor` warns about x86_64 Python on arm64 hardware, recreate the venv with a native interpreter: `pipx reinstall footprinter-cli --python /opt/homebrew/bin/python3`. This avoids compatibility issues with native-extension dependencies.
|
|
110
|
+
|
|
103
111
|
</details>
|
|
104
112
|
|
|
105
113
|
### Uninstall
|
|
@@ -160,14 +168,12 @@ All commands use the `fp` entry point.
|
|
|
160
168
|
| `fp status` | System health and data counts |
|
|
161
169
|
| `fp search` | Search across all indexed sources |
|
|
162
170
|
| `fp connect` | Manage optional integrations |
|
|
163
|
-
| `fp
|
|
164
|
-
| `fp api` | Start the HTTP API server |
|
|
171
|
+
| `fp permission` | Manage access policies (visibility, permissions) |
|
|
165
172
|
| `fp view` | Browse indexed data (files, folders, projects, clients, chats, emails, visits) |
|
|
166
|
-
| `fp
|
|
167
|
-
| `fp
|
|
173
|
+
| `fp add` | Create new entity records or import from CSV |
|
|
174
|
+
| `fp update` | Update existing records by ID — status, assignments, metadata |
|
|
168
175
|
| `fp delete` | Hard-delete a super entity (irreversible) |
|
|
169
|
-
| `fp
|
|
170
|
-
| `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
|
|
176
|
+
| `fp doctor` | Post-install health check (Python version, platform, FDA, MCP wiring) |
|
|
171
177
|
| `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
|
|
172
178
|
|
|
173
179
|
Run `fp <command> --help` for full usage.
|
|
@@ -176,7 +182,7 @@ Run `fp <command> --help` for full usage.
|
|
|
176
182
|
|
|
177
183
|
Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
|
|
178
184
|
|
|
179
|
-
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 +
|
|
185
|
+
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 + access) — you decide what agents can see.
|
|
180
186
|
|
|
181
187
|
## Documentation
|
|
182
188
|
|
|
@@ -184,7 +190,7 @@ Sources are scanned into SQLite with bidirectional links connecting local files
|
|
|
184
190
|
- [Data Model](https://github.com/harringjohn/footprinter-cli/blob/main/reference/data-model.md) — database schema
|
|
185
191
|
- [Pipeline](https://github.com/harringjohn/footprinter-cli/blob/main/reference/pipeline.md) — indexing stages and configuration
|
|
186
192
|
- [Content Storage](https://github.com/harringjohn/footprinter-cli/blob/main/reference/content-storage.md) — metadata vs. snippet vs. full-content tiers
|
|
187
|
-
- [Access Control](https://github.com/harringjohn/footprinter-cli/blob/main/reference/
|
|
193
|
+
- [Permission Policies and Access Control](https://github.com/harringjohn/footprinter-cli/blob/main/reference/permission-policies-and-access-control.md) — permission policies and access control
|
|
188
194
|
|
|
189
195
|
## Contributing
|
|
190
196
|
|
|
@@ -194,7 +200,7 @@ Bug fixes, documentation, and tests welcome. For new features or architectural c
|
|
|
194
200
|
|
|
195
201
|
```bash
|
|
196
202
|
git clone https://github.com/harringjohn/footprinter-cli.git
|
|
197
|
-
cd footprinter
|
|
203
|
+
cd footprinter-cli
|
|
198
204
|
python3 -m venv venv
|
|
199
205
|
./venv/bin/pip install -e ".[dev]"
|
|
200
206
|
```
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
**A local context layer for your files, browser history, chats, and email — searchable, user-owned, and served to AI agents through [MCP](https://modelcontextprotocol.io/).**
|
|
7
7
|
|
|
8
|
+
> ⚠️ **Install with `pipx`, not `pip`.** `pipx` puts the `fp` command on your PATH automatically; bare `pip` often doesn't — which leaves you with `fp: command not found` even though the install succeeded.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pipx install footprinter-cli
|
|
12
|
+
```
|
|
13
|
+
|
|
8
14
|
Your work lives across filesystems, browsers, inboxes, chat histories, and other tools. 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.
|
|
9
15
|
|
|
10
16
|
## Install
|
|
@@ -21,7 +27,7 @@ Or install with **pipx** directly:
|
|
|
21
27
|
pipx install footprinter-cli
|
|
22
28
|
```
|
|
23
29
|
|
|
24
|
-
Either method
|
|
30
|
+
Either method installs three commands: `fp` (the CLI and indexing pipeline), `fp-mcp` (the MCP server for AI agents), and `fp-api` (the HTTP API). Optional extras add more:
|
|
25
31
|
|
|
26
32
|
| Extra | What it adds |
|
|
27
33
|
|-------|-------------|
|
|
@@ -46,6 +52,8 @@ To install with extras: use the [full install script](https://raw.githubusercont
|
|
|
46
52
|
|
|
47
53
|
**ChromaDB telemetry:** Footprinter sets `anonymized_telemetry=False`. ChromaDB also removed product telemetry in v1.5.4. See [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss).
|
|
48
54
|
|
|
55
|
+
**Apple Silicon (Rosetta):** If `fp doctor` warns about x86_64 Python on arm64 hardware, recreate the venv with a native interpreter: `pipx reinstall footprinter-cli --python /opt/homebrew/bin/python3`. This avoids compatibility issues with native-extension dependencies.
|
|
56
|
+
|
|
49
57
|
</details>
|
|
50
58
|
|
|
51
59
|
### Uninstall
|
|
@@ -106,14 +114,12 @@ All commands use the `fp` entry point.
|
|
|
106
114
|
| `fp status` | System health and data counts |
|
|
107
115
|
| `fp search` | Search across all indexed sources |
|
|
108
116
|
| `fp connect` | Manage optional integrations |
|
|
109
|
-
| `fp
|
|
110
|
-
| `fp api` | Start the HTTP API server |
|
|
117
|
+
| `fp permission` | Manage access policies (visibility, permissions) |
|
|
111
118
|
| `fp view` | Browse indexed data (files, folders, projects, clients, chats, emails, visits) |
|
|
112
|
-
| `fp
|
|
113
|
-
| `fp
|
|
119
|
+
| `fp add` | Create new entity records or import from CSV |
|
|
120
|
+
| `fp update` | Update existing records by ID — status, assignments, metadata |
|
|
114
121
|
| `fp delete` | Hard-delete a super entity (irreversible) |
|
|
115
|
-
| `fp
|
|
116
|
-
| `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
|
|
122
|
+
| `fp doctor` | Post-install health check (Python version, platform, FDA, MCP wiring) |
|
|
117
123
|
| `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
|
|
118
124
|
|
|
119
125
|
Run `fp <command> --help` for full usage.
|
|
@@ -122,7 +128,7 @@ Run `fp <command> --help` for full usage.
|
|
|
122
128
|
|
|
123
129
|
Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
|
|
124
130
|
|
|
125
|
-
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 +
|
|
131
|
+
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 + access) — you decide what agents can see.
|
|
126
132
|
|
|
127
133
|
## Documentation
|
|
128
134
|
|
|
@@ -130,7 +136,7 @@ Sources are scanned into SQLite with bidirectional links connecting local files
|
|
|
130
136
|
- [Data Model](https://github.com/harringjohn/footprinter-cli/blob/main/reference/data-model.md) — database schema
|
|
131
137
|
- [Pipeline](https://github.com/harringjohn/footprinter-cli/blob/main/reference/pipeline.md) — indexing stages and configuration
|
|
132
138
|
- [Content Storage](https://github.com/harringjohn/footprinter-cli/blob/main/reference/content-storage.md) — metadata vs. snippet vs. full-content tiers
|
|
133
|
-
- [Access Control](https://github.com/harringjohn/footprinter-cli/blob/main/reference/
|
|
139
|
+
- [Permission Policies and Access Control](https://github.com/harringjohn/footprinter-cli/blob/main/reference/permission-policies-and-access-control.md) — permission policies and access control
|
|
134
140
|
|
|
135
141
|
## Contributing
|
|
136
142
|
|
|
@@ -140,7 +146,7 @@ Bug fixes, documentation, and tests welcome. For new features or architectural c
|
|
|
140
146
|
|
|
141
147
|
```bash
|
|
142
148
|
git clone https://github.com/harringjohn/footprinter-cli.git
|
|
143
|
-
cd footprinter
|
|
149
|
+
cd footprinter-cli
|
|
144
150
|
python3 -m venv venv
|
|
145
151
|
./venv/bin/pip install -e ".[dev]"
|
|
146
152
|
```
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Maps a policy scope (e.g. "global", "project:3", "folder:~/Work/") to affected
|
|
4
4
|
entity rows, calls the existing batch resolve functions, and writes resolved
|
|
5
|
-
values back to
|
|
5
|
+
values back to visibility / access columns.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
@@ -45,8 +45,8 @@ def _is_inherit_source(source: str) -> bool:
|
|
|
45
45
|
# ---------------------------------------------------------------------------
|
|
46
46
|
# Each entry describes an entity type's table and capabilities.
|
|
47
47
|
# table: SQL table name
|
|
48
|
-
# has_visibility: has
|
|
49
|
-
# has_permissions: has
|
|
48
|
+
# has_visibility: has visibility column
|
|
49
|
+
# has_permissions: has access column
|
|
50
50
|
# has_status: has status column (filter WHERE status = 'listed')
|
|
51
51
|
# has_project_id: has project_id FK
|
|
52
52
|
# has_client_id: has client_id FK
|
|
@@ -102,7 +102,7 @@ ENTITY_META: dict[str, dict[str, Any]] = {
|
|
|
102
102
|
"has_project_id": False,
|
|
103
103
|
"has_client_id": True,
|
|
104
104
|
"has_account": False,
|
|
105
|
-
"path_column":
|
|
105
|
+
"path_column": None,
|
|
106
106
|
},
|
|
107
107
|
"client": {
|
|
108
108
|
"table": "clients",
|
|
@@ -305,31 +305,34 @@ def _get_ids_for_scope(conn: sqlite3.Connection, scope: str) -> dict[str, list[i
|
|
|
305
305
|
|
|
306
306
|
|
|
307
307
|
def _write_back_visibility(conn: sqlite3.Connection, entity_type: str, results: dict[int, tuple]) -> None:
|
|
308
|
-
"""Batch UPDATE
|
|
308
|
+
"""Batch UPDATE visibility and visibility_source from resolve results.
|
|
309
309
|
|
|
310
310
|
Entities whose visibility comes from the global policy or the hardcoded
|
|
311
|
-
baseline are written as ``'inherit'``
|
|
312
|
-
|
|
311
|
+
baseline are written as ``'inherit'`` with ``visibility_source = NULL``.
|
|
312
|
+
Entities with a specific policy get the resolved value and source scope.
|
|
313
313
|
"""
|
|
314
314
|
table = ENTITY_META[entity_type]["table"]
|
|
315
315
|
conn.executemany(
|
|
316
|
-
f"UPDATE {table} SET
|
|
317
|
-
[
|
|
316
|
+
f"UPDATE {table} SET visibility = ?, visibility_source = ? WHERE id = ?",
|
|
317
|
+
[
|
|
318
|
+
("inherit", None, eid) if _is_inherit_source(source) else (state, source, eid)
|
|
319
|
+
for eid, (state, source) in results.items()
|
|
320
|
+
],
|
|
318
321
|
)
|
|
319
322
|
|
|
320
323
|
|
|
321
324
|
def _write_back_permissions(conn: sqlite3.Connection, entity_type: str, results: dict[int, tuple]) -> None:
|
|
322
|
-
"""Batch UPDATE
|
|
325
|
+
"""Batch UPDATE access and access_source from resolve results.
|
|
323
326
|
|
|
324
327
|
Entities whose permission comes from the global policy or the hardcoded
|
|
325
|
-
baseline are written as ``'inherit'``
|
|
326
|
-
|
|
328
|
+
baseline are written as ``'inherit'`` with ``access_source = NULL``.
|
|
329
|
+
Entities with a specific policy get the resolved value and source scope.
|
|
327
330
|
"""
|
|
328
331
|
table = ENTITY_META[entity_type]["table"]
|
|
329
332
|
conn.executemany(
|
|
330
|
-
f"UPDATE {table} SET
|
|
333
|
+
f"UPDATE {table} SET access = ?, access_source = ? WHERE id = ?",
|
|
331
334
|
[
|
|
332
|
-
("inherit" if _is_inherit_source(source) else ("allow" if allowed else "deny"
|
|
335
|
+
("inherit", None, eid) if _is_inherit_source(source) else ("allow" if allowed else "deny", source, eid)
|
|
333
336
|
for eid, (allowed, source) in results.items()
|
|
334
337
|
],
|
|
335
338
|
)
|
|
@@ -350,18 +353,26 @@ def count_affected_entities(conn: sqlite3.Connection, scope: str) -> dict[str, i
|
|
|
350
353
|
return {etype: len(ids) for etype, ids in _get_ids_for_scope(conn, scope).items() if ids}
|
|
351
354
|
|
|
352
355
|
|
|
353
|
-
def stamp_entities(
|
|
356
|
+
def stamp_entities(
|
|
357
|
+
conn: sqlite3.Connection,
|
|
358
|
+
ids_by_type: dict[str, list[int]],
|
|
359
|
+
*,
|
|
360
|
+
commit: bool = True,
|
|
361
|
+
) -> dict[str, int]:
|
|
354
362
|
"""Resolve and write visibility + permissions for the given entity IDs.
|
|
355
363
|
|
|
356
364
|
Used by ``recalculate_access`` (full scope resolution) and the incremental
|
|
357
365
|
pipeline path in ``processing.run_access_resolution``. The batched variant
|
|
358
366
|
(``recalculate_access_batched``) uses its own loop for per-chunk commits.
|
|
359
367
|
|
|
360
|
-
|
|
368
|
+
Commits before returning by default, even when *ids_by_type* is empty.
|
|
369
|
+
When *commit* is False the caller is responsible for committing the
|
|
370
|
+
transaction.
|
|
361
371
|
|
|
362
372
|
Args:
|
|
363
373
|
conn: SQLite connection with row_factory = sqlite3.Row
|
|
364
374
|
ids_by_type: Mapping of entity type to list of row IDs to stamp.
|
|
375
|
+
commit: If False, skip the final ``conn.commit()``.
|
|
365
376
|
|
|
366
377
|
Returns:
|
|
367
378
|
Dict mapping entity type to count of rows stamped.
|
|
@@ -384,22 +395,26 @@ def stamp_entities(conn: sqlite3.Connection, ids_by_type: dict[str, list[int]])
|
|
|
384
395
|
|
|
385
396
|
stats[entity_type] = len(ids)
|
|
386
397
|
|
|
387
|
-
|
|
398
|
+
if commit:
|
|
399
|
+
conn.commit()
|
|
388
400
|
return stats
|
|
389
401
|
|
|
390
402
|
|
|
391
|
-
def recalculate_access(
|
|
403
|
+
def recalculate_access(
|
|
404
|
+
conn: sqlite3.Connection, scope: str, *, commit: bool = True,
|
|
405
|
+
) -> dict[str, int]:
|
|
392
406
|
"""Recalculate visibility and permissions for all entities affected by *scope*.
|
|
393
407
|
|
|
394
408
|
Args:
|
|
395
409
|
conn: SQLite connection with row_factory = sqlite3.Row
|
|
396
410
|
scope: Policy scope string (e.g. "global", "project:3", "folder:~/Work/")
|
|
411
|
+
commit: If False, skip committing — caller manages the transaction.
|
|
397
412
|
|
|
398
413
|
Returns:
|
|
399
414
|
Dict mapping entity type to count of rows updated.
|
|
400
415
|
"""
|
|
401
416
|
ids_by_type = _get_ids_for_scope(conn, scope)
|
|
402
|
-
return stamp_entities(conn, ids_by_type)
|
|
417
|
+
return stamp_entities(conn, ids_by_type, commit=commit)
|
|
403
418
|
|
|
404
419
|
|
|
405
420
|
def recalculate_access_batched(
|
|
@@ -408,18 +423,24 @@ def recalculate_access_batched(
|
|
|
408
423
|
*,
|
|
409
424
|
batch_size: int = 5000,
|
|
410
425
|
on_batch: Callable[[int], None] | None = None,
|
|
426
|
+
commit: bool = True,
|
|
411
427
|
) -> dict[str, int]:
|
|
412
428
|
"""Recalculate visibility and permissions in batches with progress callback.
|
|
413
429
|
|
|
414
430
|
Same semantics as ``recalculate_access()`` but commits after each batch
|
|
415
|
-
and calls *on_batch* with the count of entities
|
|
416
|
-
Designed for large scopes where a progress bar is
|
|
431
|
+
(when *commit* is True) and calls *on_batch* with the count of entities
|
|
432
|
+
processed per chunk. Designed for large scopes where a progress bar is
|
|
433
|
+
needed.
|
|
417
434
|
|
|
418
435
|
Args:
|
|
419
436
|
conn: SQLite connection with row_factory = sqlite3.Row
|
|
420
437
|
scope: Policy scope string (e.g. "global", "folder:~/Work/")
|
|
421
438
|
batch_size: Number of entity IDs per chunk (default 5000)
|
|
422
439
|
on_batch: Optional callback receiving the count processed per chunk
|
|
440
|
+
commit: If False, skip per-batch commits — all batches accumulate
|
|
441
|
+
in the caller's transaction. This trades incremental commit
|
|
442
|
+
boundaries for atomicity; the caller is responsible for the
|
|
443
|
+
final commit.
|
|
423
444
|
|
|
424
445
|
Returns:
|
|
425
446
|
Dict mapping entity type to total count of rows updated.
|
|
@@ -443,7 +464,8 @@ def recalculate_access_batched(
|
|
|
443
464
|
perm_results = batch_resolve_permissions(conn, entity_type, chunk)
|
|
444
465
|
_write_back_permissions(conn, entity_type, perm_results)
|
|
445
466
|
|
|
446
|
-
|
|
467
|
+
if commit:
|
|
468
|
+
conn.commit()
|
|
447
469
|
|
|
448
470
|
if on_batch is not None:
|
|
449
471
|
on_batch(len(chunk))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Footprinter HTTP API — FastAPI routers calling the service layer."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
_logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _get_api_max_limit() -> int:
|
|
9
|
+
try:
|
|
10
|
+
from footprinter.source_registry import get_config
|
|
11
|
+
|
|
12
|
+
return get_config().get("limits", {}).get("api_max_limit", 200)
|
|
13
|
+
except Exception:
|
|
14
|
+
_logger.debug("Config unavailable for api_max_limit, using default 200")
|
|
15
|
+
return 200
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
MAX_LIMIT = _get_api_max_limit()
|
|
19
|
+
"""Upper bound for `limit` query params on HTTP list/search endpoints."""
|
|
@@ -137,7 +137,6 @@ def list_projects(
|
|
|
137
137
|
include: Optional[str] = Query(None, description="Comma-separated includes"),
|
|
138
138
|
status: Optional[str] = Query(None, description="Comma-separated status filter"),
|
|
139
139
|
client: Optional[str] = None,
|
|
140
|
-
project_type: Optional[str] = None,
|
|
141
140
|
limit: int = Query(50, ge=1, le=MAX_LIMIT),
|
|
142
141
|
page: int = 1,
|
|
143
142
|
):
|
|
@@ -149,7 +148,6 @@ def list_projects(
|
|
|
149
148
|
include=include_list,
|
|
150
149
|
status=status_list,
|
|
151
150
|
client=client,
|
|
152
|
-
project_type=project_type,
|
|
153
151
|
limit=limit,
|
|
154
152
|
page=page,
|
|
155
153
|
)
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"""Footprinter HTTP API — FastAPI app factory and server entry point."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
|
|
3
8
|
from fastapi import FastAPI, Request
|
|
4
9
|
from fastapi.responses import JSONResponse
|
|
5
10
|
|
|
6
11
|
from footprinter.utils.exceptions import DatabaseNotInitializedError
|
|
7
12
|
|
|
13
|
+
_LOOPBACK_HOSTS = {"127.0.0.1", "localhost", "::1"}
|
|
14
|
+
|
|
8
15
|
|
|
9
16
|
def create_app() -> "FastAPI":
|
|
10
17
|
"""Create and configure the FastAPI application.
|
|
@@ -62,5 +69,40 @@ def main(host: str = "127.0.0.1", port: int = 8000) -> None:
|
|
|
62
69
|
uvicorn.run(app, host=host, port=port)
|
|
63
70
|
|
|
64
71
|
|
|
72
|
+
def cli(argv: list[str] | None = None) -> None:
|
|
73
|
+
"""Console_script entry point — parse CLI args, validate host, start server."""
|
|
74
|
+
parser = argparse.ArgumentParser(
|
|
75
|
+
prog="fp-api",
|
|
76
|
+
description="Start the Footprinter HTTP API server.",
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument("--host", default="127.0.0.1", help="Host to bind (default: 127.0.0.1)")
|
|
79
|
+
parser.add_argument("--port", type=int, default=8000, help="Port to bind (default: 8000)")
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--allow-insecure-bind",
|
|
82
|
+
action="store_true",
|
|
83
|
+
help="Allow binding to non-loopback interfaces (no authentication!).",
|
|
84
|
+
)
|
|
85
|
+
args = parser.parse_args(argv)
|
|
86
|
+
|
|
87
|
+
if args.host not in _LOOPBACK_HOSTS:
|
|
88
|
+
if not args.allow_insecure_bind:
|
|
89
|
+
print(
|
|
90
|
+
f"error: refusing to bind to non-loopback host {args.host!r}.\n"
|
|
91
|
+
"The Footprinter HTTP API has no authentication; binding outside "
|
|
92
|
+
"loopback exposes indexed data to anyone on the network.\n"
|
|
93
|
+
"Pass --allow-insecure-bind to override.",
|
|
94
|
+
file=sys.stderr,
|
|
95
|
+
)
|
|
96
|
+
raise SystemExit(2)
|
|
97
|
+
print(
|
|
98
|
+
f"WARNING: binding to {args.host} — the HTTP API has no authentication. "
|
|
99
|
+
"Anyone reachable on this network can read indexed files, emails, "
|
|
100
|
+
"chats, and browser history.",
|
|
101
|
+
file=sys.stderr,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
main(host=args.host, port=args.port)
|
|
105
|
+
|
|
106
|
+
|
|
65
107
|
if __name__ == "__main__":
|
|
66
|
-
|
|
108
|
+
cli()
|
|
@@ -33,7 +33,7 @@ exclusions:
|
|
|
33
33
|
- ".*/\\.venv/.*" # Python virtualenvs (hidden)
|
|
34
34
|
- ".*/site-packages/.*" # Python packages
|
|
35
35
|
- ".*\\.pyc$" # Python compiled files
|
|
36
|
-
- ".*/\\.vscode
|
|
36
|
+
- ".*/\\.vscode/.*" # VS Code config and extensions
|
|
37
37
|
- ".*/\\.npm/.*" # npm cache
|
|
38
38
|
- ".*/\\.nvm/.*" # Node version manager
|
|
39
39
|
- ".*/\\.cache/.*" # Generic caches
|
|
@@ -44,6 +44,13 @@ exclusions:
|
|
|
44
44
|
- ".*/\\.browser_state/.*" # Playwright/Puppeteer browser state
|
|
45
45
|
- ".*/\\.context/.*" # IDE/agent context directories
|
|
46
46
|
- ".*/\\.ai-dev/.*" # AI dev tool scratch dirs
|
|
47
|
+
# Build output and tool config dot-folders (no archival value)
|
|
48
|
+
- ".*/\\.next/.*" # Next.js build output
|
|
49
|
+
- ".*/\\.husky/.*" # Git hooks manager
|
|
50
|
+
- ".*/\\.astro/.*" # Astro build cache
|
|
51
|
+
- ".*/\\.githooks/.*" # Custom git hooks
|
|
52
|
+
- ".*/\\.aesthetic/.*" # Aesthetic tool config
|
|
53
|
+
- ".*/\\.users/.*" # IDE user preferences
|
|
47
54
|
# Home-level Claude dirs only (keep .claude within Work/Personal)
|
|
48
55
|
- "^~/\\.claude/.*" # Home-level .claude (includes session-env snapshots)
|
|
49
56
|
- "^~/\\.claude-worktrees/.*" # Home-level .claude-worktrees
|
|
@@ -81,9 +88,6 @@ indexing:
|
|
|
81
88
|
max_file_size_mb: 50 # MB; 0 = no size limit. 50 is generous for prose/docs.
|
|
82
89
|
lookback_days: 14 # Browser history window (days back to index)
|
|
83
90
|
content_snippets: false # Extract file/email content previews for keyword search
|
|
84
|
-
# `fp ingest --preview` (FPR-1723) — pre-scan summary tuning
|
|
85
|
-
preview_top_n: 10 # rows shown for top files / top directories
|
|
86
|
-
preview_size_threshold_mb: 50 # files at or above this size are flagged as outliers
|
|
87
91
|
|
|
88
92
|
# Semantic search — stores content as embeddings in a local ChromaDB database
|
|
89
93
|
# Enables finding files and chats by meaning, not just keywords
|
|
@@ -91,6 +95,10 @@ indexing:
|
|
|
91
95
|
semantic:
|
|
92
96
|
file_vectorization: false
|
|
93
97
|
chat_vectorization: false
|
|
98
|
+
# File statuses eligible for vectorization. Default: [listed].
|
|
99
|
+
# Add 'unlisted' to also embed hidden/dot-files.
|
|
100
|
+
# vectorize_statuses:
|
|
101
|
+
# - listed
|
|
94
102
|
|
|
95
103
|
# Vectorization — controls what gets embedded for semantic search
|
|
96
104
|
# Requires semantic.file_vectorization: true to take effect for files
|
|
@@ -140,6 +148,21 @@ vectorization:
|
|
|
140
148
|
- "**/.github/**" # GitHub workflow files (FTS-only)
|
|
141
149
|
- "**/.ai-dev/**" # AI dev tool scratch dirs
|
|
142
150
|
|
|
151
|
+
# Operational limits — tune for your data volume
|
|
152
|
+
# All values have sensible defaults; omit the section entirely to use them.
|
|
153
|
+
limits:
|
|
154
|
+
# Zip upload safety checks (chat imports via fp upload)
|
|
155
|
+
zip:
|
|
156
|
+
max_decompressed_size_mb: 2048 # 2 GB; raise for very large exports
|
|
157
|
+
max_entries: 10000 # Maximum files in a zip archive
|
|
158
|
+
max_compression_ratio: 100 # Ratio ceiling (100:1) for zip bomb detection
|
|
159
|
+
# HTTP API pagination cap — requires server restart to take effect
|
|
160
|
+
api_max_limit: 200
|
|
161
|
+
# MCP search result cap per source (protocol payload limit)
|
|
162
|
+
mcp_search_limit_cap: 200
|
|
163
|
+
# Embedding batch size for vector rebuild
|
|
164
|
+
vector_batch_size: 100
|
|
165
|
+
|
|
143
166
|
# Source registry seeds — loaded into the sources table on init
|
|
144
167
|
# Connector sources added by: fp connect install <name>
|
|
145
168
|
source_seeds:
|
|
@@ -163,12 +186,3 @@ source_seeds:
|
|
|
163
186
|
account: null
|
|
164
187
|
label: "Chat"
|
|
165
188
|
icon: message
|
|
166
|
-
|
|
167
|
-
# Display labels for the group/project hierarchy
|
|
168
|
-
# Customize these to match your organization's terminology
|
|
169
|
-
domain:
|
|
170
|
-
labels:
|
|
171
|
-
group_singular: "Client"
|
|
172
|
-
group_plural: "Clients"
|
|
173
|
-
project_singular: "Project"
|
|
174
|
-
project_plural: "Projects"
|
|
@@ -39,7 +39,6 @@ def main(argv=None) -> None:
|
|
|
39
39
|
epilog=(
|
|
40
40
|
"getting started:\n"
|
|
41
41
|
" fp setup Run the configuration wizard\n"
|
|
42
|
-
" fp setup --check Validate existing configuration\n"
|
|
43
42
|
" fp connect list Show available data source connectors\n"
|
|
44
43
|
"\n"
|
|
45
44
|
"data commands:\n"
|
|
@@ -57,13 +56,23 @@ def main(argv=None) -> None:
|
|
|
57
56
|
" fp view emails List indexed emails\n"
|
|
58
57
|
" fp view visits List browser history\n"
|
|
59
58
|
"\n"
|
|
60
|
-
"
|
|
61
|
-
" fp
|
|
62
|
-
" fp
|
|
63
|
-
" fp
|
|
59
|
+
"manage records:\n"
|
|
60
|
+
" fp add client --name Acme Create a new entity record\n"
|
|
61
|
+
" fp update client 5 --name X Update an existing record by ID\n"
|
|
62
|
+
" fp update file 42 --project-id 3 Assign a file to a project\n"
|
|
63
|
+
" fp update files data.csv Bulk update from CSV\n"
|
|
64
|
+
"\n"
|
|
65
|
+
"access control:\n"
|
|
66
|
+
" fp permission list Show all configured access policies\n"
|
|
67
|
+
" fp permission set Set visibility and/or access for a scope\n"
|
|
68
|
+
" fp permission check Check access resolution for a target\n"
|
|
69
|
+
" fp permission reset Remove policy (fall back to inheritance)\n"
|
|
70
|
+
" fp permission recalculate Re-resolve access stamps from the policy chain\n"
|
|
64
71
|
"\n"
|
|
65
72
|
"diagnostics:\n"
|
|
66
73
|
" fp doctor Check installation health\n"
|
|
74
|
+
" fp doctor search Rebuild FTS search indexes\n"
|
|
75
|
+
" fp doctor semantic Rebuild vector store\n"
|
|
67
76
|
"\n"
|
|
68
77
|
"cleanup:\n"
|
|
69
78
|
" fp uninstall Remove Footprinter (MCP entry, data, package)\n"
|
|
@@ -81,35 +90,31 @@ def main(argv=None) -> None:
|
|
|
81
90
|
subparsers.required = False
|
|
82
91
|
|
|
83
92
|
from footprinter.cli import (
|
|
84
|
-
|
|
93
|
+
add,
|
|
85
94
|
connect,
|
|
86
|
-
data,
|
|
87
95
|
delete,
|
|
88
96
|
doctor,
|
|
89
97
|
ingest,
|
|
90
|
-
|
|
98
|
+
permission_cmd,
|
|
91
99
|
search,
|
|
92
100
|
setup,
|
|
93
101
|
status,
|
|
94
102
|
uninstall,
|
|
95
|
-
|
|
96
|
-
vectorize,
|
|
103
|
+
update,
|
|
97
104
|
view,
|
|
98
105
|
)
|
|
99
106
|
|
|
100
107
|
for mod in [
|
|
108
|
+
add,
|
|
101
109
|
ingest,
|
|
102
|
-
|
|
103
|
-
api_cmd,
|
|
110
|
+
permission_cmd,
|
|
104
111
|
status,
|
|
105
112
|
search,
|
|
106
113
|
setup,
|
|
107
114
|
connect,
|
|
108
115
|
view,
|
|
109
|
-
|
|
110
|
-
data,
|
|
116
|
+
update,
|
|
111
117
|
delete,
|
|
112
|
-
vectorize,
|
|
113
118
|
uninstall,
|
|
114
119
|
doctor,
|
|
115
120
|
]:
|
|
@@ -128,7 +133,10 @@ def main(argv=None) -> None:
|
|
|
128
133
|
from footprinter.cli._prompt import PromptCancelled
|
|
129
134
|
|
|
130
135
|
try:
|
|
131
|
-
|
|
136
|
+
# A handler may signal its exit status by returning an int; None means
|
|
137
|
+
# success. This complements the raise SystemExit(n) pattern used
|
|
138
|
+
# elsewhere — those bubble out before the wrapper here ever runs.
|
|
139
|
+
raise SystemExit(args.func(args) or 0)
|
|
132
140
|
except _ConfigError as e:
|
|
133
141
|
print(str(e), file=_sys.stderr)
|
|
134
142
|
_sys.exit(1)
|