footprinter-cli 1.0.3__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. {footprinter_cli-1.0.3/footprinter_cli.egg-info → footprinter_cli-1.0.4}/PKG-INFO +28 -63
  2. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/README.md +25 -62
  3. footprinter_cli-1.0.3/footprinter/access.py → footprinter_cli-1.0.4/footprinter/access_stamper.py +63 -21
  4. footprinter_cli-1.0.4/footprinter/api/db.py +38 -0
  5. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/server.py +1 -1
  6. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/config.example.yaml +3 -3
  7. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/__init__.py +6 -6
  8. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/_common.py +9 -2
  9. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/_policy_helpers.py +3 -12
  10. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/_prompt.py +1 -1
  11. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/_vectorize_stage.py +1 -1
  12. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/connect.py +3 -3
  13. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/ingest.py +4 -4
  14. footprinter_cli-1.0.4/footprinter/cli/mcp_cmd.py +469 -0
  15. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/search.py +61 -3
  16. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/setup.py +50 -54
  17. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/status.py +84 -0
  18. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/upsert.py +309 -14
  19. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/connectors/__init__.py +2 -0
  20. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/__init__.py +8 -1
  21. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/browser.py +4 -41
  22. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/chats.py +23 -59
  23. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/emails.py +4 -41
  24. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/files.py +18 -43
  25. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/folders.py +46 -48
  26. footprinter_cli-1.0.4/footprinter/db/protocols.py +16 -0
  27. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/search.py +12 -7
  28. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/sql_utils.py +64 -0
  29. footprinter_cli-1.0.3/footprinter/mcp/db.py → footprinter_cli-1.0.4/footprinter/db_base.py +10 -25
  30. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/browser.py +4 -4
  31. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/browser_indexer.py +1 -1
  32. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/chat_indexer.py +0 -2
  33. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/db/schema.py +4 -36
  34. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/file_indexer.py +8 -2
  35. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/file_scanner.py +12 -2
  36. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/full_content_extractor.py +24 -39
  37. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/orchestrator.py +6 -3
  38. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/pipe_runner.py +0 -7
  39. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/processing.py +1 -1
  40. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/registry.py +2 -2
  41. footprinter_cli-1.0.3/footprinter/ingest/cli.py → footprinter_cli-1.0.4/footprinter/ingest/vector_ops.py +3 -4
  42. footprinter_cli-1.0.4/footprinter/mcp/db.py +34 -0
  43. footprinter_cli-1.0.4/footprinter/mcp/resources/__init__.py +1 -0
  44. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/navigation.py +3 -10
  45. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/read.py +1 -1
  46. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/search.py +1 -9
  47. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/permissions.py +3 -3
  48. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/semantic/chunking.py +27 -4
  49. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/semantic/hybrid_search.py +3 -8
  50. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/semantic/vector_store.py +25 -8
  51. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/__init__.py +7 -0
  52. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/access_service.py +20 -6
  53. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/content_service.py +15 -5
  54. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/ingest_service.py +3 -5
  55. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/search_service.py +7 -41
  56. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/source_registry.py +1 -1
  57. footprinter_cli-1.0.4/footprinter/utils/exceptions.py +5 -0
  58. footprinter_cli-1.0.4/footprinter/utils/paths.py +15 -0
  59. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/visibility.py +43 -5
  60. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4/footprinter_cli.egg-info}/PKG-INFO +28 -63
  61. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter_cli.egg-info/SOURCES.txt +9 -8
  62. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/pyproject.toml +3 -1
  63. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_access_control_bypasses.py +6 -6
  64. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_access_control_docs.py +2 -2
  65. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_access_recalculate.py +329 -50
  66. footprinter_cli-1.0.4/tests/test_db_base.py +96 -0
  67. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_edit_recalculate.py +2 -2
  68. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_security_layer.py +0 -1
  69. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_security_permissions.py +2 -2
  70. footprinter_cli-1.0.3/footprinter/api/db.py +0 -61
  71. footprinter_cli-1.0.3/footprinter/cli/mcp_cmd.py +0 -750
  72. footprinter_cli-1.0.3/footprinter/cli/search_cmd.py +0 -69
  73. footprinter_cli-1.0.3/footprinter/cli/status_cmd.py +0 -104
  74. footprinter_cli-1.0.3/footprinter/ingest/db/migration.py +0 -371
  75. footprinter_cli-1.0.3/footprinter/ingest/db/security.py +0 -6
  76. footprinter_cli-1.0.3/footprinter/mcp/resources/__init__.py +0 -1
  77. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/LICENSE +0 -0
  78. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/__init__.py +0 -0
  79. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/__init__.py +0 -0
  80. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/entities.py +0 -0
  81. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/search.py +0 -0
  82. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/semantic.py +0 -0
  83. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/api/status.py +0 -0
  84. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/__init__.py +0 -0
  85. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/context_patterns.yaml +0 -0
  86. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/extensions.yaml +0 -0
  87. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/filename_patterns.yaml +0 -0
  88. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/mime_mappings.yaml +0 -0
  89. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/salesforce_rules.yaml +0 -0
  90. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/bundled/patterns/security_patterns.yaml +0 -0
  91. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/__main__.py +0 -0
  92. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/api_cmd.py +0 -0
  93. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/data.py +0 -0
  94. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/delete.py +0 -0
  95. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/doctor.py +0 -0
  96. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/mcp_setup.py +0 -0
  97. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/uninstall.py +0 -0
  98. /footprinter_cli-1.0.3/footprinter/cli/vectorize_cmd.py → /footprinter_cli-1.0.4/footprinter/cli/vectorize.py +0 -0
  99. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/cli/view.py +0 -0
  100. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/connectors/config_utils.py +0 -0
  101. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/clients.py +0 -0
  102. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/messages.py +0 -0
  103. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/policies.py +0 -0
  104. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/projects.py +0 -0
  105. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/status.py +0 -0
  106. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/db/uploads.py +0 -0
  107. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/__init__.py +0 -0
  108. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/__init__.py +0 -0
  109. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/chat.py +0 -0
  110. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/ingest.py +0 -0
  111. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/local_files.py +0 -0
  112. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/local_folders.py +0 -0
  113. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/adapters/protocol.py +0 -0
  114. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/chat_parsers/__init__.py +0 -0
  115. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/chat_parsers/chatgpt_parser.py +0 -0
  116. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/chat_parsers/claude_parser.py +0 -0
  117. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/content_extractors.py +0 -0
  118. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/database.py +0 -0
  119. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/db/__init__.py +0 -0
  120. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/db/connector_schema.py +0 -0
  121. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/folder_indexer.py +0 -0
  122. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/run_record.py +0 -0
  123. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/scan_summary.py +0 -0
  124. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/ingest/status.py +0 -0
  125. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/__init__.py +0 -0
  126. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/__main__.py +0 -0
  127. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/errors.py +0 -0
  128. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/resources/context.py +0 -0
  129. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/resources/discoverability.py +0 -0
  130. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/server.py +0 -0
  131. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/__init__.py +0 -0
  132. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/semantic.py +0 -0
  133. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/mcp/tools/status.py +0 -0
  134. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/paths.py +0 -0
  135. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/semantic/__init__.py +0 -0
  136. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/semantic/embeddings.py +0 -0
  137. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/chat_service.py +0 -0
  138. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/client_service.py +0 -0
  139. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/email_service.py +0 -0
  140. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/file_service.py +0 -0
  141. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/folder_service.py +0 -0
  142. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/includes.py +0 -0
  143. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/project_service.py +0 -0
  144. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/roles.py +0 -0
  145. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/semantic_service.py +0 -0
  146. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/status_service.py +0 -0
  147. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/services/visit_service.py +0 -0
  148. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/__init__.py +0 -0
  149. {footprinter_cli-1.0.3/footprinter/mcp → footprinter_cli-1.0.4/footprinter/utils}/extraction.py +0 -0
  150. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/hash_utils.py +0 -0
  151. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/logging_config.py +0 -0
  152. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/mime.py +0 -0
  153. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/text.py +0 -0
  154. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter/utils/time.py +0 -0
  155. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter_cli.egg-info/dependency_links.txt +0 -0
  156. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter_cli.egg-info/entry_points.txt +0 -0
  157. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter_cli.egg-info/requires.txt +0 -0
  158. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/footprinter_cli.egg-info/top_level.txt +0 -0
  159. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/setup.cfg +0 -0
  160. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_build_status_filter.py +0 -0
  161. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_bundled.py +0 -0
  162. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_e2e_install.py +0 -0
  163. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_e2e_pipeline.py +0 -0
  164. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_examples.py +0 -0
  165. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_files_rename.py +0 -0
  166. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_files_surface.py +0 -0
  167. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_inherit_resolution.py +0 -0
  168. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_logging.py +0 -0
  169. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_no_project_root.py +0 -0
  170. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_package_init.py +0 -0
  171. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_paths_no_test_marker.py +0 -0
  172. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_pip_install_e2e.py +0 -0
  173. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_prompt_safety.py +0 -0
  174. {footprinter_cli-1.0.3 → footprinter_cli-1.0.4}/tests/test_resolver.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: footprinter-cli
