code-context-control 2.113.0__tar.gz → 2.114.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 (494) hide show
  1. {code_context_control-2.113.0 → code_context_control-2.114.0}/PKG-INFO +1 -1
  2. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/c3.py +3 -2
  3. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_dispatch.py +1 -1
  4. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/mcp_server.py +40 -1
  5. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/project.py +11 -0
  6. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/shell.py +3 -2
  7. code_context_control-2.114.0/cli/tools/shell_job.py +363 -0
  8. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/PKG-INFO +1 -1
  9. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/SOURCES.txt +3 -0
  10. {code_context_control-2.113.0 → code_context_control-2.114.0}/pyproject.toml +1 -1
  11. code_context_control-2.114.0/services/shell_jobs.py +1160 -0
  12. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/shell_output.py +11 -4
  13. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_c3_shell.py +1 -1
  14. code_context_control-2.114.0/tests/test_shell_jobs_s3.py +488 -0
  15. {code_context_control-2.113.0 → code_context_control-2.114.0}/LICENSE +0 -0
  16. {code_context_control-2.113.0 → code_context_control-2.114.0}/README.md +0 -0
  17. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/__init__.py +0 -0
  18. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/_hook_utils.py +0 -0
  19. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/_shell_writes.py +0 -0
  20. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/commands/__init__.py +0 -0
  21. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/commands/common.py +0 -0
  22. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/commands/parser.py +0 -0
  23. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/docs.html +0 -0
  24. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/edits.html +0 -0
  25. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/access.html +0 -0
  26. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/bitbucket.html +0 -0
  27. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/credentials.html +0 -0
  28. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/getting-started.html +0 -0
  29. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/index.html +0 -0
  30. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/masking.html +0 -0
  31. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/oracle.html +0 -0
  32. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/shared.css +0 -0
  33. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/tools.html +0 -0
  34. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/guide/workflow.html +0 -0
  35. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_access_guard.py +0 -0
  36. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_artifact.py +0 -0
  37. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_auto_snapshot.py +0 -0
  38. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_c3_signal.py +0 -0
  39. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_c3read.py +0 -0
  40. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_edit_ledger.py +0 -0
  41. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_edit_unlock.py +0 -0
  42. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_filter.py +0 -0
  43. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_ghost_files.py +0 -0
  44. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_pretool_enforce.py +0 -0
  45. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_prompt_recall.py +0 -0
  46. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_read.py +0 -0
  47. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_session_stats.py +0 -0
  48. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hook_terse_advisor.py +0 -0
  49. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_server.py +0 -0
  50. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/app.js +0 -0
  51. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/add_project.js +0 -0
  52. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/config_editor.js +0 -0
  53. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  54. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_health.js +0 -0
  55. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_panel.js +0 -0
  56. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  57. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  58. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/drill_views.js +0 -0
  59. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/global_search.js +0 -0
  60. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_access.js +0 -0
  61. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_ci.js +0 -0
  62. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  63. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  64. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  65. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_locks.js +0 -0
  66. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  67. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  68. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/modals.js +0 -0
  69. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/project_card.js +0 -0
  70. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/project_tree.js +0 -0
  71. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/session_drawer.js +0 -0
  72. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/settings_modal.js +0 -0
  73. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/sidebar.js +0 -0
  74. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/summary_bar.js +0 -0
  75. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/task_board.js +0 -0
  76. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/toasts.js +0 -0
  77. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/components/topbar.js +0 -0
  78. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui/state.js +0 -0
  79. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/hub_ui.html +0 -0
  80. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/mcp_proxy.py +0 -0
  81. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/progress.py +0 -0
  82. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/server.py +0 -0
  83. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/__init__.py +0 -0
  84. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/_grants.py +0 -0
  85. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/_helpers.py +0 -0
  86. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/agent.py +0 -0
  87. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/artifacts.py +0 -0
  88. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/bitbucket.py +0 -0
  89. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/ci.py +0 -0
  90. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/compress.py +0 -0
  91. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/credentials.py +0 -0
  92. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/delegate.py +0 -0
  93. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/edit.py +0 -0
  94. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/edit_verify.py +0 -0
  95. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/edits.py +0 -0
  96. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/federate.py +0 -0
  97. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/filter.py +0 -0
  98. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/impact.py +0 -0
  99. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/jira.py +0 -0
  100. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/locks.py +0 -0
  101. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/memory.py +0 -0
  102. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/override.py +0 -0
  103. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/read.py +0 -0
  104. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/search.py +0 -0
  105. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/session.py +0 -0
  106. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/shell_parsers.py +0 -0
  107. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/shell_render.py +0 -0
  108. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/status.py +0 -0
  109. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/tasks.py +0 -0
  110. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/tools/validate.py +0 -0
  111. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/api.js +0 -0
  112. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/app.js +0 -0
  113. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/access.js +0 -0
  114. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/bitbucket.js +0 -0
  115. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/chat.js +0 -0
  116. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/credentials.js +0 -0
  117. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/dashboard.js +0 -0
  118. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/edits.js +0 -0
  119. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/enforcement.js +0 -0
  120. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/instructions.js +0 -0
  121. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/jira.js +0 -0
  122. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/memory.js +0 -0
  123. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/sessions.js +0 -0
  124. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/settings.js +0 -0
  125. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/sidebar.js +0 -0
  126. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/components/tasks.js +0 -0
  127. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/icons.js +0 -0
  128. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/pm_shared.js +0 -0
  129. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/shared.js +0 -0
  130. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui/theme.js +0 -0
  131. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui.html +0 -0
  132. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui_legacy.html +0 -0
  133. {code_context_control-2.113.0 → code_context_control-2.114.0}/cli/ui_nano.html +0 -0
  134. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  135. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/entry_points.txt +0 -0
  136. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/requires.txt +0 -0
  137. {code_context_control-2.113.0 → code_context_control-2.114.0}/code_context_control.egg-info/top_level.txt +0 -0
  138. {code_context_control-2.113.0 → code_context_control-2.114.0}/core/__init__.py +0 -0
  139. {code_context_control-2.113.0 → code_context_control-2.114.0}/core/config.py +0 -0
  140. {code_context_control-2.113.0 → code_context_control-2.114.0}/core/ide.py +0 -0
  141. {code_context_control-2.113.0 → code_context_control-2.114.0}/core/mcp_toml.py +0 -0
  142. {code_context_control-2.113.0 → code_context_control-2.114.0}/core/web_security.py +0 -0
  143. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/__init__.py +0 -0
  144. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/config.py +0 -0
  145. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/mcp_oracle.py +0 -0
  146. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/oracle_server.py +0 -0
  147. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/oracle_ui.html +0 -0
  148. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/__init__.py +0 -0
  149. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/activity_reporter.py +0 -0
  150. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/api_auth.py +0 -0
  151. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/c3_bridge.py +0 -0
  152. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/chat_engine.py +0 -0
  153. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/chat_poll.py +0 -0
  154. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/chat_store.py +0 -0
  155. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/cross_memory.py +0 -0
  156. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/discovery_audit.py +0 -0
  157. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/federated_graph.py +0 -0
  158. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/health_checker.py +0 -0
  159. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/insight_engine.py +0 -0
  160. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/local_session.py +0 -0
  161. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/memory_reader.py +0 -0
  162. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/memory_writer.py +0 -0
  163. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/mobile_api.py +0 -0
  164. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/project_scanner.py +0 -0
  165. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/review_agent.py +0 -0
  166. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/tool_executor.py +0 -0
  167. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/services/tool_registry.py +0 -0
  168. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/activity.js +0 -0
  169. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/agents.js +0 -0
  170. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/app.js +0 -0
  171. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/busy.js +0 -0
  172. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/conversations.js +0 -0
  173. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/input.js +0 -0
  174. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/markdown.js +0 -0
  175. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/send.js +0 -0
  176. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/stream_renderer.js +0 -0
  177. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/chat/toolbar.js +0 -0
  178. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/core.js +0 -0
  179. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/crossgraph.js +0 -0
  180. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/header.js +0 -0
  181. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/insights.js +0 -0
  182. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/projects.js +0 -0
  183. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/qrcode.js +0 -0
  184. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/settings.js +0 -0
  185. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/suggestions.js +0 -0
  186. {code_context_control-2.113.0 → code_context_control-2.114.0}/oracle/ui/theme_tabs.js +0 -0
  187. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/__init__.py +0 -0
  188. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/access_guard.py +0 -0
  189. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/access_telemetry.py +0 -0
  190. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/activity_log.py +0 -0
  191. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/agent_base.py +0 -0
  192. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/agent_locks.py +0 -0
  193. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/agents.py +0 -0
  194. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/artifact_defs.py +0 -0
  195. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/artifact_store.py +0 -0
  196. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/auto_memory.py +0 -0
  197. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/background_service.py +0 -0
  198. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/__init__.py +0 -0
  199. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/external/__init__.py +0 -0
  200. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/external/aider_polyglot.py +0 -0
  201. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/external/swe_bench.py +0 -0
  202. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/search_eval.py +0 -0
  203. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bench/shell_eval.py +0 -0
  204. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/benchmark_dashboard.py +0 -0
  205. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bitbucket_client.py +0 -0
  206. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/bitbucket_credentials.py +0 -0
  207. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_act.py +0 -0
  208. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_cache.py +0 -0
  209. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_expr.py +0 -0
  210. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_failures.py +0 -0
  211. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_github.py +0 -0
  212. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_impact.py +0 -0
  213. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_intel.py +0 -0
  214. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_runner.py +0 -0
  215. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ci_workflow.py +0 -0
  216. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/circuit_breaker.py +0 -0
  217. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/claude_md.py +0 -0
  218. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/compressor.py +0 -0
  219. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/context_snapshot.py +0 -0
  220. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/conversation_store.py +0 -0
  221. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/cred_audit.py +0 -0
  222. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/cred_telemetry.py +0 -0
  223. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/credential_store.py +0 -0
  224. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/doc_index.py +0 -0
  225. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/e2e_benchmark.py +0 -0
  226. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/e2e_evaluator.py +0 -0
  227. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/e2e_tasks.py +0 -0
  228. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/edit_ledger.py +0 -0
  229. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/embedding_index.py +0 -0
  230. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/enforcement_policy.py +0 -0
  231. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/error_reporting.py +0 -0
  232. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/file_memory.py +0 -0
  233. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/git_context.py +0 -0
  234. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/hub_service.py +0 -0
  235. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/index_store.py +0 -0
  236. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/indexer.py +0 -0
  237. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/jira_client.py +0 -0
  238. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/jira_cloud.py +0 -0
  239. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/jira_credentials.py +0 -0
  240. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/jira_data_center.py +0 -0
  241. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/jira_links.py +0 -0
  242. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/lexical_index.py +0 -0
  243. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/mask_activation.py +0 -0
  244. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/mask_mirror.py +0 -0
  245. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/mask_presets.py +0 -0
  246. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory.py +0 -0
  247. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_consolidator.py +0 -0
  248. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_distiller.py +0 -0
  249. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_graph.py +0 -0
  250. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_grounder.py +0 -0
  251. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_queue.py +0 -0
  252. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/memory_scorer.py +0 -0
  253. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/metrics.py +0 -0
  254. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/notifications.py +0 -0
  255. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ollama_bridge.py +0 -0
  256. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ollama_client.py +0 -0
  257. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/ollama_credentials.py +0 -0
  258. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/oracle_service.py +0 -0
  259. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/output_filter.py +0 -0
  260. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/override_grants.py +0 -0
  261. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/override_policy.py +0 -0
  262. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/override_requests.py +0 -0
  263. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/override_wake.py +0 -0
  264. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/parser.py +0 -0
  265. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/project_manager.py +0 -0
  266. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/project_runtime.py +0 -0
  267. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/protocol.py +0 -0
  268. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/proxy_state.py +0 -0
  269. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/repo_map.py +0 -0
  270. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/repo_shape.py +0 -0
  271. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/reranker.py +0 -0
  272. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/retention.py +0 -0
  273. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/retrieval.py +0 -0
  274. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/retrieval_broker.py +0 -0
  275. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/router.py +0 -0
  276. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/runtime.py +0 -0
  277. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/scanner.py +0 -0
  278. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/session_benchmark.py +0 -0
  279. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/session_manager.py +0 -0
  280. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/session_preloader.py +0 -0
  281. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/subprojects.py +0 -0
  282. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/task_store.py +0 -0
  283. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/telemetry.py +0 -0
  284. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/text_index.py +0 -0
  285. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/time_tracker.py +0 -0
  286. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/tool_classifier.py +0 -0
  287. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/transcript_index.py +0 -0
  288. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/validation_cache.py +0 -0
  289. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/vector_store.py +0 -0
  290. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/watcher.py +0 -0
  291. {code_context_control-2.113.0 → code_context_control-2.114.0}/services/win_subprocess.py +0 -0
  292. {code_context_control-2.113.0 → code_context_control-2.114.0}/setup.cfg +0 -0
  293. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_builtin_optout.py +0 -0
  294. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_guard.py +0 -0
  295. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_guard_meta.py +0 -0
  296. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_guard_shell_project.py +0 -0
  297. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_guard_surfaces.py +0 -0
  298. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_access_guard_wiring.py +0 -0
  299. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_activity_reporter.py +0 -0
  300. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_agent_locks.py +0 -0
  301. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_aider_polyglot.py +0 -0
  302. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_antigravity_transition.py +0 -0
  303. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_artifact_store.py +0 -0
  304. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_artifact_tool.py +0 -0
  305. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_background_service.py +0 -0
  306. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  307. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_bitbucket_client.py +0 -0
  308. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_bitbucket_config_fallback.py +0 -0
  309. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_bitbucket_credentials.py +0 -0
  310. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_bitbucket_tool.py +0 -0
  311. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_builtin_modes.py +0 -0
  312. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  313. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_chat_poll.py +0 -0
  314. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_act.py +0 -0
  315. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_cache.py +0 -0
  316. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_expr.py +0 -0
  317. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_impact.py +0 -0
  318. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_intel.py +0 -0
  319. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_runner.py +0 -0
  320. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ci_workflow.py +0 -0
  321. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_circuit_breaker.py +0 -0
  322. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_claude_md_merge.py +0 -0
  323. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_claude_md_updater.py +0 -0
  324. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_cli_smoke.py +0 -0
  325. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_compressor_large_file.py +0 -0
  326. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_confirm_guard.py +0 -0
  327. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_confirm_guard_wiring.py +0 -0
  328. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_cooccurrence_bounds.py +0 -0
  329. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_cred_audit.py +0 -0
  330. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_cred_telemetry.py +0 -0
  331. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_credential_login_kind.py +0 -0
  332. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_credential_store.py +0 -0
  333. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_credential_ui_parity.py +0 -0
  334. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_credentials_routes.py +0 -0
  335. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_credentials_tool.py +0 -0
  336. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_creds_cli_smoke.py +0 -0
  337. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_delegate_cascade.py +0 -0
  338. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_delegate_version_probe.py +0 -0
  339. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_e2e_benchmark.py +0 -0
  340. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_edit_ledger_deadline.py +0 -0
  341. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_edit_ledger_hook.py +0 -0
  342. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_edit_locking.py +0 -0
  343. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_edit_normalization.py +0 -0
  344. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_edit_verify.py +0 -0
  345. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_embedding_index_deadlock.py +0 -0
  346. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_enforcement_flip.py +0 -0
  347. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_enforcement_policy.py +0 -0
  348. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_enforcement_routes.py +0 -0
  349. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_env_parser.py +0 -0
  350. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  351. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_federated_graph.py +0 -0
  352. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_filter_backoff.py +0 -0
  353. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ghost_files.py +0 -0
  354. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ghost_generation.py +0 -0
  355. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_git_branch_awareness.py +0 -0
  356. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_access_guard.py +0 -0
  357. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_codex_compat.py +0 -0
  358. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_dispatch.py +0 -0
  359. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_pretool_enforce.py +0 -0
  360. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_prompt_recall.py +0 -0
  361. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_smoke.py +0 -0
  362. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_state.py +0 -0
  363. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hook_utf8_stdio.py +0 -0
  364. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_credentials_route.py +0 -0
  365. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_credentials_routes_write.py +0 -0
  366. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_enforcement_routes.py +0 -0
  367. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_inspect_api.py +0 -0
  368. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_locks_routes.py +0 -0
  369. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_oracle_service_routes.py +0 -0
  370. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_override_routes.py +0 -0
  371. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_server_smoke.py +0 -0
  372. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_hub_subproject_links.py +0 -0
  373. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ide_workflow_adaptation.py +0 -0
  374. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_index_cap_not_hardcoded.py +0 -0
  375. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  376. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_init_scan.py +0 -0
  377. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_install_mcp_entrypoint.py +0 -0
  378. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_cli_smoke.py +0 -0
  379. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_client.py +0 -0
  380. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_config_fallback.py +0 -0
  381. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_credentials.py +0 -0
  382. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_links.py +0 -0
  383. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_routes.py +0 -0
  384. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_jira_tool.py +0 -0
  385. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_lazy_store_init.py +0 -0
  386. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mask_guard.py +0 -0
  387. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mask_routes.py +0 -0
  388. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mask_surfaces.py +0 -0
  389. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mcp_host_guard.py +0 -0
  390. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mcp_memory_timeout.py +0 -0
  391. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mcp_server_smoke.py +0 -0
  392. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mcp_toml.py +0 -0
  393. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_memory_distiller.py +0 -0
  394. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_memory_graph_api.py +0 -0
  395. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_memory_queue.py +0 -0
  396. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_memory_system.py +0 -0
  397. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mobile_api.py +0 -0
  398. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mobile_extras.py +0 -0
  399. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mobile_override_routes.py +0 -0
  400. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_mobile_security_api.py +0 -0
  401. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_no_stale_model_pins.py +0 -0
  402. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_notification_dedup.py +0 -0
  403. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_notification_discipline.py +0 -0
  404. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ollama_credentials.py +0 -0
  405. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_api_auth.py +0 -0
  406. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_apikey_api.py +0 -0
  407. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_c3_bridge.py +0 -0
  408. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_chat_engine.py +0 -0
  409. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_chat_store.py +0 -0
  410. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_discovery_api.py +0 -0
  411. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_discovery_audit.py +0 -0
  412. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_health_probe.py +0 -0
  413. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_local_auth.py +0 -0
  414. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_ollama_bridge.py +0 -0
  415. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_scanner_cache.py +0 -0
  416. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_security_fixes.py +0 -0
  417. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_session_bootstrap.py +0 -0
  418. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_subproject_awareness.py +0 -0
  419. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_oracle_ui_bundle.py +0 -0
  420. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_output_filter.py +0 -0
  421. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_override_grants.py +0 -0
  422. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_override_grants_mcp.py +0 -0
  423. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_override_requests.py +0 -0
  424. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_override_wake.py +0 -0
  425. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_permissions.py +0 -0
  426. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_pm_api.py +0 -0
  427. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_project_manager.py +0 -0
  428. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_project_manager_merge.py +0 -0
  429. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_project_tool.py +0 -0
  430. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_read_coercion.py +0 -0
  431. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_read_edit_parity.py +0 -0
  432. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_related_facts.py +0 -0
  433. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_repo_map.py +0 -0
  434. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_repo_shape.py +0 -0
  435. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_response_boilerplate.py +0 -0
  436. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_retention.py +0 -0
  437. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_review_digest.py +0 -0
  438. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_eval.py +0 -0
  439. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p1.py +0 -0
  440. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p2.py +0 -0
  441. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p2b.py +0 -0
  442. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p3.py +0 -0
  443. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p4.py +0 -0
  444. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_search_p5.py +0 -0
  445. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_service_durability.py +0 -0
  446. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_session_benchmark.py +0 -0
  447. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_session_budget.py +0 -0
  448. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_budget_s1.py +0 -0
  449. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_creds.py +0 -0
  450. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_eval.py +0 -0
  451. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_output.py +0 -0
  452. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_parsers_s2.py +0 -0
  453. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_robustness.py +0 -0
  454. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_telemetry_s0.py +0 -0
  455. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_write_ledger.py +0 -0
  456. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_shell_writes.py +0 -0
  457. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subproject_clear_scope.py +0 -0
  458. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subproject_depth_consumers.py +0 -0
  459. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subproject_exclusion.py +0 -0
  460. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subproject_federation.py +0 -0
  461. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subproject_linkage_api.py +0 -0
  462. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_subprojects.py +0 -0
  463. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_swe_bench.py +0 -0
  464. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_task_store.py +0 -0
  465. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_task_tool.py +0 -0
  466. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_time_tracker.py +0 -0
  467. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_token_telemetry.py +0 -0
  468. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_token_tracking.py +0 -0
  469. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_tool_registry.py +0 -0
  470. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_ui_jsx_syntax.py +0 -0
  471. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_upgrade_and_version.py +0 -0
  472. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_validate.py +0 -0
  473. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_vault_write_guard.py +0 -0
  474. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_version_sync.py +0 -0
  475. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_web_security.py +0 -0
  476. {code_context_control-2.113.0 → code_context_control-2.114.0}/tests/test_windows_reliability.py +0 -0
  477. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/__init__.py +0 -0
  478. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/backend.py +0 -0
  479. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/main.py +0 -0
  480. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/__init__.py +0 -0
  481. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/benchmark_view.py +0 -0
  482. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/claudemd_view.py +0 -0
  483. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/compress_view.py +0 -0
  484. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/index_view.py +0 -0
  485. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/init_view.py +0 -0
  486. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/mcp_view.py +0 -0
  487. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/optimize_view.py +0 -0
  488. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/pipe_view.py +0 -0
  489. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/projects_view.py +0 -0
  490. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/search_view.py +0 -0
  491. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/session_view.py +0 -0
  492. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/stats.py +0 -0
  493. {code_context_control-2.113.0 → code_context_control-2.114.0}/tui/screens/ui_view.py +0 -0
  494. {code_context_control-2.113.0 → code_context_control-2.114.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.113.0
3
+ Version: 2.114.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
@@ -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.113.0"
95
+ __version__ = "2.114.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -261,7 +261,7 @@ _C3_MCP_ALLOW = [
261
261
  "mcp__c3__c3_bitbucket",
262
262
  "mcp__c3__c3_jira", "mcp__c3__c3_credentials",
263
263
  "mcp__c3__c3_project", "mcp__c3__c3_task", "mcp__c3__c3_artifacts",
264
- "mcp__c3__c3_override", "mcp__c3__c3_ci",
264
+ "mcp__c3__c3_override", "mcp__c3__c3_ci", "mcp__c3__c3_shell_job",
265
265
  ]
