code-context-control 2.79.0__tar.gz → 2.80.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 (427) hide show
  1. {code_context_control-2.79.0/code_context_control.egg-info → code_context_control-2.80.0}/PKG-INFO +1 -1
  2. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/c3.py +6 -4
  3. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/commands/parser.py +3 -0
  4. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/mcp_server.py +7 -3
  5. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/ci.py +4 -3
  6. {code_context_control-2.79.0 → code_context_control-2.80.0/code_context_control.egg-info}/PKG-INFO +1 -1
  7. {code_context_control-2.79.0 → code_context_control-2.80.0}/code_context_control.egg-info/SOURCES.txt +2 -0
  8. {code_context_control-2.79.0 → code_context_control-2.80.0}/pyproject.toml +1 -1
  9. code_context_control-2.80.0/services/ci_expr.py +435 -0
  10. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ci_runner.py +139 -10
  11. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ci_workflow.py +72 -17
  12. code_context_control-2.80.0/tests/test_ci_expr.py +340 -0
  13. {code_context_control-2.79.0 → code_context_control-2.80.0}/LICENSE +0 -0
  14. {code_context_control-2.79.0 → code_context_control-2.80.0}/README.md +0 -0
  15. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/__init__.py +0 -0
  16. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/_hook_utils.py +0 -0
  17. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/commands/__init__.py +0 -0
  18. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/commands/common.py +0 -0
  19. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/docs.html +0 -0
  20. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/edits.html +0 -0
  21. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/access.html +0 -0
  22. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/bitbucket.html +0 -0
  23. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/credentials.html +0 -0
  24. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/getting-started.html +0 -0
  25. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/index.html +0 -0
  26. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/masking.html +0 -0
  27. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/oracle.html +0 -0
  28. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/shared.css +0 -0
  29. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/tools.html +0 -0
  30. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/guide/workflow.html +0 -0
  31. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_access_guard.py +0 -0
  32. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_artifact.py +0 -0
  33. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_auto_snapshot.py +0 -0
  34. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_c3_signal.py +0 -0
  35. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_c3read.py +0 -0
  36. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_dispatch.py +0 -0
  37. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_edit_ledger.py +0 -0
  38. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_edit_unlock.py +0 -0
  39. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_filter.py +0 -0
  40. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_ghost_files.py +0 -0
  41. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_pretool_enforce.py +0 -0
  42. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_prompt_recall.py +0 -0
  43. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_read.py +0 -0
  44. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_session_stats.py +0 -0
  45. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hook_terse_advisor.py +0 -0
  46. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_server.py +0 -0
  47. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/app.js +0 -0
  48. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/add_project.js +0 -0
  49. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/config_editor.js +0 -0
  50. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  51. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_health.js +0 -0
  52. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_panel.js +0 -0
  53. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  54. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  55. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/drill_views.js +0 -0
  56. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/global_search.js +0 -0
  57. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/hub_ci.js +0 -0
  58. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  59. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  60. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/hub_locks.js +0 -0
  61. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  62. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/modals.js +0 -0
  63. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/project_card.js +0 -0
  64. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/project_tree.js +0 -0
  65. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/session_drawer.js +0 -0
  66. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/settings_modal.js +0 -0
  67. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/sidebar.js +0 -0
  68. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/summary_bar.js +0 -0
  69. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/task_board.js +0 -0
  70. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/toasts.js +0 -0
  71. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/components/topbar.js +0 -0
  72. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui/state.js +0 -0
  73. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/hub_ui.html +0 -0
  74. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/mcp_proxy.py +0 -0
  75. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/progress.py +0 -0
  76. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/server.py +0 -0
  77. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/__init__.py +0 -0
  78. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/_grants.py +0 -0
  79. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/_helpers.py +0 -0
  80. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/agent.py +0 -0
  81. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/artifacts.py +0 -0
  82. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/bitbucket.py +0 -0
  83. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/compress.py +0 -0
  84. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/credentials.py +0 -0
  85. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/delegate.py +0 -0
  86. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/edit.py +0 -0
  87. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/edit_verify.py +0 -0
  88. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/edits.py +0 -0
  89. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/federate.py +0 -0
  90. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/filter.py +0 -0
  91. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/impact.py +0 -0
  92. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/jira.py +0 -0
  93. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/locks.py +0 -0
  94. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/memory.py +0 -0
  95. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/override.py +0 -0
  96. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/project.py +0 -0
  97. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/read.py +0 -0
  98. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/search.py +0 -0
  99. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/session.py +0 -0
  100. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/shell.py +0 -0
  101. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/status.py +0 -0
  102. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/tasks.py +0 -0
  103. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/tools/validate.py +0 -0
  104. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/api.js +0 -0
  105. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/app.js +0 -0
  106. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/access.js +0 -0
  107. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/bitbucket.js +0 -0
  108. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/chat.js +0 -0
  109. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/credentials.js +0 -0
  110. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/dashboard.js +0 -0
  111. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/edits.js +0 -0
  112. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/enforcement.js +0 -0
  113. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/instructions.js +0 -0
  114. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/jira.js +0 -0
  115. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/memory.js +0 -0
  116. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/sessions.js +0 -0
  117. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/settings.js +0 -0
  118. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/sidebar.js +0 -0
  119. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/components/tasks.js +0 -0
  120. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/icons.js +0 -0
  121. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/pm_shared.js +0 -0
  122. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/shared.js +0 -0
  123. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui/theme.js +0 -0
  124. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui.html +0 -0
  125. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui_legacy.html +0 -0
  126. {code_context_control-2.79.0 → code_context_control-2.80.0}/cli/ui_nano.html +0 -0
  127. {code_context_control-2.79.0 → code_context_control-2.80.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  128. {code_context_control-2.79.0 → code_context_control-2.80.0}/code_context_control.egg-info/entry_points.txt +0 -0
  129. {code_context_control-2.79.0 → code_context_control-2.80.0}/code_context_control.egg-info/requires.txt +0 -0
  130. {code_context_control-2.79.0 → code_context_control-2.80.0}/code_context_control.egg-info/top_level.txt +0 -0
  131. {code_context_control-2.79.0 → code_context_control-2.80.0}/core/__init__.py +0 -0
  132. {code_context_control-2.79.0 → code_context_control-2.80.0}/core/config.py +0 -0
  133. {code_context_control-2.79.0 → code_context_control-2.80.0}/core/ide.py +0 -0
  134. {code_context_control-2.79.0 → code_context_control-2.80.0}/core/mcp_toml.py +0 -0
  135. {code_context_control-2.79.0 → code_context_control-2.80.0}/core/web_security.py +0 -0
  136. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/__init__.py +0 -0
  137. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/config.py +0 -0
  138. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/mcp_oracle.py +0 -0
  139. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/oracle_server.py +0 -0
  140. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/oracle_ui.html +0 -0
  141. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/__init__.py +0 -0
  142. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/activity_reporter.py +0 -0
  143. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/api_auth.py +0 -0
  144. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/c3_bridge.py +0 -0
  145. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/chat_engine.py +0 -0
  146. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/chat_poll.py +0 -0
  147. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/chat_store.py +0 -0
  148. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/cross_memory.py +0 -0
  149. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/discovery_audit.py +0 -0
  150. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/federated_graph.py +0 -0
  151. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/health_checker.py +0 -0
  152. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/insight_engine.py +0 -0
  153. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/local_session.py +0 -0
  154. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/memory_reader.py +0 -0
  155. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/memory_writer.py +0 -0
  156. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/mobile_api.py +0 -0
  157. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/project_scanner.py +0 -0
  158. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/review_agent.py +0 -0
  159. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/tool_executor.py +0 -0
  160. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/services/tool_registry.py +0 -0
  161. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/activity.js +0 -0
  162. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/agents.js +0 -0
  163. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/app.js +0 -0
  164. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/busy.js +0 -0
  165. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/conversations.js +0 -0
  166. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/input.js +0 -0
  167. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/markdown.js +0 -0
  168. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/send.js +0 -0
  169. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/stream_renderer.js +0 -0
  170. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/chat/toolbar.js +0 -0
  171. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/core.js +0 -0
  172. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/crossgraph.js +0 -0
  173. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/header.js +0 -0
  174. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/insights.js +0 -0
  175. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/projects.js +0 -0
  176. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/qrcode.js +0 -0
  177. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/settings.js +0 -0
  178. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/suggestions.js +0 -0
  179. {code_context_control-2.79.0 → code_context_control-2.80.0}/oracle/ui/theme_tabs.js +0 -0
  180. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/__init__.py +0 -0
  181. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/access_guard.py +0 -0
  182. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/access_telemetry.py +0 -0
  183. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/activity_log.py +0 -0
  184. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/agent_base.py +0 -0
  185. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/agent_locks.py +0 -0
  186. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/agents.py +0 -0
  187. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/artifact_defs.py +0 -0
  188. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/artifact_store.py +0 -0
  189. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/auto_memory.py +0 -0
  190. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bench/__init__.py +0 -0
  191. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bench/external/__init__.py +0 -0
  192. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bench/external/aider_polyglot.py +0 -0
  193. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bench/external/swe_bench.py +0 -0
  194. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/benchmark_dashboard.py +0 -0
  195. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bitbucket_client.py +0 -0
  196. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/bitbucket_credentials.py +0 -0
  197. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ci_failures.py +0 -0
  198. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/circuit_breaker.py +0 -0
  199. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/claude_md.py +0 -0
  200. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/compressor.py +0 -0
  201. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/context_snapshot.py +0 -0
  202. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/conversation_store.py +0 -0
  203. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/credential_store.py +0 -0
  204. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/doc_index.py +0 -0
  205. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/e2e_benchmark.py +0 -0
  206. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/e2e_evaluator.py +0 -0
  207. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/e2e_tasks.py +0 -0
  208. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/edit_ledger.py +0 -0
  209. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/embedding_index.py +0 -0
  210. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/enforcement_policy.py +0 -0
  211. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/error_reporting.py +0 -0
  212. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/file_memory.py +0 -0
  213. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/git_context.py +0 -0
  214. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/hub_service.py +0 -0
  215. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/indexer.py +0 -0
  216. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/jira_client.py +0 -0
  217. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/jira_cloud.py +0 -0
  218. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/jira_credentials.py +0 -0
  219. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/jira_data_center.py +0 -0
  220. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/jira_links.py +0 -0
  221. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/mask_activation.py +0 -0
  222. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/mask_mirror.py +0 -0
  223. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/mask_presets.py +0 -0
  224. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory.py +0 -0
  225. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_consolidator.py +0 -0
  226. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_distiller.py +0 -0
  227. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_graph.py +0 -0
  228. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_grounder.py +0 -0
  229. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_queue.py +0 -0
  230. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/memory_scorer.py +0 -0
  231. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/metrics.py +0 -0
  232. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/notifications.py +0 -0
  233. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ollama_bridge.py +0 -0
  234. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ollama_client.py +0 -0
  235. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/ollama_credentials.py +0 -0
  236. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/output_filter.py +0 -0
  237. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/override_grants.py +0 -0
  238. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/override_policy.py +0 -0
  239. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/override_requests.py +0 -0
  240. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/override_wake.py +0 -0
  241. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/parser.py +0 -0
  242. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/project_manager.py +0 -0
  243. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/project_runtime.py +0 -0
  244. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/protocol.py +0 -0
  245. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/proxy_state.py +0 -0
  246. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/repo_map.py +0 -0
  247. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/retention.py +0 -0
  248. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/retrieval_broker.py +0 -0
  249. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/router.py +0 -0
  250. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/runtime.py +0 -0
  251. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/scanner.py +0 -0
  252. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/session_benchmark.py +0 -0
  253. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/session_manager.py +0 -0
  254. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/session_preloader.py +0 -0
  255. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/subprojects.py +0 -0
  256. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/task_store.py +0 -0
  257. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/telemetry.py +0 -0
  258. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/text_index.py +0 -0
  259. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/time_tracker.py +0 -0
  260. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/tool_classifier.py +0 -0
  261. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/transcript_index.py +0 -0
  262. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/validation_cache.py +0 -0
  263. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/vector_store.py +0 -0
  264. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/watcher.py +0 -0
  265. {code_context_control-2.79.0 → code_context_control-2.80.0}/services/win_subprocess.py +0 -0
  266. {code_context_control-2.79.0 → code_context_control-2.80.0}/setup.cfg +0 -0
  267. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_builtin_optout.py +0 -0
  268. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_guard.py +0 -0
  269. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_guard_meta.py +0 -0
  270. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_guard_shell_project.py +0 -0
  271. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_guard_surfaces.py +0 -0
  272. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_access_guard_wiring.py +0 -0
  273. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_activity_reporter.py +0 -0
  274. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_agent_locks.py +0 -0
  275. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_aider_polyglot.py +0 -0
  276. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_antigravity_transition.py +0 -0
  277. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_artifact_store.py +0 -0
  278. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_artifact_tool.py +0 -0
  279. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  280. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_bitbucket_client.py +0 -0
  281. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_bitbucket_config_fallback.py +0 -0
  282. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_bitbucket_credentials.py +0 -0
  283. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_bitbucket_tool.py +0 -0
  284. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  285. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_c3_shell.py +0 -0
  286. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_chat_poll.py +0 -0
  287. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ci_runner.py +0 -0
  288. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ci_workflow.py +0 -0
  289. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_circuit_breaker.py +0 -0
  290. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_claude_md_merge.py +0 -0
  291. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_cli_smoke.py +0 -0
  292. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_compressor_large_file.py +0 -0
  293. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_credential_store.py +0 -0
  294. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_credentials_routes.py +0 -0
  295. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_credentials_tool.py +0 -0
  296. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_creds_cli_smoke.py +0 -0
  297. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_delegate_cascade.py +0 -0
  298. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_delegate_version_probe.py +0 -0
  299. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_e2e_benchmark.py +0 -0
  300. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_edit_ledger_deadline.py +0 -0
  301. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_edit_ledger_hook.py +0 -0
  302. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_edit_locking.py +0 -0
  303. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_edit_normalization.py +0 -0
  304. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_edit_verify.py +0 -0
  305. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_embedding_index_deadlock.py +0 -0
  306. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_enforcement_flip.py +0 -0
  307. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_enforcement_policy.py +0 -0
  308. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_enforcement_routes.py +0 -0
  309. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_federated_graph.py +0 -0
  310. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_filter_backoff.py +0 -0
  311. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ghost_files.py +0 -0
  312. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ghost_generation.py +0 -0
  313. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_git_branch_awareness.py +0 -0
  314. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_access_guard.py +0 -0
  315. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_codex_compat.py +0 -0
  316. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_dispatch.py +0 -0
  317. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_pretool_enforce.py +0 -0
  318. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_prompt_recall.py +0 -0
  319. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_smoke.py +0 -0
  320. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_state.py +0 -0
  321. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hook_utf8_stdio.py +0 -0
  322. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_credentials_route.py +0 -0
  323. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_credentials_routes_write.py +0 -0
  324. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_enforcement_routes.py +0 -0
  325. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_inspect_api.py +0 -0
  326. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_locks_routes.py +0 -0
  327. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_server_smoke.py +0 -0
  328. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_hub_subproject_links.py +0 -0
  329. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ide_workflow_adaptation.py +0 -0
  330. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_init_scan.py +0 -0
  331. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_install_mcp_entrypoint.py +0 -0
  332. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_cli_smoke.py +0 -0
  333. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_client.py +0 -0
  334. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_config_fallback.py +0 -0
  335. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_credentials.py +0 -0
  336. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_links.py +0 -0
  337. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_routes.py +0 -0
  338. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_jira_tool.py +0 -0
  339. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_lazy_store_init.py +0 -0
  340. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mask_guard.py +0 -0
  341. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mask_routes.py +0 -0
  342. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mask_surfaces.py +0 -0
  343. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mcp_host_guard.py +0 -0
  344. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mcp_memory_timeout.py +0 -0
  345. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mcp_server_smoke.py +0 -0
  346. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mcp_toml.py +0 -0
  347. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_memory_distiller.py +0 -0
  348. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_memory_graph_api.py +0 -0
  349. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_memory_queue.py +0 -0
  350. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_memory_system.py +0 -0
  351. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mobile_api.py +0 -0
  352. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mobile_extras.py +0 -0
  353. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mobile_override_routes.py +0 -0
  354. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_mobile_security_api.py +0 -0
  355. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_no_stale_model_pins.py +0 -0
  356. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_notification_dedup.py +0 -0
  357. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_notification_discipline.py +0 -0
  358. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_ollama_credentials.py +0 -0
  359. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_api_auth.py +0 -0
  360. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_apikey_api.py +0 -0
  361. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_c3_bridge.py +0 -0
  362. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_chat_engine.py +0 -0
  363. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_chat_store.py +0 -0
  364. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_discovery_api.py +0 -0
  365. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_discovery_audit.py +0 -0
  366. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_local_auth.py +0 -0
  367. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_ollama_bridge.py +0 -0
  368. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_scanner_cache.py +0 -0
  369. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_security_fixes.py +0 -0
  370. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_session_bootstrap.py +0 -0
  371. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_subproject_awareness.py +0 -0
  372. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_oracle_ui_bundle.py +0 -0
  373. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_output_filter.py +0 -0
  374. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_override_grants.py +0 -0
  375. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_override_grants_mcp.py +0 -0
  376. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_override_requests.py +0 -0
  377. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_override_wake.py +0 -0
  378. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_permissions.py +0 -0
  379. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_pm_api.py +0 -0
  380. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_project_manager.py +0 -0
  381. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_project_manager_merge.py +0 -0
  382. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_project_tool.py +0 -0
  383. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_read_coercion.py +0 -0
  384. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_read_edit_parity.py +0 -0
  385. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_related_facts.py +0 -0
  386. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_repo_map.py +0 -0
  387. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_response_boilerplate.py +0 -0
  388. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_retention.py +0 -0
  389. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_review_digest.py +0 -0
  390. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_service_durability.py +0 -0
  391. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_session_benchmark.py +0 -0
  392. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_session_budget.py +0 -0
  393. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_shell_creds.py +0 -0
  394. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_shell_robustness.py +0 -0
  395. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_subproject_exclusion.py +0 -0
  396. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_subproject_federation.py +0 -0
  397. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_subprojects.py +0 -0
  398. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_swe_bench.py +0 -0
  399. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_task_store.py +0 -0
  400. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_task_tool.py +0 -0
  401. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_time_tracker.py +0 -0
  402. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_token_telemetry.py +0 -0
  403. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_tool_registry.py +0 -0
  404. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_upgrade_and_version.py +0 -0
  405. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_validate.py +0 -0
  406. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_vault_write_guard.py +0 -0
  407. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_version_sync.py +0 -0
  408. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_web_security.py +0 -0
  409. {code_context_control-2.79.0 → code_context_control-2.80.0}/tests/test_windows_reliability.py +0 -0
  410. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/__init__.py +0 -0
  411. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/backend.py +0 -0
  412. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/main.py +0 -0
  413. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/__init__.py +0 -0
  414. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/benchmark_view.py +0 -0
  415. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/claudemd_view.py +0 -0
  416. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/compress_view.py +0 -0
  417. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/index_view.py +0 -0
  418. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/init_view.py +0 -0
  419. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/mcp_view.py +0 -0
  420. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/optimize_view.py +0 -0
  421. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/pipe_view.py +0 -0
  422. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/projects_view.py +0 -0
  423. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/search_view.py +0 -0
  424. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/session_view.py +0 -0
  425. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/stats.py +0 -0
  426. {code_context_control-2.79.0 → code_context_control-2.80.0}/tui/screens/ui_view.py +0 -0
  427. {code_context_control-2.79.0 → code_context_control-2.80.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.79.0
3
+ Version: 2.80.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.79.0"
95
+ __version__ = "2.80.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -6065,7 +6065,7 @@ def _ci_main(args) -> int:
6065
6065
  from services import ci_runner as cr
6066
6066
  from services.ci_workflow import inspect_project
6067
6067
  if sub == "inspect":
6068
- payload = inspect_project(project_path)
6068
+ payload = inspect_project(project_path, event=getattr(args, "event", "") or "")
6069
6069
  elif sub in ("run", "rerun"):
6070
6070
  only = None
6071
6071
  if sub == "rerun":
@@ -6078,7 +6078,8 @@ def _ci_main(args) -> int:
6078
6078
  project_path, selector=getattr(args, "job", ""),
6079
6079
  allow_foreign=bool(getattr(args, "allow_foreign", False)),
6080
6080
  only=only, timeout=getattr(args, "timeout", 0) or cr.DEFAULT_STEP_TIMEOUT,
6081
- workflow=getattr(args, "workflow", "")).to_dict()
6081
+ workflow=getattr(args, "workflow", ""),
6082
+ event=getattr(args, "event", "") or "").to_dict()
6082
6083
  elif sub == "runs":
