code-context-control 2.86.0__tar.gz → 2.88.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. {code_context_control-2.86.0/code_context_control.egg-info → code_context_control-2.88.2}/PKG-INFO +1 -1
  2. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/c3.py +128 -9
  3. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/commands/parser.py +15 -2
  4. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/credentials.html +80 -0
  5. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_pretool_enforce.py +2 -1
  6. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_server.py +33 -2
  7. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_panel.js +2 -2
  8. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/hub_credentials.js +227 -23
  9. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/mcp_server.py +18 -6
  10. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/server.py +34 -10
  11. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/credentials.py +105 -4
  12. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/shell.py +52 -8
  13. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/credentials.js +251 -23
  14. {code_context_control-2.86.0 → code_context_control-2.88.2/code_context_control.egg-info}/PKG-INFO +1 -1
  15. {code_context_control-2.86.0 → code_context_control-2.88.2}/code_context_control.egg-info/SOURCES.txt +2 -0
  16. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/oracle_server.py +4 -4
  17. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/local_session.py +28 -0
  18. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/mobile_api.py +29 -0
  19. {code_context_control-2.86.0 → code_context_control-2.88.2}/pyproject.toml +1 -1
  20. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/claude_md.py +1 -1
  21. code_context_control-2.88.2/services/cred_telemetry.py +303 -0
  22. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/credential_store.py +399 -23
  23. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/parser.py +24 -0
  24. code_context_control-2.88.2/tests/test_cred_telemetry.py +189 -0
  25. code_context_control-2.88.2/tests/test_credential_store.py +525 -0
  26. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_credentials_routes.py +82 -0
  27. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_credentials_tool.py +96 -0
  28. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_delegate_cascade.py +52 -1
  29. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_credentials_routes_write.py +54 -0
  30. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mobile_security_api.py +32 -1
  31. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_session_bootstrap.py +101 -0
  32. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_shell_creds.py +85 -2
  33. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_validate.py +57 -0
  34. code_context_control-2.86.0/tests/test_credential_store.py +0 -270
  35. {code_context_control-2.86.0 → code_context_control-2.88.2}/LICENSE +0 -0
  36. {code_context_control-2.86.0 → code_context_control-2.88.2}/README.md +0 -0
  37. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/__init__.py +0 -0
  38. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/_hook_utils.py +0 -0
  39. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/commands/__init__.py +0 -0
  40. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/commands/common.py +0 -0
  41. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/docs.html +0 -0
  42. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/edits.html +0 -0
  43. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/access.html +0 -0
  44. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/bitbucket.html +0 -0
  45. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/getting-started.html +0 -0
  46. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/index.html +0 -0
  47. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/masking.html +0 -0
  48. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/oracle.html +0 -0
  49. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/shared.css +0 -0
  50. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/tools.html +0 -0
  51. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/guide/workflow.html +0 -0
  52. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_access_guard.py +0 -0
  53. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_artifact.py +0 -0
  54. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_auto_snapshot.py +0 -0
  55. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_c3_signal.py +0 -0
  56. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_c3read.py +0 -0
  57. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_dispatch.py +0 -0
  58. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_edit_ledger.py +0 -0
  59. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_edit_unlock.py +0 -0
  60. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_filter.py +0 -0
  61. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_ghost_files.py +0 -0
  62. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_prompt_recall.py +0 -0
  63. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_read.py +0 -0
  64. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_session_stats.py +0 -0
  65. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hook_terse_advisor.py +0 -0
  66. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/app.js +0 -0
  67. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/add_project.js +0 -0
  68. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/config_editor.js +0 -0
  69. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_artifacts.js +0 -0
  70. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_health.js +0 -0
  71. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_subprojects.js +0 -0
  72. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_tasks.js +0 -0
  73. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/drill_views.js +0 -0
  74. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/global_search.js +0 -0
  75. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/hub_ci.js +0 -0
  76. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/hub_enforcement.js +0 -0
  77. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/hub_locks.js +0 -0
  78. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/mcp_manager.js +0 -0
  79. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/modals.js +0 -0
  80. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/project_card.js +0 -0
  81. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/project_tree.js +0 -0
  82. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/session_drawer.js +0 -0
  83. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/settings_modal.js +0 -0
  84. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/sidebar.js +0 -0
  85. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/summary_bar.js +0 -0
  86. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/task_board.js +0 -0
  87. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/toasts.js +0 -0
  88. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/components/topbar.js +0 -0
  89. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui/state.js +0 -0
  90. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/hub_ui.html +0 -0
  91. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/mcp_proxy.py +0 -0
  92. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/progress.py +0 -0
  93. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/__init__.py +0 -0
  94. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/_grants.py +0 -0
  95. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/_helpers.py +0 -0
  96. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/agent.py +0 -0
  97. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/artifacts.py +0 -0
  98. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/bitbucket.py +0 -0
  99. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/ci.py +0 -0
  100. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/compress.py +0 -0
  101. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/delegate.py +0 -0
  102. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/edit.py +0 -0
  103. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/edit_verify.py +0 -0
  104. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/edits.py +0 -0
  105. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/federate.py +0 -0
  106. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/filter.py +0 -0
  107. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/impact.py +0 -0
  108. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/jira.py +0 -0
  109. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/locks.py +0 -0
  110. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/memory.py +0 -0
  111. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/override.py +0 -0
  112. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/project.py +0 -0
  113. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/read.py +0 -0
  114. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/search.py +0 -0
  115. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/session.py +0 -0
  116. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/status.py +0 -0
  117. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/tasks.py +0 -0
  118. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/tools/validate.py +0 -0
  119. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/api.js +0 -0
  120. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/app.js +0 -0
  121. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/access.js +0 -0
  122. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/bitbucket.js +0 -0
  123. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/chat.js +0 -0
  124. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/dashboard.js +0 -0
  125. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/edits.js +0 -0
  126. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/enforcement.js +0 -0
  127. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/instructions.js +0 -0
  128. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/jira.js +0 -0
  129. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/memory.js +0 -0
  130. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/sessions.js +0 -0
  131. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/settings.js +0 -0
  132. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/sidebar.js +0 -0
  133. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/components/tasks.js +0 -0
  134. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/icons.js +0 -0
  135. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/pm_shared.js +0 -0
  136. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/shared.js +0 -0
  137. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui/theme.js +0 -0
  138. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui.html +0 -0
  139. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui_legacy.html +0 -0
  140. {code_context_control-2.86.0 → code_context_control-2.88.2}/cli/ui_nano.html +0 -0
  141. {code_context_control-2.86.0 → code_context_control-2.88.2}/code_context_control.egg-info/dependency_links.txt +0 -0
  142. {code_context_control-2.86.0 → code_context_control-2.88.2}/code_context_control.egg-info/entry_points.txt +0 -0
  143. {code_context_control-2.86.0 → code_context_control-2.88.2}/code_context_control.egg-info/requires.txt +0 -0
  144. {code_context_control-2.86.0 → code_context_control-2.88.2}/code_context_control.egg-info/top_level.txt +0 -0
  145. {code_context_control-2.86.0 → code_context_control-2.88.2}/core/__init__.py +0 -0
  146. {code_context_control-2.86.0 → code_context_control-2.88.2}/core/config.py +0 -0
  147. {code_context_control-2.86.0 → code_context_control-2.88.2}/core/ide.py +0 -0
  148. {code_context_control-2.86.0 → code_context_control-2.88.2}/core/mcp_toml.py +0 -0
  149. {code_context_control-2.86.0 → code_context_control-2.88.2}/core/web_security.py +0 -0
  150. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/__init__.py +0 -0
  151. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/config.py +0 -0
  152. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/mcp_oracle.py +0 -0
  153. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/oracle_ui.html +0 -0
  154. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/__init__.py +0 -0
  155. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/activity_reporter.py +0 -0
  156. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/api_auth.py +0 -0
  157. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/c3_bridge.py +0 -0
  158. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/chat_engine.py +0 -0
  159. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/chat_poll.py +0 -0
  160. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/chat_store.py +0 -0
  161. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/cross_memory.py +0 -0
  162. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/discovery_audit.py +0 -0
  163. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/federated_graph.py +0 -0
  164. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/health_checker.py +0 -0
  165. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/insight_engine.py +0 -0
  166. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/memory_reader.py +0 -0
  167. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/memory_writer.py +0 -0
  168. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/project_scanner.py +0 -0
  169. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/review_agent.py +0 -0
  170. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/tool_executor.py +0 -0
  171. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/services/tool_registry.py +0 -0
  172. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/activity.js +0 -0
  173. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/agents.js +0 -0
  174. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/app.js +0 -0
  175. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/busy.js +0 -0
  176. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/conversations.js +0 -0
  177. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/input.js +0 -0
  178. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/markdown.js +0 -0
  179. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/send.js +0 -0
  180. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/stream_renderer.js +0 -0
  181. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/chat/toolbar.js +0 -0
  182. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/core.js +0 -0
  183. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/crossgraph.js +0 -0
  184. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/header.js +0 -0
  185. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/insights.js +0 -0
  186. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/projects.js +0 -0
  187. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/qrcode.js +0 -0
  188. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/settings.js +0 -0
  189. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/suggestions.js +0 -0
  190. {code_context_control-2.86.0 → code_context_control-2.88.2}/oracle/ui/theme_tabs.js +0 -0
  191. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/__init__.py +0 -0
  192. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/access_guard.py +0 -0
  193. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/access_telemetry.py +0 -0
  194. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/activity_log.py +0 -0
  195. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/agent_base.py +0 -0
  196. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/agent_locks.py +0 -0
  197. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/agents.py +0 -0
  198. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/artifact_defs.py +0 -0
  199. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/artifact_store.py +0 -0
  200. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/auto_memory.py +0 -0
  201. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bench/__init__.py +0 -0
  202. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bench/external/__init__.py +0 -0
  203. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bench/external/aider_polyglot.py +0 -0
  204. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bench/external/swe_bench.py +0 -0
  205. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/benchmark_dashboard.py +0 -0
  206. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bitbucket_client.py +0 -0
  207. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/bitbucket_credentials.py +0 -0
  208. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_act.py +0 -0
  209. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_cache.py +0 -0
  210. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_expr.py +0 -0
  211. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_failures.py +0 -0
  212. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_github.py +0 -0
  213. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_impact.py +0 -0
  214. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_intel.py +0 -0
  215. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_runner.py +0 -0
  216. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ci_workflow.py +0 -0
  217. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/circuit_breaker.py +0 -0
  218. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/compressor.py +0 -0
  219. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/context_snapshot.py +0 -0
  220. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/conversation_store.py +0 -0
  221. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/doc_index.py +0 -0
  222. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/e2e_benchmark.py +0 -0
  223. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/e2e_evaluator.py +0 -0
  224. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/e2e_tasks.py +0 -0
  225. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/edit_ledger.py +0 -0
  226. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/embedding_index.py +0 -0
  227. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/enforcement_policy.py +0 -0
  228. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/error_reporting.py +0 -0
  229. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/file_memory.py +0 -0
  230. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/git_context.py +0 -0
  231. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/hub_service.py +0 -0
  232. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/indexer.py +0 -0
  233. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/jira_client.py +0 -0
  234. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/jira_cloud.py +0 -0
  235. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/jira_credentials.py +0 -0
  236. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/jira_data_center.py +0 -0
  237. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/jira_links.py +0 -0
  238. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/mask_activation.py +0 -0
  239. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/mask_mirror.py +0 -0
  240. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/mask_presets.py +0 -0
  241. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory.py +0 -0
  242. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_consolidator.py +0 -0
  243. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_distiller.py +0 -0
  244. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_graph.py +0 -0
  245. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_grounder.py +0 -0
  246. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_queue.py +0 -0
  247. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/memory_scorer.py +0 -0
  248. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/metrics.py +0 -0
  249. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/notifications.py +0 -0
  250. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ollama_bridge.py +0 -0
  251. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ollama_client.py +0 -0
  252. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/ollama_credentials.py +0 -0
  253. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/output_filter.py +0 -0
  254. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/override_grants.py +0 -0
  255. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/override_policy.py +0 -0
  256. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/override_requests.py +0 -0
  257. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/override_wake.py +0 -0
  258. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/project_manager.py +0 -0
  259. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/project_runtime.py +0 -0
  260. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/protocol.py +0 -0
  261. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/proxy_state.py +0 -0
  262. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/repo_map.py +0 -0
  263. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/retention.py +0 -0
  264. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/retrieval_broker.py +0 -0
  265. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/router.py +0 -0
  266. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/runtime.py +0 -0
  267. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/scanner.py +0 -0
  268. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/session_benchmark.py +0 -0
  269. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/session_manager.py +0 -0
  270. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/session_preloader.py +0 -0
  271. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/subprojects.py +0 -0
  272. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/task_store.py +0 -0
  273. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/telemetry.py +0 -0
  274. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/text_index.py +0 -0
  275. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/time_tracker.py +0 -0
  276. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/tool_classifier.py +0 -0
  277. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/transcript_index.py +0 -0
  278. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/validation_cache.py +0 -0
  279. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/vector_store.py +0 -0
  280. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/watcher.py +0 -0
  281. {code_context_control-2.86.0 → code_context_control-2.88.2}/services/win_subprocess.py +0 -0
  282. {code_context_control-2.86.0 → code_context_control-2.88.2}/setup.cfg +0 -0
  283. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_builtin_optout.py +0 -0
  284. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_guard.py +0 -0
  285. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_guard_meta.py +0 -0
  286. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_guard_shell_project.py +0 -0
  287. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_guard_surfaces.py +0 -0
  288. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_access_guard_wiring.py +0 -0
  289. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_activity_reporter.py +0 -0
  290. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_agent_locks.py +0 -0
  291. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_aider_polyglot.py +0 -0
  292. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_antigravity_transition.py +0 -0
  293. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_artifact_store.py +0 -0
  294. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_artifact_tool.py +0 -0
  295. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_bitbucket_cli_smoke.py +0 -0
  296. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_bitbucket_client.py +0 -0
  297. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_bitbucket_config_fallback.py +0 -0
  298. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_bitbucket_credentials.py +0 -0
  299. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_bitbucket_tool.py +0 -0
  300. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_c3_bridge_project_artifacts.py +0 -0
  301. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_c3_shell.py +0 -0
  302. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_chat_poll.py +0 -0
  303. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_act.py +0 -0
  304. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_cache.py +0 -0
  305. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_expr.py +0 -0
  306. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_impact.py +0 -0
  307. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_intel.py +0 -0
  308. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_runner.py +0 -0
  309. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ci_workflow.py +0 -0
  310. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_circuit_breaker.py +0 -0
  311. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_claude_md_merge.py +0 -0
  312. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_cli_smoke.py +0 -0
  313. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_compressor_large_file.py +0 -0
  314. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_creds_cli_smoke.py +0 -0
  315. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_delegate_version_probe.py +0 -0
  316. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_e2e_benchmark.py +0 -0
  317. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_edit_ledger_deadline.py +0 -0
  318. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_edit_ledger_hook.py +0 -0
  319. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_edit_locking.py +0 -0
  320. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_edit_normalization.py +0 -0
  321. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_edit_verify.py +0 -0
  322. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_embedding_index_deadlock.py +0 -0
  323. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_enforcement_flip.py +0 -0
  324. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_enforcement_policy.py +0 -0
  325. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_enforcement_routes.py +0 -0
  326. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_federated_graph.py +0 -0
  327. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_filter_backoff.py +0 -0
  328. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ghost_files.py +0 -0
  329. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ghost_generation.py +0 -0
  330. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_git_branch_awareness.py +0 -0
  331. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_access_guard.py +0 -0
  332. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_codex_compat.py +0 -0
  333. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_dispatch.py +0 -0
  334. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_pretool_enforce.py +0 -0
  335. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_prompt_recall.py +0 -0
  336. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_smoke.py +0 -0
  337. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_state.py +0 -0
  338. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hook_utf8_stdio.py +0 -0
  339. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_credentials_route.py +0 -0
  340. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_enforcement_routes.py +0 -0
  341. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_inspect_api.py +0 -0
  342. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_locks_routes.py +0 -0
  343. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_server_smoke.py +0 -0
  344. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_hub_subproject_links.py +0 -0
  345. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ide_workflow_adaptation.py +0 -0
  346. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_init_scan.py +0 -0
  347. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_install_mcp_entrypoint.py +0 -0
  348. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_cli_smoke.py +0 -0
  349. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_client.py +0 -0
  350. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_config_fallback.py +0 -0
  351. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_credentials.py +0 -0
  352. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_links.py +0 -0
  353. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_routes.py +0 -0
  354. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_jira_tool.py +0 -0
  355. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_lazy_store_init.py +0 -0
  356. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mask_guard.py +0 -0
  357. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mask_routes.py +0 -0
  358. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mask_surfaces.py +0 -0
  359. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mcp_host_guard.py +0 -0
  360. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mcp_memory_timeout.py +0 -0
  361. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mcp_server_smoke.py +0 -0
  362. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mcp_toml.py +0 -0
  363. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_memory_distiller.py +0 -0
  364. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_memory_graph_api.py +0 -0
  365. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_memory_queue.py +0 -0
  366. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_memory_system.py +0 -0
  367. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mobile_api.py +0 -0
  368. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mobile_extras.py +0 -0
  369. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_mobile_override_routes.py +0 -0
  370. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_no_stale_model_pins.py +0 -0
  371. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_notification_dedup.py +0 -0
  372. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_notification_discipline.py +0 -0
  373. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_ollama_credentials.py +0 -0
  374. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_api_auth.py +0 -0
  375. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_apikey_api.py +0 -0
  376. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_c3_bridge.py +0 -0
  377. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_chat_engine.py +0 -0
  378. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_chat_store.py +0 -0
  379. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_discovery_api.py +0 -0
  380. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_discovery_audit.py +0 -0
  381. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_local_auth.py +0 -0
  382. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_ollama_bridge.py +0 -0
  383. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_scanner_cache.py +0 -0
  384. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_security_fixes.py +0 -0
  385. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_subproject_awareness.py +0 -0
  386. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_oracle_ui_bundle.py +0 -0
  387. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_output_filter.py +0 -0
  388. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_override_grants.py +0 -0
  389. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_override_grants_mcp.py +0 -0
  390. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_override_requests.py +0 -0
  391. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_override_wake.py +0 -0
  392. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_permissions.py +0 -0
  393. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_pm_api.py +0 -0
  394. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_project_manager.py +0 -0
  395. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_project_manager_merge.py +0 -0
  396. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_project_tool.py +0 -0
  397. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_read_coercion.py +0 -0
  398. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_read_edit_parity.py +0 -0
  399. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_related_facts.py +0 -0
  400. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_repo_map.py +0 -0
  401. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_response_boilerplate.py +0 -0
  402. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_retention.py +0 -0
  403. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_review_digest.py +0 -0
  404. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_service_durability.py +0 -0
  405. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_session_benchmark.py +0 -0
  406. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_session_budget.py +0 -0
  407. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_shell_robustness.py +0 -0
  408. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_subproject_exclusion.py +0 -0
  409. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_subproject_federation.py +0 -0
  410. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_subprojects.py +0 -0
  411. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_swe_bench.py +0 -0
  412. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_task_store.py +0 -0
  413. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_task_tool.py +0 -0
  414. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_time_tracker.py +0 -0
  415. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_token_telemetry.py +0 -0
  416. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_tool_registry.py +0 -0
  417. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_upgrade_and_version.py +0 -0
  418. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_vault_write_guard.py +0 -0
  419. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_version_sync.py +0 -0
  420. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_web_security.py +0 -0
  421. {code_context_control-2.86.0 → code_context_control-2.88.2}/tests/test_windows_reliability.py +0 -0
  422. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/__init__.py +0 -0
  423. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/backend.py +0 -0
  424. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/main.py +0 -0
  425. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/__init__.py +0 -0
  426. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/benchmark_view.py +0 -0
  427. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/claudemd_view.py +0 -0
  428. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/compress_view.py +0 -0
  429. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/index_view.py +0 -0
  430. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/init_view.py +0 -0
  431. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/mcp_view.py +0 -0
  432. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/optimize_view.py +0 -0
  433. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/pipe_view.py +0 -0
  434. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/projects_view.py +0 -0
  435. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/search_view.py +0 -0
  436. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/session_view.py +0 -0
  437. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/stats.py +0 -0
  438. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/screens/ui_view.py +0 -0
  439. {code_context_control-2.86.0 → code_context_control-2.88.2}/tui/theme.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.86.0