3
- Version: 1.0.3
3
+ Version: 1.0.4
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
@@ -20,6 +20,8 @@ Classifier: Operating System :: MacOS
20
20
  Classifier: Operating System :: POSIX :: Linux
21
21
  Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
23
25
  Classifier: Topic :: Database
24
26
  Classifier: Topic :: Text Processing :: Indexing
25
27
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
@@ -59,67 +61,52 @@ Requires-Dist: httpx<1.0,>=0.27.0; extra == "dev"
59
61
 
60
62
  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.
61
63
 
62
- ## Prerequisites
63
-
64
- - **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`.
65
- - **macOS 13+** or **Linux**.
66
- - **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.
67
-
68
64
  ## Install
69
65
 
70
- The fastest path on a clean machine is the install script it ensures Python 3.11+ is present and installs `footprinter-cli`:
66
+ Requires **Python 3.11+** and **macOS 13+** or **Linux**. The install script checks your Python version and handles the rest:
71
67
 
72
68
  ```bash
73
- # Base install (CLI + MCP + HTTP API)
74
69
  curl -fsSL https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install.sh | bash
75
-
76
- # Full install (adds semantic search + document parsing)
77
- curl -fsSL https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install-full.sh | bash
78
70
  ```
79
71
 
80
- If you prefer to manage the install yourself, use **pipx** (recommended) — it isolates Footprinter and sidesteps the macOS install caveats noted below:
72
+ Or install with **pipx** directly:
81
73
 
82
74
  ```bash