6083
6084
  payload = {"runs": cr.list_runs(project_path)}
6084
6085
  else:
@@ -6096,7 +6097,8 @@ def _ci_main(args) -> int:
6096
6097
  sub, getattr(args, "job", "") or "", getattr(args, "run_id", "") or "",
6097
6098
  bool(getattr(args, "allow_foreign", False)),
6098
6099
  getattr(args, "workflow", "") or "", getattr(args, "tail", 200) or 200,
6099
- getattr(args, "timeout", 0) or 0, svc, finalize)
6100
+ getattr(args, "timeout", 0) or 0, svc, finalize,
6101
+ getattr(args, "event", "") or "")
6100
6102
  print(out)
6101
6103
  # Exit code is the finding: a non-full verdict must not read as success to
6102
6104
  # a shell script or a pre-push hook.
@@ -483,6 +483,9 @@ def build_parser(version: str, parse_cli_ide_arg):
483
483
  sub.add_argument("--path", dest="project_path", default=".",
484
484
  help="Project directory (default: current)")
485
485
  sub.add_argument("--json", action="store_true", help="Machine-readable output")
486
+ sub.add_argument("--event", default="",
487
+ help="GitHub event to simulate (push, pull_request) — "
488
+ "only needed when an `if:` reads github.event_name")
486
489
  return sub