3
+ Version: 2.88.2
4
4
  Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
92
92
  # Config
93
93
  CONFIG_DIR = ".c3"
94
94
  CONFIG_FILE = ".c3/config.json"
95
- __version__ = "2.86.0"
95
+ __version__ = "2.88.2"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -5899,7 +5899,7 @@ def cmd_creds(args):
5899
5899
  """Credential vault management (global + per-project scopes)."""
5900
5900
  sub = getattr(args, "creds_cmd", None)
5901
5901
  if not sub:
5902
- print("Usage: c3 creds {set,get,list,rm,import} [args]")
5902
+ print("Usage: c3 creds {set,get,list,rm,import,usage} [args]")
5903
5903
  return
5904
5904
 
5905
5905
  project_path = getattr(args, "project_path", ".") or "."
@@ -5914,6 +5914,8 @@ def cmd_creds(args):
5914
5914
  _creds_cmd_rm(args, project_path)
5915
5915
  elif sub == "import":
5916
5916
  _creds_cmd_import(args, project_path)
5917
+ elif sub == "usage":
5918
+ _creds_cmd_usage(args, project_path)
5917
5919
  else:
5918
5920
  print(f"Unknown creds subcommand: {sub}")
5919
5921
 
@@ -5928,6 +5930,9 @@ def _creds_entry_line(name: str, entry: dict) -> str:
5928
5930
  f"{name:<24} {entry.get('scope', '?'):<8} {entry.get('type', 'token'):<10}"