266
266
 
267
267
  # Obsolete MCP tool names from earlier C3 versions. `c3 permissions clean`
@@ -5639,6 +5639,7 @@ def cmd_install_mcp(args):
5639
5639
  "mcp__c3__c3_delegate",
5640
5640
  "mcp__c3__c3_session",
5641
5641
  "mcp__c3__c3_agent",
5642
+ "mcp__c3__c3_shell_job",
5642
5643
  edit_matcher,
5643
5644
  write_matcher,
5644
5645
  *extra_edit_matchers,
@@ -97,7 +97,7 @@ _SIGNAL_TOOLS = {
97
97
  "mcp__c3__c3_compress", "mcp__c3__c3_filter", "mcp__c3__c3_memory",
98
98
  "mcp__c3__c3_validate", "mcp__c3__c3_edit", "mcp__c3__c3_edits",
99
99
  "mcp__c3__c3_impact", "mcp__c3__c3_status", "mcp__c3__c3_delegate",
100
- "mcp__c3__c3_session", "mcp__c3__c3_agent",
100
+ "mcp__c3__c3_session", "mcp__c3__c3_agent", "mcp__c3__c3_shell_job",
101
101
  }
102
102
 
103
103
  # hook_edit_unlock was registered only for c3_compress and c3_agent