83
- brew install pipx
84
- pipx ensurepath # then restart your terminal
85
75
  pipx install footprinter-cli
86
- pipx install 'footprinter-cli[full]' # with semantic + parse
87
- ```
88
-
89
- > **macOS caveats for manual installs:**
90
- > - **zsh** treats `[...]` as a glob, so keep the single quotes around any bracketed extras specifier (e.g. `'footprinter-cli[full]'`). Without quotes you'll see `zsh: no matches found`.
91
- > - **System and Homebrew Python** ship with PEP 668 enabled, which blocks bare `pip install` outside a venv. Use pipx (above) instead.
92
- > - **python.org-distributed Python** doesn't enforce PEP 668, so a bare `pip install footprinter-cli` outside pipx or a venv may succeed but place `fp` in `/Library/Frameworks/Python.framework/Versions/<x.y>/bin`, which isn't on `PATH` by default. Use pipx (above) or the install script.
93
-
94
- Inside an existing venv, `pip` works as expected:
95
-
96
- ```bash
97
- ./venv/bin/pip install footprinter-cli
98
- ./venv/bin/pip install 'footprinter-cli[full]'
99
76
  ```
100
77
 
101
- The base install includes the indexing pipeline, CLI, MCP server, HTTP API, and token encryption. Optional extras add more:
78
+ Either method gives you the `fp` command with the indexing pipeline, CLI, MCP server, and HTTP API. Optional extras add more:
102
79
 
103
80
  | Extra | What it adds |
104
81
  |-------|-------------|
105
82
  | `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
106
83
  | `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
107
- | `[full]` | All optional extras (semantic + parse) |
84
+ | `[full]` | Both of the above |
108
85
 
109
- > **Privacy note:** The `[semantic]` extra installs ChromaDB. Footprinter initializes
110
- > the ChromaDB client with `anonymized_telemetry=False`, so no telemetry is sent
111
- > regardless of which version pip resolves. ChromaDB also removed product telemetry
112
- > entirely in version 1.5.4. See
113
- > [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss) for details.
86
+ To install with extras: use the [full install script](https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install-full.sh), or `pipx install 'footprinter-cli[full]'`.
114
87
 
115
- ### Uninstall
88
+ <details>
89
+ <summary>Troubleshooting & alternative install methods</summary>
90
+
91
+ **Python version:** Stock macOS ships Python 3.9. Install 3.11+ from [python.org](https://www.python.org/downloads/) or `brew install python@3.11`.
92
+
93
+ **macOS caveats:**
94
+ - zsh treats `[...]` as a glob — quote extras specifiers: `'footprinter-cli[full]'`
95
+ - System/Homebrew Python blocks bare `pip install` (PEP 668) — use pipx or a venv instead
96
+
97
+ **Inside an existing venv:** `pip install footprinter-cli` works as expected.
98
+
99
+ **Full Disk Access:** Required for browser history indexing on macOS. `fp setup` will prompt you when needed.
100
+
101
+ **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).
116
102
 
117
- `fp uninstall` cleans up the MCP entry and user data first, then run the appropriate package uninstall:
103
+ </details>
104
+
105
+ ### Uninstall
118
106
 
119
107
  ```bash