5929
5931
  f" len={entry.get('value_len', '?')}",
5930
5932
  ]
5933
+ display = entry.get("display") or {}
5934
+ if display:
5935
+ parts.append(" ".join(str(v) for v in display.values() if v))
5931
5936
  if entry.get("env_var"):
5932
5937
  parts.append(f"env_var={entry['env_var']}")
5933
5938
  if flags:
@@ -5937,16 +5942,49 @@ def _creds_entry_line(name: str, entry: dict) -> str:
5937
5942
  return " ".join(parts)
5938
5943
 
5939
5944
 
5945
+ _CREDS_HIDDEN_FIELDS = {"number", "cvc", "ssn"} # prompted via getpass
5946
+
5947
+
5948
+ def _creds_prompt_structured(name: str, ctype: str) -> str:
5949
+ """Interactive per-field prompt for a structured entry; returns JSON.
5950
+ Sensitive fields use a hidden prompt; empty optional fields are skipped."""
5951
+ import getpass
5952
+ import json as _json
5953
+
5954
+ from services import credential_store as cred_store
5955
+
5956
+ required, optional = cred_store.schema_fields(ctype)
5957
+ print(f"Enter {ctype} fields for '{name}' "
5958
+ "(optional fields: press Enter to skip):")
5959
+ fields: dict = {}
5960
+ for fname in list(required) + list(optional):
5961
+ tag = "" if fname in required else " (optional)"
5962
+ if fname in _CREDS_HIDDEN_FIELDS:
5963
+ raw = getpass.getpass(f" {fname}{tag}: ")
5964
+ else:
5965
+ raw = input(f" {fname}{tag}: ")
5966
+ if raw.strip():
5967
+ fields[fname] = raw.strip()
5968
+ return _json.dumps(fields)
5969
+
5970
+
5940
5971
  def _creds_cmd_set(args, project_path: str) -> None:
