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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. {code_context_control-2.85.0/code_context_control.egg-info → code_context_control-2.86.0}/PKG-INFO +3 -2
  2. {code_context_control-2.85.0 → code_context_control-2.86.0}/README.md +2 -1
  3. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/c3.py +19 -1
  4. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_access_guard.py +25 -3
  5. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_server.py +14 -0
  6. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/mcp_server.py +3 -1
  7. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/server.py +14 -0
  8. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/shell.py +56 -0
  9. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/tasks.py +22 -1
  10. {code_context_control-2.85.0 → code_context_control-2.86.0/code_context_control.egg-info}/PKG-INFO +3 -2
  11. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/mobile_api.py +14 -0
  12. {code_context_control-2.85.0 → code_context_control-2.86.0}/pyproject.toml +1 -1
  13. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/access_guard.py +27 -0
  14. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/scanner.py +35 -0
  15. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/task_store.py +63 -0
  16. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard.py +72 -0
  17. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_c3_shell.py +101 -0
  18. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_access_guard.py +30 -0
  19. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_init_scan.py +76 -0
  20. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_pm_api.py +25 -0
  21. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_task_store.py +45 -0
  22. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_task_tool.py +13 -0
  23. {code_context_control-2.85.0 → code_context_control-2.86.0}/LICENSE +0 -0
  24. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/__init__.py +0 -0
  25. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/_hook_utils.py +0 -0
  26. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/__init__.py +0 -0
  27. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/common.py +0 -0
  28. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/commands/parser.py +0 -0
  29. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/docs.html +0 -0
  30. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/edits.html +0 -0
  31. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/access.html +0 -0
  32. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/bitbucket.html +0 -0
  33. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/credentials.html +0 -0
  34. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/getting-started.html +0 -0
  35. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/index.html +0 -0
  36. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/masking.html +0 -0
  37. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/oracle.html +0 -0
  38. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/shared.css +0 -0
  39. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/tools.html +0 -0
  40. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/guide/workflow.html +0 -0
  41. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_artifact.py +0 -0
  42. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_auto_snapshot.py +0 -0
  43. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_c3_signal.py +0 -0
  44. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_c3read.py +0 -0
  45. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_dispatch.py +0 -0
  46. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_edit_ledger.py +0 -0
  47. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_edit_unlock.py +0 -0
  48. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_filter.py +0 -0
  49. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_ghost_files.py +0 -0
  50. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_pretool_enforce.py +0 -0
  51. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_prompt_recall.py +0 -0
  52. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_read.py +0 -0
  53. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_session_stats.py +0 -0
  54. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hook_terse_advisor.py +0 -0
  55. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/app.js +0 -0
  56. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/add_project.js +0 -0
  57. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/config_editor.js +0 -0
  58. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  59. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_health.js +0 -0
  60. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_panel.js +0 -0
  61. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  62. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  63. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/drill_views.js +0 -0
  64. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/global_search.js +0 -0
  65. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_ci.js +0 -0
  66. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  67. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  68. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/hub_locks.js +0 -0
  69. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  70. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/modals.js +0 -0
  71. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/project_card.js +0 -0
  72. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/project_tree.js +0 -0
  73. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/session_drawer.js +0 -0
  74. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/settings_modal.js +0 -0
  75. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/sidebar.js +0 -0
  76. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/summary_bar.js +0 -0
  77. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/task_board.js +0 -0
  78. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/toasts.js +0 -0
  79. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/components/topbar.js +0 -0
  80. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui/state.js +0 -0
  81. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/hub_ui.html +0 -0
  82. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/mcp_proxy.py +0 -0
  83. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/progress.py +0 -0
  84. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/__init__.py +0 -0
  85. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/_grants.py +0 -0
  86. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/_helpers.py +0 -0
  87. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/agent.py +0 -0
  88. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/artifacts.py +0 -0
  89. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/bitbucket.py +0 -0
  90. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/ci.py +0 -0
  91. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/compress.py +0 -0
  92. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/credentials.py +0 -0
  93. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/delegate.py +0 -0
  94. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edit.py +0 -0
  95. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edit_verify.py +0 -0
  96. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/edits.py +0 -0
  97. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/federate.py +0 -0
  98. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/filter.py +0 -0
  99. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/impact.py +0 -0
  100. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/jira.py +0 -0
  101. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/locks.py +0 -0
  102. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/memory.py +0 -0
  103. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/override.py +0 -0
  104. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/project.py +0 -0
  105. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/read.py +0 -0
  106. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/search.py +0 -0
  107. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/session.py +0 -0
  108. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/status.py +0 -0
  109. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/tools/validate.py +0 -0
  110. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/api.js +0 -0
  111. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/app.js +0 -0
  112. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/access.js +0 -0
  113. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/bitbucket.js +0 -0
  114. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/chat.js +0 -0
  115. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/credentials.js +0 -0
  116. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/dashboard.js +0 -0
  117. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/edits.js +0 -0
  118. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/enforcement.js +0 -0
  119. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/instructions.js +0 -0
  120. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/jira.js +0 -0
  121. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/memory.js +0 -0
  122. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/sessions.js +0 -0
  123. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/settings.js +0 -0
  124. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/sidebar.js +0 -0
  125. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/components/tasks.js +0 -0
  126. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/icons.js +0 -0
  127. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/pm_shared.js +0 -0
  128. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/shared.js +0 -0
  129. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui/theme.js +0 -0
  130. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui.html +0 -0
  131. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui_legacy.html +0 -0
  132. {code_context_control-2.85.0 → code_context_control-2.86.0}/cli/ui_nano.html +0 -0
  133. {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/SOURCES.txt +0 -0
  134. {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  135. {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/entry_points.txt +0 -0
  136. {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/requires.txt +0 -0
  137. {code_context_control-2.85.0 → code_context_control-2.86.0}/code_context_control.egg-info/top_level.txt +0 -0
  138. {code_context_control-2.85.0 → code_context_control-2.86.0}/core/__init__.py +0 -0
  139. {code_context_control-2.85.0 → code_context_control-2.86.0}/core/config.py +0 -0
  140. {code_context_control-2.85.0 → code_context_control-2.86.0}/core/ide.py +0 -0
  141. {code_context_control-2.85.0 → code_context_control-2.86.0}/core/mcp_toml.py +0 -0
  142. {code_context_control-2.85.0 → code_context_control-2.86.0}/core/web_security.py +0 -0
  143. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/__init__.py +0 -0
  144. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/config.py +0 -0
  145. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/mcp_oracle.py +0 -0
  146. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/oracle_server.py +0 -0
  147. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/oracle_ui.html +0 -0
  148. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/__init__.py +0 -0
  149. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/activity_reporter.py +0 -0
  150. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/api_auth.py +0 -0
  151. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/c3_bridge.py +0 -0
  152. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_engine.py +0 -0
  153. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_poll.py +0 -0
  154. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/chat_store.py +0 -0
  155. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/cross_memory.py +0 -0
  156. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/discovery_audit.py +0 -0
  157. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/federated_graph.py +0 -0
  158. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/health_checker.py +0 -0
  159. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/insight_engine.py +0 -0
  160. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/local_session.py +0 -0
  161. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/memory_reader.py +0 -0
  162. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/memory_writer.py +0 -0
  163. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/project_scanner.py +0 -0
  164. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/review_agent.py +0 -0
  165. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/tool_executor.py +0 -0
  166. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/services/tool_registry.py +0 -0
  167. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/activity.js +0 -0
  168. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/agents.js +0 -0
  169. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/app.js +0 -0
  170. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/busy.js +0 -0
  171. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/conversations.js +0 -0
  172. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/input.js +0 -0
  173. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/markdown.js +0 -0
  174. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/send.js +0 -0
  175. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/stream_renderer.js +0 -0
  176. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/chat/toolbar.js +0 -0
  177. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/core.js +0 -0
  178. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/crossgraph.js +0 -0
  179. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/header.js +0 -0
  180. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/insights.js +0 -0
  181. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/projects.js +0 -0
  182. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/qrcode.js +0 -0
  183. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/settings.js +0 -0
  184. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/suggestions.js +0 -0
  185. {code_context_control-2.85.0 → code_context_control-2.86.0}/oracle/ui/theme_tabs.js +0 -0
  186. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/__init__.py +0 -0
  187. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/access_telemetry.py +0 -0
  188. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/activity_log.py +0 -0
  189. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agent_base.py +0 -0
  190. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agent_locks.py +0 -0
  191. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/agents.py +0 -0
  192. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/artifact_defs.py +0 -0
  193. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/artifact_store.py +0 -0
  194. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/auto_memory.py +0 -0
  195. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/__init__.py +0 -0
  196. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/__init__.py +0 -0
  197. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/aider_polyglot.py +0 -0
  198. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bench/external/swe_bench.py +0 -0
  199. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/benchmark_dashboard.py +0 -0
  200. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bitbucket_client.py +0 -0
  201. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/bitbucket_credentials.py +0 -0
  202. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_act.py +0 -0
  203. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_cache.py +0 -0
  204. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_expr.py +0 -0
  205. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_failures.py +0 -0
  206. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_github.py +0 -0
  207. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_impact.py +0 -0
  208. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_intel.py +0 -0
  209. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_runner.py +0 -0
  210. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ci_workflow.py +0 -0
  211. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/circuit_breaker.py +0 -0
  212. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/claude_md.py +0 -0
  213. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/compressor.py +0 -0
  214. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/context_snapshot.py +0 -0
  215. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/conversation_store.py +0 -0
  216. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/credential_store.py +0 -0
  217. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/doc_index.py +0 -0
  218. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_benchmark.py +0 -0
  219. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_evaluator.py +0 -0
  220. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/e2e_tasks.py +0 -0
  221. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/edit_ledger.py +0 -0
  222. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/embedding_index.py +0 -0
  223. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/enforcement_policy.py +0 -0
  224. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/error_reporting.py +0 -0
  225. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/file_memory.py +0 -0
  226. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/git_context.py +0 -0
  227. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/hub_service.py +0 -0
  228. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/indexer.py +0 -0
  229. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_client.py +0 -0
  230. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_cloud.py +0 -0
  231. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_credentials.py +0 -0
  232. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_data_center.py +0 -0
  233. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/jira_links.py +0 -0
  234. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_activation.py +0 -0
  235. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_mirror.py +0 -0
  236. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/mask_presets.py +0 -0
  237. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory.py +0 -0
  238. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_consolidator.py +0 -0
  239. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_distiller.py +0 -0
  240. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_graph.py +0 -0
  241. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_grounder.py +0 -0
  242. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_queue.py +0 -0
  243. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/memory_scorer.py +0 -0
  244. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/metrics.py +0 -0
  245. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/notifications.py +0 -0
  246. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_bridge.py +0 -0
  247. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_client.py +0 -0
  248. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/ollama_credentials.py +0 -0
  249. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/output_filter.py +0 -0
  250. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_grants.py +0 -0
  251. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_policy.py +0 -0
  252. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_requests.py +0 -0
  253. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/override_wake.py +0 -0
  254. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/parser.py +0 -0
  255. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/project_manager.py +0 -0
  256. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/project_runtime.py +0 -0
  257. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/protocol.py +0 -0
  258. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/proxy_state.py +0 -0
  259. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/repo_map.py +0 -0
  260. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/retention.py +0 -0
  261. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/retrieval_broker.py +0 -0
  262. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/router.py +0 -0
  263. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/runtime.py +0 -0
  264. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_benchmark.py +0 -0
  265. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_manager.py +0 -0
  266. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/session_preloader.py +0 -0
  267. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/subprojects.py +0 -0
  268. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/telemetry.py +0 -0
  269. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/text_index.py +0 -0
  270. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/time_tracker.py +0 -0
  271. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/tool_classifier.py +0 -0
  272. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/transcript_index.py +0 -0
  273. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/validation_cache.py +0 -0
  274. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/vector_store.py +0 -0
  275. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/watcher.py +0 -0
  276. {code_context_control-2.85.0 → code_context_control-2.86.0}/services/win_subprocess.py +0 -0
  277. {code_context_control-2.85.0 → code_context_control-2.86.0}/setup.cfg +0 -0
  278. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_builtin_optout.py +0 -0
  279. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_meta.py +0 -0
  280. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_shell_project.py +0 -0
  281. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_surfaces.py +0 -0
  282. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_access_guard_wiring.py +0 -0
  283. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_activity_reporter.py +0 -0
  284. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_agent_locks.py +0 -0
  285. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_aider_polyglot.py +0 -0
  286. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_antigravity_transition.py +0 -0
  287. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_artifact_store.py +0 -0
  288. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_artifact_tool.py +0 -0
  289. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  290. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_client.py +0 -0
  291. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_config_fallback.py +0 -0
  292. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_credentials.py +0 -0
  293. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_bitbucket_tool.py +0 -0
  294. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  295. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_chat_poll.py +0 -0
  296. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_act.py +0 -0
  297. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_cache.py +0 -0
  298. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_expr.py +0 -0
  299. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_impact.py +0 -0
  300. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_intel.py +0 -0
  301. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_runner.py +0 -0
  302. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ci_workflow.py +0 -0
  303. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_circuit_breaker.py +0 -0
  304. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_claude_md_merge.py +0 -0
  305. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_cli_smoke.py +0 -0
  306. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_compressor_large_file.py +0 -0
  307. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credential_store.py +0 -0
  308. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credentials_routes.py +0 -0
  309. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_credentials_tool.py +0 -0
  310. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_creds_cli_smoke.py +0 -0
  311. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_delegate_cascade.py +0 -0
  312. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_delegate_version_probe.py +0 -0
  313. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_e2e_benchmark.py +0 -0
  314. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_ledger_deadline.py +0 -0
  315. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_ledger_hook.py +0 -0
  316. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_locking.py +0 -0
  317. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_normalization.py +0 -0
  318. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_edit_verify.py +0 -0
  319. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_embedding_index_deadlock.py +0 -0
  320. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_flip.py +0 -0
  321. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_policy.py +0 -0
  322. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_enforcement_routes.py +0 -0
  323. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_federated_graph.py +0 -0
  324. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_filter_backoff.py +0 -0
  325. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ghost_files.py +0 -0
  326. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ghost_generation.py +0 -0
  327. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_git_branch_awareness.py +0 -0
  328. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_codex_compat.py +0 -0
  329. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_dispatch.py +0 -0
  330. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_pretool_enforce.py +0 -0
  331. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_prompt_recall.py +0 -0
  332. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_smoke.py +0 -0
  333. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_state.py +0 -0
  334. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hook_utf8_stdio.py +0 -0
  335. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_credentials_route.py +0 -0
  336. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_credentials_routes_write.py +0 -0
  337. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_enforcement_routes.py +0 -0
  338. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_inspect_api.py +0 -0
  339. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_locks_routes.py +0 -0
  340. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_server_smoke.py +0 -0
  341. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_hub_subproject_links.py +0 -0
  342. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ide_workflow_adaptation.py +0 -0
  343. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_install_mcp_entrypoint.py +0 -0
  344. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_cli_smoke.py +0 -0
  345. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_client.py +0 -0
  346. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_config_fallback.py +0 -0
  347. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_credentials.py +0 -0
  348. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_links.py +0 -0
  349. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_routes.py +0 -0
  350. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_jira_tool.py +0 -0
  351. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_lazy_store_init.py +0 -0
  352. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_guard.py +0 -0
  353. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_routes.py +0 -0
  354. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mask_surfaces.py +0 -0
  355. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_host_guard.py +0 -0
  356. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_memory_timeout.py +0 -0
  357. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_server_smoke.py +0 -0
  358. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mcp_toml.py +0 -0
  359. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_distiller.py +0 -0
  360. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_graph_api.py +0 -0
  361. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_queue.py +0 -0
  362. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_memory_system.py +0 -0
  363. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_api.py +0 -0
  364. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_extras.py +0 -0
  365. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_override_routes.py +0 -0
  366. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_mobile_security_api.py +0 -0
  367. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_no_stale_model_pins.py +0 -0
  368. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_notification_dedup.py +0 -0
  369. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_notification_discipline.py +0 -0
  370. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_ollama_credentials.py +0 -0
  371. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_api_auth.py +0 -0
  372. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_apikey_api.py +0 -0
  373. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_c3_bridge.py +0 -0
  374. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_chat_engine.py +0 -0
  375. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_chat_store.py +0 -0
  376. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_discovery_api.py +0 -0
  377. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_discovery_audit.py +0 -0
  378. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_local_auth.py +0 -0
  379. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_ollama_bridge.py +0 -0
  380. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_scanner_cache.py +0 -0
  381. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_security_fixes.py +0 -0
  382. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_session_bootstrap.py +0 -0
  383. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_subproject_awareness.py +0 -0
  384. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_oracle_ui_bundle.py +0 -0
  385. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_output_filter.py +0 -0
  386. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_grants.py +0 -0
  387. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_grants_mcp.py +0 -0
  388. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_requests.py +0 -0
  389. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_override_wake.py +0 -0
  390. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_permissions.py +0 -0
  391. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_manager.py +0 -0
  392. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_manager_merge.py +0 -0
  393. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_project_tool.py +0 -0
  394. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_read_coercion.py +0 -0
  395. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_read_edit_parity.py +0 -0
  396. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_related_facts.py +0 -0
  397. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_repo_map.py +0 -0
  398. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_response_boilerplate.py +0 -0
  399. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_retention.py +0 -0
  400. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_review_digest.py +0 -0
  401. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_service_durability.py +0 -0
  402. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_session_benchmark.py +0 -0
  403. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_session_budget.py +0 -0
  404. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_shell_creds.py +0 -0
  405. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_shell_robustness.py +0 -0
  406. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subproject_exclusion.py +0 -0
  407. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subproject_federation.py +0 -0
  408. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_subprojects.py +0 -0
  409. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_swe_bench.py +0 -0
  410. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_time_tracker.py +0 -0
  411. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_token_telemetry.py +0 -0
  412. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_tool_registry.py +0 -0
  413. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_upgrade_and_version.py +0 -0
  414. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_validate.py +0 -0
  415. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_vault_write_guard.py +0 -0
  416. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_version_sync.py +0 -0
  417. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_web_security.py +0 -0
  418. {code_context_control-2.85.0 → code_context_control-2.86.0}/tests/test_windows_reliability.py +0 -0
  419. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/__init__.py +0 -0
  420. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/backend.py +0 -0
  421. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/main.py +0 -0
  422. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/__init__.py +0 -0
  423. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/benchmark_view.py +0 -0
  424. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/claudemd_view.py +0 -0
  425. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/compress_view.py +0 -0
  426. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/index_view.py +0 -0
  427. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/init_view.py +0 -0
  428. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/mcp_view.py +0 -0
  429. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/optimize_view.py +0 -0
  430. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/pipe_view.py +0 -0
  431. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/projects_view.py +0 -0
  432. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/search_view.py +0 -0
  433. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/session_view.py +0 -0
  434. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/stats.py +0 -0
  435. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/screens/ui_view.py +0 -0
  436. {code_context_control-2.85.0 → code_context_control-2.86.0}/tui/theme.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.85.0
3
+ Version: 2.86.0
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
@@ -178,7 +178,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
178
178
  <img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
179
179
  </p>
180
180
 
181
- **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
181
+ **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
182
182
 
183
183
  **Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
184
184
 
@@ -243,6 +243,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
243
243
  - **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
244
244
  - **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
245
245
  - **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
246
+ - **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
246
247
  - **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
247
248
  - **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
248
249
  - **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
@@ -115,7 +115,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
115
115
  <img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
116
116
  </p>
117
117
 
118
- **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
118
+ **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
119
119
 
120
120
  **Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
121
121
 
@@ -180,6 +180,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
180
180
  - **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
181
181
  - **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
182
182
  - **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
183
+ - **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
183
184
  - **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
184
185
  - **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
185
186
  - **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
@@ -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.85.0"
95
+ __version__ = "2.86.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -5535,6 +5535,14 @@ def cmd_install_mcp(args):
5535
5535
  except Exception as e:
5536
5536
  print(f"Warning: Could not update global CLAUDE.md: {e}")
5537
5537
 
5538
+ # ── Default Access Guard rules (first run only) ─────────────
5539
+ from services import access_guard
5540
+ seeded = access_guard.seed_default_global_rules()
5541
+ if seeded.get("seeded"):
5542
+ rules = ", ".join(seeded["rules"])
5543
+ print(f"Seeded default Access Guard deny rules into global scope: {rules}")
5544
+ print(" (remove with: c3 access remove <glob> --kind deny --global)")
5545
+
5538
5546
  # ── Install /terse skill for supported IDEs ──────────────────
5539
5547
  if profile.name in ("claude-code", "codex"):
5540
5548
  try:
@@ -6603,6 +6611,16 @@ def _override_audit(grant: dict, project_path: str) -> None:
6603
6611
 
6604
6612
  def cmd_access(args):
6605
6613
  """Access Guard rule management — human-only mutation surface (spec §1)."""
6614
+ from services import access_guard
6615
+
6616
+ # First `c3 access` touch seeds the removable defaults (spec §1). A
6617
+ # no-op forever after: any existing access section, even an emptied
6618
+ # one, means the user has taken over the scope.
6619
+ seeded = access_guard.seed_default_global_rules()
6620
+ if seeded.get("seeded"):
6621
+ print(f"[seeded] default global deny rules: {', '.join(seeded['rules'])}")
6622
+ print(" Remove any of them: c3 access remove <glob> --kind deny --global\n")
6623
+
6606
6624
  sub = getattr(args, "access_cmd", None)
6607
6625
  if not sub:
6608
6626
  print("Usage: c3 access {list,add,remove,check,stats,mask,builtin} [args]")
@@ -41,7 +41,24 @@ _MAX_TOKENS = 200
41
41
  # "NTFS alternate data stream". The ADS check stays strict for real path
42
42
  # arguments (_WRITE_TOOLS/_READ_TOOLS); here it only produced false denies on
43
43
  # commit messages, curl, and gh (#50).
44
- _SCHEME_RE = re.compile(r"^[a-z][a-z0-9+.\-]*://", re.IGNORECASE)
44
+ #
45
+ # UNANCHORED, and that is the fix rather than an oversight. `^…://` only ever
46
+ # recognised a token that BEGINS with a scheme, which is the same
47
+ # whitelist-a-shape mistake #50 made and this module's own header calls out —
48
+ # and the `_SYNTAX_CHARS` generalisation does not cover the gap, because a
49
+ # token can carry a URL and no syntax at all. Observed 2026-08-11: the single
50
+ # argument of
51
+ # printf '\n---\n\nhttps://claude.ai/code/session_01Hs28…\n' >> body.md
52
+ # strips to `\n---\n\nhttps://claude.ai/…`, which has a separator (`\` and
53
+ # `/`), no syntax characters, no `::`, and no leading scheme. It reached
54
+ # ag.check, canonicalised to a residual colon, and hard-denied a command whose
55
+ # only file argument was an ordinary markdown path. Third logged instance of
56
+ # this class in five days (two on 2026-08-07 were Windows paths inside Python
57
+ # string literals).
58
+ #
59
+ # A token containing `://` anywhere is a network literal, not an NTFS stream:
60
+ # a real stream is `file:name:$TYPE`, and no spelling of it contains `//`.
61
+ _SCHEME_RE = re.compile(r"[a-z][a-z0-9+.\-]*://", re.IGNORECASE)
45
62
  # IPv6 literal or CIDR: >=2 colons, hex groups only, optional [] and /prefix.
46
63
  # 'C:/x/f.txt:stream' has one colon and non-hex parts, so it never matches.
47
64
  _IPV6_RE = re.compile(
@@ -104,8 +121,13 @@ _CD_RE = re.compile(
104
121
 
105
122
 
106
123
  def _is_network_token(tok: str) -> bool:
107
- """True for URLs and IPv6 literals/CIDRs — never for an ADS spelling."""
108
- return bool(_SCHEME_RE.match(tok) or _IPV6_RE.match(tok))
124
+ """True for URLs and IPv6 literals/CIDRs — never for an ADS spelling.
125
+
126
+ ``search`` for the scheme (a URL anywhere in the token disqualifies it as
127
+ a path), ``match`` for IPv6 — that pattern is a whole-token shape and
128
+ anchoring is what keeps `C:/x/f.txt:stream` from matching it.
129
+ """
130
+ return bool(_SCHEME_RE.search(tok) or _IPV6_RE.match(tok))
109
131
 
110
132
 
111
133
  def _is_scope_token(tok: str) -> bool:
@@ -2740,6 +2740,20 @@ def api_pm_milestone():
2740
2740
  return jsonify({"error": "id is required"}), 400
2741
2741
 
2742
2742
  if request.method == "PUT":
2743
+ # {complete: true} / {reopen: true} switch lifecycle; tasks keep
2744
+ # their milestone link (unlike DELETE = archive + detach).
2745
+ if data.get("complete"):
2746
+ res = store.complete_milestone(ms_id)
2747
+ if "error" in res:
2748
+ return jsonify(res), 400
2749
+ _pm_audit(resolved, "milestone", "complete", res["id"])
2750
+ return jsonify({"completed": True, "milestone": res})
2751
+ if data.get("reopen"):
2752
+ res = store.reopen_milestone(ms_id)
2753
+ if "error" in res:
2754
+ return jsonify(res), 400
2755
+ _pm_audit(resolved, "milestone", "reopen", res["id"])
2756
+ return jsonify({"reopened": True, "milestone": res})
2743
2757
  res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
2744
2758
  **(data.get("fields") or {}))
2745
2759
  if "error" in res:
@@ -1105,7 +1105,9 @@ async def c3_task(
1105
1105
  Time: time_add (minutes 1-1440 [+note/due_date=date/task_id]), time_update / time_delete (ref=entry id),
1106
1106
  time_list (manual entries + recent auto sessions), time_summary (today/7d/30d, auto vs manual).
1107
1107
  Auto-tracking: server startup + tool calls ping .c3/time; idle gaps >15min close a session.
1108
- Milestones: milestone_add (name [+target_date]), milestone_update, milestone_list (with progress %), milestone_archive.
1108
+ Milestones: milestone_add (name [+target_date]), milestone_update, milestone_list (with progress %),
1109
+ milestone_complete (close a shipped milestone; refuses while open tasks remain; tasks KEEP their link),
1110
+ milestone_reopen (undo complete), milestone_archive (removal: detaches tasks).
1109
1111
  Notes: note_add (note [+kind=decision] [+task_id]), note_list.
1110
1112
  History: history ([+task_id] [+limit]) — append-only event log (who/what/when, before->after), newest first.
1111
1113
  task_id accepts any unique id prefix (>=4 chars); milestone accepts id or unique name.
@@ -1295,6 +1295,20 @@ def api_pm_milestone():
1295
1295
  if not ms_id:
1296
1296
  return jsonify({"error": "id is required"}), 400
1297
1297
  if request.method == "PUT":
1298
+ # {complete: true} / {reopen: true} switch lifecycle; tasks keep
1299
+ # their milestone link (unlike DELETE = archive + detach).
1300
+ if data.get("complete"):
1301
+ res = store.complete_milestone(ms_id)
1302
+ if "error" in res:
1303
+ return jsonify(res), 400
1304
+ _pm_audit("milestone", "complete", res["id"])
1305
+ return jsonify({"completed": True, "milestone": res})
1306
+ if data.get("reopen"):
1307
+ res = store.reopen_milestone(ms_id)
1308
+ if "error" in res:
1309
+ return jsonify(res), 400
1310
+ _pm_audit("milestone", "reopen", res["id"])
1311
+ return jsonify({"reopened": True, "milestone": res})
1298
1312
  res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
1299
1313
  **(data.get("fields") or {}))
1300
1314
  if "error" in res:
@@ -69,6 +69,45 @@ _SOFT_WARN = re.compile(
69
69
 
70
70
  _DEFAULT_TIMEOUT = 60
71
71
  _MAX_TIMEOUT = 600
72
+
73
+ # The transport's own ceiling, and the reason _MAX_TIMEOUT alone is a lie.
74
+ #
75
+ # An MCP client kills a tool call at MCP_TOOL_TIMEOUT (Claude Code ships
76
+ # 120_000 ms and the value is set per-environment) — a limit this process does
77
+ # not choose and cannot raise. Until this existed, `c3_shell(timeout=600)` was
78
+ # accepted, clamped to 600, and then killed by the client at 120s with the
79
+ # subprocess still running: the caller saw the call "moved to background" and
80
+ # then fail, with no line anywhere naming the real limit or attributing the
81
+ # kill. The subprocess was NOT reaped by us, because our own deadline never
82
+ # arrived.
83
+ #
84
+ # The cost was not hypothetical. Two Higgsfield image generations (2-4 min
85
+ # each) were requested at timeout=420, killed at 120s, and the remote jobs
86
+ # completed and were BILLED while the local process died before downloading —
87
+ # one image landed, one was paid for and stranded.
88
+ #
89
+ # So: discover the client's ceiling, run just inside it, and SAY SO. Running
90
+ # inside it means OUR deadline fires first, which turns a phantom
91
+ # client-side kill into an ordinary `[c3_shell:TIMEOUT]` with stdout, a
92
+ # duration, and a process tree we actually killed.
93
+ _TRANSPORT_MARGIN_S = 5
94
+
95
+
96
+ def _transport_ceiling_s() -> int | None:
97
+ """Seconds this call may run before the MCP client kills it, if knowable.
98
+
99
+ None when the variable is unset or unparseable — then nothing is capped
100
+ and behaviour is exactly what it was, because a guess here would cap
101
+ legitimate work on a client with no such limit.
102
+ """
103
+ raw = (os.environ.get("MCP_TOOL_TIMEOUT") or "").strip()
104
+ if not raw:
105
+ return None
106
+ try:
107
+ ceiling = int(float(raw)) // 1000
108
+ except (TypeError, ValueError):
109
+ return None
110
+ return ceiling if ceiling > _TRANSPORT_MARGIN_S else None
72
111
  _FILTER_THRESHOLD_LINES = 30
73
112
  _JQ_INVOCATION = re.compile(r"(?:^|&&|\|\||[;|(])\s*jq(?:\s|$)", re.IGNORECASE)
74
113
 
@@ -468,6 +507,13 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
468
507
  )
469
508
 
470
509
  timeout = max(1, min(int(timeout or _DEFAULT_TIMEOUT), _MAX_TIMEOUT))
510
+ # Cap to what the transport will actually allow, and remember that we did
511
+ # so — the caller asked for a number, and a number quietly not honoured is
512
+ # the whole defect (see _transport_ceiling_s).
513
+ capped_from = 0
514
+ _ceiling = _transport_ceiling_s()
515
+ if _ceiling is not None and timeout > _ceiling - _TRANSPORT_MARGIN_S:
516
+ capped_from, timeout = timeout, _ceiling - _TRANSPORT_MARGIN_S
471
517
  work_cwd = cwd or svc.project_path
472
518
  work_cwd = str(Path(work_cwd).resolve())
473
519
 
@@ -601,6 +647,16 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
601
647
  warn = ""
602
648
  if _SOFT_WARN.search(cmd):
603
649
  warn = "[c3_shell:warn] destructive pattern detected — verify before re-running\n"
650
+ if capped_from:
651
+ # Named at the moment of the mistake, not in documentation nobody
652
+ # reads at the moment they need it. The alternative IS the escape
653
+ # hatch, so the line says which one.
654
+ warn += (
655
+ f"[c3_shell:capped] timeout={capped_from}s was requested but this "
656
+ f"MCP client kills a tool call at {_ceiling}s; ran with {timeout}s. "
657
+ f"For longer work use the native Bash tool with "
658
+ f"run_in_background, which is not bound by this limit.\n"
659
+ )
604
660
 
605
661
  if result["timed_out"]:
606
662
  status = "TIMEOUT"
@@ -5,7 +5,8 @@ READ_ACTIONS = {"list", "get", "board", "history", "report",
5
5
 
6
6
  _TASK_ACTIONS = ("add, update, done, list, get, board, history, report, archive, "
7
7
  "block, unblock, link, unlink, "
8
- "milestone_add, milestone_update, milestone_list, milestone_archive, "
8
+ "milestone_add, milestone_update, milestone_list, "
9
+ "milestone_complete, milestone_reopen, milestone_archive, "
9
10
  "note_add, note_list, "
10
11
  "time_add, time_update, time_delete, time_list, time_summary")
11
12
 
@@ -368,6 +369,26 @@ def handle_task(action, svc, finalize, *, title="", task_id="", status="",
368
369
  return done_resp(f"[task:error] {res['error']}", "error")
369
370
  return done_resp(f"[milestone:updated] {res['id'][:8]} \"{res['name']}\"", "updated")
370
371
 
372
+ if action == "milestone_complete":
373
+ if not milestone:
374
+ return done_resp("[task:error] milestone_complete requires milestone.", "error")
375
+ ms = store.resolve_milestone(milestone)
376
+ if ms is None:
377
+ return done_resp(f"[task:error] no milestone matches: {milestone}", "error")
378
+ res = store.complete_milestone(ms["id"])
379
+ if "error" in res:
380
+ return done_resp(f"[task:error] {res['error']}", "error")
381
+ return done_resp(f"[milestone:completed] \"{res['name']}\" "
382
+ f"(tasks keep their milestone link)", "completed")
383
+
384
+ if action == "milestone_reopen":
385
+ if not milestone:
386
+ return done_resp("[task:error] milestone_reopen requires milestone.", "error")
387
+ res = store.reopen_milestone(milestone)
388
+ if "error" in res:
389
+ return done_resp(f"[task:error] {res['error']}", "error")
390
+ return done_resp(f"[milestone:reopened] \"{res['name']}\"", "reopened")
391
+
371
392
  if action == "milestone_archive":
372
393
  if not milestone:
373
394
  return done_resp("[task:error] milestone_archive requires milestone.", "error")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.85.0
3
+ Version: 2.86.0
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
@@ -178,7 +178,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
178
178
  <img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/2026-07/ui_tasks.png" alt="C3 Tasks" width="900">
179
179
  </p>
180
180
 
181
- **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board.
181
+ **Tasks** (v2.45.0, extended v2.53.0) is a durable per-project tracker — dependencies and subtasks, milestones, decision notes, full event history, health reports, and both automatic and manual time tracking. It rolls up into the Hub's cross-project board. Shipped milestones can be **completed** (v2.86.0) — they leave the board while their tasks keep the milestone link, unlike archiving, which detaches them.
182
182
 
183
183
  **Instructions** keeps your agent-facing docs in sync. C3-generated content sits inside a `<!-- C3:BEGIN … -->` block; anything you write outside it is preserved. Since v2.60.0 generated docs point at `.c3/MAP.md` — a machine-owned, byte-stable repo map C3 refreshes automatically — instead of embedding a tree that goes stale. `AGENTS.md` serves both Codex and Antigravity; `GEMINI.md` is read if present but no longer generated (the Gemini CLI profile was removed in v2.52).
184
184
 
@@ -243,6 +243,7 @@ c3 access mask activate # purge pre-mask artifacts, buil
243
243
  - **`deny` means deny-enumerate too** — denied paths never appear in search results, maps, or the vector index.
244
244
  - **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
245
245
  - **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
246
+ - **Sensible defaults out of the box** (v2.86.0). A fresh install seeds `*.pem`, `id_rsa*`, and `*.key` as deny rules in global scope — visible in `c3 access list` and removable like any rule you wrote yourself. Delete one and it stays deleted.
246
247
  - **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
247
248
  - **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
248
249
  - **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
@@ -811,6 +811,20 @@ def mobile_pm_milestone():
811
811
  return jsonify({"error": "id is required"}), 400
812
812
 
813
813
  if request.method == "PUT":
814
+ # {complete: true} / {reopen: true} switch lifecycle; tasks keep
815
+ # their milestone link (unlike DELETE = archive + detach).
816
+ if data.get("complete"):
817
+ res = store.complete_milestone(ms_id)
818
+ if "error" in res:
819
+ return _pm_error(res)
820
+ _pm_audit(resolved, "milestone", "complete", res["id"])
821
+ return jsonify({"completed": True, "milestone": res})
822
+ if data.get("reopen"):
823
+ res = store.reopen_milestone(ms_id)
824
+ if "error" in res:
825
+ return _pm_error(res)
826
+ _pm_audit(resolved, "milestone", "reopen", res["id"])
827
+ return jsonify({"reopened": True, "milestone": res})
814
828
  res = store.update_milestone(ms_id, expected_rev=data.get("expected_rev"),
815
829
  **(data.get("fields") or {}))
816
830
  if "error" in res:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.85.0"
7
+ version = "2.86.0"
8
8
  description = "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."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1087,6 +1087,33 @@ def _write_scope_config(cfg: Path, data: dict) -> None:
1087
1087
  os.replace(tmp, cfg)
1088
1088
 
1089
1089
 
1090
+ def seed_default_global_rules() -> dict:
1091
+ """Seed DEFAULT_GLOBAL_RULES as deny rules in GLOBAL scope, once ever.
1092
+
1093
+ Spec §1: the defaults ship as visible, removable rules — so they are
1094
+ written to ``~/.c3/config.json`` only when that file has never carried
1095
+ an ``access`` section. Any existing section (even an emptied one) means
1096
+ the user has touched the scope and removal stays sticky. A corrupt or
1097
+ unreadable config is never rewritten. Never raises: install and CLI
1098
+ call this on every run and must not break on a bad home dir.
1099
+
1100
+ Returns {"seeded": bool, "rules": [...]} — ``rules`` only when seeded.
1101
+ """
1102
+ try:
1103
+ cfg = _scope_config_path("global")
1104
+ data = {}
1105
+ if cfg.is_file():
1106
+ data = json.loads(cfg.read_text(encoding="utf-8")) or {}
1107
+ if not isinstance(data, dict) or "access" in data:
1108
+ return {"seeded": False}
1109
+ data["access"] = {_KIND_DENY: [_norm_glob(g)
1110
+ for g in DEFAULT_GLOBAL_RULES]}
1111
+ _write_scope_config(cfg, data)
1112
+ return {"seeded": True, "rules": list(DEFAULT_GLOBAL_RULES)}
1113
+ except Exception:
1114
+ return {"seeded": False}
1115
+
1116
+
1090
1117
  def set_rule(glob, kind: str, scope: str, project_path: str = ".") -> dict:
1091
1118
  """Add one rule to *scope*'s config. Human surfaces only; callers log.
1092
1119
 
@@ -65,6 +65,39 @@ def gitignore_dir_names(root) -> set:
65
65
  return gitignore_dir_patterns(root)[0]
66
66
 
67
67
 
68
+ def is_nested_checkout(path) -> bool:
69
+ """True when ``path`` is the root of a DIFFERENT checkout than ours.
70
+
71
+ ``SKIP_DIRS`` cannot express this, because it matches directory NAMES and
72
+ a nested checkout is named whatever somebody called it. A linked git
73
+ worktree is the case that matters: its marker is a ``.git`` FILE holding
74
+ ``gitdir: …`` rather than a ``.git`` directory, so pruning the name
75
+ ``.git`` skips a file that was never a directory and descends into the
76
+ entire copy of the repository sitting beside it.
77
+
78
+ Measured on the Yep project, 2026-08-11 — 112 registered worktrees, most
79
+ of them agent scratch under ``.claude/worktrees/``:
80
+
81
+ .py files in the real tree 1,108
82
+ .py files under worktree dirs 100,629 (91x amplification)
83
+
84
+ A cross-project exact search there took 147.6s, against 0.11s to build
85
+ the runtime. The MCP transport kills a tool call at 120s, so the search
86
+ could never return — not slow, unreachable, and the reason
87
+ ``c3_project`` was unusable against that project at all.
88
+
89
+ Indexing them is also wrong on the merits, independent of cost: they are
90
+ other commits of files this project already has, so every hit is
91
+ duplicated ~112 times and the top result is whichever stale copy sorted
92
+ first. The search that exposed this returned a hit inside
93
+ ``.claude/worktrees/bridge-cse_01MPoh…`` rather than from src/.
94
+ """
95
+ try:
96
+ return os.path.exists(os.path.join(str(path), '.git'))
97
+ except (OSError, ValueError):
98
+ return False
99
+
100
+
68
101
  def make_dir_pruner(root, extra_skip=(), respect_gitignore: bool = True):
69
102
  """Predicate ``dirname -> bool`` (True = prune this directory).
70
103
 
@@ -177,6 +210,8 @@ def iter_files(
177
210
  continue
178
211
  if guard_excluded(os.path.join(dirpath, d)):
179
212
  continue # denied subtree — never descended, never listed
213
+ if is_nested_checkout(os.path.join(dirpath, d)):
214
+ continue # another checkout's copy of files we already index
180
215
  kept.append(d)
181
216
  dirnames[:] = kept
182
217
  seen += len(filenames) + len(kept)
@@ -864,6 +864,69 @@ class TaskStore:
864
864
  self._save(doc)
865
865
  return {**ms, "detached_tasks": detached}
866
866
 
867
+ def complete_milestone(self, milestone_id) -> dict:
868
+ """Close a finished milestone; its tasks KEEP their milestone link.
869
+
870
+ The happy-path close, distinct from archive_milestone (removal:
871
+ detaches tasks, eligible for purge). A completed milestone leaves
872
+ default listings, the board, and the report, but history still
873
+ records which tasks shipped under it. Refuses while open active
874
+ tasks remain; undo with reopen_milestone().
875
+ """
876
+ with self._guard():
877
+ doc = self._load()
878
+ ms = self._resolve(doc["milestones"], milestone_id)
879
+ if ms is None:
880
+ return {"error": f"no milestone matches: {milestone_id}"}
881
+ old = ms.get("lifecycle", "active")
882
+ if old != "active":
883
+ return {"error": f"milestone is {old}, not active"}
884
+ open_tasks = [t for t in doc["tasks"]
885
+ if t.get("milestone_id") == ms["id"]
886
+ and t.get("lifecycle", "active") == "active"
887
+ and t.get("status") != "done"]
888
+ if open_tasks:
889
+ names = ", ".join(t["id"][:8] for t in open_tasks[:5])
890
+ return {"error": f"{len(open_tasks)} open task(s) block "
891
+ f"completion: {names}"}
892
+ now = _now()
893
+ ms["lifecycle"] = "completed"
894
+ ms["completed_at"] = now
895
+ ms["updated_at"] = now
896
+ self._event("milestone", "complete", ms["id"],
897
+ patch={"lifecycle": [old, "completed"]})
898
+ self._save(doc)
899
+ return dict(ms)
900
+
901
+ def reopen_milestone(self, milestone_id) -> dict:
902
+ """Completed -> active again; clears completed_at.
903
+
904
+ Accepts id, unique id prefix, or — because resolve_milestone's
905
+ name matching deliberately covers only ACTIVE milestones — a
906
+ unique case-insensitive name among the completed ones.
907
+ """
908
+ with self._guard():
909
+ doc = self._load()
910
+ ms = self._resolve(doc["milestones"], milestone_id)
911
+ if ms is None:
912
+ want = (milestone_id or "").strip().lower()
913
+ matches = [m for m in doc["milestones"]
914
+ if m.get("lifecycle") == "completed"
915
+ and (m.get("name") or "").lower() == want]
916
+ ms = matches[0] if len(matches) == 1 else None
917
+ if ms is None:
918
+ return {"error": f"no milestone matches: {milestone_id}"}
919
+ old = ms.get("lifecycle", "active")
920
+ if old != "completed":
921
+ return {"error": f"milestone is {old}, not completed"}
922
+ ms["lifecycle"] = "active"
923
+ ms["completed_at"] = None
924
+ ms["updated_at"] = _now()
925
+ self._event("milestone", "reopen", ms["id"],
926
+ patch={"lifecycle": [old, "active"]})
927
+ self._save(doc)
928
+ return dict(ms)
929
+
867
930
  def resolve_milestone(self, ref: str):
868
931
  """Resolve by id, unique id prefix, or unique case-insensitive name."""
869
932
  doc = self._load()
@@ -289,5 +289,77 @@ class TestEnforce(GuardBase):
289
289
  ag.enforce(str(self.proj / "src/ok.py"), "read", str(self.proj))
290
290
 
291
291
 
292
+ class TestSeedDefaults(GuardBase):
293
+ """seed_default_global_rules — spec §1 removable defaults, sticky removal."""
294
+
295
+ def setUp(self):
296
+ super().setUp()
297
+ import unittest.mock as mock
298
+ self._home = Path(tempfile.mkdtemp())
299
+ self._gb = mock.patch.object(ag, "_global_base",
300
+ return_value=self._home)
301
+ self._gb.start()
302
+ self.global_cfg = self._home / ".c3" / "config.json"
303
+
304
+ def tearDown(self):
305
+ self._gb.stop()
306
+ import shutil
307
+ shutil.rmtree(self._home, ignore_errors=True)
308
+ super().tearDown()
309
+
310
+ def test_seeds_on_first_run(self):
311
+ res = ag.seed_default_global_rules()
312
+ self.assertTrue(res["seeded"])
313
+ data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
314
+ self.assertEqual(data["access"]["deny"],
315
+ list(ag.DEFAULT_GLOBAL_RULES))
316
+
317
+ def test_seeded_rules_are_enforced(self):
318
+ ag.seed_default_global_rules()
319
+ d = ag.check(str(self.proj / "server.pem"), "read", str(self.proj))
320
+ self.assertIsNotNone(d)
321
+ self.assertEqual(d.scope, "global")
322
+
323
+ def test_second_run_is_noop(self):
324
+ ag.seed_default_global_rules()
325
+ self.assertFalse(ag.seed_default_global_rules()["seeded"])
326
+
327
+ def test_removal_stays_sticky(self):
328
+ ag.seed_default_global_rules()
329
+ for glob in ag.DEFAULT_GLOBAL_RULES:
330
+ ag.remove_rule(glob, "deny", "global")
331
+ self.assertFalse(ag.seed_default_global_rules()["seeded"])
332
+ data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
333
+ self.assertEqual(data["access"]["deny"], [])
334
+
335
+ def test_existing_access_section_never_touched(self):
336
+ self._write_access({"deny": ["mine/**"]}, base=self._home)
337
+ self.assertFalse(ag.seed_default_global_rules()["seeded"])
338
+ data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
339
+ self.assertEqual(data["access"]["deny"], ["mine/**"])
340
+
341
+ def test_config_without_access_section_preserves_other_keys(self):
342
+ self.global_cfg.parent.mkdir(parents=True, exist_ok=True)
343
+ self.global_cfg.write_text(json.dumps({"other": {"k": 1}}),
344
+ encoding="utf-8")
345
+ res = ag.seed_default_global_rules()
346
+ self.assertTrue(res["seeded"])
347
+ data = json.loads(self.global_cfg.read_text(encoding="utf-8"))
348
+ self.assertEqual(data["other"], {"k": 1})
349
+ self.assertEqual(data["access"]["deny"],
350
+ list(ag.DEFAULT_GLOBAL_RULES))
351
+
352
+ def test_corrupt_config_never_rewritten(self):
353
+ self.global_cfg.parent.mkdir(parents=True, exist_ok=True)
354
+ self.global_cfg.write_text("{nope", encoding="utf-8")
355
+ self.assertFalse(ag.seed_default_global_rules()["seeded"])
356
+ self.assertEqual(self.global_cfg.read_text(encoding="utf-8"), "{nope")
357
+
358
+ def test_no_home_is_a_noop(self):
359
+ import unittest.mock as mock
360
+ with mock.patch.object(ag, "_global_base", return_value=None):
361
+ self.assertFalse(ag.seed_default_global_rules()["seeded"])
362
+
363
+
292
364
  if __name__ == "__main__":
293
365
  unittest.main()