120
- fp uninstall # remove MCP entry + user data
121
- pipx uninstall footprinter-cli # if you installed via pipx
122
- ./venv/bin/pip uninstall footprinter-cli # if you installed inside a venv
108
+ fp uninstall # remove MCP entry + user data
109
+ pipx uninstall footprinter-cli # remove the package
123
110
  ```
124
111
 
125
112
  ## Quick Start
@@ -156,14 +143,12 @@ Once configured, Claude can search your files, browse projects, and find related
156
143
  | **Local files** | Path, type, size, timestamps, content hash |
157
144
  | **Browser history** | Safari and Chrome — URLs, titles, visit times |
158
145
  | **Chat exports** | Claude and ChatGPT conversation exports |
159
- | **Email** | Subject, sender, recipients, body, timestamps — ingested via [connector plugins](#connectors) |
146
+ | **Email** | Subject, sender, recipients, body, timestamps |
160
147
  | **Documents** | PDF, Word, Excel, PowerPoint content (with `[parse]` extra) |
161
148
  | **Semantic embeddings** | Conceptual similarity across all sources (with `[semantic]` extra) |
162
149
 
163
150
  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/harringjohn/footprinter-cli/blob/main/reference/content-storage.md) for the full breakdown.
164
151
 
165
- Additional sources are available through [connector plugins](#connectors).
166
-
167
152
  ## CLI Commands
168
153
 
169
154
  All commands use the `fp` entry point.
@@ -187,30 +172,12 @@ All commands use the `fp` entry point.
187
172
 
188
173
  Run `fp <command> --help` for full usage.
189
174
 
190
- ## Connectors
191
-
192
- Connector plugins add external data sources like email, cloud storage, and third-party services. They install alongside Footprinter and register automatically:
193
-
194
- ```bash
195
- pip install footprinter-<name>
196
- ```
197
-
198
- First-party and community connectors are in development — check the repository for updates.
199
-
200
- Use `fp connect list` to see available connectors and their status.
201
-
202
175
  ## Architecture
203
176
 
204
177
  Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
205
178
 
206
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 + permissions) — you decide what agents can see.
207
180
 
208
- ## Requirements
209
-
210
- - Python 3.11+
211
- - macOS 13+ or Linux
212
- - Full Disk Access on macOS (for browser history)
213
-
214
181
  ## Documentation
215
182
 
216
183
  - [Interfaces](https://github.com/harringjohn/footprinter-cli/blob/main/reference/interfaces.md) — CLI commands, MCP tools, Python API
@@ -223,8 +190,6 @@ Sources are scanned into SQLite with bidirectional links connecting local files
223
190
 
224
191
  Bug fixes, documentation, and tests welcome. For new features or architectural changes, [open an issue](https://github.com/harringjohn/footprinter-cli/issues) first to discuss the approach.
225
192
 
226
- Connector plugins use an internal API that isn't stable yet — we're not accepting connector contributions at this time.
227
-
228
193
  ### Development setup
229
194
 
230
195
  ```bash
@@ -7,67 +7,52 @@
7
7
 
8
8
  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
9
 
10
- ## Prerequisites
11
-
12
- - **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`.
13
- - **macOS 13+** or **Linux**.
14
- - **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.
15
-
16
10
  ## Install
17
11
 
18
- The fastest path on a clean machine is the install script it ensures Python 3.11+ is present and installs `footprinter-cli`:
12
+ Requires **Python 3.11+** and **macOS 13+** or **Linux**. The install script checks your Python version and handles the rest:
19
13
 
20
14
  ```bash
21
- # Base install (CLI + MCP + HTTP API)
22
15
  curl -fsSL https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install.sh | bash
23
-
24
- # Full install (adds semantic search + document parsing)
25
- curl -fsSL https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install-full.sh | bash
26
16
  ```
27
17
 
28
- If you prefer to manage the install yourself, use **pipx** (recommended) — it isolates Footprinter and sidesteps the macOS install caveats noted below:
18
+ Or install with **pipx** directly:
29
19
 
30
20
  ```bash
31
- brew install pipx
32
- pipx ensurepath # then restart your terminal
33
21
  pipx install footprinter-cli