5941
5972
  import getpass
5942
5973
 
5943
5974
  from services import credential_store as cred_store
5944
5975
 
5976
+ ctype = getattr(args, "ctype", "token") or "token"
5945
5977
  value = getattr(args, "value", "") or ""
5946
5978
  if getattr(args, "stdin", False):
5947
5979
  value = sys.stdin.read().rstrip("\n")
5948
5980
  if not value:
5949
- value = getpass.getpass(f"Value for {args.name}: ")
5981
+ if ctype in cred_store.STRUCTURED_TYPES:
5982
+ value = _creds_prompt_structured(args.name, ctype)
5983
+ if value == "{}":
5984
+ print("Cancelled -- no fields entered.")
5985
+ return
5986
+ else:
5987
+ value = getpass.getpass(f"Value for {args.name}: ")
5950
5988
  if not value:
5951
5989
  print("Cancelled -- value required.")
5952
5990
  return
@@ -5956,7 +5994,7 @@ def _creds_cmd_set(args, project_path: str) -> None:
5956
5994
  args.name, value,
5957
5995
  scope=scope, project_path=project_path,
5958
5996
  description=getattr(args, "desc", "") or "",
5959
- ctype=getattr(args, "ctype", "token") or "token",
5997
+ ctype=ctype,
5960
5998
  env_var=getattr(args, "env_var", "") or "",
