code-context-control 2.101.0__tar.gz → 2.109.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.
- {code_context_control-2.101.0/code_context_control.egg-info → code_context_control-2.109.0}/PKG-INFO +3 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/c3.py +103 -26
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/common.py +26 -3
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/parser.py +24 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_access_guard.py +106 -9
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_dispatch.py +91 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_pretool_enforce.py +24 -5
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/mcp_server.py +20 -5
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/_grants.py +26 -9
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/artifacts.py +33 -2
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/federate.py +6 -3
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/override.py +15 -5
- code_context_control-2.109.0/cli/tools/search.py +659 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/shell.py +82 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0/code_context_control.egg-info}/PKG-INFO +3 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/SOURCES.txt +13 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/requires.txt +3 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/pyproject.toml +7 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/access_guard.py +41 -5
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/artifact_store.py +36 -9
- code_context_control-2.109.0/services/bench/search_eval.py +708 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/claude_md.py +22 -2
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/embedding_index.py +129 -4
- code_context_control-2.109.0/services/index_store.py +366 -0
- code_context_control-2.109.0/services/indexer.py +1387 -0
- code_context_control-2.109.0/services/lexical_index.py +245 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_grants.py +20 -9
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/parser.py +27 -1
- code_context_control-2.109.0/services/reranker.py +126 -0
- code_context_control-2.109.0/services/retrieval.py +58 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/runtime.py +16 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_manager.py +18 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/subprojects.py +12 -1
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/watcher.py +14 -2
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_artifact_tool.py +41 -4
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_confirm_guard.py +46 -6
- code_context_control-2.109.0/tests/test_confirm_guard_wiring.py +482 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cooccurrence_bounds.py +3 -1
- code_context_control-2.109.0/tests/test_ide_workflow_adaptation.py +235 -0
- code_context_control-2.109.0/tests/test_index_cap_not_hardcoded.py +131 -0
- code_context_control-2.109.0/tests/test_search_eval.py +162 -0
- code_context_control-2.109.0/tests/test_search_p1.py +276 -0
- code_context_control-2.109.0/tests/test_search_p2.py +296 -0
- code_context_control-2.109.0/tests/test_search_p2b.py +244 -0
- code_context_control-2.109.0/tests/test_search_p3.py +358 -0
- code_context_control-2.109.0/tests/test_search_p4.py +200 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/index_view.py +13 -4
- code_context_control-2.101.0/cli/tools/search.py +0 -417
- code_context_control-2.101.0/services/indexer.py +0 -845
- code_context_control-2.101.0/tests/test_ide_workflow_adaptation.py +0 -121
- {code_context_control-2.101.0 → code_context_control-2.109.0}/LICENSE +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/README.md +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/docs.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/edits.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/access.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/index.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_read.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_server.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/progress.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/server.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/project.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/read.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/session.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/status.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/api.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/app.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/core/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/core/config.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/core/ide.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/core/web_security.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/config.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/activity_log.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agent_base.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agent_locks.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agents.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/auto_memory.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/background_service.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_act.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_cache.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_expr.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_failures.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_github.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_impact.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_intel.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_runner.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/compressor.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/conversation_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/cred_audit.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/credential_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/doc_index.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/error_reporting.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/file_memory.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/git_context.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/hub_service.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_client.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_links.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_activation.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_presets.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_graph.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_queue.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/metrics.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/notifications.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_client.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/oracle_service.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/output_filter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_policy.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_requests.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_wake.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/project_manager.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/project_runtime.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/protocol.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/proxy_state.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/repo_map.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/repo_shape.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/retention.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/router.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/scanner.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_preloader.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/task_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/telemetry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/text_index.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/time_tracker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/transcript_index.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/validation_cache.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/vector_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/setup.cfg +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_retention.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_validate.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/backend.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/main.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/theme.tcss +0 -0
{code_context_control-2.101.0/code_context_control.egg-info → code_context_control-2.109.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.109.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
|
|
@@ -47,6 +47,8 @@ Provides-Extra: vector
|
|
|
47
47
|
Requires-Dist: scikit-learn>=1.3.0; extra == "vector"
|
|
48
48
|
Requires-Dist: numpy>=1.24.0; extra == "vector"
|
|
49
49
|
Requires-Dist: chromadb>=0.4.24; extra == "vector"
|
|
50
|
+
Provides-Extra: rerank
|
|
51
|
+
Requires-Dist: flashrank>=0.2.10; extra == "rerank"
|
|
50
52
|
Provides-Extra: tui
|
|
51
53
|
Requires-Dist: textual>=0.50.0; extra == "tui"
|
|
52
54
|
Provides-Extra: telemetry
|
|
@@ -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.
|
|
95
|
+
__version__ = "2.109.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -591,21 +591,21 @@ def _check_c3_health(project_path: str) -> dict:
|
|
|
591
591
|
issues.append(f"missing directories: {', '.join(missing_dirs)}")
|
|
592
592
|
info["missing_dirs"] = missing_dirs
|
|
593
593
|
|
|
594
|
-
# Index presence and basic stats
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
issues.append("code index
|
|
607
|
-
|
|
608
|
-
|
|
594
|
+
# Index presence and basic stats (services/index_store; index.json is
|
|
595
|
+
# the pre-2.107.0 layout and counts as "present, needs a rebuild").
|
|
596
|
+
try:
|
|
597
|
+
from services.index_store import IndexStore
|
|
598
|
+
store = IndexStore(c3_dir / "index")
|
|
599
|
+
n_docs, n_chunks = store.counts()
|
|
600
|
+
except Exception:
|
|
601
|
+
store, n_docs, n_chunks = None, 0, 0
|
|
602
|
+
info["index_files"] = n_docs
|
|
603
|
+
info["index_chunks"] = n_chunks
|
|
604
|
+
if n_docs == 0:
|
|
605
|
+
if (c3_dir / "index" / "index.json").exists():
|
|
606
|
+
issues.append("code index in the pre-2.107.0 layout; run `c3 index` to migrate")
|
|
607
|
+
else:
|
|
608
|
+
issues.append("code index not built")
|
|
609
609
|
|
|
610
610
|
# Stale file changes (tracked by the watcher inside CodeIndex)
|
|
611
611
|
# The watcher writes pending changes to .c3/index/changes.json
|
|
@@ -1500,6 +1500,42 @@ def cmd_stats(args):
|
|
|
1500
1500
|
return common_cmd_stats(args, _command_deps())
|
|
1501
1501
|
|
|
1502
1502
|
|
|
1503
|
+
def cmd_search_eval(args):
|
|
1504
|
+
"""Run the c3_search relevance suite and compare it to its baseline.
|
|
1505
|
+
|
|
1506
|
+
Exit status 1 when the baseline is violated (a must_pass case failed, a
|
|
1507
|
+
canary leaked, or an aggregate fell under its floor), so the command can
|
|
1508
|
+
stand in a pre-push gate. See docs/search-eval.md.
|
|
1509
|
+
"""
|
|
1510
|
+
from services.bench import search_eval as se
|
|
1511
|
+
|
|
1512
|
+
try:
|
|
1513
|
+
report = se.run_suite(args.suite, repo=args.repo, rebuild=args.rebuild,
|
|
1514
|
+
semantic=args.semantic, baseline=args.baseline,
|
|
1515
|
+
rerank=getattr(args, "rerank", "off"))
|
|
1516
|
+
except FileNotFoundError as e:
|
|
1517
|
+
raise RuntimeError(str(e))
|
|
1518
|
+
|
|
1519
|
+
if args.update_baseline:
|
|
1520
|
+
path = args.baseline or se.BUNDLED_BASELINES.get(report.suite)
|
|
1521
|
+
if not path:
|
|
1522
|
+
raise RuntimeError(
|
|
1523
|
+
f"suite {report.suite!r} has no bundled baseline; pass --baseline PATH")
|
|
1524
|
+
floors = json.loads(args.floors) if args.floors else None
|
|
1525
|
+
se.write_baseline(report, path, floors=floors)
|
|
1526
|
+
# Re-compare so the printed verdict reflects the file just written.
|
|
1527
|
+
report.baseline_violations, report.baseline_warnings = se.compare_to_baseline(
|
|
1528
|
+
report, se.load_baseline(path))
|
|
1529
|
+
print(f"baseline written: {path}")
|
|
1530
|
+
|
|
1531
|
+
if args.json:
|
|
1532
|
+
print(json.dumps(report.to_dict(), indent=2))
|
|
1533
|
+
else:
|
|
1534
|
+
print(report.render())
|
|
1535
|
+
if report.baseline_violations:
|
|
1536
|
+
sys.exit(1)
|
|
1537
|
+
|
|
1538
|
+
|
|
1503
1539
|
def _benchmark_extract_preview(full_path: Path, compressor: CodeCompressor, pattern: str = "", max_lines: int = 50) -> str:
|
|
1504
1540
|
"""Approximate c3_filter behavior for local benchmarking without MCP startup."""
|
|
1505
1541
|
import re as _re
|
|
@@ -4212,6 +4248,7 @@ def cmd_pipe(args):
|
|
|
4212
4248
|
|
|
4213
4249
|
|
|
4214
4250
|
from services.claude_md import C3_COMPACT_WORKFLOW as _SHARED_C3_COMPACT_WORKFLOW
|
|
4251
|
+
from services.claude_md import VSCODE_INSTRUCTIONS_FILE
|
|
4215
4252
|
from services.claude_md import VSCODE_SESSION_INIT as _VSCODE_SESSION_INIT
|
|
4216
4253
|
from services.claude_md import adapt_workflow_for_ide as _adapt_workflow_for_ide
|
|
4217
4254
|
|
|
@@ -4433,14 +4470,27 @@ def _toml_section_bool_value(toml_path: Path, section: str, key: str) -> bool |
|
|
|
4433
4470
|
return None
|
|
4434
4471
|
|
|
4435
4472
|
|
|
4436
|
-
def _ensure_instruction_workflow(instructions_path: Path, template: str,
|
|
4437
|
-
|
|
4473
|
+
def _ensure_instruction_workflow(instructions_path: Path, template: str,
|
|
4474
|
+
required_markers: list[str],
|
|
4475
|
+
project_path: str = "") -> str:
|
|
4476
|
+
"""Ensure an instructions file carries the CURRENT C3 workflow.
|
|
4438
4477
|
|
|
4439
4478
|
Returns one of: "written", "updated", "kept".
|
|
4479
|
+
|
|
4480
|
+
Marker PRESENCE used to mean "up to date", which is why this function
|
|
4481
|
+
could report `kept` on a doc generated four releases ago: the markers are
|
|
4482
|
+
stable words like "SEARCH FIRST" and "c3_edit", so they survive every
|
|
4483
|
+
template change. A doc carrying the managed sentinels is now refreshed
|
|
4484
|
+
through ``merge_c3_block`` — the same non-destructive regeneration
|
|
4485
|
+
CLAUDE.md and AGENTS.md get — and `kept` means the block already matches
|
|
4486
|
+
byte for byte (v2.102.0). A marker-less legacy doc keeps the old
|
|
4487
|
+
prepend-and-preserve path, which ``write_c3_instruction_doc`` handles.
|
|
4440
4488
|
"""
|
|
4489
|
+
from services.claude_md import C3_BLOCK_BEGIN, merge_c3_block, wrap_c3_block, write_c3_instruction_doc
|
|
4490
|
+
|
|
4441
4491
|
if not instructions_path.exists():
|
|
4442
|
-
instructions_path
|
|
4443
|
-
|
|
4492
|
+
write_c3_instruction_doc(instructions_path, template,
|
|
4493
|
+
project_path=project_path or None)
|
|
4444
4494
|
return "written"
|
|
4445
4495
|
|
|
4446
4496
|
try:
|
|
@@ -4448,6 +4498,14 @@ def _ensure_instruction_workflow(instructions_path: Path, template: str, require
|
|
|
4448
4498
|
except Exception:
|
|
4449
4499
|
existing = ""
|
|
4450
4500
|
|
|
4501
|
+
# Managed doc → regenerate the block in place, preserving user content.
|
|
4502
|
+
if C3_BLOCK_BEGIN in existing:
|
|
4503
|
+
if merge_c3_block(existing, wrap_c3_block(template)) == existing:
|
|
4504
|
+
return "kept"
|
|
4505
|
+
write_c3_instruction_doc(instructions_path, template,
|
|
4506
|
+
project_path=project_path or None)
|
|
4507
|
+
return "updated"
|
|
4508
|
+
|
|
4451
4509
|
if all(marker in existing for marker in required_markers):
|
|
4452
4510
|
return "kept"
|
|
4453
4511
|
|
|
@@ -4460,7 +4518,8 @@ def _ensure_instruction_workflow(instructions_path: Path, template: str, require
|
|
|
4460
4518
|
return "updated"
|
|
4461
4519
|
|
|
4462
4520
|
|
|
4463
|
-
def _ensure_codex_agents_workflow(agents_md_path: Path
|
|
4521
|
+
def _ensure_codex_agents_workflow(agents_md_path: Path,
|
|
4522
|
+
project_path: str = "") -> str:
|
|
4464
4523
|
"""Ensure AGENTS.md contains the mandatory C3 workflow for Codex sessions."""
|
|
4465
4524
|
required_markers = [
|
|
4466
4525
|
"C3 Tools",
|
|
@@ -4474,10 +4533,12 @@ def _ensure_codex_agents_workflow(agents_md_path: Path) -> str:
|
|
|
4474
4533
|
"c3_memory",
|
|
4475
4534
|
"c3_filter",
|
|
4476
4535
|
]
|
|
4477
|
-
return _ensure_instruction_workflow(agents_md_path, _AGENTS_MD_CONTENT,
|
|
4536
|
+
return _ensure_instruction_workflow(agents_md_path, _AGENTS_MD_CONTENT,
|
|
4537
|
+
required_markers, project_path)
|
|
4478
4538
|
|
|
4479
4539
|
|
|
4480
|
-
def _ensure_vscode_instructions_workflow(instructions_path: Path
|
|
4540
|
+
def _ensure_vscode_instructions_workflow(instructions_path: Path,
|
|
4541
|
+
project_path: str = "") -> str:
|
|
4481
4542
|
"""Ensure VS Code Copilot instructions include the latest C3 workflow markers."""
|
|
4482
4543
|
required_markers = [
|
|
4483
4544
|
"C3 Tools",
|
|
@@ -4491,7 +4552,9 @@ def _ensure_vscode_instructions_workflow(instructions_path: Path) -> str:
|
|
|
4491
4552
|
"c3_memory",
|
|
4492
4553
|
"c3_filter",
|
|
4493
4554
|
]
|
|
4494
|
-
return _ensure_instruction_workflow(instructions_path,
|
|
4555
|
+
return _ensure_instruction_workflow(instructions_path,
|
|
4556
|
+
_COPILOT_INSTRUCTIONS_CONTENT,
|
|
4557
|
+
required_markers, project_path)
|
|
4495
4558
|
|
|
4496
4559
|
|
|
4497
4560
|
def _safe_read_json(path: Path, label: str = "") -> dict:
|
|
@@ -4957,6 +5020,7 @@ back to native tools as the task progresses.
|
|
|
4957
5020
|
- **Bitbucket** (v2.30.0+, when `c3 bitbucket login` has run): `c3_bitbucket(action='list_prs|get_pr|merge_pr|...')` — self-hosted Bitbucket Data Center / Server. Token in OS keyring; mutating actions auto-log to the edit ledger.
|
|
4958
5021
|
- **Cross-project** (v2.31.0+): `c3_project(action='list|scan|search|read|edit|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. Reads run freely; writes (edit/shell/memory) need `allow_write=true`.
|
|
4959
5022
|
- **Masked paths** (v2.63.0+): content prefixed `[c3-mask:transformed]` is a policy-transformed VIEW, not the file. Values may be synthetic, rows withheld, bodies stripped — don't copy literals out of it or infer completeness from it. Masked paths are read-only and refuse shell/git/validate/impact/filter/delegate (`[c3-mask:unsupported]`). That's policy, not a transient error — report the block instead of routing around it.
|
|
5023
|
+
- **Confirm holds** (v2.97.0+): `[c3-access:confirm]` is a PAUSE, not a block — a human must approve this exact write. Since v2.100.0 the agent-config files (`.mcp.json`, instruction docs, `.claude` hook/skill/agent/command bodies) hold by default in EVERY C3 project, reads stay open. Read the S8 tail: it names the filed request (`c3_override(action='wait', request_id='...', timeout_s=180)`, then retry the same call once if approved), or names a surface that files one, or gives a reason to obey. Never retry before a decision and never route around a hold via the shell.
|
|
4960
5024
|
|
|
4961
5025
|
## Self-Check
|
|
4962
5026
|
If you haven't called a c3_* tool in several turns during active development, re-engage
|
|
@@ -5034,10 +5098,20 @@ def _instruction_documents_for_project() -> list[tuple[str, str]]:
|
|
|
5034
5098
|
|
|
5035
5099
|
Used by uninstall/cleanup paths, so it must keep listing legacy docs
|
|
5036
5100
|
(GEMINI.md — profile removed in v2.52; empty template, never generated).
|
|
5101
|
+
|
|
5102
|
+
``.github/copilot-instructions.md`` was absent from this list until
|
|
5103
|
+
v2.102.0, and that absence was the whole bug: the managed-block sync
|
|
5104
|
+
that regenerates CLAUDE.md and AGENTS.md on every install-mcp never
|
|
5105
|
+
touched it, while ``_ensure_vscode_instructions_workflow`` reported
|
|
5106
|
+
`kept` on marker presence alone. In a vscode-primary project the third
|
|
5107
|
+
git-tracked instruction doc silently drifted a release behind on every
|
|
5108
|
+
template change — v2.100.0's agent-config confirm tier reached the
|
|
5109
|
+
Claude Code and Codex docs and never reached Copilot's.
|
|
5037
5110
|
"""
|
|
5038
5111
|
return [
|
|
5039
5112
|
("CLAUDE.md", _CLAUDE_MD_CONTENT),
|
|
5040
5113
|
("AGENTS.md", _AGENTS_MD_CONTENT),
|
|
5114
|
+
(VSCODE_INSTRUCTIONS_FILE, _COPILOT_INSTRUCTIONS_CONTENT),
|
|
5041
5115
|
("GEMINI.md", ""),
|
|
5042
5116
|
]
|
|
5043
5117
|
|
|
@@ -5692,7 +5766,8 @@ def cmd_install_mcp(args):
|
|
|
5692
5766
|
if profile.name == "vscode":
|
|
5693
5767
|
# 1. Ensure copilot-instructions.md has the latest C3 workflow markers
|
|
5694
5768
|
instructions_path = target / ".github" / "copilot-instructions.md"
|
|
5695
|
-
vs_state = _ensure_vscode_instructions_workflow(instructions_path
|
|
5769
|
+
vs_state = _ensure_vscode_instructions_workflow(instructions_path,
|
|
5770
|
+
str(target))
|
|
5696
5771
|
if vs_state == "written":
|
|
5697
5772
|
print(f"Wrote {instructions_path}")
|
|
5698
5773
|
elif vs_state == "updated":
|
|
@@ -5731,7 +5806,8 @@ def cmd_install_mcp(args):
|
|
|
5731
5806
|
# ── Codex AGENTS.md enforcement file ──────────────────────
|
|
5732
5807
|
if profile.name == "codex":
|
|
5733
5808
|
agents_md_path = target / "AGENTS.md"
|
|
5734
|
-
agents_state = _ensure_codex_agents_workflow(agents_md_path
|
|
5809
|
+
agents_state = _ensure_codex_agents_workflow(agents_md_path,
|
|
5810
|
+
str(target))
|
|
5735
5811
|
if agents_state == "written":
|
|
5736
5812
|
print(f"Wrote {agents_md_path}")
|
|
5737
5813
|
elif agents_state == "updated":
|
|
@@ -9123,6 +9199,7 @@ def main():
|
|
|
9123
9199
|
"claudemd": cmd_claudemd,
|
|
9124
9200
|
"map": cmd_map,
|
|
9125
9201
|
"stats": cmd_stats,
|
|
9202
|
+
"search-eval": cmd_search_eval,
|
|
9126
9203
|
"benchmark": cmd_benchmark,
|
|
9127
9204
|
"session-benchmark": cmd_session_benchmark,
|
|
9128
9205
|
"benchmark-e2e": cmd_benchmark_e2e,
|
|
@@ -26,25 +26,48 @@ class CommandDeps:
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def cmd_index(args, deps: CommandDeps):
|
|
29
|
-
"""Rebuild the code index.
|
|
29
|
+
"""Rebuild the code index.
|
|
30
|
+
|
|
31
|
+
``--max-files`` defaults to None so an unset flag falls through to
|
|
32
|
+
``CodeIndex.build_index``, which reads ``index_max_files`` from
|
|
33
|
+
``.c3/config.json`` (2000 by default). Passing a hard-coded number here
|
|
34
|
+
would shadow that config for every caller who did not type the flag.
|
|
35
|
+
|
|
36
|
+
A truncated index is reported, never silent: the caller who sees only
|
|
37
|
+
"Files Indexed: 500" has no way to know 1400 files were skipped, and a
|
|
38
|
+
partial index answers searches with confident absences.
|
|
39
|
+
"""
|
|
30
40
|
config = deps.load_config()
|
|
31
41
|
project_path = config.get("project_path", ".")
|
|
32
42
|
|
|
33
43
|
deps.print_header("Rebuilding Code Index")
|
|
34
44
|
indexer = deps.CodeIndex(project_path)
|
|
35
|
-
result = indexer.build_index(max_files=args.max_files
|
|
45
|
+
result = indexer.build_index(max_files=args.max_files)
|
|
46
|
+
|
|
47
|
+
capped = result.get("files_capped", 0) or 0
|
|
48
|
+
candidates = result["files_indexed"] + capped
|
|
36
49
|
|
|
37
50
|
if deps.HAS_RICH:
|
|
38
51
|
table = deps.Table(title="Index Results")
|
|
39
52
|
table.add_column("Metric", style="cyan")
|
|
40
53
|
table.add_column("Value", style="green")
|
|
41
|
-
|
|
54
|
+
files_cell = str(result["files_indexed"])
|
|
55
|
+
if capped:
|
|
56
|
+
files_cell = f"{result['files_indexed']} of {candidates}"
|
|
57
|
+
table.add_row("Files Indexed", files_cell)
|
|
42
58
|
table.add_row("Chunks Created", str(result["chunks_created"]))
|
|
43
59
|
table.add_row("Unique Symbols", str(result["unique_symbols"]))
|
|
60
|
+
if capped:
|
|
61
|
+
table.add_row("Files Skipped (cap)", str(capped))
|
|
44
62
|
deps.console.print(table)
|
|
45
63
|
else:
|
|
46
64
|
print(f" Files: {result['files_indexed']}, Chunks: {result['chunks_created']}, Symbols: {result['unique_symbols']}")
|
|
47
65
|
|
|
66
|
+
if capped:
|
|
67
|
+
print(f" [!] Indexed {result['files_indexed']} of {candidates} candidate files "
|
|
68
|
+
f"(cap: index_max_files={result.get('max_files')}). {capped} skipped.")
|
|
69
|
+
print(" Raise index_max_files in .c3/config.json for full coverage.")
|
|
70
|
+
|
|
48
71
|
|
|
49
72
|
def cmd_compress(args, deps: CommandDeps):
|
|
50
73
|
"""Compress a file and show results."""
|
|
@@ -34,7 +34,30 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
34
34
|
help="Only report whether a newer version exists; don't install")
|
|
35
35
|
|
|
36
36
|
p_index = subparsers.add_parser("index", help="Rebuild code index")
|
|
37
|
-
p_index.add_argument("--max-files", type=int, default=
|
|
37
|
+
p_index.add_argument("--max-files", type=int, default=None,
|
|
38
|
+
help="Cap files indexed this run. Unset reads "
|
|
39
|
+
"index_max_files from .c3/config.json (2000).")
|
|
40
|
+
|
|
41
|
+
p_search_eval = subparsers.add_parser(
|
|
42
|
+
"search-eval", help="Run the c3_search relevance suite (docs/search-eval.md)")
|
|
43
|
+
p_search_eval.add_argument("--suite", default="fixture",
|
|
44
|
+
help="'fixture' (synthetic repo, CI gate), 'golden' (this repo), or a .jsonl path")
|
|
45
|
+
p_search_eval.add_argument("--repo", default=None,
|
|
46
|
+
help="Project to evaluate; overrides the suite header (real repos only)")
|
|
47
|
+
p_search_eval.add_argument("--semantic", choices=["off", "auto", "on"], default="auto",
|
|
48
|
+
help="off: skip semantic cases; auto: run when embeddings are ready; "
|
|
49
|
+
"on: build embeddings first (needs Ollama)")
|
|
50
|
+
p_search_eval.add_argument("--rerank", choices=["off", "on"], default="off",
|
|
51
|
+
help="on: attach the FlashRank reranker (needs the `rerank` extra) to measure it "
|
|
52
|
+
"against the same suite; off: the project's own config decides")
|
|
53
|
+
p_search_eval.add_argument("--rebuild", action="store_true",
|
|
54
|
+
help="Rebuild the code index before running (real repos; fixtures always rebuild)")
|
|
55
|
+
p_search_eval.add_argument("--baseline", default=None, help="Baseline JSON to compare against / write")
|
|
56
|
+
p_search_eval.add_argument("--update-baseline", action="store_true",
|
|
57
|
+
help="Write aggregates + per-query status to the baseline (floors are kept)")
|
|
58
|
+
p_search_eval.add_argument("--floors", default=None,
|
|
59
|
+
help='With --update-baseline: JSON object of metric floors, e.g. \'{"mrr": 0.85}\'')
|
|
60
|
+
p_search_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
|
|
38
61
|
|
|
39
62
|
p_compress = subparsers.add_parser("compress", help="Compress a file")
|
|
40
63
|
p_compress.add_argument("file", help="File to compress")
|
|
@@ -6,9 +6,11 @@ dispatcher's deny-beats-allow merge makes a deny here final. hook_dispatch
|
|
|
6
6
|
treats this module as _FAIL_CLOSED: if it fails to import or raises, write-
|
|
7
7
|
class native tools are denied instead of sailing through.
|
|
8
8
|
|
|
9
|
-
Bash coverage is a best-effort
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Bash coverage is a best-effort token scan — advisory by design
|
|
10
|
+
(docs/access-guard.md §3/§6); it catches an agent naming a denied path, not
|
|
11
|
+
an adversary hiding one. Two passes: every path-shaped token as a READ
|
|
12
|
+
(existence-gated), then the command's WRITE targets as writes (v2.102.0), so
|
|
13
|
+
a redirect into a confirm-held or read-only file holds like any other write.
|
|
12
14
|
"""
|
|
13
15
|
import os
|
|
14
16
|
import re
|
|
@@ -29,6 +31,16 @@ try:
|
|
|
29
31
|
except Exception: # pragma: no cover — telemetry is never load-bearing
|
|
30
32
|
access_telemetry = None
|
|
31
33
|
|
|
34
|
+
# The same write-target extractor the edit ledger uses after the fact. Its
|
|
35
|
+
# absence degrades the shell branch to the read-only scan, never to a crash.
|
|
36
|
+
try:
|
|
37
|
+
from _shell_writes import shell_write_targets
|
|
38
|
+
except Exception: # pragma: no cover — package-style import (dispatcher, tests)
|
|
39
|
+
try:
|
|
40
|
+
from cli._shell_writes import shell_write_targets
|
|
41
|
+
except Exception:
|
|
42
|
+
shell_write_targets = None
|
|
43
|
+
|
|
32
44
|
_WRITE_TOOLS = {"Edit", "Write", "MultiEdit", "NotebookEdit"}
|
|
33
45
|
_READ_TOOLS = {"Read", "SearchText"}
|
|
34
46
|
_SEARCH_TOOLS = {"Grep", "Glob", "FindFiles"}
|
|
@@ -206,21 +218,41 @@ def _record(denial, tool: str, operation: str, path: str,
|
|
|
206
218
|
|
|
207
219
|
|
|
208
220
|
def _override_allows(base: str, denial, *, tool: str, op: str, path: str,
|
|
209
|
-
session_id: str):
|
|
221
|
+
session_id: str, peek: bool = False):
|
|
210
222
|
"""A live override grant covering this exact call, or None (spec §5).
|
|
211
223
|
|
|
212
224
|
Lazy import and policy-before-grants ordering keep the hot path free: a
|
|
213
225
|
project that never turned overrides on pays one dict lookup and never
|
|
214
226
|
opens the grants file. Any failure returns None — the denial stands.
|
|
227
|
+
|
|
228
|
+
``peek`` looks without consuming; see ``_granted`` for why.
|
|
215
229
|
"""
|
|
216
230
|
try:
|
|
217
231
|
from services import override_grants as og # noqa: PLC0415 — lazy
|
|
218
232
|
return og.gate_access(base, denial, tool=tool, op=op, path=path,
|
|
219
|
-
session_id=session_id)
|
|
233
|
+
session_id=session_id, peek=peek)
|
|
220
234
|
except Exception:
|
|
221
235
|
return None # fail closed: no grant, ordinary denial
|
|
222
236
|
|
|
223
237
|
|
|
238
|
+
def _granted(line: str, defer: bool, consume) -> dict:
|
|
239
|
+
"""The allow-by-grant output.
|
|
240
|
+
|
|
241
|
+
Under the dispatcher (``defer`` True) the use is NOT burned here: the
|
|
242
|
+
provisional line goes out with an ``_on_allow`` callable, and
|
|
243
|
+
hook_dispatch runs it only once every PreToolUse sub-hook has voted
|
|
244
|
+
allow. Before v2.102.0 this hook consumed first and a strict-mode
|
|
245
|
+
discipline deny from hook_pretool_enforce then won the merge — grant
|
|
246
|
+
spent, nothing written, and the user asked twice for one edit. Run
|
|
247
|
+
standalone (``defer`` False) the use was already consumed by the peek-
|
|
248
|
+
less lookup, so the line is final.
|
|
249
|
+
"""
|
|
250
|
+
out = {"additionalContext": line}
|
|
251
|
+
if defer:
|
|
252
|
+
out["_on_allow"] = consume
|
|
253
|
+
return out
|
|
254
|
+
|
|
255
|
+
|
|
224
256
|
def _confirm_request(base: str, denial, *, tool: str, op: str, path: str,
|
|
225
257
|
session_id: str) -> tuple:
|
|
226
258
|
"""Auto-file an Override Request for a ``confirm`` denial (S8).
|
|
@@ -349,7 +381,68 @@ def _scan_shell(cmd: str, base: str):
|
|
|
349
381
|
return None, ""
|
|
350
382
|
|
|
351
383
|
|
|
352
|
-
def
|
|
384
|
+
def _scan_shell_writes(cmd: str, base: str, session_id: str,
|
|
385
|
+
defer: bool) -> dict | None:
|
|
386
|
+
"""WRITE-class verdict for the files a shell command writes (v2.102.0).
|
|
387
|
+
|
|
388
|
+
``_scan_shell`` evaluates every token as a READ. Confirm holds, read_only
|
|
389
|
+
rules and the builtin write-denies are all write-class, so ``cat >>
|
|
390
|
+
CLAUDE.md``, ``sed -i`` on .mcp.json or a heredoc into a hook body sailed
|
|
391
|
+
through with no hold — the one bypass docs/confirm-guard.md could only
|
|
392
|
+
ask the agent not to use. Targets come from the extractor the edit
|
|
393
|
+
ledger already trusts after the fact (cli/_shell_writes), with the same
|
|
394
|
+
best-effort caveat: a missed target costs a missed hold, a false one
|
|
395
|
+
costs a hold the human clears in one tap. Synthetic spelling denials are
|
|
396
|
+
skipped exactly as the read scan skips them (a token that is not a path
|
|
397
|
+
must not veto the command); the corrupt-config deny-all still refuses.
|
|
398
|
+
|
|
399
|
+
Grant identity is ``tool="Bash", op="write", path=<target>`` — bound to
|
|
400
|
+
the file, not the command text, the same stated limitation as the
|
|
401
|
+
shell_warn layer. Several held targets need several grants; the command
|
|
402
|
+
runs only when every one is covered, and the uses are burned together
|
|
403
|
+
(or not at all) by the dispatcher's settle step.
|
|
404
|
+
"""
|
|
405
|
+
if shell_write_targets is None:
|
|
406
|
+
return None
|
|
407
|
+
lines, consumers = [], []
|
|
408
|
+
for target in shell_write_targets(cmd, base):
|
|
409
|
+
denial = ag.check(target, "write", base)
|
|
410
|
+
if denial is None:
|
|
411
|
+
continue
|
|
412
|
+
if denial.rule.startswith("<") and denial.rule != "<corrupt-config>":
|
|
413
|
+
continue
|
|
414
|
+
granted = _override_allows(base, denial, tool="Bash", op="write",
|
|
415
|
+
path=target, session_id=session_id,
|
|
416
|
+
peek=defer)
|
|
417
|
+
if granted:
|
|
418
|
+
lines.append(granted)
|
|
419
|
+
if defer:
|
|
420
|
+
consumers.append(lambda t=target, d=denial: _override_allows(
|
|
421
|
+
base, d, tool="Bash", op="write", path=t,
|
|
422
|
+
session_id=session_id))
|
|
423
|
+
continue
|
|
424
|
+
_record(denial, "Bash", "write", target, base, session_id)
|
|
425
|
+
if denial.kind == "confirm":
|
|
426
|
+
rid, note = _confirm_request(base, denial, tool="Bash", op="write",
|
|
427
|
+
path=target, session_id=session_id)
|
|
428
|
+
return _deny(ag.refusal(denial, target, "write", surface="hook",
|
|
429
|
+
tool="Bash", request_id=rid,
|
|
430
|
+
request_note=note)
|
|
431
|
+
+ " (best-effort shell scan)")
|
|
432
|
+
return _deny(ag.refusal(denial, target, "write", surface="hook",
|
|
433
|
+
tool="Bash") + " (best-effort shell scan)")
|
|
434
|
+
if not lines:
|
|
435
|
+
return None
|
|
436
|
+
|
|
437
|
+
def _settle():
|
|
438
|
+
got = [fn() for fn in consumers]
|
|
439
|
+
return "\n".join(got) if all(got) else None
|
|
440
|
+
|
|
441
|
+
return _granted("\n".join(lines), bool(consumers), _settle)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def run(payload: dict, project_path: Path | None = None,
|
|
445
|
+
defer_consume: bool = False) -> dict | None:
|
|
353
446
|
tool = normalize_tool_name(payload.get("tool_name", ""))
|
|
354
447
|
tool_input = payload.get("tool_input", {}) or {}
|
|
355
448
|
base = str(project_path if project_path is not None else Path.cwd())
|
|
@@ -363,9 +456,13 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
363
456
|
denial = ag.check(fp, op, base)
|
|
364
457
|
if denial:
|
|
365
458
|
granted = _override_allows(base, denial, tool=tool, op=op,
|
|
366
|
-
path=fp, session_id=session_id
|
|
459
|
+
path=fp, session_id=session_id,
|
|
460
|
+
peek=defer_consume)
|
|
367
461
|
if granted:
|
|
368
|
-
return
|
|
462
|
+
return _granted(granted, defer_consume,
|
|
463
|
+
lambda: _override_allows(
|
|
464
|
+
base, denial, tool=tool, op=op, path=fp,
|
|
465
|
+
session_id=session_id))
|
|
369
466
|
_record(denial, tool, op, fp, base, session_id)
|
|
370
467
|
if denial.kind == "confirm":
|
|
371
468
|
# A confirm hold files its own request (grants were consulted
|
|
@@ -401,6 +498,6 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
401
498
|
return _deny(ag.refusal(denial, tok, "read",
|
|
402
499
|
surface="hook", tool=tool)
|
|
403
500
|
+ " (best-effort shell scan)")
|
|
404
|
-
return
|
|
501
|
+
return _scan_shell_writes(cmd, base, session_id, defer_consume)
|
|
405
502
|
|
|
406
503
|
return None
|
|
@@ -36,6 +36,7 @@ emit a short "[c3:hook-error] ..." additionalContext warning so enforcement
|
|
|
36
36
|
cannot silently stop enforcing.
|
|
37
37
|
"""
|
|
38
38
|
import importlib
|
|
39
|
+
import inspect
|
|
39
40
|
import json
|
|
40
41
|
import sys
|
|
41
42
|
from pathlib import Path
|
|
@@ -166,6 +167,16 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
|
|
|
166
167
|
|
|
167
168
|
_RUN_CACHE: dict = {}
|
|
168
169
|
|
|
170
|
+
# PreToolUse sub-hooks that consult override grants. Under the dispatcher
|
|
171
|
+
# they are asked to DEFER consumption (`defer_consume=True`): each returns a
|
|
172
|
+
# provisional allow carrying an `_on_allow` callable, and `_settle_grants`
|
|
173
|
+
# runs those only once every sub-hook has voted allow. Before v2.102.0 the
|
|
174
|
+
# access guard consumed a grant first and a strict-mode discipline deny from
|
|
175
|
+
# the next sub-hook then won the merge — grant spent, nothing written, the
|
|
176
|
+
# user asked twice for one edit. The same hole ran the other way for a
|
|
177
|
+
# discipline grant followed by a policy deny.
|
|
178
|
+
_DEFER_CONSUME = {"hook_access_guard", "hook_pretool_enforce"}
|
|
179
|
+
|
|
169
180
|
# Modules whose failure must DENY rather than fall through (fail closed).
|
|
170
181
|
# Scoped to write-class tools + shell: a broken guard must not let mutations
|
|
171
182
|
# sail through, but read-class fail-open avoids bricking whole sessions.
|
|
@@ -189,6 +200,77 @@ def _fail_closed_deny(module_name: str, err: str) -> dict:
|
|
|
189
200
|
}
|
|
190
201
|
|
|
191
202
|
|
|
203
|
+
def _is_deny(out) -> bool:
|
|
204
|
+
hso = out.get("hookSpecificOutput") if isinstance(out, dict) else None
|
|
205
|
+
return isinstance(hso, dict) and hso.get("permissionDecision") == "deny"
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _call_run(run_fn, module_name: str, event: str, payload: dict,
|
|
209
|
+
project_path):
|
|
210
|
+
"""Invoke a sub-hook, asking the grant-aware ones to defer consumption.
|
|
211
|
+
|
|
212
|
+
Signature-checked rather than assumed: tests stub these modules with
|
|
213
|
+
two-argument lambdas, and a legacy single-file hook must keep working.
|
|
214
|
+
"""
|
|
215
|
+
if event == "pretool" and module_name in _DEFER_CONSUME:
|
|
216
|
+
try:
|
|
217
|
+
accepts = "defer_consume" in inspect.signature(run_fn).parameters
|
|
218
|
+
except (TypeError, ValueError):
|
|
219
|
+
accepts = False
|
|
220
|
+
if accepts:
|
|
221
|
+
return run_fn(payload, project_path, defer_consume=True)
|
|
222
|
+
return run_fn(payload, project_path)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _grant_lost_deny() -> dict:
|
|
226
|
+
return {
|
|
227
|
+
"hookSpecificOutput": {
|
|
228
|
+
"hookEventName": "PreToolUse",
|
|
229
|
+
"permissionDecision": "deny",
|
|
230
|
+
"permissionDecisionReason": (
|
|
231
|
+
"[c3-override:spent] the override grant that would have "
|
|
232
|
+
"allowed this call was used up between check and use (a "
|
|
233
|
+
"concurrent call spent it). The rule stands — ask again "
|
|
234
|
+
"with c3_override if it is still needed."
|
|
235
|
+
),
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _settle_grants(outputs: list) -> list:
|
|
241
|
+
"""Burn deferred grant uses — only when the merged verdict is allow.
|
|
242
|
+
|
|
243
|
+
Any deny among the outputs means the call will not run, so every
|
|
244
|
+
`_on_allow` is dropped unrun and the grants stay live for the retry. On
|
|
245
|
+
an allow each consumer runs; the line it returns replaces the
|
|
246
|
+
provisional one (it carries the post-consumption uses count). A consumer
|
|
247
|
+
that finds nothing left — the grant was spent by a concurrent call
|
|
248
|
+
between peek and settle — turns its allow into a deny: the call must
|
|
249
|
+
not proceed on a grant that no longer exists.
|
|
250
|
+
"""
|
|
251
|
+
denied = any(_is_deny(o) for o in outputs)
|
|
252
|
+
settled = []
|
|
253
|
+
for out in outputs:
|
|
254
|
+
if not isinstance(out, dict):
|
|
255
|
+
settled.append(out)
|
|
256
|
+
continue
|
|
257
|
+
consume = out.pop("_on_allow", None)
|
|
258
|
+
if consume is None or denied:
|
|
259
|
+
settled.append(out)
|
|
260
|
+
continue
|
|
261
|
+
try:
|
|
262
|
+
line = consume()
|
|
263
|
+
except Exception as exc:
|
|
264
|
+
log_hook_error("hook_dispatch:settle", exc)
|
|
265
|
+
line = None
|
|
266
|
+
if line:
|
|
267
|
+
out["additionalContext"] = str(line)
|
|
268
|
+
settled.append(out)
|
|
269
|
+
else:
|
|
270
|
+
settled.append(_grant_lost_deny())
|
|
271
|
+
return settled
|
|
272
|
+
|
|
273
|
+
|
|
192
274
|
def _load_run(module_name: str):
|
|
193
275
|
"""Import cli.<module_name> and return its run() (cached).
|
|
194
276
|
|
|
@@ -353,7 +435,7 @@ def dispatch(event: str, payload: dict, project_path: Path | None = None) -> dic
|
|
|
353
435
|
outputs.append(_fail_closed_deny(module_name, err))
|
|
354
436
|
continue
|
|
355
437
|
try:
|
|
356
|
-
out = run_fn
|
|
438
|
+
out = _call_run(run_fn, module_name, event, payload, project_path)
|
|
357
439
|
if out:
|
|
358
440
|
outputs.append(out)
|
|
359
441
|
except Exception as exc:
|
|
@@ -368,7 +450,15 @@ def dispatch(event: str, payload: dict, project_path: Path | None = None) -> dic
|
|
|
368
450
|
# Critical state-layer warnings (corrupt enforcement_state.json)
|
|
369
451
|
# become visible instead of silently disabling enforcement.
|
|
370
452
|
warnings.extend(_hook_utils.drain_state_warnings())
|
|
453
|
+
# A PreToolUse deny is final — merge keeps the first deny and no
|
|
454
|
+
# allow readmits it — so the sub-hooks after it have nothing to add,
|
|
455
|
+
# and running them could only spend a grant or log a block for a
|
|
456
|
+
# call that will not happen.
|
|
457
|
+
if event == "pretool" and outputs and _is_deny(outputs[-1]):
|
|
458
|
+
break
|
|
371
459
|
|
|
460
|
+
if event == "pretool":
|
|
461
|
+
outputs = _settle_grants(outputs)
|
|
372
462
|
return merge_outputs(outputs, warnings, event=event, host=host)
|
|
373
463
|
|
|
374
464
|
|