footprinter-cli 1.0.3__tar.gz → 1.0.5__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 (185) hide show
  1. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/PKG-INFO +34 -71
  2. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/README.md +31 -70
  3. footprinter_cli-1.0.3/footprinter/access.py → footprinter_cli-1.0.5/footprinter/access_stamper.py +80 -35
  4. footprinter_cli-1.0.5/footprinter/api/__main__.py +5 -0
  5. footprinter_cli-1.0.5/footprinter/api/db.py +38 -0
  6. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/entities.py +0 -2
  7. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/server.py +44 -2
  8. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/config.example.yaml +3 -15
  9. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/__init__.py +24 -19
  10. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/_common.py +99 -32
  11. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/_policy_helpers.py +153 -112
  12. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/_prompt.py +1 -1
  13. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/_vectorize_stage.py +11 -4
  14. footprinter_cli-1.0.5/footprinter/cli/add.py +813 -0
  15. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/connect.py +3 -3
  16. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/delete.py +4 -4
  17. footprinter_cli-1.0.5/footprinter/cli/diagnostics.py +148 -0
  18. footprinter_cli-1.0.5/footprinter/cli/doctor.py +410 -0
  19. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/ingest.py +21 -324
  20. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/mcp_setup.py +11 -107
  21. footprinter_cli-1.0.5/footprinter/cli/permission_cmd.py +577 -0
  22. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/search.py +61 -3
  23. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/setup.py +78 -421
  24. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/status.py +118 -3
  25. footprinter_cli-1.0.5/footprinter/cli/update.py +884 -0
  26. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/view.py +221 -7
  27. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/connectors/__init__.py +2 -0
  28. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/__init__.py +8 -1
  29. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/browser.py +36 -53
  30. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/chats.py +52 -67
  31. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/clients.py +35 -26
  32. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/emails.py +18 -49
  33. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/files.py +52 -105
  34. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/folders.py +85 -62
  35. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/messages.py +18 -9
  36. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/policies.py +3 -3
  37. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/projects.py +74 -129
  38. footprinter_cli-1.0.5/footprinter/db/protocols.py +16 -0
  39. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/search.py +50 -32
  40. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/sql_utils.py +64 -0
  41. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/status.py +39 -9
  42. footprinter_cli-1.0.3/footprinter/mcp/db.py → footprinter_cli-1.0.5/footprinter/db_base.py +10 -25
  43. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/browser.py +4 -4
  44. footprinter_cli-1.0.5/footprinter/ingest/adapters/chat.py +120 -0
  45. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/local_files.py +1 -1
  46. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/local_folders.py +6 -6
  47. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/protocol.py +1 -1
  48. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/browser_indexer.py +1 -1
  49. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/chat_indexer.py +2 -4
  50. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/chat_parsers/__init__.py +2 -1
  51. footprinter_cli-1.0.5/footprinter/ingest/chat_parsers/claude_code_parser.py +165 -0
  52. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/db/schema.py +216 -114
  53. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/file_indexer.py +23 -15
  54. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/file_scanner.py +16 -6
  55. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/folder_indexer.py +3 -3
  56. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/full_content_extractor.py +24 -39
  57. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/orchestrator.py +8 -10
  58. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/pipe_runner.py +0 -7
  59. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/processing.py +31 -10
  60. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/registry.py +2 -2
  61. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/scan_summary.py +1 -1
  62. footprinter_cli-1.0.5/footprinter/ingest/status.py +133 -0
  63. footprinter_cli-1.0.3/footprinter/ingest/cli.py → footprinter_cli-1.0.5/footprinter/ingest/vector_ops.py +17 -18
  64. footprinter_cli-1.0.5/footprinter/mcp/db.py +34 -0
  65. footprinter_cli-1.0.5/footprinter/mcp/resources/__init__.py +1 -0
  66. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/resources/discoverability.py +1 -1
  67. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/navigation.py +3 -18
  68. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/read.py +1 -1
  69. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/search.py +1 -9
  70. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/permissions.py +3 -3
  71. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/semantic/chunking.py +27 -4
  72. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/semantic/embeddings.py +1 -1
  73. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/semantic/hybrid_search.py +3 -8
  74. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/semantic/vector_store.py +26 -9
  75. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/__init__.py +7 -0
  76. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/access_service.py +33 -19
  77. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/chat_service.py +4 -0
  78. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/client_service.py +4 -9
  79. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/content_service.py +15 -5
  80. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/ingest_service.py +4 -6
  81. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/project_service.py +14 -32
  82. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/search_service.py +7 -41
  83. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/semantic_service.py +10 -10
  84. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/visit_service.py +5 -1
  85. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/source_registry.py +1 -1
  86. footprinter_cli-1.0.5/footprinter/utils/exceptions.py +5 -0
  87. footprinter_cli-1.0.5/footprinter/utils/paths.py +15 -0
  88. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/visibility.py +83 -45
  89. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter_cli.egg-info/PKG-INFO +34 -71
  90. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter_cli.egg-info/SOURCES.txt +16 -12
  91. footprinter_cli-1.0.5/footprinter_cli.egg-info/entry_points.txt +4 -0
  92. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/pyproject.toml +5 -1
  93. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_access_control_bypasses.py +13 -13
  94. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_access_control_docs.py +2 -2
  95. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_access_recalculate.py +441 -162
  96. footprinter_cli-1.0.5/tests/test_access_source_provenance.py +263 -0
  97. footprinter_cli-1.0.5/tests/test_db_base.py +96 -0
  98. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_e2e_install.py +48 -65
  99. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_edit_recalculate.py +18 -18
  100. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_files_surface.py +3 -3
  101. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_inherit_resolution.py +13 -13
  102. footprinter_cli-1.0.5/tests/test_no_issue_ids.py +53 -0
  103. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_pip_install_e2e.py +4 -6
  104. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_resolver.py +17 -10
  105. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_security_layer.py +87 -88
  106. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_security_permissions.py +26 -26
  107. footprinter_cli-1.0.3/footprinter/api/db.py +0 -61
  108. footprinter_cli-1.0.3/footprinter/cli/api_cmd.py +0 -61
  109. footprinter_cli-1.0.3/footprinter/cli/data.py +0 -879
  110. footprinter_cli-1.0.3/footprinter/cli/doctor.py +0 -251
  111. footprinter_cli-1.0.3/footprinter/cli/mcp_cmd.py +0 -750
  112. footprinter_cli-1.0.3/footprinter/cli/search_cmd.py +0 -69
  113. footprinter_cli-1.0.3/footprinter/cli/status_cmd.py +0 -104
  114. footprinter_cli-1.0.3/footprinter/cli/upsert.py +0 -792
  115. footprinter_cli-1.0.3/footprinter/cli/vectorize_cmd.py +0 -215
  116. footprinter_cli-1.0.3/footprinter/ingest/adapters/chat.py +0 -57
  117. footprinter_cli-1.0.3/footprinter/ingest/db/migration.py +0 -371
  118. footprinter_cli-1.0.3/footprinter/ingest/db/security.py +0 -6
  119. footprinter_cli-1.0.3/footprinter/ingest/status.py +0 -347
  120. footprinter_cli-1.0.3/footprinter/mcp/resources/__init__.py +0 -1
  121. footprinter_cli-1.0.3/footprinter_cli.egg-info/entry_points.txt +0 -2
  122. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/LICENSE +0 -0
  123. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/__init__.py +0 -0
  124. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/__init__.py +0 -0
  125. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/search.py +0 -0
  126. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/semantic.py +0 -0
  127. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/api/status.py +0 -0
  128. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/__init__.py +0 -0
  129. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/context_patterns.yaml +0 -0
  130. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/extensions.yaml +0 -0
  131. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/filename_patterns.yaml +0 -0
  132. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/mime_mappings.yaml +0 -0
  133. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/salesforce_rules.yaml +0 -0
  134. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/bundled/patterns/security_patterns.yaml +0 -0
  135. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/__main__.py +0 -0
  136. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/cli/uninstall.py +0 -0
  137. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/connectors/config_utils.py +0 -0
  138. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/db/uploads.py +0 -0
  139. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/__init__.py +0 -0
  140. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/__init__.py +0 -0
  141. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/adapters/ingest.py +0 -0
  142. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/chat_parsers/chatgpt_parser.py +0 -0
  143. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/chat_parsers/claude_parser.py +0 -0
  144. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/content_extractors.py +0 -0
  145. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/database.py +0 -0
  146. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/db/__init__.py +0 -0
  147. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/db/connector_schema.py +0 -0
  148. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/ingest/run_record.py +0 -0
  149. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/__init__.py +0 -0
  150. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/__main__.py +0 -0
  151. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/errors.py +0 -0
  152. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/resources/context.py +0 -0
  153. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/server.py +0 -0
  154. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/__init__.py +0 -0
  155. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/semantic.py +0 -0
  156. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/mcp/tools/status.py +0 -0
  157. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/paths.py +0 -0
  158. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/semantic/__init__.py +0 -0
  159. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/email_service.py +0 -0
  160. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/file_service.py +0 -0
  161. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/folder_service.py +0 -0
  162. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/includes.py +0 -0
  163. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/roles.py +0 -0
  164. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/services/status_service.py +0 -0
  165. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/__init__.py +0 -0
  166. {footprinter_cli-1.0.3/footprinter/mcp → footprinter_cli-1.0.5/footprinter/utils}/extraction.py +0 -0
  167. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/hash_utils.py +0 -0
  168. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/logging_config.py +0 -0
  169. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/mime.py +0 -0
  170. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/text.py +0 -0
  171. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter/utils/time.py +0 -0
  172. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter_cli.egg-info/dependency_links.txt +0 -0
  173. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter_cli.egg-info/requires.txt +0 -0
  174. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/footprinter_cli.egg-info/top_level.txt +0 -0
  175. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/setup.cfg +0 -0
  176. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_build_status_filter.py +0 -0
  177. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_bundled.py +0 -0
  178. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_e2e_pipeline.py +0 -0
  179. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_examples.py +0 -0
  180. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_files_rename.py +0 -0
  181. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_logging.py +0 -0
  182. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_no_project_root.py +0 -0
  183. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_package_init.py +0 -0
  184. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/tests/test_paths_no_test_marker.py +0 -0
  185. {footprinter_cli-1.0.3 → footprinter_cli-1.0.5}/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