5961
5999
  agent_readable=bool(getattr(args, "agent_readable", False)),
5962
6000
  inject=bool(getattr(args, "inject", False)),
@@ -5971,6 +6009,19 @@ def _creds_cmd_set(args, project_path: str) -> None:
5971
6009
  "into its context and transcripts.")
5972
6010
 
5973
6011
 
6012
+ def _creds_count_show(refs, project_path: str) -> None:
6013
+ """Count a terminal --show like any other use: state counter + history."""
6014
+ from services import credential_store as cred_store
6015
+ try:
6016
+ cred_store.touch_last_used(
6017
+ sorted({str(r).partition(".")[0] for r in refs}), project_path)
6018
+ from services import cred_telemetry as ct
6019
+ ct.record_use(refs, project_path=project_path,
6020
+ action=ct.ACTION_CLI_SHOW, surface="cli")
6021
+ except Exception:
6022
+ pass
6023
+
6024
+
5974
6025
  def _creds_cmd_get(args, project_path: str) -> None:
5975
6026
  from services import credential_store as cred_store
5976
6027
 
@@ -5981,11 +6032,46 @@ def _creds_cmd_get(args, project_path: str) -> None:
5981
6032
  print(_creds_entry_line(args.name, entry))
5982
6033
  print(f"storage={entry.get('storage', 'keyring')} "
5983
6034
  f"created={entry.get('created', '?')} updated={entry.get('updated', '?')}")
5984
- fp = cred_store.fingerprint(args.name, project_path=project_path)
5985
- print(f"fingerprint={fp or 'unresolvable'}")
5986
- if getattr(args, "show", False):
5987
- value = cred_store.get_value(args.name, project_path=project_path)
5988
- print(value if value is not None else "[error] value missing from store")
6035
+ stype = cred_store.structured_type(args.name, project_path=project_path)
6036
+ field = (getattr(args, "field", "") or "").strip()
6037
+ if not stype:
6038
+ fp = cred_store.fingerprint(args.name, project_path=project_path)
6039
+ print(f"fingerprint={fp or 'unresolvable'}")
6040
+ if field:
6041
+ print(f"[error] '{args.name}' is not structured -- --field does not apply")
6042
+ return
6043
+ if getattr(args, "show", False):
6044
+ value = cred_store.get_value(args.name, project_path=project_path)
6045
+ print(value if value is not None
6046
+ else "[error] value missing from store")
6047
+ if value is not None:
6048
+ _creds_count_show([args.name], project_path)
6049
+ return
6050
+ print(f"fields: {', '.join(entry.get('fields') or []) or 'none recorded'}")
6051
+ if not getattr(args, "show", False):
6052
+ if field:
6053
+ print("[hint] add --show to print the field value")
6054
+ return
6055
+ # --show: the deliberate human read-back path (terminal only; the wire
6056
+ # never carries these values). Counted as usage like any other reveal.
6057
+ if field:
6058
+ value = cred_store.get_value(args.name, project_path=project_path,
6059
+ field=field)
6060
+ if value is None:
6061
+ print(f"[error] no field '{field}' on '{args.name}'")
6062
+ return
6063
+ print(value)
6064
+ _creds_count_show([f"{args.name}.{field}"], project_path)
6065
+ else:
6066
+ fields = cred_store.get_structured_fields(
6067
+ args.name, project_path=project_path)
6068
+ if fields is None:
6069
+ print("[error] value missing from store")
6070
+ return
6071
+ width = max(len(k) for k in fields)
6072
+ for key in sorted(fields):
6073
+ print(f"{key:<{width}} {fields[key]}")
6074
+ _creds_count_show([args.name], project_path)
5989
6075
 