@@ -917,7 +917,10 @@ async def c3_shell(cmd: str = "", cwd: str = "", timeout: int = 60,
917
917
  $HOME/~; fork bombs; whole-drive wipes) — a guard, NOT a sandbox. Soft-warns on
918
918
  --force, --no-verify, reset --hard.
919
919
  Git Bash may not include optional tools such as jq; use `python -m json.tool`
920
- for portable JSON formatting. Native Bash remains the fallback for interactive/TTY commands."""
920
+ for portable JSON formatting. Native Bash remains the fallback for interactive/TTY commands.
921
+ Work longer than this client's tool-call ceiling (full test suites, builds, device
922
+ commands) belongs in c3_shell_job, which runs it in a detached supervisor for up to 6 h
923
+ and keeps its output in the same store — a timeout here is never converted into a job."""
921
924
  svc = _svc(ctx)
922
925
 
923
926
  def finalize(name, args, resp, summ, **kw):
@@ -930,6 +933,42 @@ async def c3_shell(cmd: str = "", cwd: str = "", timeout: int = 60,
930
933
  max_bytes=max_bytes or None)
931
934
 
932
935
 
936
+ @mcp.tool()
937
+ async def c3_shell_job(action: str, cmd: str = "", cwd: str = "", timeout: int = 1800,
938
+ env_creds: str = "", job_id: str = "", stream: str = "stdout",
939
+ lines: str = "", max_bytes: int = 0,
940
+ ctx: Context = None) -> str:
941
+ """BACKGROUND shell job — start | status | tail | cancel | list. For work that outlives a
942
+ tool call: full test suites, long builds, device/emulator commands, anything over the
943
+ client's ~2 min ceiling on c3_shell. Prefer c3_ci for a repository's own workflows.
944
+ start: cmd (+cwd, env_creds, timeout in seconds — default 1800, ceiling 21600 = 6 h)
945
+ runs c3_shell's full pre-flight (blocklist, access-guard cwd deny, advisory read scan,
946
+ write scan with confirm holds, credential expansion) and then hands the command to a
947
+ DETACHED supervisor process that survives this server; replies with a job_id='j-…'
948
+ at once. Nothing here waits on the job, and a c3_shell timeout is never turned into one.
949
+ status: one line — queued|running|done|failed|timeout|cancelled|lost, exit code,
950
+ duration, and the output_id once finished. tail: the last `lines` (default 50) of
951
+ stream='stdout'|'stderr' — the GROWING output while running, the kept output after —
952
+ under the same byte budget as c3_shell (max_bytes may only lower it). cancel: kills the
953
+ child process tree ONLY if the recorded pid still has the creation time recorded at
954
+ spawn (a reused pid is never signalled) and records 'cancelled'. list: this project +
955
+ session's jobs.
956
+ Output lands in the same spill store as c3_shell, ALWAYS kept for 3 days: page it with
957
+ c3_shell(output_id='o-…', output_action='read'|'search'|'tail'). Jobs and their output
958
+ are per project AND per session, resolved under the current access rules; another
959
+ project or session sees 'not found'. Credentials are redacted in the kept output and
960
+ never touch the command line, the environment of the supervisor, or disk."""
961
+ svc = _svc(ctx)
962
+
963
+ def finalize(name, args, resp, summ, **kw):
964
+ return _finalize_response(ctx, name, args, resp, summ, **kw)
965
+
966
+ from cli.tools.shell_job import handle_shell_job
967
+ return await asyncio.to_thread(handle_shell_job, action, cmd, cwd, timeout, env_creds,
968
+ job_id, stream, lines or None, max_bytes or None,
969
+ svc, finalize)
970
+
971
+
933
972
  @mcp.tool()