3
+ Version: 1.0.5
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 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:
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.
@@ -175,41 +160,21 @@ All commands use the `fp` entry point.
175
160
  | `fp status` | System health and data counts |
176
161
  | `fp search` | Search across all indexed sources |
177
162
  | `fp connect` | Manage optional integrations |
178
- | `fp mcp` | MCP server and access policies |
179
- | `fp api` | Start the HTTP API server |
163
+ | `fp permission` | Manage access policies (visibility, permissions) |
180
164
  | `fp view` | Browse indexed data (files, folders, projects, clients, chats, emails, visits) |
181
- | `fp upsert` | Create/update records, assign relationships, or soft-delete via `--status removed` |
182
- | `fp data` | Export data, generate templates, or import metadata corrections |
165
+ | `fp add` | Create new entity records or import from CSV |
166
+ | `fp update` | Update existing records by ID — status, assignments, metadata |
183
167
  | `fp delete` | Hard-delete a super entity (irreversible) |
184
- | `fp vectorize` | Manage per-record vectorization control |
185
- | `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
168
+ | `fp doctor` | Post-install health check (Python version, platform, FDA, MCP wiring) |
186
169
  | `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
187
170
 
188
171
  Run `fp <command> --help` for full usage.
189
172
 
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
173
  ## Architecture