34
- pipx install 'footprinter-cli[full]' # with semantic + parse
35
- ```
36
-
37
- > **macOS caveats for manual installs:**
38
- > - **zsh** treats `[...]` as a glob, so keep the single quotes around any bracketed extras specifier (e.g. `'footprinter-cli[full]'`). Without quotes you'll see `zsh: no matches found`.
39
- > - **System and Homebrew Python** ship with PEP 668 enabled, which blocks bare `pip install` outside a venv. Use pipx (above) instead.
40
- > - **python.org-distributed Python** doesn't enforce PEP 668, so a bare `pip install footprinter-cli` outside pipx or a venv may succeed but place `fp` in `/Library/Frameworks/Python.framework/Versions/<x.y>/bin`, which isn't on `PATH` by default. Use pipx (above) or the install script.
41
-
42
- Inside an existing venv, `pip` works as expected:
43
-
44
- ```bash
45
- ./venv/bin/pip install footprinter-cli
46
- ./venv/bin/pip install 'footprinter-cli[full]'
47
22
  ```
48
23
 
49
- The base install includes the indexing pipeline, CLI, MCP server, HTTP API, and token encryption. Optional extras add more:
24
+ Either method gives you the `fp` command with the indexing pipeline, CLI, MCP server, and HTTP API. Optional extras add more:
50
25
 
51
26
  | Extra | What it adds |
52
27
  |-------|-------------|
53
28
  | `[semantic]` | Semantic search via ChromaDB + ONNX embeddings |
54
29
  | `[parse]` | PDF, Word, Excel, PowerPoint content extraction |
55
- | `[full]` | All optional extras (semantic + parse) |
30
+ | `[full]` | Both of the above |
56
31
 
57
- > **Privacy note:** The `[semantic]` extra installs ChromaDB. Footprinter initializes
58
- > the ChromaDB client with `anonymized_telemetry=False`, so no telemetry is sent
59
- > regardless of which version pip resolves. ChromaDB also removed product telemetry
60
- > entirely in version 1.5.4. See
61
- > [Chroma OSS overview](https://docs.trychroma.com/docs/overview/oss) for details.
32
+ To install with extras: use the [full install script](https://raw.githubusercontent.com/harringjohn/footprinter-cli/main/scripts/release/install-full.sh), or `pipx install 'footprinter-cli[full]'`.
62
33
 
63
- ### Uninstall
34
+ <details>
35
+ <summary>Troubleshooting & alternative install methods</summary>
36
+
37
+ **Python version:** Stock macOS ships Python 3.9. Install 3.11+ from [python.org](https://www.python.org/downloads/) or `brew install python@3.11`.
38
+
39
+ **macOS caveats:**
40
+ - zsh treats `[...]` as a glob — quote extras specifiers: `'footprinter-cli[full]'`
41
+ - System/Homebrew Python blocks bare `pip install` (PEP 668) — use pipx or a venv instead
42
+
43
+ **Inside an existing venv:** `pip install footprinter-cli` works as expected.
44
+
45
+ **Full Disk Access:** Required for browser history indexing on macOS. `fp setup` will prompt you when needed.
46
+
47
+ **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).
64
48
 
65
- `fp uninstall` cleans up the MCP entry and user data first, then run the appropriate package uninstall:
49
+ </details>
50
+
51
+ ### Uninstall
66
52
 
67
53
  ```bash
68
- fp uninstall # remove MCP entry + user data
69
- pipx uninstall footprinter-cli # if you installed via pipx
70
- ./venv/bin/pip uninstall footprinter-cli # if you installed inside a venv
54
+ fp uninstall # remove MCP entry + user data
55
+ pipx uninstall footprinter-cli # remove the package
71
56
  ```
72
57
 
73
58
  ## Quick Start
@@ -104,14 +89,12 @@ Once configured, Claude can search your files, browse projects, and find related
104
89
  | **Local files** | Path, type, size, timestamps, content hash |
105
90
  | **Browser history** | Safari and Chrome — URLs, titles, visit times |
106
91
  | **Chat exports** | Claude and ChatGPT conversation exports |
107
- | **Email** | Subject, sender, recipients, body, timestamps — ingested via [connector plugins](#connectors) |
92
+ | **Email** | Subject, sender, recipients, body, timestamps |
108
93
  | **Documents** | PDF, Word, Excel, PowerPoint content (with `[parse]` extra) |
109
94
  | **Semantic embeddings** | Conceptual similarity across all sources (with `[semantic]` extra) |
110
95
 
111
96
  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/harringjohn/footprinter-cli/blob/main/reference/content-storage.md) for the full breakdown.
112
97
 
113
- Additional sources are available through [connector plugins](#connectors).
114
-
115
98
  ## CLI Commands
116
99
 
117
100
  All commands use the `fp` entry point.
@@ -135,30 +118,12 @@ All commands use the `fp` entry point.
135
118
 
136
119
  Run `fp <command> --help` for full usage.
137
120
 
138
- ## Connectors
139
-
140
- Connector plugins add external data sources like email, cloud storage, and third-party services. They install alongside Footprinter and register automatically:
141
-
142
- ```bash
143
- pip install footprinter-<name>
144
- ```
145
-
146
- First-party and community connectors are in development — check the repository for updates.
147
-
148
- Use `fp connect list` to see available connectors and their status.
149
-
150
121
  ## Architecture
151
122
 
152
123
  Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
153
124
 
154
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 + permissions) — you decide what agents can see.
155
126
 
156
- ## Requirements
157
-
158
- - Python 3.11+
159
- - macOS 13+ or Linux
160
- - Full Disk Access on macOS (for browser history)
161
-
162
127
  ## Documentation
163
128
 
164
129
  - [Interfaces](https://github.com/harringjohn/footprinter-cli/blob/main/reference/interfaces.md) — CLI commands, MCP tools, Python API
@@ -171,8 +136,6 @@ Sources are scanned into SQLite with bidirectional links connecting local files
171
136
 
172
137
  Bug fixes, documentation, and tests welcome. For new features or architectural changes, [open an issue](https://github.com/harringjohn/footprinter-cli/issues) first to discuss the approach.
173
138
 
174
- Connector plugins use an internal API that isn't stable yet — we're not accepting connector contributions at this time.
175
-
176
139
  ### Development setup
177
140
 
178
141
  ```bash