5990
6076
 
5991
6077
  def _creds_cmd_list(args, project_path: str) -> None:
@@ -6039,6 +6125,39 @@ def _creds_cmd_import(args, project_path: str) -> None:
6039
6125
  "(use --overwrite to replace)")
6040
6126
 
6041
6127
 
6128
+ def _creds_cmd_usage(args, project_path: str) -> None:
6129
+ import json as _json
6130
+
6131
+ from services import cred_telemetry as ct
6132
+
6133
+ name = getattr(args, "name", "") or ""
6134
+ limit = max(1, int(getattr(args, "limit", 20) or 20))
6135
+ agg = ct.aggregate(project_path, name=name)
6136
+ recent = ct.search_events(project_path, name=name, limit=limit)
6137
+ if getattr(args, "as_json", False):
6138
+ print(_json.dumps({"aggregate": agg, "recent": recent}, indent=2))
6139
+ return
6140
+ if not agg["total"]:
6141
+ target = f" for '{name}'" if name else ""
6142
+ print(f"No recorded credential uses{target} yet.")
6143
+ return
6144
+ surf = " ".join(f"{s}:{c}" for s, c in sorted(agg["by_surface"].items()))
6145
+ print(f"{agg['total']} use(s) across {len(agg['rows'])} credential(s)"
6146
+ f" [{surf}]")
6147
+ for row in agg["rows"]:
6148
+ fields = f" fields: {', '.join(row['fields'])}" if row["fields"] else ""
6149
+ print(f" {row['name']:<24} {row['hits']:>4}x last {row['last_ts'] or '?'}"
6150
+ f" projects={row['projects']}{fields}")
6151
+ print(f"recent (newest first, {len(recent['events'])}"
6152
+ f"/{recent['matched']}):")
6153
+ for e in recent["events"]:
6154
+ ref = e["name"] + (f".{e['field']}" if e.get("field") else "")
6155
+ exit_part = f" exit={e['exit']}" if "exit" in e else ""
6156
+ cmd_part = f" {e['cmd']}" if e.get("cmd") else ""
6157
+ print(f" {e.get('ts', '?')} {e.get('action', '?'):<10} {ref:<28}"
6158
+ f" [{e.get('surface', '?')}]{exit_part}{cmd_part}")
6159
+
6160
+
6042
6161
  def cmd_ci(args):
