code-context-control 2.128.1__tar.gz → 2.129.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 (531) hide show
  1. {code_context_control-2.128.1 → code_context_control-2.129.0}/PKG-INFO +1 -1
  2. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/c3.py +1 -1
  3. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/mcp_server.py +4 -1
  4. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/_helpers.py +34 -0
  5. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/ci.py +9 -0
  6. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/compress.py +50 -18
  7. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/read.py +88 -24
  8. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/PKG-INFO +1 -1
  9. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/SOURCES.txt +1 -0
  10. {code_context_control-2.128.1 → code_context_control-2.129.0}/pyproject.toml +1 -1
  11. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_act.py +60 -0
  12. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_runner.py +11 -0
  13. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/dir_map.py +42 -12
  14. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/file_memory.py +49 -10
  15. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_act.py +78 -0
  16. code_context_control-2.129.0/tests/test_read_outside_root.py +289 -0
  17. {code_context_control-2.128.1 → code_context_control-2.129.0}/LICENSE +0 -0
  18. {code_context_control-2.128.1 → code_context_control-2.129.0}/README.md +0 -0
  19. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/__init__.py +0 -0
  20. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/_hook_utils.py +0 -0
  21. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/_shell_writes.py +0 -0
  22. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/commands/__init__.py +0 -0
  23. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/commands/common.py +0 -0
  24. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/commands/parser.py +0 -0
  25. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/docs.html +0 -0
  26. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/edits.html +0 -0
  27. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/access.html +0 -0
  28. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/bitbucket.html +0 -0
  29. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/credentials.html +0 -0
  30. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/getting-started.html +0 -0
  31. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/index.html +0 -0
  32. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/masking.html +0 -0
  33. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/oracle.html +0 -0
  34. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/shared.css +0 -0
  35. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/tools.html +0 -0
  36. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/guide/workflow.html +0 -0
  37. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_access_guard.py +0 -0
  38. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_artifact.py +0 -0
  39. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_auto_snapshot.py +0 -0
  40. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_c3_signal.py +0 -0
  41. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_c3read.py +0 -0
  42. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_codex_lifecycle.py +0 -0
  43. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_dispatch.py +0 -0
  44. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_edit_ledger.py +0 -0
  45. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_edit_unlock.py +0 -0
  46. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_filter.py +0 -0
  47. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_ghost_files.py +0 -0
  48. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_pretool_enforce.py +0 -0
  49. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_prompt_recall.py +0 -0
  50. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_read.py +0 -0
  51. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_session_end.py +0 -0
  52. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_session_open.py +0 -0
  53. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_session_stats.py +0 -0
  54. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hook_terse_advisor.py +0 -0
  55. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_server.py +0 -0
  56. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/app.js +0 -0
  57. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/add_project.js +0 -0
  58. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/config_editor.js +0 -0
  59. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  60. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_health.js +0 -0
  61. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_panel.js +0 -0
  62. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  63. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  64. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/drill_views.js +0 -0
  65. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/global_search.js +0 -0
  66. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_access.js +0 -0
  67. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_ci.js +0 -0
  68. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  69. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  70. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  71. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_locks.js +0 -0
  72. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  73. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  74. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/modals.js +0 -0
  75. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/project_card.js +0 -0
  76. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/project_tree.js +0 -0
  77. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/session_drawer.js +0 -0
  78. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/settings_modal.js +0 -0
  79. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/sidebar.js +0 -0
  80. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/summary_bar.js +0 -0
  81. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/task_board.js +0 -0
  82. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/toasts.js +0 -0
  83. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/components/topbar.js +0 -0
  84. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui/state.js +0 -0
  85. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/hub_ui.html +0 -0
  86. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/mcp_proxy.py +0 -0
  87. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/progress.py +0 -0
  88. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/server.py +0 -0
  89. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/__init__.py +0 -0
  90. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/_grants.py +0 -0
  91. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/agent.py +0 -0
  92. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/artifacts.py +0 -0
  93. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/bitbucket.py +0 -0
  94. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/credentials.py +0 -0
  95. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/delegate.py +0 -0
  96. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/edit.py +0 -0
  97. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/edit_verify.py +0 -0
  98. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/edits.py +0 -0
  99. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/federate.py +0 -0
  100. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/filter.py +0 -0
  101. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/impact.py +0 -0
  102. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/jira.py +0 -0
  103. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/locks.py +0 -0
  104. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/memory.py +0 -0
  105. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/override.py +0 -0
  106. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/project.py +0 -0
  107. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/search.py +0 -0
  108. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/session.py +0 -0
  109. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/shell.py +0 -0
  110. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/shell_job.py +0 -0
  111. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/shell_nudge.py +0 -0
  112. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/shell_parsers.py +0 -0
  113. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/shell_render.py +0 -0
  114. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/status.py +0 -0
  115. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/tasks.py +0 -0
  116. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/tools/validate.py +0 -0
  117. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/api.js +0 -0
  118. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/app.js +0 -0
  119. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/access.js +0 -0
  120. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/bitbucket.js +0 -0
  121. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/chat.js +0 -0
  122. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/credentials.js +0 -0
  123. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/dashboard.js +0 -0
  124. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/edits.js +0 -0
  125. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/enforcement.js +0 -0
  126. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/instructions.js +0 -0
  127. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/jira.js +0 -0
  128. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/memory.js +0 -0
  129. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/sessions.js +0 -0
  130. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/settings.js +0 -0
  131. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/sidebar.js +0 -0
  132. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/components/tasks.js +0 -0
  133. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/icons.js +0 -0
  134. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/pm_shared.js +0 -0
  135. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/shared.js +0 -0
  136. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui/theme.js +0 -0
  137. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui.html +0 -0
  138. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui_legacy.html +0 -0
  139. {code_context_control-2.128.1 → code_context_control-2.129.0}/cli/ui_nano.html +0 -0
  140. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  141. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/entry_points.txt +0 -0
  142. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/requires.txt +0 -0
  143. {code_context_control-2.128.1 → code_context_control-2.129.0}/code_context_control.egg-info/top_level.txt +0 -0
  144. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/__init__.py +0 -0
  145. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/codex_patch.py +0 -0
  146. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/config.py +0 -0
  147. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/host.py +0 -0
  148. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/ide.py +0 -0
  149. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/mcp_toml.py +0 -0
  150. {code_context_control-2.128.1 → code_context_control-2.129.0}/core/web_security.py +0 -0
  151. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/__init__.py +0 -0
  152. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/config.py +0 -0
  153. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/listeners.py +0 -0
  154. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/mcp_oracle.py +0 -0
  155. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/oracle_server.py +0 -0
  156. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/oracle_ui.html +0 -0
  157. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/__init__.py +0 -0
  158. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/activity_reporter.py +0 -0
  159. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/api_auth.py +0 -0
  160. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/c3_bridge.py +0 -0
  161. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/chat_engine.py +0 -0
  162. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/chat_poll.py +0 -0
  163. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/chat_store.py +0 -0
  164. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/client_tokens.py +0 -0
  165. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/cross_memory.py +0 -0
  166. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/discovery_audit.py +0 -0
  167. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/federated_graph.py +0 -0
  168. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/health_checker.py +0 -0
  169. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/insight_engine.py +0 -0
  170. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/local_session.py +0 -0
  171. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/memory_reader.py +0 -0
  172. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/memory_writer.py +0 -0
  173. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/mobile_api.py +0 -0
  174. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/project_scanner.py +0 -0
  175. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/review_agent.py +0 -0
  176. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/tool_executor.py +0 -0
  177. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/services/tool_registry.py +0 -0
  178. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/activity.js +0 -0
  179. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/agents.js +0 -0
  180. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/app.js +0 -0
  181. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/busy.js +0 -0
  182. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/conversations.js +0 -0
  183. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/input.js +0 -0
  184. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/markdown.js +0 -0
  185. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/send.js +0 -0
  186. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/stream_renderer.js +0 -0
  187. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/chat/toolbar.js +0 -0
  188. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/core.js +0 -0
  189. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/crossgraph.js +0 -0
  190. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/header.js +0 -0
  191. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/insights.js +0 -0
  192. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/projects.js +0 -0
  193. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/qrcode.js +0 -0
  194. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/settings.js +0 -0
  195. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/suggestions.js +0 -0
  196. {code_context_control-2.128.1 → code_context_control-2.129.0}/oracle/ui/theme_tabs.js +0 -0
  197. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/__init__.py +0 -0
  198. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/access_guard.py +0 -0
  199. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/access_telemetry.py +0 -0
  200. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/activity_log.py +0 -0
  201. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/agent_base.py +0 -0
  202. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/agent_locks.py +0 -0
  203. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/agents.py +0 -0
  204. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/artifact_defs.py +0 -0
  205. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/artifact_store.py +0 -0
  206. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/atomic_json.py +0 -0
  207. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/auto_memory.py +0 -0
  208. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/background_service.py +0 -0
  209. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/__init__.py +0 -0
  210. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/external/__init__.py +0 -0
  211. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/external/aider_polyglot.py +0 -0
  212. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/external/swe_bench.py +0 -0
  213. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/map_eval.py +0 -0
  214. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/search_eval.py +0 -0
  215. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bench/shell_eval.py +0 -0
  216. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/benchmark_dashboard.py +0 -0
  217. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bitbucket_client.py +0 -0
  218. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/bitbucket_credentials.py +0 -0
  219. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_cache.py +0 -0
  220. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_expr.py +0 -0
  221. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_failures.py +0 -0
  222. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_github.py +0 -0
  223. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_impact.py +0 -0
  224. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_intel.py +0 -0
  225. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ci_workflow.py +0 -0
  226. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/circuit_breaker.py +0 -0
  227. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/claude_md.py +0 -0
  228. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/codex_integration.py +0 -0
  229. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/codex_transcript.py +0 -0
  230. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/compressor.py +0 -0
  231. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/context_snapshot.py +0 -0
  232. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/conversation_store.py +0 -0
  233. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/cred_audit.py +0 -0
  234. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/cred_telemetry.py +0 -0
  235. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/credential_store.py +0 -0
  236. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/doc_index.py +0 -0
  237. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/e2e_benchmark.py +0 -0
  238. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/e2e_evaluator.py +0 -0
  239. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/e2e_tasks.py +0 -0
  240. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/edit_ledger.py +0 -0
  241. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/embedding_index.py +0 -0
  242. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/enforcement_policy.py +0 -0
  243. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/error_reporting.py +0 -0
  244. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/file_map.py +0 -0
  245. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/git_context.py +0 -0
  246. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/host_sessions.py +0 -0
  247. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/hub_service.py +0 -0
  248. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/index_store.py +0 -0
  249. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/indexer.py +0 -0
  250. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/jira_client.py +0 -0
  251. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/jira_cloud.py +0 -0
  252. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/jira_credentials.py +0 -0
  253. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/jira_data_center.py +0 -0
  254. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/jira_links.py +0 -0
  255. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/lexical_index.py +0 -0
  256. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/mask_activation.py +0 -0
  257. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/mask_mirror.py +0 -0
  258. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/mask_presets.py +0 -0
  259. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory.py +0 -0
  260. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_consolidator.py +0 -0
  261. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_distiller.py +0 -0
  262. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_graph.py +0 -0
  263. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_grounder.py +0 -0
  264. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_queue.py +0 -0
  265. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/memory_scorer.py +0 -0
  266. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/metrics.py +0 -0
  267. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/notifications.py +0 -0
  268. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ollama_bridge.py +0 -0
  269. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ollama_client.py +0 -0
  270. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/ollama_credentials.py +0 -0
  271. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/oracle_service.py +0 -0
  272. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/output_filter.py +0 -0
  273. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/override_costs.py +0 -0
  274. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/override_grants.py +0 -0
  275. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/override_policy.py +0 -0
  276. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/override_requests.py +0 -0
  277. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/override_wake.py +0 -0
  278. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/parser.py +0 -0
  279. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/project_manager.py +0 -0
  280. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/project_runtime.py +0 -0
  281. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/protocol.py +0 -0
  282. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/proxy_state.py +0 -0
  283. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/repo_map.py +0 -0
  284. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/repo_shape.py +0 -0
  285. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/reranker.py +0 -0
  286. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/retention.py +0 -0
  287. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/retrieval.py +0 -0
  288. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/retrieval_broker.py +0 -0
  289. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/router.py +0 -0
  290. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/runtime.py +0 -0
  291. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/scanner.py +0 -0
  292. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/session_benchmark.py +0 -0
  293. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/session_live.py +0 -0
  294. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/session_manager.py +0 -0
  295. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/session_preloader.py +0 -0
  296. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/shell_jobs.py +0 -0
  297. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/shell_output.py +0 -0
  298. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/subprojects.py +0 -0
  299. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/task_store.py +0 -0
  300. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/telemetry.py +0 -0
  301. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/text_index.py +0 -0
  302. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/time_tracker.py +0 -0
  303. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/tool_classifier.py +0 -0
  304. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/transcript_index.py +0 -0
  305. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/validation_cache.py +0 -0
  306. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/vector_store.py +0 -0
  307. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/watcher.py +0 -0
  308. {code_context_control-2.128.1 → code_context_control-2.129.0}/services/win_subprocess.py +0 -0
  309. {code_context_control-2.128.1 → code_context_control-2.129.0}/setup.cfg +0 -0
  310. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_builtin_optout.py +0 -0
  311. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_guard.py +0 -0
  312. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_guard_meta.py +0 -0
  313. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_guard_shell_project.py +0 -0
  314. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_guard_surfaces.py +0 -0
  315. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_access_guard_wiring.py +0 -0
  316. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_activity_log_find_last.py +0 -0
  317. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_activity_reporter.py +0 -0
  318. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_agent_locks.py +0 -0
  319. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_aider_polyglot.py +0 -0
  320. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_antigravity_transition.py +0 -0
  321. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_artifact_store.py +0 -0
  322. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_artifact_tool.py +0 -0
  323. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_atomic_json.py +0 -0
  324. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_background_service.py +0 -0
  325. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  326. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_bitbucket_client.py +0 -0
  327. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_bitbucket_config_fallback.py +0 -0
  328. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_bitbucket_credentials.py +0 -0
  329. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_bitbucket_tool.py +0 -0
  330. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_builtin_modes.py +0 -0
  331. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  332. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_c3_shell.py +0 -0
  333. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_chat_poll.py +0 -0
  334. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_cache.py +0 -0
  335. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_expr.py +0 -0
  336. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_impact.py +0 -0
  337. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_intel.py +0 -0
  338. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_runner.py +0 -0
  339. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ci_workflow.py +0 -0
  340. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_circuit_breaker.py +0 -0
  341. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_claude_md_merge.py +0 -0
  342. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_claude_md_updater.py +0 -0
  343. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_cli_smoke.py +0 -0
  344. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_codex_mcp_transport.py +0 -0
  345. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_codex_native.py +0 -0
  346. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_compressor_large_file.py +0 -0
  347. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_confirm_guard.py +0 -0
  348. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_confirm_guard_wiring.py +0 -0
  349. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_cooccurrence_bounds.py +0 -0
  350. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_cred_audit.py +0 -0
  351. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_cred_telemetry.py +0 -0
  352. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_credential_login_kind.py +0 -0
  353. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_credential_store.py +0 -0
  354. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_credential_ui_parity.py +0 -0
  355. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_credentials_routes.py +0 -0
  356. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_credentials_tool.py +0 -0
  357. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_creds_cli_smoke.py +0 -0
  358. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_delegate_cascade.py +0 -0
  359. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_delegate_version_probe.py +0 -0
  360. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_dir_map_c3.py +0 -0
  361. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_e2e_benchmark.py +0 -0
  362. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_edit_ledger_deadline.py +0 -0
  363. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_edit_ledger_hook.py +0 -0
  364. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_edit_locking.py +0 -0
  365. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_edit_normalization.py +0 -0
  366. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_edit_verify.py +0 -0
  367. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_embedding_index_deadlock.py +0 -0
  368. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_enforcement_flip.py +0 -0
  369. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_enforcement_policy.py +0 -0
  370. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_enforcement_routes.py +0 -0
  371. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_env_parser.py +0 -0
  372. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  373. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_federated_graph.py +0 -0
  374. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_file_map_c1.py +0 -0
  375. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_filter_backoff.py +0 -0
  376. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ghost_files.py +0 -0
  377. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ghost_generation.py +0 -0
  378. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_git_branch_awareness.py +0 -0
  379. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_access_guard.py +0 -0
  380. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_codex_compat.py +0 -0
  381. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_dispatch.py +0 -0
  382. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_pretool_enforce.py +0 -0
  383. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_prompt_recall.py +0 -0
  384. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_session_end.py +0 -0
  385. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_smoke.py +0 -0
  386. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_state.py +0 -0
  387. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hook_utf8_stdio.py +0 -0
  388. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_credentials_route.py +0 -0
  389. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_credentials_routes_write.py +0 -0
  390. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_enforcement_routes.py +0 -0
  391. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_hook_migration.py +0 -0
  392. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_inspect_api.py +0 -0
  393. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_locks_routes.py +0 -0
  394. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_oracle_service_routes.py +0 -0
  395. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_override_routes.py +0 -0
  396. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_server_smoke.py +0 -0
  397. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_hub_subproject_links.py +0 -0
  398. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ide_workflow_adaptation.py +0 -0
  399. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_index_cap_not_hardcoded.py +0 -0
  400. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  401. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_init_scan.py +0 -0
  402. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_install_mcp_entrypoint.py +0 -0
  403. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_cli_smoke.py +0 -0
  404. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_client.py +0 -0
  405. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_config_fallback.py +0 -0
  406. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_credentials.py +0 -0
  407. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_links.py +0 -0
  408. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_routes.py +0 -0
  409. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_jira_tool.py +0 -0
  410. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_large_files_c4.py +0 -0
  411. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_lazy_store_init.py +0 -0
  412. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_map_eval.py +0 -0
  413. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_map_telemetry_c0.py +0 -0
  414. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mask_guard.py +0 -0
  415. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mask_routes.py +0 -0
  416. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mask_surfaces.py +0 -0
  417. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mcp_host_guard.py +0 -0
  418. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mcp_memory_timeout.py +0 -0
  419. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mcp_server_smoke.py +0 -0
  420. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mcp_toml.py +0 -0
  421. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_memory_distiller.py +0 -0
  422. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_memory_graph_api.py +0 -0
  423. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_memory_queue.py +0 -0
  424. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_memory_system.py +0 -0
  425. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_api.py +0 -0
  426. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_clients.py +0 -0
  427. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_extras.py +0 -0
  428. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_jobs_ci.py +0 -0
  429. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_override_costs.py +0 -0
  430. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_override_routes.py +0 -0
  431. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_mobile_security_api.py +0 -0
  432. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_no_stale_model_pins.py +0 -0
  433. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_notification_dedup.py +0 -0
  434. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_notification_discipline.py +0 -0
  435. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_notification_kinds.py +0 -0
  436. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ollama_credentials.py +0 -0
  437. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_api_auth.py +0 -0
  438. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_apikey_api.py +0 -0
  439. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_c3_bridge.py +0 -0
  440. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_chat_engine.py +0 -0
  441. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_chat_store.py +0 -0
  442. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_discovery_api.py +0 -0
  443. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_discovery_audit.py +0 -0
  444. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_health_probe.py +0 -0
  445. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_local_auth.py +0 -0
  446. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_loopback.py +0 -0
  447. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_ollama_bridge.py +0 -0
  448. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_scanner_cache.py +0 -0
  449. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_security_fixes.py +0 -0
  450. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_session_bootstrap.py +0 -0
  451. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_subproject_awareness.py +0 -0
  452. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_oracle_ui_bundle.py +0 -0
  453. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_output_filter.py +0 -0
  454. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_override_costs.py +0 -0
  455. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_override_grants.py +0 -0
  456. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_override_grants_mcp.py +0 -0
  457. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_override_requests.py +0 -0
  458. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_override_wake.py +0 -0
  459. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_permissions.py +0 -0
  460. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_pm_api.py +0 -0
  461. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_project_manager.py +0 -0
  462. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_project_manager_merge.py +0 -0
  463. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_project_tool.py +0 -0
  464. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_read_coercion.py +0 -0
  465. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_read_edit_parity.py +0 -0
  466. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_related_facts.py +0 -0
  467. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_repo_map.py +0 -0
  468. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_repo_shape.py +0 -0
  469. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_response_boilerplate.py +0 -0
  470. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_retention.py +0 -0
  471. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_review_digest.py +0 -0
  472. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_eval.py +0 -0
  473. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p1.py +0 -0
  474. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p2.py +0 -0
  475. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p2b.py +0 -0
  476. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p3.py +0 -0
  477. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p4.py +0 -0
  478. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_search_p5.py +0 -0
  479. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_service_durability.py +0 -0
  480. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_session_benchmark.py +0 -0
  481. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_session_budget.py +0 -0
  482. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_session_live.py +0 -0
  483. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_budget_s1.py +0 -0
  484. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_creds.py +0 -0
  485. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_eval.py +0 -0
  486. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_jobs_s3.py +0 -0
  487. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_nudge_s4.py +0 -0
  488. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_output.py +0 -0
  489. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_parsers_s2.py +0 -0
  490. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_robustness.py +0 -0
  491. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_telemetry_s0.py +0 -0
  492. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_write_ledger.py +0 -0
  493. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_shell_writes.py +0 -0
  494. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subproject_clear_scope.py +0 -0
  495. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subproject_depth_consumers.py +0 -0
  496. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subproject_exclusion.py +0 -0
  497. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subproject_federation.py +0 -0
  498. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subproject_linkage_api.py +0 -0
  499. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_subprojects.py +0 -0
  500. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_swe_bench.py +0 -0
  501. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_task_store.py +0 -0
  502. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_task_tool.py +0 -0
  503. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_time_tracker.py +0 -0
  504. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_token_telemetry.py +0 -0
  505. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_token_tracking.py +0 -0
  506. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_tool_registry.py +0 -0
  507. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_ui_jsx_syntax.py +0 -0
  508. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_upgrade_and_version.py +0 -0
  509. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_validate.py +0 -0
  510. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_vault_write_guard.py +0 -0
  511. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_version_sync.py +0 -0
  512. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_web_security.py +0 -0
  513. {code_context_control-2.128.1 → code_context_control-2.129.0}/tests/test_windows_reliability.py +0 -0
  514. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/__init__.py +0 -0
  515. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/backend.py +0 -0
  516. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/main.py +0 -0
  517. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/__init__.py +0 -0
  518. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/benchmark_view.py +0 -0
  519. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/claudemd_view.py +0 -0
  520. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/compress_view.py +0 -0
  521. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/index_view.py +0 -0
  522. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/init_view.py +0 -0
  523. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/mcp_view.py +0 -0
  524. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/optimize_view.py +0 -0
  525. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/pipe_view.py +0 -0
  526. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/projects_view.py +0 -0
  527. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/search_view.py +0 -0
  528. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/session_view.py +0 -0
  529. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/stats.py +0 -0
  530. {code_context_control-2.128.1 → code_context_control-2.129.0}/tui/screens/ui_view.py +0 -0
  531. {code_context_control-2.128.1 → code_context_control-2.129.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.128.1
3
+ Version: 2.129.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
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
91
91
  # Config
92
92
  CONFIG_DIR = ".c3"
93
93
  CONFIG_FILE = ".c3/config.json"
94
- __version__ = "2.128.1"
94
+ __version__ = "2.129.0"
95
95
 
96
96
 
97
97
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -734,7 +734,10 @@ async def c3_read(file_path: str, symbols: Any = None, lines: Any = None,
734
734
  """READ source, or MAP a file when called with only file_path (read-only, plan-mode safe).
735
735
  file_path: single or comma-separated. symbols: names as the map prints them (Class.method ok).
736
736
  lines: int, [start,end], or list of ranges. No symbols/lines = one line per symbol with
737
- signature and [La-Lb] range at ~10% of the file's tokens; then read the symbols you need."""
737
+ signature and [La-Lb] range at ~10% of the file's tokens; then read the symbols you need.
738
+ Paths OUTSIDE the project root are read too (sibling repo, extra working dir, installed
739
+ package source): tagged [c3-read:external], served from a transient record, never added
740
+ to this project's index or related facts. Access Guard rules still apply there."""
738
741
  path_err = validate_file_path(file_path)
739
742
  if path_err:
740
743
  return f"[c3_read:error] {path_err}"
@@ -147,6 +147,40 @@ _HEREDOC_MARKERS = {
147
147
  _GHOST_NAMES = _PYTHON_TYPE_NAMES | _HEREDOC_MARKERS
148
148
 
149
149
 
150
+ EXTERNAL_TAG = "[c3-read:external]"
151
+
152
+
153
+ def external_banner(path: str) -> str:
154
+ """The one line every outside-the-root response opens with.
155
+
156
+ One definition so c3_read and c3_compress cannot drift apart on it.
157
+ """
158
+ return (f"{EXTERNAL_TAG} {path} — outside the project root; served but "
159
+ f"not indexed, and absent from this project's search, map cache "
160
+ f"and related facts.\n")
161
+
162
+
163
+ def project_key(full, project_path) -> tuple[str, bool]:
164
+ """``(key, external)`` for an already-resolved-or-not path.
165
+
166
+ Inside the root the key is the project-relative posix path — how
167
+ file_memory, the edit ledger and related facts all address a file.
168
+ Outside it there is no such key, so the absolute posix path stands in and
169
+ ``external`` tells the caller to serve from a transient record rather than
170
+ the index (docs/file-map.md § Outside the root).
171
+
172
+ This used to be a bare ``relative_to`` whose ValueError escaped as a tool
173
+ crash. It is not a containment check and must not become one: Access Guard
174
+ already rules on the absolute canonical path, and it runs before this.
175
+ """
176
+ resolved = Path(full).resolve()
177
+ try:
178
+ rel = resolved.relative_to(Path(project_path).resolve())
179
+ return str(rel).replace("\\", "/"), False
180
+ except ValueError:
181
+ return resolved.as_posix(), True
182
+
183
+
150
184
  def validate_file_path(file_path: str) -> str | None:
151
185
  """Return an error message if file_path looks like a ghost-file path, else None.
152
186
 
@@ -385,6 +385,15 @@ def handle_ci(action: str, job: str, run_id: str, allow_foreign: bool,
385
385
  f" runs Linux jobs in a container "
386
386
  f"({ci_act.DEFAULT_IMAGE}), real `uses:` actions included",
387
387
  ]
388
+ if state.get("warning"):
389
+ lines.append(f" WARNING: {state['warning']}")
390
+ # An image that is present locally is still not proof act can pull
391
+ # it: act sends the stored registry credential where the CLI sends
392
+ # none, so an expired token fails a public pull (issue #173). Say
393
+ # so rather than let `available` read as a guarantee.
394
+ lines.append(" a runner failure before any step runs is "
395
+ "reported as a container-setup failure, not as 0 "
396
+ "parsed failures")
388
397
  else:
389
398
  lines += [" act UNAVAILABLE", f" {state['reason']}"]
390
399
  lines += [
@@ -11,9 +11,10 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
11
11
  from pathlib import Path
12
12
 
13
13
  from cli.tools import _grants
14
- from cli.tools._helpers import finalize_with_tokens, show_token_ratios
14
+ from cli.tools._helpers import external_banner, finalize_with_tokens, project_key, show_token_ratios
15
15
  from core import count_tokens
16
16
  from services import access_guard
17
+ from services.file_map import render_map
17
18
 
18
19
  #: Every mode name c3_compress ever accepted, and what to say about it now.
19
20
  RETIRED_MODES = {
@@ -35,7 +36,8 @@ def deprecation_line(requested: str) -> str:
35
36
 
36
37
 
37
38
  def map_detail(svc, rel: str, requested_mode: str, *, cache_hit: bool,
38
- symbols: int = 0, fallback: str = "") -> dict:
39
+ symbols: int = 0, fallback: str = "", record: dict = None,
40
+ external: bool = False) -> dict:
39
41
  """Telemetry `detail` for a map served from file_memory (C0, 2.120.0).
40
42
 
41
43
  backend names the code path, parser the extractor that built the record
@@ -43,13 +45,15 @@ def map_detail(svc, rel: str, requested_mode: str, *, cache_hit: bool,
43
45
  whether the record was already fresh. `symbols` is how many the caller
44
46
  asked for and `fallback` why a read served a map instead of source.
45
47
  `deprecated_mode` (2.122.0) is set when a retired mode name was asked for.
48
+ `record` is a caller-supplied transient record (an outside-the-root read,
49
+ which is deliberately absent from file_memory) and `external` flags it.
46
50
  Flat so telemetry.aggregate_tool_telemetry can fold it without a schema.
47
51
  """
48
- record = None
49
- try:
50
- record = svc.file_memory.get(rel)
51
- except Exception:
52
- record = None
52
+ if record is None:
53
+ try:
54
+ record = svc.file_memory.get(rel)
55
+ except Exception:
56
+ record = None
53
57
  if not isinstance(record, dict):
54
58
  record = None
55
59
  detail = {
@@ -65,6 +69,9 @@ def map_detail(svc, rel: str, requested_mode: str, *, cache_hit: bool,
65
69
  detail["fallback"] = fallback
66
70
  if requested_mode not in ("map", "read"):
67
71
  detail["deprecated_mode"] = requested_mode
72
+ if external:
73
+ detail["backend"] = "transient"
74
+ detail["external"] = True
68
75
  return detail
69
76
 
70
77
 
@@ -136,20 +143,37 @@ def _compress_single(file_path: str, requested: str, note: str, svc, finalize) -
136
143
  if not full.exists():
137
144
  return ("[file_map:error] not found. To create a new file use "
138
145
  "c3_edit(file_path=..., old_string='', new_string=<content>).")
139
- rel = str(full.resolve().relative_to(Path(svc.project_path).resolve())).replace("\\", "/")
140
- # C0 measurement: was the record already fresh before this call?
141
- cache_hit = not svc.file_memory.needs_update(rel)
142
- res = _build_map(svc, rel)
146
+ resolved = full.resolve()
147
+ rel, external = project_key(resolved, svc.project_path)
148
+ # Outside the root the map comes from a transient record — same parser,
149
+ # never written to an index keyed by project-relative path
150
+ # (docs/file-map.md § Outside the root). c3_read does the same thing; the
151
+ # two map surfaces must not disagree about where a file may live.
152
+ banner = external_banner(rel) if external else ""
153
+ if external:
154
+ ext_record = svc.file_memory.build_transient_record(resolved, key=rel)
155
+ cache_hit = False
156
+ body = (render_map(ext_record, max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
157
+ if ext_record
158
+ else f"[file_map] Could not build map for {rel} — unreadable.")
159
+ else:
160
+ ext_record = None
161
+ # C0 measurement: was the record already fresh before this call?
162
+ cache_hit = not svc.file_memory.needs_update(rel)
163
+ body = _build_map(svc, rel)
164
+ res = banner + body
143
165
  raw_tokens = None
144
166
  map_tokens = 0
145
167
  try:
146
168
  raw_text = full.read_text(encoding="utf-8", errors="replace")
147
169
  raw_tokens = count_tokens(raw_text)
148
170
  map_tokens = count_tokens(res)
149
- if map_tokens >= raw_tokens and not res.startswith("[file_map]"):
171
+ if map_tokens >= raw_tokens and not body.startswith("[file_map]"):
150
172
  # A map that costs more than the file is worth nothing
151
173
  # (docs/file-map.md § Small files).
152
- res = f"[compress:{file_path}] whole file — smaller than its map\n" + raw_text
174
+ res = (banner
175
+ + f"[compress:{file_path}] whole file — smaller than its map\n"
176
+ + raw_text)
153
177
  map_tokens = count_tokens(res)
154
178
  summary = "map"
155
179
  except Exception:
@@ -162,7 +186,8 @@ def _compress_single(file_path: str, requested: str, note: str, svc, finalize) -
162
186
  res, summary,
163
187
  raw_tokens=raw_tokens, optimized_tokens=map_tokens or None,
164
188
  response_tokens=map_tokens,
165
- detail=map_detail(svc, rel, requested, cache_hit=cache_hit))
189
+ detail=map_detail(svc, rel, requested, cache_hit=cache_hit,
190
+ record=ext_record, external=external))
166
191
 
167
192
 
168
193
  def _compress_batch(paths: list, requested: str, note: str, svc, finalize) -> str:
@@ -195,10 +220,17 @@ def _compress_batch(paths: list, requested: str, note: str, svc, finalize) -> st
195
220
  full = Path(fp)
196
221
  if not full.exists():
197
222
  return fp, None, None, None, "not found"
198
- rel = str(full.resolve().relative_to(
199
- Path(svc.project_path).resolve())).replace("\\", "/")
200
- res = svc.file_memory.get_or_build_map(
201
- rel, max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
223
+ resolved = full.resolve()
224
+ rel, external = project_key(resolved, svc.project_path)
225
+ if external:
226
+ record = svc.file_memory.build_transient_record(resolved, key=rel)
227
+ res = external_banner(rel) + (
228
+ render_map(record, max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
229
+ if record
230
+ else f"[file_map] Could not build map for {rel} — unreadable.")
231
+ else:
232
+ res = svc.file_memory.get_or_build_map(
233
+ rel, max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
202
234
  try:
203
235
  raw_tok = count_tokens(full.read_text(encoding="utf-8", errors="replace"))
204
236
  map_tok = count_tokens(res)
@@ -7,10 +7,11 @@ from pathlib import Path
7
7
  from typing import Any
8
8
 
9
9
  from cli.tools import _grants
10
- from cli.tools._helpers import finalize_with_tokens, maybe_related_facts
10
+ from cli.tools._helpers import external_banner, finalize_with_tokens, maybe_related_facts, project_key
11
11
  from cli.tools.compress import map_detail
12
12
  from core import count_tokens
13
13
  from services import access_guard
14
+ from services.file_map import render_map
14
15
 
15
16
 
16
17
  def _coerce_list(val: Any) -> list[str] | None:
@@ -175,7 +176,21 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
175
176
  if not full.exists():
176
177
  return f"[read:error] File not found: {file_path}"
177
178
 
178
- rel_path = str(full.resolve().relative_to(Path(svc.project_path).resolve())).replace("\\", "/")
179
+ # A path outside the project root is READ, not refused (docs/file-map.md
180
+ # § Outside the root). The root was never the control here: Access Guard
181
+ # ruled above and its rules match the absolute canonical path as well as
182
+ # the project-relative one, so the builtin denies still cover an outside
183
+ # file; and the PreToolUse hook stands down outside the root, so native
184
+ # Read already went there unimpeded. Refusing only pushed the agent off
185
+ # the budgeted, guarded tool onto the unbudgeted one.
186
+ #
187
+ # What the root DOES decide is indexing. file_memory is keyed by
188
+ # project-relative path and feeds the text index, the map cache and
189
+ # prune_stale, so an outside file is served from a transient record and
190
+ # never written into this project's store.
191
+ resolved = full.resolve()
192
+ rel_path, external = project_key(resolved, svc.project_path)
193
+ banner = external_banner(rel_path) if external else ""
179
194
 
180
195
  if full.is_dir():
181
196
  # A directory maps to one line per file, budgeted
@@ -184,7 +199,9 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
184
199
  budget = DEFAULT_MAX_TOKENS
185
200
  if isinstance(lines, int) and not isinstance(lines, bool) and lines > 0:
186
201
  budget = lines
187
- text, dir_detail = render_directory_map(svc, rel_path, max_tokens=budget)
202
+ text, dir_detail = render_directory_map(svc, rel_path, max_tokens=budget,
203
+ external=external)
204
+ text = banner + text
188
205
  tok = count_tokens(text)
189
206
  if finalize is None:
190
207
  return text
@@ -228,15 +245,56 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
228
245
  # Ensure file_memory index is fresh.
229
246
  # When the watcher is running, it handles updates in the background —
230
247
  # only force-update if file_memory has no record at all (first access).
231
- try:
232
- watcher_active = (hasattr(svc, "watcher") and svc.watcher._observer.is_alive())
233
- if watcher_active:
234
- if not svc.file_memory.get(rel_path):
248
+ # An outside-the-root file is never indexed; it gets a transient record
249
+ # instead, built lazily below.
250
+ if not external:
251
+ try:
252
+ watcher_active = (hasattr(svc, "watcher") and svc.watcher._observer.is_alive())
253
+ if watcher_active:
254
+ if not svc.file_memory.get(rel_path):
255
+ svc.file_memory.update(rel_path)
256
+ elif svc.file_memory.needs_update(rel_path):
235
257
  svc.file_memory.update(rel_path)
236
- elif svc.file_memory.needs_update(rel_path):
237
- svc.file_memory.update(rel_path)
238
- except Exception:
239
- pass
258
+ except Exception:
259
+ pass
260
+
261
+ _ext_cache = []
262
+
263
+ def _ext_record():
264
+ """The transient record for an outside file — same parser and schema
265
+ as an indexed one, never persisted (docs/file-map.md § Outside the
266
+ root).
267
+
268
+ Built at most once, and only where a map or a symbol lookup actually
269
+ needs it: a `lines=[a,b]` read must not pay for a full parse of the
270
+ file it is slicing two lines out of, which is the whole reason the
271
+ large-file bounds exist.
272
+ """
273
+ if not external:
274
+ return None
275
+ if not _ext_cache:
276
+ _ext_cache.append(
277
+ svc.file_memory.build_transient_record(resolved, key=rel_path))
278
+ return _ext_cache[0]
279
+
280
+ def _file_map(max_tokens=None) -> str:
281
+ """The map, from the project index or from the transient record."""
282
+ if not external:
283
+ return svc.file_memory.get_or_build_map(rel_path, max_tokens=max_tokens)
284
+ record = _ext_record()
285
+ if not record:
286
+ return f"[file_map] Could not build map for {rel_path} — unreadable."
287
+ return render_map(record, max_tokens=max_tokens)
288
+
289
+ def _map_cached() -> bool:
290
+ return False if external else not svc.file_memory.needs_update(rel_path)
291
+
292
+ def _facts() -> str:
293
+ # Facts are project knowledge keyed by project-relative path; an
294
+ # outside file has none, and matching one by basename would be a lie.
295
+ if external:
296
+ return ""
297
+ return maybe_related_facts(svc, rel_path, top_k=3, context="read")
240
298
 
241
299
  raw_text = full.read_text(encoding="utf-8", errors="replace")
242
300
  # EOL-normalize exactly the way c3_edit's matcher does (\r\n and \r → \n),
@@ -256,7 +314,9 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
256
314
  return _full_tok_cache[0]
257
315
 
258
316
  if symbols:
259
- matches = svc.file_memory.get_symbol_ranges(rel_path, symbols, return_matches=True)
317
+ matches = svc.file_memory.get_symbol_ranges(rel_path, symbols,
318
+ return_matches=True,
319
+ record=_ext_record())
260
320
 
261
321
  # Check for ambiguity
262
322
  disambiguation_msgs = []
@@ -292,7 +352,7 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
292
352
  ranges.append(m["range"])
293
353
 
294
354
  if '<main>' in symbols or '<globals>' in symbols:
295
- record = svc.file_memory.get(rel_path)
355
+ record = _ext_record() or svc.file_memory.get(rel_path)
296
356
  if record and "sections" in record:
297
357
  covered = set()
298
358
 
@@ -318,29 +378,31 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
318
378
  ranges.extend(main_ranges)
319
379
 
320
380
  if not ranges and symbols:
321
- map_cached = not svc.file_memory.needs_update(rel_path)
322
- file_map = svc.file_memory.get_or_build_map(rel_path)
323
- resp = f"[read:{file_path}] symbols not found: {symbols}. Showing file map:\n{file_map}"
381
+ map_cached = _map_cached()
382
+ file_map = _file_map()
383
+ resp = (banner
384
+ + f"[read:{file_path}] symbols not found: {symbols}. "
385
+ f"Showing file map:\n{file_map}")
324
386
  map_tok = count_tokens(file_map)
325
387
  return finalize_with_tokens(
326
388
  finalize, svc, "c3_read", {"file": file_path, "symbols": symbols},
327
389
  resp, f"{full_file_tokens()}->{map_tok}tok",
328
390
  raw_tokens=full_file_tokens(), optimized_tokens=map_tok,
329
391
  detail=map_detail(svc, rel_path, "read", cache_hit=map_cached,
330
- symbols=len(symbols), fallback="symbols_not_found"))
392
+ symbols=len(symbols), fallback="symbols_not_found",
393
+ record=_ext_record(), external=external))
331
394
 
332
395
  if not ranges:
333
- map_cached = not svc.file_memory.needs_update(rel_path)
334
- file_map = svc.file_memory.get_or_build_map(
335
- rel_path, max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
396
+ map_cached = _map_cached()
397
+ file_map = _file_map(max_tokens=svc.file_memory.MAP_TOKEN_BUDGET)
336
398
  if count_tokens(file_map) >= full_file_tokens():
337
399
  # A map that costs more than the file is worth nothing: serve the
338
400
  # file (docs/file-map.md § Small files).
339
401
  file_map = (f"[read:{file_path}] whole file — smaller than its map\n"
340
402
  + raw_text)
341
- resp = (file_map
403
+ resp = (banner + file_map
342
404
  + "\n[map only — pass lines=[start,end] or symbols=[...] for exact source]"
343
- + maybe_related_facts(svc, rel_path, top_k=3, context="read"))
405
+ + _facts())
344
406
  map_tok = count_tokens(resp)
345
407
  if finalize is None:
346
408
  return resp
@@ -350,7 +412,8 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
350
412
  raw_tokens=full_file_tokens(), optimized_tokens=map_tok,
351
413
  response_tokens=map_tok,
352
414
  detail=map_detail(svc, rel_path, "read", cache_hit=map_cached,
353
- fallback="map_only"))
415
+ fallback="map_only", record=_ext_record(),
416
+ external=external))
354
417
  else:
355
418
  # Sort and merge overlapping ranges
356
419
  ranges.sort()
@@ -387,7 +450,7 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
387
450
  prev_end = end
388
451
 
389
452
  final_content = "\n".join(parts)
390
- resp = final_content + maybe_related_facts(svc, rel_path, top_k=3, context="read")
453
+ resp = banner + final_content + _facts()
391
454
  tokens = count_tokens(resp)
392
455
  summary = f"{full_file_tokens()}->{tokens}tok" if tokens < full_file_tokens() else f"{tokens}tok"
393
456
  # C0 measurement: what the read asked for and how much source it took.
@@ -398,6 +461,7 @@ def handle_read(file_path: str, symbols: Any = None, lines: Any = None,
398
461
  "ranges": len(ranges),
399
462
  "lines_served": sum(e - s_ + 1 for s_, e in ranges),
400
463
  "file_lines": len(content_lines),
464
+ "external": external,
401
465
  }
402
466
  return finalize_with_tokens(
403
467
  finalize, svc, "c3_read", {"file": file_path, "symbols": symbols}, resp, summary,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.128.1
3
+ Version: 2.129.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
@@ -460,6 +460,7 @@ tests/test_project_manager_merge.py
460
460
  tests/test_project_tool.py
461
461
  tests/test_read_coercion.py
462
462
  tests/test_read_edit_parity.py
463
+ tests/test_read_outside_root.py
463
464
  tests/test_related_facts.py
464
465
  tests/test_repo_map.py
465
466
  tests/test_repo_shape.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.128.1"
7
+ version = "2.129.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"
@@ -116,6 +116,19 @@ def availability() -> dict:
116
116
  info["docker"] = True
117
117
  info["docker_version"] = out.strip().splitlines()[-1] if out.strip() else ""
118
118
  info["ok"] = True
119
+
120
+ # Is the default runner image already local? Absent, the first act run
121
+ # pulls ~1 GB, which is worth warning about but is not unreadiness. This
122
+ # probe deliberately does NOT pull: it cannot, in any case, predict the
123
+ # failure in issue #173 — there the image is present and `docker pull`
124
+ # succeeds, while act's own pull fails because act sends the stored
125
+ # registry credential and the CLI does not. Only a real act run shows
126
+ # that, which is why the runner classifies it (see setup_failure).
127
+ rc, _ = _probe(["docker", "image", "inspect", DEFAULT_IMAGE], timeout=20)
128
+ info["image_present"] = rc == 0
129
+ if rc != 0:
130
+ info["warning"] = (f"runner image {DEFAULT_IMAGE} is not present "
131
+ "locally; the first act run pulls ~1 GB.")
119
132
  return info
120
133
 
121
134
 
@@ -243,6 +256,53 @@ def build_command(inst, project, act_path: str, event: str = "",
243
256
  _ACT_OUTPUT_LINE = re.compile(r"^\[[^\]]*\]\s{0,3}\|\s?(.*)$")
244
257
 
245
258
 
259
+ # ── Setup-phase failures ────────────────────────────────────────────────────
260
+ # act can fail BEFORE any workflow step runs: the runner image cannot be
261
+ # pulled, the daemon refuses, the container never starts. Nothing the failure
262
+ # parsers look for was ever printed, so parsing that log yields `unparsed` and
263
+ # `c3_ci(action='failures')` answers "0 parsed failures" — for what is really
264
+ # "the runner image could not be obtained" (issue #173). Classify it instead.
265
+ SETUP_PARSER = "container-setup"
266
+
267
+ _SETUP_FAILED = re.compile(r"(?:❌\s*)?Failure\s+-\s+Set up job", re.I)
268
+ _DAEMON_ERROR = re.compile(r"Error response from daemon:\s*(.+)", re.I)
269
+ _SETUP_REASONS = (
270
+ (re.compile(r"authentication required|incorrect username or password", re.I),
271
+ "the Docker registry rejected the runner image pull with an "
272
+ "authentication error. act sends the stored Docker credential where the "
273
+ "CLI sends none for a public image, so an expired token turns a public "
274
+ "pull into an auth failure — `docker logout` clears it."),
275
+ (re.compile(r"pull access denied|repository does not exist|manifest unknown", re.I),
276
+ "the runner image could not be found in the registry."),
277
+ (re.compile(r"Cannot connect to the Docker daemon|daemon is not running|"
278
+ r"docker daemon is not running", re.I),
279
+ "the Docker daemon is not reachable — start Docker and retry."),
280
+ (re.compile(r"no space left on device", re.I),
281
+ "the Docker host ran out of disk space pulling the runner image."),
282
+ )
283
+
284
+
285
+ def setup_failure(text: str) -> str:
286
+ """Why act failed before any workflow step ran, or '' if it got that far.
287
+
288
+ The verdict marker is act's own `Failure - Set up job`; the patterns after
289
+ it only supply a reason a human can act on. A job that reached its steps
290
+ and failed there is NOT a setup failure and must still go to the parsers.
291
+ """
292
+ text = text or ""
293
+ if not _SETUP_FAILED.search(text):
294
+ return ""
295
+ for pattern, reason in _SETUP_REASONS:
296
+ if pattern.search(text):
297
+ return f"act could not start the runner container: {reason}"
298
+ daemon = _DAEMON_ERROR.search(text)
299
+ if daemon:
300
+ return ("act could not start the runner container — the Docker daemon "
301
+ f"said: {daemon.group(1).strip()[:200]}")
302
+ return ("act failed during 'Set up job': the runner container never "
303
+ "started, so no workflow step ran.")
304
+
305
+
246
306
  def program_output(text: str) -> str:
247
307
  """Just what the commands printed, with act's prefixes removed.
248
308
 
@@ -413,6 +413,17 @@ def _run_job_act(inst, project: Path, run_dir: Path, event: str,
413
413
  pass
414
414
 
415
415
  if result.status in (FAILED, TIMEOUT):
416
+ # A setup-phase failure has no program output to parse: the container
417
+ # never started. Parsing it anyway reported `unparsed` with a log
418
+ # tail, so `c3_ci(action='failures')` answered "0 parsed failures" for
419
+ # a broken runner (issue #173). Say what actually happened. The status
420
+ # stays FAILED — a job that could not run is never a green light.
421
+ setup_reason = ci_act.setup_failure(outcome.get("output") or "")
422
+ if setup_reason:
423
+ result.reason = setup_reason
424
+ result.parser = ci_act.SETUP_PARSER
425
+ result.failures = []
426
+ return result
416
427
  # Parse what the commands printed, not act's narration around it —
417
428
  # otherwise every file path arrives wearing a `[CI/lint] |` prefix.
418
429
  parsed = ci_failures.parse(
@@ -87,12 +87,44 @@ def _line_count(path: Path) -> int:
87
87
  return 0
88
88
 
89
89
 
90
- def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOKENS) -> tuple:
91
- """Return (text, detail) for the directory `rel_dir` (project-relative, posix)."""
92
- root = Path(svc.project_path).resolve()
93
- rel_dir = str(rel_dir).replace("\\", "/").strip("/")
94
- target = (root / rel_dir).resolve() if rel_dir else root
95
- label = (rel_dir + "/") if rel_dir else "./"
90
+ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOKENS,
91
+ external: bool = False) -> tuple:
92
+ """Return (text, detail) for the directory `rel_dir` (project-relative, posix).
93
+
94
+ `external=True` maps a directory OUTSIDE the project root: `rel_dir` is an
95
+ absolute path and names are relative to it. Symbols are still extracted,
96
+ under the same file/deadline/byte bounds — but through transient records
97
+ that are never persisted or looked up, because an outside file has no
98
+ project-relative key and indexing it would poison a store the rest of C3
99
+ addresses by that key. The edit ledger, which supplies the recency
100
+ ranking, likewise has nothing to say about a file outside the project.
101
+ """
102
+ store = getattr(svc, "file_memory", None)
103
+ if external:
104
+ root = Path(rel_dir).resolve()
105
+ target = root
106
+ name_base = ""
107
+ label = root.as_posix().rstrip("/") + "/"
108
+ recent = {}
109
+
110
+ def _cached(rel):
111
+ return None # nothing outside the root is ever in the store
112
+
113
+ def _extract(rel):
114
+ return store.build_transient_record(root / rel, key=rel)
115
+ else:
116
+ root = Path(svc.project_path).resolve()
117
+ rel_dir = str(rel_dir).replace("\\", "/").strip("/")
118
+ target = (root / rel_dir).resolve() if rel_dir else root
119
+ name_base = rel_dir
120
+ label = (rel_dir + "/") if rel_dir else "./"
121
+ recent = _recent_edit_ranks(svc)
122
+
123
+ def _cached(rel):
124
+ return store.get(rel)
125
+
126
+ def _extract(rel):
127
+ return store.update(rel)
96
128
 
97
129
  files = []
98
130
  capped = False
@@ -104,9 +136,6 @@ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOK
104
136
  files.append(fp.resolve().relative_to(root).as_posix())
105
137
  except ValueError:
106
138
  continue
107
-
108
- store = getattr(svc, "file_memory", None)
109
- recent = _recent_edit_ranks(svc)
110
139
  started = time.monotonic()
111
140
  extracted = 0
112
141
  rows = []
@@ -115,7 +144,7 @@ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOK
115
144
  record = None
116
145
  if store is not None:
117
146
  try:
118
- record = store.get(rel)
147
+ record = _cached(rel)
119
148
  except Exception:
120
149
  record = None
121
150
  ext = Path(rel).suffix.lower()
@@ -124,7 +153,7 @@ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOK
124
153
  and time.monotonic() - started < EXTRACT_DEADLINE_S):
125
154
  try:
126
155
  if (root / rel).stat().st_size <= MAX_EXTRACT_BYTES:
127
- record = store.update(rel)
156
+ record = _extract(rel)
128
157
  extracted += 1
129
158
  except Exception:
130
159
  record = None
@@ -135,7 +164,7 @@ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOK
135
164
  symbols = _top_symbols(record)
136
165
  rows.append({
137
166
  "rel": rel,
138
- "name": rel[len(rel_dir) + 1:] if rel_dir and rel.startswith(rel_dir + "/") else rel,
167
+ "name": rel[len(name_base) + 1:] if name_base and rel.startswith(name_base + "/") else rel,
139
168
  "lines": lines,
140
169
  "lang": lang,
141
170
  "symbols": symbols,
@@ -172,5 +201,6 @@ def render_directory_map(svc, rel_dir: str, *, max_tokens: int = DEFAULT_MAX_TOK
172
201
  "listed": len(kept),
173
202
  "extracted": extracted,
174
203
  "capped": capped,
204
+ "external": bool(external),
175
205
  }
176
206
  return text, detail