@@ -12,6 +12,7 @@ import sqlite3
12
12
  from collections.abc import Callable
13
13
  from typing import Any
14
14
 
15
+ from footprinter.db.policies import is_folder_path_scope
15
16
  from footprinter.permissions import batch_resolve_permissions
16
17
  from footprinter.visibility import batch_resolve_visibility
17
18
 
@@ -113,10 +114,21 @@ ENTITY_META: dict[str, dict[str, Any]] = {
113
114
  "has_account": False,
114
115
  "path_column": None,
115
116
  },
117
+ "visit": {
118
+ "table": "visits",
119
+ "has_visibility": True,
120
+ "has_permissions": True,
121
+ "has_status": False,
122
+ "has_project_id": False,
123
+ "has_client_id": False,
124
+ "has_account": False,
125
+ "path_column": None,
126
+ },
116
127
  }
117
128
 
118
129
  # Reverse map: source scope suffix → entity type (e.g. "files" → "file")
119
130
  _SOURCE_TO_ENTITY = {meta["table"]: etype for etype, meta in ENTITY_META.items()}
131
+ _SOURCE_TO_ENTITY["browser"] = "visit"
120
132
 
121
133
 
122
134
  # ---------------------------------------------------------------------------
@@ -170,28 +182,58 @@ def _get_ids_for_scope(conn: sqlite3.Connection, scope: str) -> dict[str, list[i
170
182
  return result
171
183
 
172
184
  if prefix == "folder":
173
- # folder:{path} → files/folders with matching path prefix
174
- path = os.path.expanduser(value)
175
- # Escape LIKE metacharacters so literal %, _ in paths match correctly
176
- escaped = path.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
177
- result = {}
178
- for etype in ENTITY_META:
179
- meta = ENTITY_META[etype]
180
- path_col = meta["path_column"]
181
- if path_col is None:
182
- continue
183
- table = meta["table"]
184
- where = f"{path_col} LIKE ? ESCAPE '\\'"
185
- if meta["has_status"]:
186
- where += " AND status = 'listed'"
187
- rows = conn.execute(
188
- f"SELECT id FROM {table} WHERE {where}",
189
- (escaped + "%",),
185
+ if is_folder_path_scope(scope):
186
+ # folder:{path} files/folders with matching path prefix
187
+ path = os.path.expanduser(value)
188
+ # Escape LIKE metacharacters so literal %, _ in paths match correctly
189
+ escaped = path.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
190
+ result = {}
191
+ for etype in ENTITY_META:
192
+ meta = ENTITY_META[etype]
193
+ path_col = meta["path_column"]
194
+ if path_col is None:
195
+ continue
196
+ table = meta["table"]
197
+ where = f"{path_col} LIKE ? ESCAPE '\\'"
198
+ if meta["has_status"]:
199
+ where += " AND status = 'listed'"
200
+ rows = conn.execute(
201
+ f"SELECT id FROM {table} WHERE {where}",
202
+ (escaped + "%",),
203
+ ).fetchall()
204
+ ids = [r["id"] for r in rows]
205
+ if ids:
206
+ result[etype] = ids
207
+ return result
208
+ else:
209
+ # folder:{id} → folder + all descendants via parent_folder_id
210
+ folder_id = int(value)
211
+ descendants_cte = """
212
+ WITH RECURSIVE descendants(id) AS (
213
+ SELECT id FROM folders WHERE id = ?
214
+ UNION ALL
215
+ SELECT folder.id FROM folders folder
216
+ JOIN descendants descendant ON folder.parent_folder_id = descendant.id
217
+ )
218
+ """
219
+ cursor = conn.cursor()
220
+ cursor.execute(
221
+ f"{descendants_cte} SELECT id FROM descendants",
222
+ (folder_id,),
223
+ )
224
+ desc_ids = [row["id"] for row in cursor.fetchall()]
225
+ if not desc_ids:
226
+ return {}
227
+ result: dict[str, list[int]] = {"folder": desc_ids}
228
+ ph = ",".join("?" * len(desc_ids))
229
+ file_rows = conn.execute(
230
+ f"SELECT id FROM files WHERE folder_id IN ({ph}) AND status = 'listed'",
231
+ tuple(desc_ids),
190
232
  ).fetchall()
191
- ids = [r["id"] for r in rows]
192
- if ids:
193
- result[etype] = ids
194
- return result
233
+ file_ids = [r["id"] for r in file_rows]
234
+ if file_ids:
235
+ result["file"] = file_ids
236
+ return result
195
237
 
196
238
  if prefix == "project":
197
239
  project_id = int(value)
@@ -0,0 +1,38 @@
1
+ """Database connection for Footprinter HTTP API."""
2
+
3
+ import sqlite3
4
+ from contextlib import contextmanager
5
+ from typing import Generator
6
+
7
+ from footprinter.db_base import open_checked_connection
8
+
9
+
10
+ @contextmanager
11
+ def get_db() -> Generator[sqlite3.Connection, None, None]:
12
+ """Context manager for database connections.
13
+
14
+ Divergences from MCP's ``get_db()``:
15
+
16
+ - No ``PRAGMA query_only`` — the HTTP API uses Role.ADMIN and may need
17
+ write access for future endpoints.
18
+ - No ``handle_db_errors`` decorator — ``DatabaseNotInitializedError`` is
19
+ caught by a FastAPI exception handler registered in ``server.create_app()``.
20
+
21
+ Calls ``load_globals()`` to refresh the global visibility/permission
22
+ policy cache in ``access_service`` for the current request.
23
+ """
24
+ with open_checked_connection() as conn:
25
+ yield conn
26
+
27
+
28
+ def get_conn():
29
+ """FastAPI dependency that yields a database connection.
30
+
31
+ Usage::
32
+
33
+ @router.get("/endpoint")
34
+ def handler(conn=Depends(get_conn)):
35
+ ...
36
+ """
37
+ with get_db() as conn:
38
+ yield conn
@@ -3,7 +3,7 @@
3
3
  from fastapi import FastAPI, Request
4
4
  from fastapi.responses import JSONResponse
5
5
 
6
- from footprinter.api.db import DatabaseNotInitializedError
6
+ from footprinter.utils.exceptions import DatabaseNotInitializedError
7
7
 
8
8
 
9
9
  def create_app() -> "FastAPI":
@@ -116,9 +116,9 @@ vectorization:
116
116
  # ~1000 chars ≈ 250 tokens. Larger chunks get silently truncated by the model,
117
117
  # meaning content past the window is invisible to semantic search.
118
118
  chunk_size: 1000
119
- # Overlap between consecutive chunks (fraction of chunk_size, 0.0 to 1.0).
120
- # Applies to file vectorization only. Chat message chunking uses a fixed
121
- # character overlap defined in footprinter/semantic/chunking.py.
119
+ # Fractional overlap between consecutive chunks (0.01.0).
120
+ # 0.15 = 15% of chunk_size chars shared between adjacent chunks.
121
+ # Legacy integer values (>= 1) are accepted but deprecated.
122
122
  chunk_overlap: 0.15
123
123
  # Patterns (fnmatch syntax) for file paths to skip during vectorization.
124
124
  # Matched against the full absolute path (e.g. ~/Work/file.json expands at runtime).
@@ -88,12 +88,12 @@ def main(argv=None) -> None:
88
88
  doctor,
89
89
  ingest,
90
90
  mcp_cmd,
91
- search_cmd,
91
+ search,
92
92
  setup,
93
- status_cmd,
93
+ status,
94
94
  uninstall,
95
95
  upsert,
96
- vectorize_cmd,
96
+ vectorize,
97
97
  view,
98
98
  )
99
99
 
@@ -101,15 +101,15 @@ def main(argv=None) -> None:
101
101
  ingest,
102
102
  mcp_cmd,
103
103
  api_cmd,
104
- status_cmd,
105
- search_cmd,
104
+ status,
105
+ search,
106
106
  setup,
107
107
  connect,
108
108
  view,
109
109
  upsert,
110
110
  data,
111
111
  delete,
112
- vectorize_cmd,
112
+ vectorize,
113
113
  uninstall,
114
114
  doctor,
115
115
  ]:
@@ -80,6 +80,10 @@ def connect_db(db_path: Union[str, Path]) -> Optional[sqlite3.Connection]:
80
80
  def open_db(db_path=None):
81
81
  """Open the Footprinter DB; yields conn, closes on exit.
82
82
 
83
+ Calls :func:`~footprinter.services.access_service.load_globals` to
84
+ populate the global visibility/permission cache, mirroring the MCP
85
+ layer's ``get_db()``.
86
+
83
87
  Exits with code 1 if the database file does not exist.
84
88
  """
85
89
  if db_path is None:
@@ -92,6 +96,7 @@ def open_db(db_path=None):
92
96
  "[red]Database not found.[/red] Run [bold]fp setup[/bold] then [bold]fp ingest[/bold] to initialize."
93
97
  )