203
174
 
204
175
  Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
205
176
 
206
- 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
-
208
- ## Requirements
209
-
210
- - Python 3.11+
211
- - macOS 13+ or Linux
212
- - Full Disk Access on macOS (for browser history)
177
+ 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.
213
178
 
214
179
  ## Documentation
215
180
 
@@ -223,13 +188,11 @@ Sources are scanned into SQLite with bidirectional links connecting local files
223
188
 
224
189
  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
190
 
226
- Connector plugins use an internal API that isn't stable yet — we're not accepting connector contributions at this time.
227
-
228
191
  ### Development setup
229
192
 
230
193
  ```bash
231
194
  git clone https://github.com/harringjohn/footprinter-cli.git
232
- cd footprinter
195
+ cd footprinter-cli
233
196
  python3 -m venv venv
234
197
  ./venv/bin/pip install -e ".[dev]"
235
198
  ```
@@ -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 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:
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.
@@ -123,41 +106,21 @@ All commands use the `fp` entry point.
123
106
  | `fp status` | System health and data counts |
124
107
  | `fp search` | Search across all indexed sources |
125
108
  | `fp connect` | Manage optional integrations |
126
- | `fp mcp` | MCP server and access policies |
127
- | `fp api` | Start the HTTP API server |
109
+ | `fp permission` | Manage access policies (visibility, permissions) |
128
110
  | `fp view` | Browse indexed data (files, folders, projects, clients, chats, emails, visits) |
129
- | `fp upsert` | Create/update records, assign relationships, or soft-delete via `--status removed` |
130
- | `fp data` | Export data, generate templates, or import metadata corrections |
111
+ | `fp add` | Create new entity records or import from CSV |
112
+ | `fp update` | Update existing records by ID — status, assignments, metadata |
131
113
  | `fp delete` | Hard-delete a super entity (irreversible) |
132
- | `fp vectorize` | Manage per-record vectorization control |
133
- | `fp doctor` | Post-install health check (Python version, install location, FDA, MCP wiring) |
114
+ | `fp doctor` | Post-install health check (Python version, platform, FDA, MCP wiring) |
134
115
  | `fp uninstall` | Remove Footprinter — MCP entry, user data, package |
135
116
 
136
117
  Run `fp <command> --help` for full usage.
137
118
 
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
119
  ## Architecture
151
120
 