6043
6162
  """AgentCI entry point — exits with the finding.
6044
6163
 
@@ -417,9 +417,14 @@ def build_parser(version: str, parse_cli_ide_arg):
417
417
  "set", help="Create or update a credential (value via hidden prompt)"
418
418
  )
419
419
  cr_set.add_argument("name", help="Entry name (env-var safe: [A-Za-z_][A-Za-z0-9_]*)")
420
- cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred)")
420
+ cr_set.add_argument("--value", default="", help="Secret value (prompted via getpass if omitted — preferred). Structured types take a JSON object of fields")
421
421
  cr_set.add_argument("--stdin", action="store_true", help="Read the value from stdin (piped/multiline values)")
422
- cr_set.add_argument("--type", dest="ctype", choices=["token", "env", "multiline"], default="token", help="Entry type")
422
+ cr_set.add_argument("--type", dest="ctype",
423
+ choices=["token", "env", "multiline",
424
+ "address", "identity", "card"],
425
+ default="token",
426
+ help="Entry type; address/identity/card are structured "
427
+ "(field payload, inject-only, never revealable to the agent)")
423
428
  cr_set.add_argument("--desc", default="", help="Human description shown in list/UI")
424
429
  cr_set.add_argument("--env-var", default="", help="Env var name used at injection (default: entry name)")
425
430
  cr_set.add_argument("--agent-readable", action="store_true", help="Allow the agent to reveal the decoded value into its context (default: injection-only)")
@@ -432,6 +437,7 @@ def build_parser(version: str, parse_cli_ide_arg):
432
437
  cr_get = creds_subs.add_parser("get", help="Show entry metadata (masked; --show prints the value)")
433
438
  cr_get.add_argument("name")
434
439
  cr_get.add_argument("--show", action="store_true", help="Print the decoded value to the terminal")
440
+ cr_get.add_argument("--field", default="", help="For structured entries: limit --show to one field (e.g. number)")
435
441
  cr_get.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
436
442
 
437
443
  cr_list = creds_subs.add_parser("list", help="List credentials visible to this project")
@@ -448,6 +454,13 @@ def build_parser(version: str, parse_cli_ide_arg):
448
454
  cr_import.add_argument("--overwrite", action="store_true", help="Replace entries already registered in the target scope")
449
455
  cr_import.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
450
456
 
457
+ cr_usage = creds_subs.add_parser(
458
+ "usage", help="Usage history — when, where, and how often credentials were used")
459
+ cr_usage.add_argument("name", nargs="?", default="", help="Limit to one credential (default: all)")
460
+ cr_usage.add_argument("--limit", type=int, default=20, help="Recent events to show (default: 20)")
461
+ cr_usage.add_argument("--json", dest="as_json", action="store_true", help="Emit raw JSON")
462
+ cr_usage.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
463
+
451
464
  # ── Agent Locks (docs/agent-locks.md) ───────────────────────────────
452
465
  # force-release is human-only: it bumps the fencing counter so a holder
453
466
  # that comes back is stale by construction. Agents get c3_locks instead,
@@ -105,11 +105,13 @@
105
105
  <a href="#storage" class="sidebar-link"><span class="icon">🗄️</span> Where values live</a>
106
106
  <a href="#scopes" class="sidebar-link"><span class="icon">🌍</span> Scopes &amp; overriding</a>
107
107
  <a href="#agent-use" class="sidebar-link"><span class="icon">🤖</span> How agents use them</a>
108
+ <a href="#structured" class="sidebar-link"><span class="icon">💳</span> Structured kinds</a>
108
109
  <a href="#exposure" class="sidebar-link"><span class="icon">⚠️</span> Exposure flags</a>
109
110
  <a href="#hub-ui" class="sidebar-link"><span class="icon">🖥️</span> Hub UI</a>
110
111
  <a href="#search" class="sidebar-link"><span class="icon">🔎</span> Search &amp; qualifiers</a>
111
112
  <a href="#cli" class="sidebar-link"><span class="icon">💻</span> CLI commands</a>
112
113
  <a href="#actions" class="sidebar-link"><span class="icon">⚙️</span> Tool actions</a>
114
+ <a href="#usage" class="sidebar-link"><span class="icon">📊</span> Usage history</a>
113
115
  <a href="#audit" class="sidebar-link"><span class="icon">📝</span> Audit trail</a>
114
116
  <a href="#troubleshooting" class="sidebar-link"><span class="icon">🛠️</span> Troubleshooting</a>
115
117
  </div>
@@ -293,6 +295,48 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
293
295
 
294
296
  <hr class="divider">
295
297
 
298
+ <!-- ═══════════════════════════════════ STRUCTURED ═══ -->
299
+ <section id="structured" class="tool-section">
300
+ <h2>Structured kinds — cards, addresses, identity (v2.87.0)</h2>
301
+
302
+ <p>Three entry types hold <strong>named fields</strong> instead of one opaque value:
303
+ <code>card</code> (cardholder, number, expiry, optional cvc/billing_zip — Luhn-checked),
304
+ <code>address</code> (street1, city, state, zip, optional recipient/street2/country/phone) and
305
+ <code>identity</code> (full_name, optional dob/ssn/phone/email). The payload is stored as one
306
+ canonical JSON object through the same keyring / encrypted-sidecar path as any other value.</p>
307
+
308
+ <p>They are <strong>inject-only by construction</strong>, which is stricter than a normal secret:</p>
309
+ <ul>
310
+ <li><strong>Reveal is permanently disabled</strong> — <code>agent_readable</code> and
311
+ <code>inject</code> are refused at every surface, for every caller, forever. There is no flag to flip.</li>
312
+ <li><strong>Only single fields cross the boundary.</strong> The agent addresses a field —
313
+ <code>env_creds='CARD.number'</code> (exported as <code>$CARD_NUMBER</code>) or
314
+ <code>{{cred:CARD.number}}</code> inline — and a bare <code>{{cred:CARD}}</code> fails with
315
+ the field list rather than expanding the whole payload.</li>
316
+ <li><strong>The registry shows a projection, not the data.</strong> Lists and the UI display
317
+ <code>visa ••••4242</code> for a card (brand + last4, deliberately <em>not</em> expiry),
318
+ city/state for an address, the name for an identity. Field <em>names</em> are public;
319
+ field <em>values</em> never transit any HTTP response — a sweep test enforces this.</li>
320
+ <li><strong>Echoes redact per field</strong> to <code>[cred:NAME.field]</code>. Caveat: the
321
+ redactor only tracks values of 4+ characters, so a 3-digit CVC or 2-letter state that a
322
+ child process echoes cannot be scrubbed after the fact. The real guarantee remains
323
+ decode-at-the-subprocess-boundary; redaction is the belt over it.</li>
324
+ <li><strong>The type boundary is immutable.</strong> A card cannot be rewritten into a
325
+ plain token (or vice versa) by <code>set</code>, metadata update, or <code>.env</code>
326
+ import — delete and re-create is the only path across, and a keyring attestation keeps an
327
+ entry structured even if <code>.c3/config.json</code> is edited by hand.</li>
328
+ </ul>
329
+
330
+ <p>Updating one field never requires retyping the rest: a partial payload
331
+ <strong>merges</strong> (<code>{"expiry": "01/30"}</code> updates the expiry, JSON
332
+ <code>null</code> deletes an optional field). Read-back for <em>you</em> is terminal-only:
333
+ <code>c3 creds get NAME --show</code> (all fields) or <code>--show --field number</code> —
334
+ the browser and the mobile gateway never carry the values, and mobile cannot create
335
+ structured entries at all.</p>
336
+ </section>
337
+
338
+ <hr class="divider">
339
+
296
340
  <!-- ═══════════════════════════════════════ EXPOSURE ═══ -->
297
341
  <section id="exposure" class="tool-section">
298
342
  <h2>Exposure flags</h2>
@@ -478,6 +522,42 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
478
522
  <hr class="divider">
479
523
 
480
524
  <!-- ═══════════════════════════════════════ AUDIT ═══ -->
525
+ <section id="usage" class="tool-section">
526
+ <h2>Usage history (v2.88.0)</h2>
527
+
528
+ <p>Every time a value leaves the vault — an <code>env_creds</code> injection, a
529
+ <code>{{cred:NAME}}</code> expansion, a gated reveal, a terminal
530
+ <code>c3 creds get --show</code> — one event is appended to the owning scope's
531
+ <code>.c3/cred_usage.jsonl</code>: timestamp, name (and field for structured entries),
532
+ action, surface, project, exit code, and the command in its <strong>raw template
533
+ form</strong>, capped at 120 characters. Never the expanded string, never a value.
534
+ A global credential's usage from every project lands in <code>~/.c3</code>, so its
535
+ history is complete in one place.</p>
536
+
537
+ <p>Reading it back:</p>
538
+ <ul>
539
+ <li><strong>UI</strong> — the Credentials tab's <em>usage</em> sub-view (totals,
540
+ per-credential counts by surface, expandable recent events) and the hub drawer's
541
+ “Usage &amp; relationships” section.</li>
542
+ <li><strong>CLI</strong> — <code>c3 creds usage [NAME] [--limit N] [--json]</code>.</li>
543
+ <li><strong>Agent</strong> — <code>c3_credentials(action='usage')</code>. Scoped on
544
+ purpose: the agent sees full events (including command previews) only for the
545
+ <em>current</em> project; other projects' use of a shared global credential is
546
+ reduced to counts, so one project's agent cannot read another's command lines
547
+ through the vault. Your surfaces (UI/CLI) show everything.</li>
548
+ <li><strong>REST</strong> — <code>GET /api/credentials/usage</code> and
549
+ <code>GET /api/credentials/&lt;name&gt;/usage</code> (hub:
550
+ <code>/api/projects/credentials/usage</code>).</li>
551
+ </ul>
552
+
553
+ <p>The log rotates at 512KB (one <code>.1</code> generation retained), both filenames
554
+ are vault-write-protected and gitignored, and the lightweight
555
+ <code>last_used</code>/<code>use_count</code> counters you already see on list rows
556
+ keep working exactly as before — they are the summary; this is the history.</p>
557
+ </section>
558
+
559
+ <hr class="divider">
560
+
481
561
  <section id="audit" class="tool-section">
482
562
  <h2>Audit trail</h2>
483
563
 
@@ -113,7 +113,8 @@ _WRITE_CLASS_ALWAYS = frozenset({"Edit", "Write", "MultiEdit"})
113
113
  # Vault files no native write may touch, regardless of unlock state.
114
114
  # Mirrors services.credential_store.VAULT_PROTECTED_FILES (parity-tested);
115
115
  # duplicated because hooks must stay import-light.
116
- _VAULT_FILES = frozenset({"config.json", "secrets.enc", "cred_state.json"})
116
+ _VAULT_FILES = frozenset({"config.json", "secrets.enc", "cred_state.json",
117
+ "cred_usage.jsonl", "cred_usage.jsonl.1"})
117
118
 
118
119
  # Redirect messages per native tool
119
120
  _REDIRECTS = {
@@ -2026,7 +2026,9 @@ def api_projects_credentials_set():
2026
2026
  str(data.get("path") or "").strip(), scope, mutation=True)
2027
2027
  if err:
2028
2028
  return err
2029
- value = str(data.get("value") or "")
2029
+ value = data.get("value")
2030
+ # Structured kinds submit a field OBJECT; the store takes JSON text.
2031
+ value = json.dumps(value) if isinstance(value, dict) else str(value or "")
2030
2032
  ctype = str(data.get("type") or data.get("ctype") or "token")
2031
2033
  try:
2032
2034
  if value:
@@ -2123,11 +2125,40 @@ def api_projects_credentials_check(name):
2123
2125
  "name": name,
2124
2126
  "scope": entry["scope"],
2125
2127
  "storage": entry.get("storage", "keyring"),
2126
- "resolvable": cred_store.get_value(name, project_path=store_path) is not None,
2128
+ # is_resolvable, not get_value: a structured entry never resolves
2129
+ # whole, but its payload being decodable is what "check" asks.
2130
+ "resolvable": cred_store.is_resolvable(name, project_path=store_path),
2127
2131
  "fingerprint": cred_store.fingerprint(name, project_path=store_path),
2128
2132
  })
2129
2133
 
2130
2134
 
2135
+ @app.route("/api/projects/credentials/usage", methods=["GET"])
2136
+ def api_projects_credentials_usage():
2137
+ """Usage history — `path` scopes to a project (merged view); omit it for
2138
+ the global vault only. `name` filters to one credential. Names, counts
2139
+ and cmd previews only; never values."""
2140
+ from services import cred_telemetry as ct
2141
+ from services import credential_store as cred_store
2142
+ path = (request.args.get("path") or "").strip()
2143
+ if path:
2144
+ try:
2145
+ base = str(_resolve_project_path(path))
2146
+ except ValueError as e:
2147
+ return jsonify({"error": str(e)}), 404
2148
+ else:
2149
+ home = cred_store.global_base()
2150
+ if home is None:
2151
+ return jsonify({"error": "global scope unresolvable"}), 500
2152
+ base = str(home)
2153
+ name = (request.args.get("name") or "").strip()
2154
+ return jsonify({
2155
+ "path": base if path else "",
2156
+ "aggregate": ct.aggregate(base, name=name),
2157
+ "recent": ct.search_events(base, name=name,
2158
+ limit=request.args.get("limit", 100)),
2159
+ })
2160
+
2161
+
2131
2162
  @app.route("/api/hub/credentials/overview", methods=["GET"])
2132
2163
  def api_hub_credentials_overview():
2133
2164
  """Cross-project credential inventory: the global vault plus each
@@ -182,8 +182,8 @@ function DrillPanel({ project, tab, setTab, onClose, onChanged, onOpenModal, pro
182
182
  </button>
183
183
  </div>
184
184
  <div style={{
185
- display: 'flex', gap: 2, padding: '4px 20px 0',
186
- borderBottom: `1px solid ${T.border}`, overflowX: 'auto', flexShrink: 0,
185
+ display: 'flex', flexWrap: 'wrap', gap: 2, padding: '4px 20px 0',
186
+ borderBottom: `1px solid ${T.border}`, flexShrink: 0,
187
187
  }}>
188
188
  {tabs.map(([id, label]) => (
189
189
  <button key={id} onClick={() => setTab(id)} style={{