934
973
  async def c3_bitbucket(
935
974
  action: str,
@@ -467,6 +467,17 @@ def handle_project(action, svc, finalize, *, project="", query="", file_path="",
467
467
  from_project=str(getattr(svc, "project_path", ""))),
468
468
  action)
469
469
 
470
+ if action in ("shell_job", "job", "jobs"):
471
+ # S3: a background job is bound to the project AND session that
472
+ # started it (services/shell_jobs.py); proxying one would either run
473
+ # it under the caller's identity or hand another project's session a
474
+ # handle it must not have. Not offered cross-project.
475
+ return done(
476
+ "[c3_project:error] c3_shell_job is not proxied across projects — "
477
+ "start, poll and cancel background jobs from the target project's "
478
+ "own session.",
479
+ "error")
480
+
470
481
  if action not in _READ_OPS and action not in _WRITE_OPS:
471
482
  return done(
472
483
  f"[c3_project:error] Unknown action '{action}'. "
@@ -1234,8 +1234,9 @@ async def handle_shell(cmd: str, cwd: str, timeout: int, filter_output: bool,
1234
1234
  capped_note = (
1235
1235
  f"[c3_shell:capped] timeout={capped_from}s was requested but this "
1236
1236
  f"MCP client kills a tool call at {_ceiling}s; ran with {timeout}s. "
1237
- f"For longer work use the native Bash tool with "
1238
- f"run_in_background, which is not bound by this limit.\n"
1237
+ f"For longer work use c3_shell_job(action='start', cmd=..., timeout=...), "
1238
+ f"which runs detached (up to 6 h), keeps the ledger and telemetry, and "
1239
+ f"pages its output back by id.\n"
1239
1240
  )
1240
1241
 
1241
1242
  try:
@@ -0,0 +1,363 @@
1
+ """c3_shell_job — background shell jobs: start | status | tail | cancel | list (S3).
2
+
3
+ A job is a c3_shell command that outlives the MCP tool call: the run happens
4
+ in a detached supervisor (services/shell_jobs.py) and this handler only
5
+ starts, polls, tails and cancels it — nothing here ever waits on a job.
6
+
7
+ ``start`` performs c3_shell's FULL pre-flight before anything is spawned:
8
+ the catastrophic-command blocklist, the Access Guard cwd deny, credential
9
+ expansion (``{{cred:NAME}}`` + ``env_creds``), the advisory read scan, and the
10
+ write scan with its confirm holds. Those pieces are imported from
11
+ cli.tools.shell so the two surfaces cannot drift; only the credential block
12
+ is repeated here, because it lives inline in handle_shell (S2 owns that file
13
+ during this phase — see the S3 brief).
14
+
15
+ A synchronous c3_shell timeout is never converted into a job: the caller
16
+ chooses this surface explicitly, and c3_shell's own `[c3_shell:capped]`
17
+ note names it as the escape hatch.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import re
22
+ from pathlib import Path
23
+
24
+ from cli.tools import _grants
25
+ from cli.tools._helpers import finalize_with_tokens
26
+ from cli.tools.shell import (
27
+ _BLOCKED,
28
+ _advisory_guard_scan,
29
+ _scan_candidates,
30
+ _write_scan,
31
+ )
32
+ from cli.tools.shell_render import effective_budget, human_bytes
33
+ from core import count_tokens
34
+ from services import access_guard
35
+ from services.shell_jobs import (
36
+ DEFAULT_TIMEOUT_S,
37
+ MAX_TIMEOUT_S,
38
+ JobAccessError,
39
+ JobState,
40
+ JobStore,
41
+ _log_tail,
42
+ )
43
+
44
+ TOOL = "c3_shell_job"
45
+ _ACTIONS = ("start", "status", "tail", "cancel", "list")
46
+ _TAG = "[c3_shell_job"
47
+
48
+
49
+ def _err(msg: str) -> str:
50
+ return f"{_TAG}:error] {msg}"
51
+
52
+
53
+ def _guard_check(svc):
54
+ project_path = str(svc.project_path)
55
+
56
+ def check(path: str):
57
+ try:
58
+ return access_guard.check(path, "read", project_path)
59
+ except Exception as exc: # evaluator error fails closed
60
+ return access_guard.Denial("<evaluator-error>", "deny", "builtin",
61
+ f"evaluator error: {type(exc).__name__}")
62
+ return check
63
+
64
+
65
+ def _log_denied(svc, work_cwd: str, denial, surface: str) -> None:
66
+ if not getattr(svc, "activity_log", None):
67
+ return
68
+ try:
69
+ svc.activity_log.log("access_denied", {
70
+ "tool": TOOL, "surface": surface, "cwd": work_cwd,
71
+ "rule": denial.rule, "scope": denial.scope,
72
+ })
73
+ except Exception:
74
+ pass
75
+
76
+
77
+ def _redact(text: str) -> str:
78
+ try:
79
+ from services import credential_store as _creds
80
+ return _creds.redact_text(text)
81
+ except Exception:
82
+ return text
83
+
84
+
85
+ def _fmt_s(seconds: float) -> str:
86
+ seconds = float(seconds or 0)
87
+ if seconds < 60:
88
+ return f"{seconds:.1f}s"
89
+ if seconds < 3600:
90
+ return f"{int(seconds // 60)}m{int(seconds % 60):02d}s"
91
+ return f"{int(seconds // 3600)}h{int((seconds % 3600) // 60):02d}m"
92
+
93
+
94
+ def _stream_note(job: JobState, stream: str) -> str:
95
+ facts = getattr(job, stream) or {}
96
+ if facts:
97
+ return f"{stream} {human_bytes(int(facts.get('bytes', 0)))}/{int(facts.get('lines', 0))} lines"
98
+ path = (job.spool or {}).get(stream)
99
+ if path:
100
+ try:
101
+ return f"{stream} {human_bytes(Path(path).stat().st_size)} so far"
102
+ except OSError:
103
+ pass
104
+ return f"{stream} —"
105
+
106
+
107
+ def _status_line(job: JobState) -> str:
108
+ """One line the agent can act on: state, exit, duration, and where the output is."""
109
+ head = f"{_TAG}:status] {job.id} {job.status}"
110
+ if job.status == "running":
111
+ body = (f"{head} {_fmt_s(job.elapsed_s())} of {job.timeout_s}s · $ {job.cmd_display} · "
112
+ f"child pid {job.child_pid} · {_stream_note(job, 'stdout')}, {_stream_note(job, 'stderr')}\n"
113
+ f"poll with action='status', read with action='tail' (stream='stdout'|'stderr', lines='80'), "
114
+ f"stop with action='cancel'\n")
115
+ elif job.status == "queued":
116
+ body = f"{head} · $ {job.cmd_display} · supervisor pid {job.supervisor_pid} starting\n"
117
+ else:
118
+ exit_note = f"exit {job.exit_code}" if job.exit_code is not None else "no exit code"
119
+ if job.timed_out:
120
+ exit_note += f" (timed out at {job.timeout_s}s)"
121
+ body = f"{head} {exit_note} in {_fmt_s((job.duration_ms or 0) / 1000)} · $ {job.cmd_display}"
122
+ if job.output_id:
123
+ body += (f"\noutput_id={job.output_id} ({_stream_note(job, 'stdout')}, {_stream_note(job, 'stderr')}) — "
124
+ f"page with c3_shell(output_id='{job.output_id}', output_action='read'|'search'|'tail')")
125
+ if job.error:
126
+ body += f"\nnote: {job.error}"
127
+ body += "\n"
128
+ return body
129
+
130
+
131
+ def _list_line(job: JobState) -> str:
132
+ when = job.finished_at or job.started_at or job.created_at
133
+ extra = ""
134
+ if job.status == "running":
135
+ extra = f" {_fmt_s(job.elapsed_s())}/{job.timeout_s}s"
136
+ elif job.exit_code is not None:
137
+ extra = f" exit {job.exit_code}"
138
+ if job.output_id:
139
+ extra += f" output_id={job.output_id}"
140
+ return f"{job.id} {job.status}{extra} · {when[:19]} · $ {job.cmd_display}"
141
+
142
+
143
+ def _finalize(svc, finalize, action: str, args: dict, body: str, summary: str, job_id: str = "") -> str:
144
+ if not body.endswith("\n"):
145
+ body += "\n"
146
+ tokens = count_tokens(body)
147
+ return finalize_with_tokens(
148
+ finalize, svc, TOOL, {"action": action, **args}, body, summary,
149
+ detail={"cmd_class": "job", "action": action, "job_id": job_id,
150
+ "response_bytes": len(body.encode("utf-8", errors="replace")),
151
+ "response_tokens": tokens},
152
+ response_tokens=tokens,
153
+ )
154
+
155
+
156
+ # ── start ───────────────────────────────────────────────────────────────────
157
+
158
+ def _start(cmd: str, cwd: str, timeout, env_creds: str, svc, finalize) -> str:
159
+ if not cmd or not cmd.strip():
160
+ return _err("empty command")
161
+ # _BLOCKED never consults grants — no approval flow reaches the
162
+ # catastrophic tier, by spec (docs/confirm-guard.md §7).
163
+ if _BLOCKED.search(cmd):
164
+ return _err("blocked pattern — use native Bash with explicit approval if this is truly intended")
165
+ try:
166
+ timeout_s = int(timeout or DEFAULT_TIMEOUT_S)
167
+ except (TypeError, ValueError):
168
+ timeout_s = DEFAULT_TIMEOUT_S
169
+ capped_from = 0
170
+ if timeout_s > MAX_TIMEOUT_S:
171
+ capped_from, timeout_s = timeout_s, MAX_TIMEOUT_S
172
+ timeout_s = max(1, timeout_s)
173
+ work_cwd = str(Path(cwd or svc.project_path).resolve())
174
+ project_path = str(svc.project_path)
175
+
176
+ # ── Access Guard: HARD deny when the effective cwd is under a deny rule
177
+ # (same row as handle_shell; evaluator errors fail closed).
178
+ try:
179
+ cwd_denial = access_guard.check(work_cwd, "read", project_path)
180
+ except Exception as exc:
181
+ cwd_denial = access_guard.Denial("<evaluator-error>", "deny", "builtin",
182
+ f"evaluator error: {type(exc).__name__}")
183
+ if cwd_denial is not None and cwd_denial.kind == "deny":
184
+ _log_denied(svc, work_cwd, cwd_denial, "cwd")
185
+ return access_guard.refusal(cwd_denial, work_cwd, "read")
186
+
187
+ # ── credential expansion — `cmd` stays the RAW template form for every
188
+ # echo/log; `exec_cmd` and the decoded values travel to the supervisor on
189
+ # its stdin only (never argv, env or a file).
190
+ from services import credential_store as _creds
191
+ exec_cmd = cmd
192
+ extra_env: dict[str, str] = {}
193
+ secret_values: dict[str, str] = {}
194
+ cred_names: list[str] = []
195
+ tmpl_used: list[str] = []
196
+ try:
197
+ exec_cmd, tmpl_used, tmpl_missing = _creds.expand_templates(cmd, project_path)
198
+ requested = [n.strip() for n in (env_creds or "").split(",") if n.strip()]
199
+ auto = [n for n, e in _creds.list_entries(project_path).items()
200
+ if e.get("inject") and n not in requested
201
+ and e.get("type") not in _creds.STRUCTURED_TYPES]
202
+ values, missing = _creds.resolve(requested + auto, project_path)
203
+ hard_missing = sorted(set(tmpl_missing) | (set(missing) & set(requested)))
204
+ if hard_missing:
205
+ reasons = _creds.describe_missing(hard_missing, project_path)
206
+ detail = "\n".join(f" {r}: {reasons.get(r, 'unresolvable')}" for r in hard_missing)
207
+ return _err(f"unresolvable credential ref(s):\n{detail}\nsee c3_credentials(action='list')")
208
+ env_owner: dict[str, str] = {}
209
+ for ref, cval in values.items():
210
+ base_name, _, fld = ref.partition(".")
211
+ entry = _creds.get_entry(base_name, project_path=project_path) or {}
212
+ env_name = entry.get("env_var") or base_name
213
+ if fld:
214
+ env_name = f"{env_name}_{fld.upper()}"
215
+ if env_name in env_owner and env_owner[env_name] != ref:
216
+ return _err(f"env-var collision: {env_owner[env_name]} and {ref} both map to "
217
+ f"${env_name} — set a distinct env_var on one of the entries")
218
+ env_owner[env_name] = ref
219
+ extra_env[env_name] = cval
220
+ secret_values[ref] = cval
221
+ if tmpl_used:
222
+ tvals, _ = _creds.resolve(list(tmpl_used), project_path)
223
+ secret_values.update({k: v for k, v in tvals.items() if isinstance(v, str)})
224
+ cred_names = sorted(set(tmpl_used) | set(values))
225
+ except RuntimeError as exc: # keyring/crypto unavailable
226
+ return _err(f"credential store unavailable: {exc}")
227
+ if exec_cmd != cmd and _BLOCKED.search(exec_cmd):
228
+ return _err("blocked pattern after credential expansion")
229
+
230
+ # ── Access Guard ADVISORY token scan — best-effort, not enforcement;
231
+ # the raw and (when different) the expanded command are both scanned.
232
+ for scan_text in ([cmd] if exec_cmd == cmd else [cmd, exec_cmd]):
233
+ scan_denial, hit_tok = _advisory_guard_scan(scan_text, work_cwd, project_path)
234
+ if scan_denial is not None:
235
+ _log_denied(svc, work_cwd, scan_denial, "token_scan")
236
+ return _redact(access_guard.refusal(scan_denial, hit_tok, "read") + (
237
+ f"\n{_TAG}:note] shell path scanning is best-effort (advisory) — a denied hit "
238
+ "refuses the whole job, but a clean scan is not enforcement."))
239
+
240
+ # ── Access Guard WRITE-class scan with confirm holds (v2.102.0 semantics).
241
+ write_refusal, write_grants = _write_scan(cmd, exec_cmd, work_cwd, svc)
242
+ if write_refusal:
243
+ return _redact(write_refusal.replace("[c3_shell:note]", f"{_TAG}:note]"))
244
+
245
+ payload = {"cmd": cmd, "exec_cmd": exec_cmd, "env": extra_env, "secrets": secret_values,
246
+ "cred_names": cred_names, "tmpl_used": list(tmpl_used)}
247
+ session_id = _grants.session_id(svc)
248
+ store = JobStore()
249
+ try:
250
+ job = store.start(project_path=project_path, session_id=session_id, cmd=cmd, cwd=work_cwd,
251
+ timeout_s=timeout_s, payload=payload,
252
+ guard_paths=_scan_candidates(cmd, work_cwd), cred_names=cred_names)
253
+ except Exception as exc:
254
+ return _err(f"could not start the supervisor: {type(exc).__name__}: {exc}")
255
+ if cred_names:
256
+ try:
257
+ _creds.touch_last_used(sorted({r.partition(".")[0] for r in cred_names}), project_path)
258
+ except Exception:
259
+ pass
260
+ if getattr(svc, "activity_log", None):
261
+ try:
262
+ svc.activity_log.log("shell_job", {
263
+ "action": "start", "job_id": job.id, "cmd": cmd[:200], "cwd": work_cwd,
264
+ "timeout_s": timeout_s, "creds": cred_names, "status": job.status,
265
+ })
266
+ except Exception:
267
+ pass
268
+
269
+ if job.status in ("failed", "lost"):
270
+ log_tail = _log_tail(job.log_path)
271
+ body = (f"{_TAG}:error] {job.id} {job.status} before running: {job.error or 'no detail'}"
272
+ + (f"\n--- supervisor log ---\n{log_tail}" if log_tail else "") + "\n")
273
+ return _finalize(svc, finalize, "start", {"cmd": cmd[:120], "cwd": work_cwd}, body,
274
+ f"shell job {job.id} {job.status}", job.id)
275
+ lines = [f"{_TAG}:started] {job.id} $ {job.cmd_display} (timeout {timeout_s}s) — "
276
+ f"poll with action='status', read with action='tail'"]
277
+ pids = f"supervisor pid {job.supervisor_pid}"
278
+ if job.child_pid:
279
+ pids += f", child pid {job.child_pid}"
280
+ lines.append(f"{job.status} · {pids} · cwd {work_cwd}" + (f" · creds {', '.join(cred_names)}" if cred_names else ""))
281
+ if capped_from:
282
+ lines.append(f"{_TAG}:capped] timeout={capped_from}s was requested; jobs run at most "
283
+ f"{MAX_TIMEOUT_S}s (6 h)")
284
+ lines.extend(write_grants)
285
+ body = "\n".join(lines) + "\n"
286
+ return _finalize(svc, finalize, "start", {"cmd": cmd[:120], "cwd": work_cwd}, body,
287
+ f"shell job started {job.id}", job.id)
288
+
289
+
290
+ # ── entry point ─────────────────────────────────────────────────────────────
291
+
292
+ def handle_shell_job(action: str, cmd: str = "", cwd: str = "", timeout=DEFAULT_TIMEOUT_S,
293
+ env_creds: str = "", job_id: str = "", stream: str = "stdout",
294
+ lines=None, max_bytes=None, svc=None, finalize=None) -> str:
295
+ action = (action or "").strip().lower()
296
+ if action not in _ACTIONS:
297
+ return _err(f"action must be one of {', '.join(_ACTIONS)}; got {action!r}")
298
+ if finalize is None:
299
+ def finalize(name, args, resp, summ, **kw): # noqa: E306 — plain passthrough
300
+ return resp
301
+ if action == "start":
302
+ return _start(cmd, cwd, timeout, env_creds, svc, finalize)
303
+
304
+ project_path = str(svc.project_path)
305
+ session_id = _grants.session_id(svc)
306
+ store = JobStore()
307
+ if action == "list":
308
+ jobs = store.list(project_path=project_path, session_id=session_id)
309
+ if not jobs:
310
+ body = f"{_TAG}:list] no jobs for this project and session\n"
311
+ else:
312
+ body = f"{_TAG}:list] {len(jobs)} job(s) for this project and session\n" + "\n".join(
313
+ _list_line(j) for j in jobs) + "\n"
314
+ return _finalize(svc, finalize, "list", {}, body, f"shell jobs list ({len(jobs)})")
315
+
316
+ if not job_id:
317
+ return _err(f"action='{action}' needs job_id='j-…'")
318
+ guard_check = _guard_check(svc)
319
+ try:
320
+ job = store.resolve(job_id, project_path=project_path, session_id=session_id, guard_check=guard_check)
321
+ except JobAccessError as exc:
322
+ return _err(str(exc))
323
+
324
+ if action == "status":
325
+ return _finalize(svc, finalize, "status", {"job_id": job.id}, _status_line(job),
326
+ f"shell job {job.id} {job.status}", job.id)
327
+
328
+ if action == "cancel":
329
+ job, note = store.cancel(job)
330
+ body = f"{_TAG}:cancel] {job.id} {note}\n" + _status_line(job)
331
+ return _finalize(svc, finalize, "cancel", {"job_id": job.id}, body,
332
+ f"shell job {job.id} cancel → {job.status}", job.id)
333
+
334
+ # tail
335
+ stream = (stream or "stdout").strip().lower()
336
+ if stream not in ("stdout", "stderr"):
337
+ return _err("stream must be 'stdout' or 'stderr'")
338
+ n = 50
339
+ if isinstance(lines, int) and not isinstance(lines, bool) and lines > 0:
340
+ n = lines
341
+ elif isinstance(lines, str) and lines.strip():
342
+ digits = re.sub(r"[^0-9]", "", lines)
343
+ if digits:
344
+ n = max(int(digits), 1)
345
+ config_default = None
346
+ try:
347
+ config_default = (getattr(svc, "hybrid_config", None) or {}).get("shell_budget_bytes")
348
+ except Exception:
349
+ pass
350
+ budget = effective_budget(max_bytes, config_default=config_default) - 512
351
+ try:
352
+ text = store.tail(job, stream, lines=n, max_bytes=budget, guard_check=guard_check)
353
+ except Exception as exc:
354
+ return _err(f"{job.id}: {exc}")
355
+ header = f"{_TAG}:tail] {job.id} {job.status} · $ {job.cmd_display}"
356
+ if job.terminal and job.output_id:
357
+ header += f" · output_id={job.output_id}"
358
+ body = header + "\n" + text + "\n"
359
+ return _finalize(svc, finalize, "tail", {"job_id": job.id, "stream": stream, "lines": n}, body,
360
+ f"shell job {job.id} tail {stream}", job.id)
361
+
362
+
363
+ __all__ = ["handle_shell_job", "TOOL"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.113.0
3
+ Version: 2.114.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
@@ -98,6 +98,7 @@ cli/tools/read.py
98
98
  cli/tools/search.py
99
99
  cli/tools/session.py
100
100
  cli/tools/shell.py
101
+ cli/tools/shell_job.py
101
102
  cli/tools/shell_parsers.py
102
103
  cli/tools/shell_render.py
103
104
  cli/tools/status.py
@@ -266,6 +267,7 @@ services/scanner.py
266
267
  services/session_benchmark.py
267
268
  services/session_manager.py
268
269
  services/session_preloader.py
270
+ services/shell_jobs.py
269
271
  services/shell_output.py
270
272
  services/subprojects.py
271
273
  services/task_store.py
@@ -443,6 +445,7 @@ tests/test_session_budget.py
443
445
  tests/test_shell_budget_s1.py
444
446
  tests/test_shell_creds.py
445
447
  tests/test_shell_eval.py
448
+ tests/test_shell_jobs_s3.py
446
449
  tests/test_shell_output.py
447
450
  tests/test_shell_parsers_s2.py
448
451
  tests/test_shell_robustness.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.113.0"
7
+ version = "2.114.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"