152
121
  Single-process CLI with optional MCP server. SQLite database. No containers, no cloud, no accounts.
153
122
 
154
- 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
-
156
- ## Requirements
157
-
158
- - Python 3.11+
159
- - macOS 13+ or Linux
160
- - Full Disk Access on macOS (for browser history)
123
+ 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.
161
124
 
162
125
  ## Documentation
163
126
 
@@ -171,13 +134,11 @@ Sources are scanned into SQLite with bidirectional links connecting local files
171
134
 
172
135
  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
136
 
174
- Connector plugins use an internal API that isn't stable yet — we're not accepting connector contributions at this time.
175
-
176
137
  ### Development setup
177
138
 
178
139
  ```bash
179
140
  git clone https://github.com/harringjohn/footprinter-cli.git
180
- cd footprinter
141
+ cd footprinter-cli
181
142
  python3 -m venv venv
182
143
  ./venv/bin/pip install -e ".[dev]"
183
144
  ```
@@ -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 mcp_view / mcp_read columns.
5
+ values back to visibility / access columns.
6
6
  """
7
7
 
8
8
  from __future__ import annotations
@@ -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
 
@@ -44,8 +45,8 @@ def _is_inherit_source(source: str) -> bool:
44
45
  # ---------------------------------------------------------------------------
45
46
  # Each entry describes an entity type's table and capabilities.
46
47
  # table: SQL table name
47
- # has_visibility: has mcp_view column
48
- # has_permissions: has mcp_read column
48
+ # has_visibility: has visibility column
49
+ # has_permissions: has access column
49
50
  # has_status: has status column (filter WHERE status = 'listed')
50
51
  # has_project_id: has project_id FK
51
52
  # has_client_id: has client_id FK
@@ -101,7 +102,7 @@ ENTITY_META: dict[str, dict[str, Any]] = {
101
102
  "has_project_id": False,
102
103
  "has_client_id": True,
103
104
  "has_account": False,
104
- "path_column": "root_path",
105
+ "path_column": None,
105
106
  },
106
107
  "client": {
107
108
  "table": "clients",
@@ -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)
@@ -263,31 +305,34 @@ def _get_ids_for_scope(conn: sqlite3.Connection, scope: str) -> dict[str, list[i
263
305
 
264
306
 
265
307
  def _write_back_visibility(conn: sqlite3.Connection, entity_type: str, results: dict[int, tuple]) -> None:
266
- """Batch UPDATE mcp_view from resolve results.
308
+ """Batch UPDATE visibility and visibility_source from resolve results.
267
309
 
268
310
  Entities whose visibility comes from the global policy or the hardcoded
269
- baseline are written as ``'inherit'`` the MCP layer resolves them at
270
- query time. Entities with a specific policy get the resolved value.
311
+ baseline are written as ``'inherit'`` with ``visibility_source = NULL``.
312
+ Entities with a specific policy get the resolved value and source scope.
271
313
  """
272
314
  table = ENTITY_META[entity_type]["table"]
273
315
  conn.executemany(
274
- f"UPDATE {table} SET mcp_view = ? WHERE id = ?",
275
- [("inherit" if _is_inherit_source(source) else state, eid) for eid, (state, source) in results.items()],
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
+ ],
276
321
  )
277
322
 
278
323
 
279
324
  def _write_back_permissions(conn: sqlite3.Connection, entity_type: str, results: dict[int, tuple]) -> None:
280
- """Batch UPDATE mcp_read from resolve results.
325
+ """Batch UPDATE access and access_source from resolve results.
281
326
 
282
327
  Entities whose permission comes from the global policy or the hardcoded
283
- baseline are written as ``'inherit'`` the MCP layer resolves them at
284
- query time. Entities with a specific policy get the resolved value.
328
+ baseline are written as ``'inherit'`` with ``access_source = NULL``.
329
+ Entities with a specific policy get the resolved value and source scope.
285
330
  """
286
331
  table = ENTITY_META[entity_type]["table"]
287
332
  conn.executemany(
288
- f"UPDATE {table} SET mcp_read = ? WHERE id = ?",
333
+ f"UPDATE {table} SET access = ?, access_source = ? WHERE id = ?",
289
334
  [
290
- ("inherit" if _is_inherit_source(source) else ("allow" if allowed else "deny"), eid)
335
+ ("inherit", None, eid) if _is_inherit_source(source) else ("allow" if allowed else "deny", source, eid)
291
336
  for eid, (allowed, source) in results.items()
292
337
  ],
293
338
  )
@@ -0,0 +1,5 @@
1
+ """Allow running as: python -m footprinter.api"""
2
+
3
+ from footprinter.api.server import cli
4
+
5
+ cli()
@@ -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
@@ -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
  )