487
490
 
488
491
  _ci_common(ci_subs.add_parser(
@@ -769,7 +769,8 @@ async def c3_locks(action: str = "list", paths: str = "", intent: str = "",
769
769
  @mcp.tool()
770
770
  async def c3_ci(action: str = "inspect", job: str = "", run_id: str = "",
771
771
  allow_foreign: bool = False, workflow: str = "",
772
- tail: int = 200, timeout: int = 0, ctx: Context = None) -> str:
772
+ tail: int = 200, timeout: int = 0, event: str = "",
773
+ ctx: Context = None) -> str:
773
774
  """RUN THIS REPO'S REAL CI LOCALLY — before pushing, not after.
774
775
  Reads .github/workflows/*.yml as the source of truth (no second CI config).
775
776
  actions: inspect (default) | run | rerun | status | failures | logs | runs.
@@ -783,7 +784,10 @@ async def c3_ci(action: str = "inspect", job: str = "", run_id: str = "",
783
784
  that means "safe to push". PARTIAL_PASS means something did not run
784
785
  (different OS, unsupported action, or you selected a subset); it is NOT a
785
786
  green light. Jobs targeting another OS are refused unless allow_foreign=true,
786
- which runs them and labels the result cross-OS."""
787
+ which runs them and labels the result cross-OS.
788
+ event: declare which GitHub event you are simulating ('push',
789
+ 'pull_request'). Needed only when an `if:` reads github.event_name —
790
+ there is no event locally, so C3 refuses to guess one."""
787
791
  svc = _svc(ctx)
788
792
 
789
793
  def finalize(name, args, resp, summ, **kw):
@@ -792,7 +796,7 @@ async def c3_ci(action: str = "inspect", job: str = "", run_id: str = "",
792
796
  from cli.tools.ci import handle_ci
793
797
  return await asyncio.to_thread(handle_ci, action, job, run_id,
794
798
  allow_foreign, workflow, tail, timeout,
795
- svc, finalize)
799
+ svc, finalize, event)
796
800
 
797
801
 
798
802
  @mcp.tool()
@@ -74,7 +74,8 @@ def _failure_rows(jobs: list, limit: int = 25) -> list:
74
74
 
75
75
 
76
76
  def handle_ci(action: str, job: str, run_id: str, allow_foreign: bool,
77
- workflow: str, tail: int, timeout: int, svc, finalize) -> str:
77
+ workflow: str, tail: int, timeout: int, svc, finalize,
78
+ event: str = "") -> str:
78
79
  """Route c3_ci actions."""
79
80
  project = str(svc.project_path)
80
81
  action = (action or "inspect").strip().lower()
@@ -84,7 +85,7 @@ def handle_ci(action: str, job: str, run_id: str, allow_foreign: bool,
84
85
 
85
86
  # ── inspect ──────────────────────────────────────────────────────────
86
87
  if action in ("", "inspect", "jobs"):
87
- data = inspect_project(project)
88
+ data = inspect_project(project, event=event)
88
89
  if not data["workflows"]:
89
90
  return finalize(
90
91
  "c3_ci", args,
@@ -150,7 +151,7 @@ def handle_ci(action: str, job: str, run_id: str, allow_foreign: bool,
150
151
 
151
152
  result = cr.run_ci(project, selector=job, allow_foreign=allow_foreign,
152
153
  only=only, timeout=timeout or cr.DEFAULT_STEP_TIMEOUT,
153
- workflow=workflow)
154
+ workflow=workflow, event=event)
154
155
  run = result.to_dict()
155
156
  lines = [_verdict_line(run), f"run {run['run_id']} host={run['host_os']}"]
156
157
  fp = run.get("fingerprint") or {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.79.0
3
+ Version: 2.80.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
@@ -185,6 +185,7 @@ services/auto_memory.py
185
185
  services/benchmark_dashboard.py
186
186
  services/bitbucket_client.py
187
187
  services/bitbucket_credentials.py
188
+ services/ci_expr.py
188
189
  services/ci_failures.py
189
190
  services/ci_runner.py
190
191
  services/ci_workflow.py
@@ -280,6 +281,7 @@ tests/test_bitbucket_tool.py
280
281
  tests/test_c3_bridge_project_artifacts.py
281
282
  tests/test_c3_shell.py
282
283
  tests/test_chat_poll.py
284
+ tests/test_ci_expr.py
283
285
  tests/test_ci_runner.py
284
286
  tests/test_ci_workflow.py
285
287
  tests/test_circuit_breaker.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.79.0"
7
+ version = "2.80.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"
@@ -0,0 +1,435 @@
1
+ """AgentCI — a GitHub Actions expression evaluator, for `if:` conditions.
2
+
3
+ Before this existed, `if:` was parsed and ignored, so every guarded step ran
4
+ locally whether or not CI would have run it. That over-runs rather than
5
+ under-runs — it cannot manufacture a false green — but it wastes time and
6
+ reports failures for steps that were never going to execute.
7
+
8
+ Three rules keep the evaluator honest, and they are the whole design:
9
+
10
+ 1. **An expression we cannot parse blocks the job.** Not "assume true" (which
11
+ silently runs steps CI skips) and not "assume false" (which silently skips
12
+ steps CI runs). Both are guesses; a blocker is a fact.
13
+
14
+ 2. **A reference we cannot resolve blocks the job.** `github.event_name` has no
15
+ honest local value — there is no event. Rather than inventing `"push"` and
16
+ evaluating a condition against fiction, an unknown reference raises, and the
17
+ caller can pass `--event pull_request` to state what it is simulating.
18
+
19
+ 3. **Status functions are runtime, not parse-time.** `success()` depends on
20
+ what already ran, so validation happens when the DAG is built and evaluation
21
+ happens in the runner, with a context that knows results.
22
+
23
+ Grammar implemented (the subset that appears in real workflows):
24
+
25
+ expr := or
26
+ or := and ( '||' and )*
27
+ and := cmp ( '&&' cmp )*
28
+ cmp := unary ( ('=='|'!='|'<'|'<='|'>'|'>=') unary )?
29
+ unary := '!' unary | primary
30
+ primary := literal | path | call | '(' expr ')'
31
+
32
+ Functions: success, failure, always, cancelled, contains, startsWith,
33
+ endsWith, format, join, fromJSON, toJSON.
34
+ """
35
+ from __future__ import annotations
36
+
37
+ import json
38
+ import re
39
+ from dataclasses import dataclass, field
40
+
41
+ # Context roots we can populate. A reference to anything else — `secrets`,
42
+ # `vars`, `inputs` — is unresolvable locally and must block rather than
43
+ # evaluate to empty, which is how a job passes here and fails in CI.
44
+ KNOWN_ROOTS = {"github", "env", "matrix", "runner", "job", "needs", "steps",
45
+ "strategy"}
46
+
47
+
48
+ class ExprError(ValueError):
49
+ """The expression could not be parsed."""
50
+
51
+
52
+ class UnknownRef(ValueError):
53
+ """The expression referenced something we cannot honestly resolve."""
54
+
55
+
56
+ # ── Tokenizer ───────────────────────────────────────────────────────────────
57
+
58
+ _TOKEN_RE = re.compile(r"""
59
+ (?P<ws>\s+)
60
+ | (?P<str>'(?:[^']|'')*')
61
+ | (?P<num>-?\d+(?:\.\d+)?)
62
+ | (?P<op>==|!=|<=|>=|&&|\|\||[<>!(),.\[\]])
63
+ | (?P<ident>[A-Za-z_][A-Za-z0-9_-]*)
64
+ """, re.VERBOSE)
65
+
66
+
67
+ @dataclass
68
+ class Token:
69
+ kind: str
70
+ value: str
71
+ pos: int
72
+
73
+
74
+ def tokenize(src: str) -> list:
75
+ tokens: list = []
76
+ i = 0
77
+ while i < len(src):
78
+ m = _TOKEN_RE.match(src, i)
79
+ if not m:
80
+ raise ExprError(f"unexpected character {src[i]!r} at {i}")
81
+ i = m.end()
82
+ kind = m.lastgroup
83
+ if kind == "ws":
84
+ continue
85
+ tokens.append(Token(kind, m.group(), m.start()))
86
+ return tokens
87
+
88
+
89
+ # ── Parser → a tiny AST of tuples ───────────────────────────────────────────
90
+ # ("lit", value) ("path", [parts]) ("call", name, [args])
91
+ # ("not", node) ("bin", op, left, right)
92
+
93
+ class _Parser:
94
+ def __init__(self, tokens: list):
95
+ self.tokens = tokens
96
+ self.i = 0
97
+
98
+ def peek(self):
99
+ return self.tokens[self.i] if self.i < len(self.tokens) else None
100
+
101
+ def take(self, value: str = ""):
102
+ tok = self.peek()
103
+ if tok is None:
104
+ raise ExprError("unexpected end of expression")
105
+ if value and tok.value != value:
106
+ raise ExprError(f"expected {value!r} but found {tok.value!r}")
107
+ self.i += 1
108
+ return tok
109
+
110
+ def parse(self):
111
+ node = self.parse_or()
112
+ if self.peek() is not None:
113
+ raise ExprError(f"trailing input at {self.peek().value!r}")
114
+ return node
115
+
116
+ def parse_or(self):
117
+ node = self.parse_and()
118
+ while self.peek() and self.peek().value == "||":
119
+ self.take()
120
+ node = ("bin", "||", node, self.parse_and())
121
+ return node
122
+
123
+ def parse_and(self):
124
+ node = self.parse_cmp()
125
+ while self.peek() and self.peek().value == "&&":
126
+ self.take()
127
+ node = ("bin", "&&", node, self.parse_cmp())
128
+ return node
129
+
130
+ def parse_cmp(self):
131
+ node = self.parse_unary()
132
+ tok = self.peek()
133
+ if tok and tok.value in ("==", "!=", "<", "<=", ">", ">="):
134
+ self.take()
135
+ node = ("bin", tok.value, node, self.parse_unary())
136
+ return node
137
+
138
+ def parse_unary(self):
139
+ tok = self.peek()
140
+ if tok and tok.value == "!":
141
+ self.take()
142
+ return ("not", self.parse_unary())
143
+ return self.parse_primary()
144
+
145
+ def parse_primary(self):
146
+ tok = self.peek()
147
+ if tok is None:
148
+ raise ExprError("unexpected end of expression")
149
+
150
+ if tok.value == "(":
151
+ self.take("(")
152
+ node = self.parse_or()
153
+ self.take(")")
154
+ return node
155
+
156
+ if tok.kind == "str":
157
+ self.take()
158
+ # GitHub escapes a single quote by doubling it.
159
+ return ("lit", tok.value[1:-1].replace("''", "'"))
160
+
161
+ if tok.kind == "num":
162
+ self.take()
163
+ text = tok.value
164
+ return ("lit", float(text) if "." in text else int(text))
165
+
166
+ if tok.kind == "ident":
167
+ self.take()
168
+ low = tok.value.lower()
169
+ if low in ("true", "false"):
170
+ return ("lit", low == "true")
171
+ if low == "null":
172
+ return ("lit", None)
173
+ nxt = self.peek()
174
+ if nxt and nxt.value == "(":
175
+ return self.parse_call(tok.value)
176
+ return self.parse_path(tok.value)
177
+
178
+ raise ExprError(f"unexpected token {tok.value!r}")
179
+
180
+ def parse_call(self, name: str):
181
+ self.take("(")
182
+ args: list = []
183
+ if self.peek() and self.peek().value != ")":
184
+ args.append(self.parse_or())
185
+ while self.peek() and self.peek().value == ",":
186
+ self.take(",")
187
+ args.append(self.parse_or())
188
+ self.take(")")
189
+ return ("call", name.lower(), args)
190
+
191
+ def parse_path(self, root: str):
192
+ parts = [root]
193
+ while self.peek() and self.peek().value in (".", "["):
194
+ tok = self.take()
195
+ if tok.value == ".":
196
+ nxt = self.take()
197
+ if nxt.kind not in ("ident", "num"):
198
+ raise ExprError(f"bad property name {nxt.value!r}")
199
+ parts.append(nxt.value)
200
+ else:
201
+ inner = self.parse_or()
202
+ self.take("]")
203
+ if inner[0] != "lit":
204
+ raise ExprError("only literal index access is supported")
205
+ parts.append(str(inner[1]))
206
+ return ("path", parts)
207
+
208
+
209
+ def parse(src: str):
210
+ return _Parser(tokenize(src)).parse()
211
+
212
+
213
+ # ── Evaluation ──────────────────────────────────────────────────────────────
214
+
215
+ @dataclass
216
+ class EvalContext:
217
+ """Everything an `if:` may legitimately read, locally.
218
+
219
+ `statuses` carries the runtime facts that make status functions meaningful:
220
+ whether anything has failed so far in the relevant scope.
221
+ """
222
+ values: dict = field(default_factory=dict) # github/env/matrix/... roots
223
+ failed: bool = False # something upstream failed
224
+ cancelled: bool = False # never true locally
225
+
226
+
227
+ def _truthy(value) -> bool:
228
+ if isinstance(value, bool):
229
+ return value
230
+ if value is None:
231
+ return False
232
+ if isinstance(value, (int, float)):
233
+ return value != 0
234
+ if isinstance(value, str):
235
+ return value != ""
236
+ if isinstance(value, (list, dict)):
237
+ return True
238
+ return bool(value)
239
+
240
+
241
+ def _coerce_pair(left, right) -> tuple:
242
+ """GitHub compares loosely. Numbers stay numbers; otherwise compare as
243
+ lower-cased strings, which is what `== 'Push'` vs `'push'` relies on."""
244
+ if isinstance(left, bool) or isinstance(right, bool):
245
+ return _truthy(left), _truthy(right)
246
+ if isinstance(left, (int, float)) and isinstance(right, (int, float)):
247
+ return left, right
248
+ return (str(left).lower() if left is not None else "",
249
+ str(right).lower() if right is not None else "")
250
+
251
+
252
+ def _resolve(parts: list, ctx: EvalContext):
253
+ root = parts[0]
254
+ if root not in KNOWN_ROOTS:
255
+ raise UnknownRef(
256
+ f"`{'.'.join(parts)}` — the `{root}` context is not available "
257
+ "locally, so this condition cannot be evaluated honestly")
258
+ value = ctx.values.get(root)
259
+ if value is None:
260
+ raise UnknownRef(f"`{root}` context is not populated for this run")
261
+ for part in parts[1:]:
262
+ if isinstance(value, dict):
263
+ if part not in value:
264
+ raise UnknownRef(
265
+ f"`{'.'.join(parts)}` — `{part}` is unknown locally. "
266
+ "If this is the event, pass the event you are simulating.")
267
+ value = value[part]
268
+ else:
269
+ raise UnknownRef(f"`{'.'.join(parts)}` — `{part}` is not a mapping")
270
+ return value
271
+
272
+
273
+ def _call(name: str, args: list, ctx: EvalContext):
274
+ if name == "success":
275
+ return not ctx.failed and not ctx.cancelled
276
+ if name == "failure":
277
+ return ctx.failed and not ctx.cancelled
278
+ if name == "always":
279
+ return True
280
+ if name == "cancelled":
281
+ return ctx.cancelled
282
+
283
+ if name == "contains":
284
+ haystack, needle = args[0], args[1]
285
+ if isinstance(haystack, list):
286
+ return any(_coerce_pair(item, needle)[0] == _coerce_pair(item, needle)[1]
287
+ for item in haystack)
288
+ return str(needle).lower() in str(haystack).lower()
289
+ if name == "startswith":
290
+ return str(args[0]).lower().startswith(str(args[1]).lower())
291
+ if name == "endswith":
292
+ return str(args[0]).lower().endswith(str(args[1]).lower())
293
+ if name == "format":
294
+ out = str(args[0])
295
+ for idx, val in enumerate(args[1:]):
296
+ out = out.replace("{" + str(idx) + "}", str(val))
297
+ return out
298
+ if name == "join":
299
+ items = args[0] if isinstance(args[0], list) else [args[0]]
300
+ sep = str(args[1]) if len(args) > 1 else ","
301
+ return sep.join(str(i) for i in items)
302
+ if name == "tojson":
303
+ return json.dumps(args[0])
304
+ if name == "fromjson":
305
+ try:
306
+ return json.loads(str(args[0]))
307
+ except json.JSONDecodeError as exc:
308
+ raise ExprError(f"fromJSON: {exc}") from exc
309
+
310
+ raise ExprError(f"unsupported function `{name}()`")
311
+
312
+
313
+ def _eval(node, ctx: EvalContext):
314
+ kind = node[0]
315
+ if kind == "lit":
316
+ return node[1]
317
+ if kind == "path":
318
+ return _resolve(node[1], ctx)
319
+ if kind == "call":
320
+ return _call(node[1], [_eval(a, ctx) for a in node[2]], ctx)
321
+ if kind == "not":
322
+ return not _truthy(_eval(node[1], ctx))
323
+ if kind == "bin":
324
+ op = node[1]
325
+ # Short-circuit, so `x && y.z` does not blow up on an unknown y.z when
326
+ # x is already false — same as GitHub, and it keeps honest conditions
327
+ # evaluable even when a branch references something we lack.
328
+ if op == "&&":
329
+ left = _eval(node[2], ctx)
330
+ return _eval(node[3], ctx) if _truthy(left) else left
331
+ if op == "||":
332
+ left = _eval(node[2], ctx)
333
+ return left if _truthy(left) else _eval(node[3], ctx)
334
+ left, right = _eval(node[2], ctx), _eval(node[3], ctx)
335
+ a, b = _coerce_pair(left, right)
336
+ if op == "==":
337
+ return a == b
338
+ if op == "!=":
339
+ return a != b
340
+ try:
341
+ if op == "<":
342
+ return a < b
343
+ if op == "<=":
344
+ return a <= b
345
+ if op == ">":
346
+ return a > b
347
+ if op == ">=":
348
+ return a >= b
349
+ except TypeError as exc:
350
+ raise ExprError(f"cannot compare {left!r} and {right!r}") from exc
351
+ raise ExprError(f"cannot evaluate node {node!r}")
352
+
353
+
354
+ # ── Public surface ──────────────────────────────────────────────────────────
355
+
356
+ _STATUS_FNS = ("success(", "failure(", "always(", "cancelled(")
357
+
358
+
359
+ def normalize(src: str) -> str:
360
+ """An `if:` value is already an expression; `${{ }}` around it is optional.
361
+
362
+ GitHub also implies `success() &&` unless the condition names a status
363
+ function itself, which is why `if: always()` is the documented way to run a
364
+ step after a failure.
365
+ """
366
+ text = str(src or "").strip()
367
+ if text.startswith("${{") and text.endswith("}}"):
368
+ text = text[3:-2].strip()
369
+ if not text:
370
+ return ""
371
+ if not any(fn in text.replace(" ", "").lower() for fn in _STATUS_FNS):
372
+ text = f"success() && ({text})"
373
+ return text
374
+
375
+
376
+ def validate(src: str, github_fields: set = None) -> str:
377
+ """Parse-check an `if:` at DAG-build time. Returns '' or a blocker reason.
378
+
379
+ Checks syntax, reference roots, and — because it is knowable now — which
380
+ `github.*` fields we can actually supply. Values that legitimately vary at
381
+ runtime (`needs.*.result`, `steps.*`) are accepted here and resolved later.
382
+
383
+ `github.event_name` is the field this exists for: there is no event
384
+ locally, so a condition on it is unjudgeable until the caller declares
385
+ which event they are simulating.
386
+ """
387
+ text = normalize(src)
388
+ if not text:
389
+ return ""
390
+ try:
391
+ node = parse(text)
392
+ except ExprError as exc:
393
+ return f"cannot parse `if:` condition ({exc})"
394
+
395
+ bad_roots: list = []
396
+ bad_fields: list = []
397
+ _collect_refs(node, bad_roots, bad_fields, github_fields or set())
398
+ if bad_roots:
399
+ return (f"`if:` condition reads the `{sorted(set(bad_roots))[0]}` "
400
+ "context, which is not available locally")
401
+ if bad_fields:
402
+ field = sorted(set(bad_fields))[0]
403
+ hint = (" — pass the event you are simulating (e.g. --event push)"
404
+ if field == "event_name" else "")
405
+ return (f"`if:` condition reads `github.{field}`, which has no honest "
406
+ f"local value{hint}")
407
+ return ""
408
+
409
+
410
+ def _collect_refs(node, bad_roots: list, bad_fields: list,
411
+ github_fields: set) -> None:
412
+ kind = node[0]
413
+ if kind == "path":
414
+ parts = node[1]
415
+ if parts[0] not in KNOWN_ROOTS:
416
+ bad_roots.append(parts[0])
417
+ elif parts[0] == "github" and len(parts) > 1:
418
+ if parts[1] not in github_fields:
419
+ bad_fields.append(parts[1])
420
+ elif kind == "call":
421
+ for arg in node[2]:
422
+ _collect_refs(arg, bad_roots, bad_fields, github_fields)
423
+ elif kind == "not":
424
+ _collect_refs(node[1], bad_roots, bad_fields, github_fields)
425
+ elif kind == "bin":
426
+ _collect_refs(node[2], bad_roots, bad_fields, github_fields)
427
+ _collect_refs(node[3], bad_roots, bad_fields, github_fields)
428
+
429
+
430
+ def evaluate(src: str, ctx: EvalContext) -> bool:
431
+ """True when the guarded job/step should run. Raises on an honest unknown."""
432
+ text = normalize(src)
433
+ if not text:
434
+ return True
435
+ return _truthy(_eval(parse(text), ctx))