94
98
  sys.exit(1)
99
+ _access.load_globals(conn)
95
100
  try:
96
101
  yield conn
97
102
  finally:
@@ -261,8 +266,10 @@ def enrich_verbose_access(
261
266
  """Annotate rows in-place with access, access_source, visibility.
262
267
 
263
268
  Uses ``resolve_inherit_visibility`` / ``resolve_inherit_permission``
264
- so that ``inherit`` values resolve to the global policy (when loaded
265
- via ``load_globals``) or fall back to the hardcoded baseline.
269
+ so that ``inherit`` values resolve to the global policy. Since
270
+ ``open_db()`` calls ``load_globals`` before yielding, ``inherit``
271
+ values resolve to the actual global policy in normal CLI usage.
272
+ The baseline fallback remains as a defence-in-depth measure.
266
273
 
267
274
  Three cases based on the ``mcp_read`` key in each row dict:
268
275
 
@@ -1,5 +1,5 @@
1
1
  """Shared MCP access-policy helpers used by ``setup.py`` and ``mcp_cmd.py``
2
- (``fp mcp view/read/check/bulk``).
2
+ (``fp mcp check/set/reset/bulk``).
3
3
  """
4
4
 
5
5
  import os
@@ -7,7 +7,7 @@ import sqlite3
7
7
 
8
8
  from rich.table import Table
9
9
 
10
- from footprinter.access import (
10
+ from footprinter.access_stamper import (
11
11
  count_affected_entities,
12
12
  recalculate_access,
13
13
  recalculate_access_batched,
@@ -22,6 +22,7 @@ from footprinter.db.policies import (
22
22
  set_visibility_policy,
23
23
  )
24
24
  from footprinter.paths import get_db_path
25
+ from footprinter.utils.paths import abbreviate_home
25
26
 
26
27
  CONFIRM_THRESHOLD = 100
27
28
  """Entity count above which policy changes require interactive confirmation."""
@@ -105,16 +106,6 @@ def normalize_path(path: str) -> str:
105
106
  return normalized
106
107
 
107
108
 
108
- def abbreviate_home(path: str) -> str:
109
- """Replace ``$HOME`` prefix with ``~`` for display."""
110
- home = os.path.expanduser("~")
111
- if path.startswith(home + os.sep):
112
- return "~" + path[len(home) :]
113
- elif path == home:
114
- return "~"
115
- return path
116
-
117
-
118
109
  # ---------------------------------------------------------------------------
119
110
  # Single-path check helpers
120
111
  # ---------------------------------------------------------------------------
@@ -140,7 +140,7 @@ def _safe_readline(password: bool = False) -> str:
140
140
  raise PromptCancelled("Ctrl+D")
141
141
 
142
142
  if byte in (0x0D, 0x0A): # Enter
143
- sys.stdout.write("\n")
143
+ sys.stdout.write("\r\n")
144
144
  sys.stdout.flush()
145
145
  return "".join(buf)
146
146
 
@@ -99,7 +99,7 @@ def run_vectorization_stage(*, quiet: bool = False) -> None:
99
99
  trail += f", {skipped_large} too large"
100
100
  console.print(f" [green]✓[/green] Deep Read complete: {new} embedded" + trail)
101
101
  if skipped_large_files:
102
- from footprinter.cli._policy_helpers import abbreviate_home
102
+ from footprinter.utils.paths import abbreviate_home
103
103
 
104
104
  console.print(
105
105
  f" [yellow]⚠[/yellow] Skipped {len(skipped_large_files)}"
@@ -57,7 +57,7 @@ def register(subparsers) -> None:
57
57
  "Connectors add support for external data sources.\n"
58
58
  "Each connector is a separate package.\n\n"
59
59
  "No connectors are installed.\n\n"
60
- "Learn more: https://github.com/swellcitygroup/footprinter"
60
+ "Learn more: https://github.com/harringjohn/footprinter-cli"
61
61
  )
62
62
  return
63
63
  _parser.print_help()
@@ -190,7 +190,7 @@ def _cmd_list(args) -> None:
190
190
  "No connectors installed.\n\n"
191
191
  "Connectors are separate packages that plug into Footprinter's\n"
192
192
  "ingest pipeline. To get started, visit:\n"
193
- " https://github.com/swellcitygroup/footprinter"
193
+ " https://github.com/harringjohn/footprinter-cli"
194
194
  )
195
195
  return
196
196
 
@@ -240,7 +240,7 @@ def _cmd_install(args) -> None:
240
240
  console.print(f" [bold]{spec.name}[/bold] — {spec.description}")
241
241
  console.print("\nInstall one: [bold]fp connect install <name>[/bold]")
242
242
  else:
243
- console.print("No connectors available.\n\nLearn more: https://github.com/swellcitygroup/footprinter")
243
+ console.print("No connectors available.\n\nLearn more: https://github.com/harringjohn/footprinter-cli")
244
244
  return
245
245
  spec = connectors.get(name)
246
246
  if spec is None: