code-context-control 2.138.0__tar.gz → 2.139.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.138.0 → code_context_control-2.139.0}/PKG-INFO +1 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/c3.py +15 -2
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/commands/parser.py +2 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/tools.html +10 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_access_guard.py +71 -3
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/mcp_server.py +4 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/delegate.py +286 -12
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/status.py +3 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/SOURCES.txt +4 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/config.py +4 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/pyproject.toml +3 -1
- code_context_control-2.139.0/services/bench/delegate_write_eval.py +370 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/claude_md.py +1 -1
- code_context_control-2.139.0/services/delegate_write.py +243 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/telemetry.py +5 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_adoption_d4.py +9 -1
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_telemetry_d0.py +18 -0
- code_context_control-2.139.0/tests/test_delegate_write.py +477 -0
- code_context_control-2.139.0/tests/test_delegate_write_eval.py +48 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/LICENSE +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/README.md +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/commands/common.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/docs.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/edits.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/access.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/index.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_read.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_session_end.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_session_open.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_server.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/progress.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/server.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/override.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/project.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/read.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/search.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/session.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/api.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/app.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/codex_patch.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/grok_payload.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/hook_command.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/host.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/ide.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/core/web_security.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/config.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/listeners.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/client_tokens.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/access_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/activity_log.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/agent_base.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/agent_locks.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/agents.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/agents_workflow.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/artifact_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/atomic_json.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/auto_memory.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/background_service.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/delegate_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/map_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_act.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_cache.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_expr.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_failures.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_github.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_impact.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_intel.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_runner.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/codex_integration.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/codex_transcript.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/compressor.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/conversation_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/cred_audit.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/credential_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/delegate_agents.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/dir_map.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/doc_index.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/embedding_index.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/error_reporting.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/file_map.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/file_memory.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/git_context.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/grok_integration.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/grok_transcript.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/host_sessions.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/hub_service.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/index_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/indexer.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/jira_client.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/jira_links.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/lexical_index.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/mask_activation.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/mask_presets.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_graph.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_queue.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/metrics.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/notifications.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ollama_client.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/oracle_service.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/output_filter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/override_costs.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/override_grants.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/override_policy.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/override_requests.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/override_wake.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/parser.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/project_manager.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/project_runtime.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/protocol.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/proxy_state.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/repo_map.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/repo_shape.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/reranker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/retention.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/retrieval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/router.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/runtime.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/scanner.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/session_live.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/session_manager.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/session_preloader.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/shell_jobs.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/shell_output.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/subprojects.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/task_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/text_index.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/time_tracker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/transcript_index.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/validation_cache.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/vector_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/watcher.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/setup.cfg +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_activity_log_find_last.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_dag_ownership.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_codex_native.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_claude_d1.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_grok.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_host_d2.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_scout_d3.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_thinking_cap.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_tuning.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_grok_native.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_grok_compat.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_session_end.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_hook_migration.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_override_policy_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_map_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_clients.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_jobs_ci.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_override_costs.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_notification_kinds.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_loopback.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_override_costs.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_read_outside_root.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_retention.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_session_live.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_jobs_s3.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_validate.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_watcher_pruning.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/backend.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/main.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.138.0 → code_context_control-2.139.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.
|
|
3
|
+
Version: 2.139.0
|
|
4
4
|
Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
|
|
|
91
91
|
# Config
|
|
92
92
|
CONFIG_DIR = ".c3"
|
|
93
93
|
CONFIG_FILE = ".c3/config.json"
|
|
94
|
-
__version__ = "2.
|
|
94
|
+
__version__ = "2.139.0"
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -1583,6 +1583,19 @@ def cmd_delegate_eval(args):
|
|
|
1583
1583
|
|
|
1584
1584
|
targets = [t.strip() for t in (args.targets or "").split(",") if t.strip()]
|
|
1585
1585
|
case_ids = [c.strip() for c in (args.cases or "").split(",") if c.strip()]
|
|
1586
|
+
if args.suite == "write":
|
|
1587
|
+
# Write mode (docs/delegate-write.md): graded on the files left behind.
|
|
1588
|
+
from services.bench import delegate_write_eval as dwe
|
|
1589
|
+
if not targets:
|
|
1590
|
+
raise RuntimeError("--suite write needs --targets (e.g. claude:small,claude:medium, or gold)")
|
|
1591
|
+
try:
|
|
1592
|
+
overrides = json.loads(args.config) if getattr(args, "config", None) else None
|
|
1593
|
+
report = dwe.run_write_suite(targets, case_ids=case_ids or None, record=args.record,
|
|
1594
|
+
delegate_overrides=overrides)
|
|
1595
|
+
except ValueError as e:
|
|
1596
|
+
raise RuntimeError(str(e))
|
|
1597
|
+
print(json.dumps(report, indent=2) if args.json else dwe.render(report))
|
|
1598
|
+
return
|
|
1586
1599
|
overrides = json.loads(args.config) if getattr(args, "config", None) else None
|
|
1587
1600
|
if overrides is not None and not isinstance(overrides, dict):
|
|
1588
1601
|
raise RuntimeError("--config must be a JSON object")
|
|
@@ -5065,7 +5078,7 @@ back to native tools as the task progresses.
|
|
|
5065
5078
|
- **Filter**: `c3_filter(text=...)` — for terminal output >10 lines
|
|
5066
5079
|
- **Shell**: `c3_shell(cmd, timeout=60)` — structured shell exec (tests/git/build). Auto-filters output, logs git mutations to the ledger. Native Bash for interactive/TTY only
|
|
5067
5080
|
- **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
|
|
5068
|
-
- **Delegate**: `c3_delegate(task, task_type, context|file_path)` — your own provider one tier down (default `backend='host'`, `tier='small'`; Claude Code: Haiku) for bounded answers: summarize a diff/log, explain a function, triage a traceback. `scout=true` lets it look files up itself. Multi-step work: the `c3-scout` (haiku) / `c3-worker` (sonnet) subagents
|
|
5081
|
+
- **Delegate**: `c3_delegate(task, task_type, context|file_path)` — your own provider one tier down (default `backend='host'`, `tier='small'`; Claude Code: Haiku) for bounded answers: summarize a diff/log, explain a function, triage a traceback. `scout=true` lets it look files up itself; `write_paths='a.py,b.py'` has Sonnet make a change you specified in only those files and return the diff. Multi-step work: the `c3-scout` (haiku) / `c3-worker` (sonnet) subagents
|
|
5069
5082
|
- **Local CI** (v2.79.0+): `c3_ci(action='inspect|run|rerun|failures')` — run THIS repo's real `.github/workflows` here instead of pushing for feedback. `run` executes in `needs` order; `failures` gives {file,line,message}; `rerun` retries only what failed. Only `FULL_CI_PASS` means safe to push — `PARTIAL_PASS` means something did not run (other OS, unsupported action, or your selection).
|
|
5070
5083
|
- **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.
|
|
5071
5084
|
- **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`.
|
|
@@ -92,7 +92,8 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
92
92
|
p_delegate_eval = subparsers.add_parser(
|
|
93
93
|
"delegate-eval", help="Grade c3_delegate answers per backend/tier (docs/delegate-eval.md)")
|
|
94
94
|
p_delegate_eval.add_argument("--suite", default="gold",
|
|
95
|
-
help="'gold' (bundled)
|
|
95
|
+
help="'gold' (bundled), 'write' (write mode, docs/delegate-write.md) "
|
|
96
|
+
"or a .jsonl path")
|
|
96
97
|
p_delegate_eval.add_argument("--targets", default="",
|
|
97
98
|
help="Comma-separated backend[:tier] list, e.g. 'claude:small,claude:medium'")
|
|
98
99
|
p_delegate_eval.add_argument("--cases", default="", help="Comma-separated case ids (default: all)")
|
|
@@ -954,6 +954,12 @@ c3_status(view=<span class="str">'sessions'</span>) <span class="com">#
|
|
|
954
954
|
<td class="param-default">false</td>
|
|
955
955
|
<td class="param-desc">Let the delegate Read/Grep/Glob the project itself, for lookups when you cannot name the files. Claude runs <code>--restricted</code> with Access Guard's read denies; Codex uses its read-only sandbox.</td>
|
|
956
956
|
</tr>
|
|
957
|
+
<tr>
|
|
958
|
+
<td class="param-name">write_paths</td>
|
|
959
|
+
<td class="param-type">string</td>
|
|
960
|
+
<td class="param-default">""</td>
|
|
961
|
+
<td class="param-desc">Write mode (Claude only, defaults to Sonnet). Comma-separated project-relative globs the delegate may edit or create. You decide the change; it makes it with Read/Grep/Glob/Edit/Write, no commands. You get back the diff, and each change is in the edit ledger. Access Guard applies; confirm-held, locked, <code>.git/</code> and <code>.c3/</code> paths are refused. Review the diff and run the tests yourself.</td>
|
|
962
|
+
</tr>
|
|
957
963
|
</tbody>
|
|
958
964
|
</table>
|
|
959
965
|
|
|
@@ -965,7 +971,10 @@ c3_delegate(task=<span class="str">'Summarize this diff for a changelog in three
|
|
|
965
971
|
c3_delegate(task=<span class="str">'What does resolve_host return inside a grok child?'</span>, file_path=<span class="str">'core/host.py'</span>, task_type=<span class="str">'explain'</span>, tier=<span class="str">'medium'</span>)
|
|
966
972
|
|
|
967
973
|
<span class="com"># A lookup the delegate does itself</span>
|
|
968
|
-
c3_delegate(task=<span class="str">'Which functions call charge_card, and where?'</span>, scout=<span class="kw">True</span>)
|
|
974
|
+
c3_delegate(task=<span class="str">'Which functions call charge_card, and where?'</span>, scout=<span class="kw">True</span>)
|
|
975
|
+
|
|
976
|
+
<span class="com"># A change you have decided, made by Sonnet inside a write set</span>
|
|
977
|
+
c3_delegate(task=<span class="str">'Rename calc_total to order_total in its definition and every use; no alias'</span>, write_paths=<span class="str">'inv/orders.py, inv/report.py, tests/test_orders.py'</span>)</code></pre>
|
|
969
978
|
|
|
970
979
|
<div class="callout callout-info">
|
|
971
980
|
<span class="callout-icon">ℹ️</span>
|
|
@@ -503,14 +503,77 @@ def run(payload: dict, project_path: Path | None = None,
|
|
|
503
503
|
return None
|
|
504
504
|
|
|
505
505
|
|
|
506
|
+
def _worker_refusal(rel: str, why: str) -> dict:
|
|
507
|
+
return _deny(f"[c3-delegate:refused] {rel}: {why}. Do not write it another way; "
|
|
508
|
+
"leave it and say in your report what change it needed.")
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def worker_run(payload: dict, project_path: Path, state_dir: Path) -> dict | None:
|
|
512
|
+
"""PreToolUse for a ``c3_delegate`` write-mode worker (see services/delegate_write).
|
|
513
|
+
|
|
514
|
+
Reads go through ``run`` exactly as for a scout. A write must pass, in
|
|
515
|
+
order: canonicalization inside the project, never ``.git/`` or ``.c3/``,
|
|
516
|
+
never the credential vault, Access Guard with NO grants and NO filed
|
|
517
|
+
requests (a confirm hold is a refusal here — a headless worker cannot
|
|
518
|
+
wait for a human, and the caller can make that edit itself), the caller's
|
|
519
|
+
write set, and another agent's lock. Then the pre-image is saved before
|
|
520
|
+
the write is allowed. Raises on a broken spec; main() turns that into a
|
|
521
|
+
deny.
|
|
522
|
+
"""
|
|
523
|
+
from services import delegate_write as dw
|
|
524
|
+
|
|
525
|
+
tool = normalize_tool_name(payload.get("tool_name", ""))
|
|
526
|
+
if tool not in _WRITE_TOOLS:
|
|
527
|
+
return run(payload, project_path)
|
|
528
|
+
spec = dw.load_spec(state_dir)
|
|
529
|
+
fp = _target(payload.get("tool_input", {}) or {})
|
|
530
|
+
if not fp:
|
|
531
|
+
return _deny("[c3-delegate:refused] a write with no target path")
|
|
532
|
+
base = str(project_path)
|
|
533
|
+
canon, rel, denial = ag.canonicalize(fp, base)
|
|
534
|
+
if denial:
|
|
535
|
+
return _worker_refusal(fp, f"path refused ({denial.reason})")
|
|
536
|
+
if not rel:
|
|
537
|
+
return _worker_refusal(fp, "outside the project")
|
|
538
|
+
if dw.forbidden(rel):
|
|
539
|
+
return _worker_refusal(rel, "under .git/ or .c3/, never delegate-writable")
|
|
540
|
+
try:
|
|
541
|
+
from services import credential_store as _cs
|
|
542
|
+
vault = _cs.vault_guard_reason(fp)
|
|
543
|
+
except Exception as exc: # fail closed: an unloadable vault check refuses
|
|
544
|
+
vault = f"vault check unavailable ({type(exc).__name__})"
|
|
545
|
+
if vault:
|
|
546
|
+
return _worker_refusal(rel, "credential vault file")
|
|
547
|
+
op = "write" if os.path.exists(fp) else "create"
|
|
548
|
+
denial = ag.check(fp, op, base)
|
|
549
|
+
if denial:
|
|
550
|
+
_record(denial, tool, op, fp, base, str(payload.get("session_id") or ""))
|
|
551
|
+
return _worker_refusal(rel, f"Access Guard {denial.kind} rule '{denial.rule}' "
|
|
552
|
+
f"({denial.scope})")
|
|
553
|
+
if not dw.in_write_set(rel, spec["write_paths"]):
|
|
554
|
+
return _worker_refusal(rel, "outside the write set the caller gave ("
|
|
555
|
+
+ ", ".join(spec["write_paths"]) + ")")
|
|
556
|
+
try:
|
|
557
|
+
from services import agent_locks
|
|
558
|
+
holder = agent_locks.check(fp, base, str(spec.get("session_id") or ""))
|
|
559
|
+
except Exception:
|
|
560
|
+
holder = None
|
|
561
|
+
if holder:
|
|
562
|
+
return _worker_refusal(rel, f"locked by {holder.get('agent_id', 'another agent')}")
|
|
563
|
+
dw.snapshot(state_dir, fp, canon)
|
|
564
|
+
return None
|
|
565
|
+
|
|
566
|
+
|
|
506
567
|
def main() -> None:
|
|
507
|
-
"""Standalone PreToolUse entry for a ``c3_delegate`` scout run.
|
|
568
|
+
"""Standalone PreToolUse entry for a ``c3_delegate`` scout or worker run.
|
|
508
569
|
|
|
509
570
|
A scout is ``claude -p --restricted`` with Read/Grep/Glob and no C3 MCP
|
|
510
571
|
server, so the dispatcher's discipline hook (hook_pretool_enforce) would
|
|
511
572
|
refuse every native read. Only the access guard runs here. It prints a
|
|
512
573
|
deny and nothing else: grants and search footers are for an agent that
|
|
513
574
|
can act on them. Any failure denies (fail closed).
|
|
575
|
+
|
|
576
|
+
``--worker-state DIR``: a write-mode worker; see ``worker_run``.
|
|
514
577
|
"""
|
|
515
578
|
import argparse
|
|
516
579
|
import json
|
|
@@ -520,6 +583,7 @@ def main() -> None:
|
|
|
520
583
|
ensure_utf8_stdio()
|
|
521
584
|
parser = argparse.ArgumentParser()
|
|
522
585
|
parser.add_argument("--project", required=True)
|
|
586
|
+
parser.add_argument("--worker-state", default="")
|
|
523
587
|
args = parser.parse_args()
|
|
524
588
|
try:
|
|
525
589
|
raw = sys.stdin.read()
|
|
@@ -527,9 +591,13 @@ def main() -> None:
|
|
|
527
591
|
if not isinstance(payload, dict):
|
|
528
592
|
raise ValueError("hook payload must be a JSON object")
|
|
529
593
|
# access_guard canonicalizes the base itself (no direct resolve here).
|
|
530
|
-
|
|
594
|
+
if args.worker_state:
|
|
595
|
+
out = worker_run(payload, Path(args.project), Path(args.worker_state))
|
|
596
|
+
else:
|
|
597
|
+
out = run(payload, Path(args.project))
|
|
531
598
|
except Exception as exc:
|
|
532
|
-
|
|
599
|
+
who = "worker" if args.worker_state else "scout"
|
|
600
|
+
out = _deny(f"[c3-access:error] {who} guard failed ({type(exc).__name__}: {exc}); "
|
|
533
601
|
"refusing the call")
|
|
534
602
|
if isinstance(out, dict) and isinstance(out.get("hookSpecificOutput"), dict):
|
|
535
603
|
print(json.dumps({"hookSpecificOutput": out["hookSpecificOutput"]}))
|
|
@@ -806,11 +806,13 @@ async def c3_delegate(task: str, task_type: str = "ask", context: str = "",
|
|
|
806
806
|
file_path: str = "", backend: str = "host",
|
|
807
807
|
allow_write_delegation: bool = False,
|
|
808
808
|
tier: str = "", model: str = "", scout: bool = False,
|
|
809
|
+
write_paths: str = "",
|
|
809
810
|
ctx: Context = None) -> str:
|
|
810
811
|
"""OFFLOAD to another model — use when the subtask is local-model-sized or needs a different perspective.
|
|
811
812
|
backend: host (default: your own provider, one tier down — Claude Code->claude, Codex->codex, Grok->grok, Antigravity->gemini) | claude|codex|gemini|grok|ollama|auto. task_type: auto, summarize, explain, review, ask, test, diagnose, ping (live auth check), available, codex_check, gemini_check, grok_check, codex_resume.
|
|
812
813
|
tier: small (default; scout=true defaults to medium) | medium | large | default. claude: haiku/sonnet/opus; codex/grok: reasoning effort; gemini: flash-lite/flash/pro. model overrides the tier. Context + file_path are packed by C3 under Access Guard; a file over 8k tokens goes as its map, so for line-level questions on a big file paste the excerpt or use scout=true.
|
|
813
814
|
scout=true: the delegate may Read/Grep/Glob the project itself (claude: read-only, guard-denied paths refused; codex: its read-only sandbox) — for lookups when you cannot name the files.
|
|
815
|
+
write_paths: comma-separated project-relative globs the delegate may edit or create (write mode; claude only, tier defaults to medium). You decide the change: say what to change, where, and the intended behaviour. It cannot run commands. You get back the diff (each change is in the edit ledger): review it and run the tests yourself. Access Guard applies; confirm-held, locked, .git/ and .c3/ paths are refused.
|
|
814
816
|
grok runs read-only in a temp dir unless delegate.grok_allow_write=true (then --yolo in the project, loading its trusted .grok MCP servers and hooks).
|
|
815
817
|
allow_write_delegation: explicit user opt-in for write-capable backends (gemini/grok write mode/codex_resume) while Access Guard rules are active; codex is pinned read-only instead."""
|
|
816
818
|
svc = _svc(ctx)
|
|
@@ -828,7 +830,8 @@ async def c3_delegate(task: str, task_type: str = "ask", context: str = "",
|
|
|
828
830
|
try:
|
|
829
831
|
return await asyncio.to_thread(handle_delegate, task, task_type, context,
|
|
830
832
|
file_path, svc, finalize, backend,
|
|
831
|
-
allow_write_delegation, tier, model, scout
|
|
833
|
+
allow_write_delegation, tier, model, scout,
|
|
834
|
+
write_paths)
|
|
832
835
|
finally:
|
|
833
836
|
svc._agent_progress_cb = None
|
|
834
837
|
|
|
@@ -364,6 +364,21 @@ _CLAUDE_SCOUT_RULES = (
|
|
|
364
364
|
|
|
365
365
|
SCOUT_TOOLS = "Read,Grep,Glob"
|
|
366
366
|
|
|
367
|
+
_CLAUDE_WORKER_RULES = (
|
|
368
|
+
"You are a worker making one code change that a lead agent has already "
|
|
369
|
+
"decided. You have Read, Grep, Glob, Edit and Write in this repository and "
|
|
370
|
+
"nothing else: no commands, no tests, no network. Do exactly the change the "
|
|
371
|
+
"task describes: no refactors, renames, reformatting or extras it did not "
|
|
372
|
+
"ask for. Edit or create only paths in the write set; a refused path is off "
|
|
373
|
+
"limits, do not reach it another way. Read a file before editing it and "
|
|
374
|
+
"match its style. If the task is ambiguous, contradicts the code, or needs a "
|
|
375
|
+
"file outside the write set, do the part you can do safely and report the "
|
|
376
|
+
"rest instead of guessing. Make the edits first, then finish with a short "
|
|
377
|
+
"report: each file changed and what changed, anything left undone and why, "
|
|
378
|
+
"and any assumption the lead should check. The lead reviews your diff and "
|
|
379
|
+
"runs the tests."
|
|
380
|
+
)
|
|
381
|
+
|
|
367
382
|
|
|
368
383
|
def _permission_pattern(glob: str, root: str) -> str:
|
|
369
384
|
"""An Access Guard glob as a Claude Code ``Read()`` permission pattern.
|
|
@@ -431,6 +446,53 @@ def scout_settings(project_path) -> dict:
|
|
|
431
446
|
}
|
|
432
447
|
|
|
433
448
|
|
|
449
|
+
def worker_edit_denies(project_path) -> list[str]:
|
|
450
|
+
"""``Edit()`` deny patterns: every deny, read_only, confirm and mask glob.
|
|
451
|
+
|
|
452
|
+
A worker never gets a grant or files a request, so a confirm hold is a
|
|
453
|
+
refusal for it. Deny beats allow in Claude Code, so a broad write set
|
|
454
|
+
cannot reopen any of these. Raises ValueError on a corrupt rule scope.
|
|
455
|
+
"""
|
|
456
|
+
rules, mask_rules, corrupt = access_guard.load_all(str(project_path))
|
|
457
|
+
if corrupt:
|
|
458
|
+
raise ValueError(f"Access Guard config is unreadable in scope(s) {', '.join(corrupt)}")
|
|
459
|
+
globs = [r.glob for r in rules if r.kind in ("deny", "read_only", "confirm")]
|
|
460
|
+
globs += [m.glob for m in mask_rules]
|
|
461
|
+
root = Path(project_path).resolve().as_posix().casefold()
|
|
462
|
+
patterns = []
|
|
463
|
+
for glob in dict.fromkeys(globs):
|
|
464
|
+
pattern = _permission_pattern(glob, root)
|
|
465
|
+
if pattern:
|
|
466
|
+
patterns.append(f"Edit({pattern})")
|
|
467
|
+
return patterns
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def worker_settings(project_path, write_globs, state_dir) -> dict:
|
|
471
|
+
"""``--settings`` for a write-mode worker (services/delegate_write).
|
|
472
|
+
|
|
473
|
+
Edit() allow rules are the write set, rooted at the project (a bare name
|
|
474
|
+
is that file at the root, never a basename match anywhere). Read and
|
|
475
|
+
Edit denies come from Access Guard. The guard hook runs in worker mode on
|
|
476
|
+
every file tool: it re-checks all of that on the canonical path and saves
|
|
477
|
+
pre-images into ``state_dir``.
|
|
478
|
+
"""
|
|
479
|
+
from cli._hook_utils import hook_command_arg
|
|
480
|
+
|
|
481
|
+
hook = Path(__file__).resolve().parents[1] / "hook_access_guard.py"
|
|
482
|
+
project = str(Path(project_path).resolve())
|
|
483
|
+
command = (f"{hook_command_arg(sys.executable)} {hook_command_arg(str(hook))} "
|
|
484
|
+
f"--project {hook_command_arg(project)} "
|
|
485
|
+
f"--worker-state {hook_command_arg(str(state_dir))}")
|
|
486
|
+
return {
|
|
487
|
+
"permissions": {
|
|
488
|
+
"allow": [f"Edit(./{g})" for g in write_globs],
|
|
489
|
+
"deny": scout_read_denies(project) + worker_edit_denies(project),
|
|
490
|
+
},
|
|
491
|
+
"hooks": {"PreToolUse": [{"matcher": "Read|Grep|Glob|Edit|Write|MultiEdit|NotebookEdit",
|
|
492
|
+
"hooks": [{"type": "command", "command": command}]}]},
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
|
|
434
496
|
_EFFORT_LEVELS = frozenset({"low", "medium", "high", "xhigh", "max"})
|
|
435
497
|
|
|
436
498
|
|
|
@@ -468,19 +530,22 @@ def claude_thinking_cap_for(tier: str, dcfg: dict) -> int | None:
|
|
|
468
530
|
return cap if cap >= 0 else None
|
|
469
531
|
|
|
470
532
|
|
|
471
|
-
def claude_default_tier_key(scout: bool) -> str:
|
|
533
|
+
def claude_default_tier_key(scout: bool, write: bool = False) -> str:
|
|
472
534
|
"""Which config key names the default Claude tier.
|
|
473
535
|
|
|
474
536
|
A scout defaults to its own key (medium): measured 2026-09-14, a Haiku
|
|
475
537
|
scout took 28 turns and $0.24 to find one function that Sonnet found in
|
|
476
538
|
8 turns for $0.046; the eval's canary case showed the same (15 turns
|
|
477
|
-
against 2).
|
|
539
|
+
against 2). A write-mode worker has its own key too (see
|
|
540
|
+
docs/delegate-write.md for the measurement behind its default).
|
|
478
541
|
"""
|
|
542
|
+
if write:
|
|
543
|
+
return "claude_write_default_tier"
|
|
479
544
|
return "claude_scout_default_tier" if scout else "claude_default_tier"
|
|
480
545
|
|
|
481
546
|
|
|
482
547
|
def resolve_claude_tier(tier: str, model: str, dcfg: dict,
|
|
483
|
-
scout: bool = False) -> tuple[str, str, str]:
|
|
548
|
+
scout: bool = False, write: bool = False) -> tuple[str, str, str]:
|
|
484
549
|
"""(tier, model_arg, error). An explicit ``model`` wins over the tier.
|
|
485
550
|
|
|
486
551
|
``model_arg`` empty means omit --model. ``error`` is non-empty when the
|
|
@@ -490,7 +555,7 @@ def resolve_claude_tier(tier: str, model: str, dcfg: dict,
|
|
|
490
555
|
if not _MODEL_NAME_RE.match(model):
|
|
491
556
|
return "", "", f"model name {model!r} is not a Claude model alias or id"
|
|
492
557
|
return "custom", model, ""
|
|
493
|
-
resolved = normalize_tier(tier, dcfg, claude_default_tier_key(scout))
|
|
558
|
+
resolved = normalize_tier(tier, dcfg, claude_default_tier_key(scout, write))
|
|
494
559
|
if not resolved:
|
|
495
560
|
return "", "", f"unknown tier {tier!r} (use one of {', '.join(CLAUDE_TIERS)})"
|
|
496
561
|
table = {**CLAUDE_TIER_MODELS, **(dcfg.get("claude_tier_models") or {})}
|
|
@@ -502,7 +567,8 @@ def resolve_claude_tier(tier: str, model: str, dcfg: dict,
|
|
|
502
567
|
|
|
503
568
|
|
|
504
569
|
def _claude_cmd(exe: str, model: str, system_prompt: str, *, effort: str = "",
|
|
505
|
-
max_budget_usd: float = 0.0, settings: dict | None = None
|
|
570
|
+
max_budget_usd: float = 0.0, settings: dict | None = None,
|
|
571
|
+
tools: str = SCOUT_TOOLS) -> list:
|
|
506
572
|
"""The locked-down headless argv. The prompt goes on stdin.
|
|
507
573
|
|
|
508
574
|
--safe-mode: no CLAUDE.md, skills, plugins, hooks or MCP servers — but
|
|
@@ -515,12 +581,14 @@ def _claude_cmd(exe: str, model: str, system_prompt: str, *, effort: str = "",
|
|
|
515
581
|
and Glob only, confined to the project, no user/project/local settings
|
|
516
582
|
files, no CLAUDE.md, and the given --settings as the only permissions and
|
|
517
583
|
hooks. --permission-mode dontAsk refuses anything not already allowed.
|
|
584
|
+
A write-mode worker is the same run with ``tools`` adding Edit and Write,
|
|
585
|
+
allowed only by the settings' Edit() rules.
|
|
518
586
|
"""
|
|
519
587
|
cmd = [exe, "-p", "--output-format", "json", "--no-session-persistence"]
|
|
520
588
|
if settings is None:
|
|
521
589
|
cmd += ["--safe-mode", "--strict-mcp-config", "--tools", ""]
|
|
522
590
|
else:
|
|
523
|
-
cmd += ["--restricted", "--strict-mcp-config", "--tools",
|
|
591
|
+
cmd += ["--restricted", "--strict-mcp-config", "--tools", tools,
|
|
524
592
|
"--permission-mode", "dontAsk", "--settings", json.dumps(settings)]
|
|
525
593
|
cmd += ["--system-prompt", system_prompt]
|
|
526
594
|
if model:
|
|
@@ -601,6 +669,8 @@ def parse_claude_json(stdout: str, requested_model: str = "") -> tuple[str, bool
|
|
|
601
669
|
stats["model"] = primary
|
|
602
670
|
if len(model_usage) > 1:
|
|
603
671
|
stats["models_used"] = sorted(model_usage)
|
|
672
|
+
if isinstance(data.get("permission_denials"), list) and data["permission_denials"]:
|
|
673
|
+
stats["denials"] = data["permission_denials"]
|
|
604
674
|
text = str(data.get("result") or "").strip()
|
|
605
675
|
if data.get("is_error") or data.get("subtype") not in (None, "success"):
|
|
606
676
|
reason = text or str(data.get("terminal_reason") or data.get("subtype") or "error")
|
|
@@ -614,7 +684,8 @@ def _run_claude(prompt: str, system_prompt: str, model: str = "", *,
|
|
|
614
684
|
timeout: int = 120, effort: str = "",
|
|
615
685
|
max_budget_usd: float = 0.0, scout_project: str | None = None,
|
|
616
686
|
settings: dict | None = None,
|
|
617
|
-
thinking_cap: int | None = None
|
|
687
|
+
thinking_cap: int | None = None,
|
|
688
|
+
tools: str = SCOUT_TOOLS) -> tuple[str, bool, dict]:
|
|
618
689
|
"""Run the locked-down ``claude -p``.
|
|
619
690
|
|
|
620
691
|
Tool-less (default): in a throwaway directory. Scout (``scout_project``
|
|
@@ -630,7 +701,7 @@ def _run_claude(prompt: str, system_prompt: str, model: str = "", *,
|
|
|
630
701
|
try:
|
|
631
702
|
cmd = _claude_cmd(exe, model, system_prompt, effort=effort,
|
|
632
703
|
max_budget_usd=max_budget_usd,
|
|
633
|
-
settings=settings if scout else None)
|
|
704
|
+
settings=settings if scout else None, tools=tools)
|
|
634
705
|
proc = subprocess.Popen(
|
|
635
706
|
harden_win_argv(cmd),
|
|
636
707
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE,
|
|
@@ -808,6 +879,165 @@ def _handle_claude_delegate(task: str, task_type: str, context: str,
|
|
|
808
879
|
return finalize("c3_delegate", meta, output, "ok")
|
|
809
880
|
|
|
810
881
|
|
|
882
|
+
def _worker_timeout(dcfg: dict) -> tuple[int, str]:
|
|
883
|
+
"""(seconds, note). Inside the MCP client's own ceiling when it is known:
|
|
884
|
+
a worker the client abandons keeps writing with nobody to report to, so
|
|
885
|
+
C3's deadline must fire first and kill it."""
|
|
886
|
+
want = int(dcfg.get("claude_write_timeout", 600) or 600)
|
|
887
|
+
try:
|
|
888
|
+
from cli.tools.shell import _transport_ceiling_s
|
|
889
|
+
ceiling = _transport_ceiling_s()
|
|
890
|
+
except Exception:
|
|
891
|
+
ceiling = None
|
|
892
|
+
if ceiling and want > ceiling - 15:
|
|
893
|
+
return max(30, ceiling - 15), f"capped at {max(30, ceiling - 15)}s by the MCP client's {ceiling}s limit"
|
|
894
|
+
return want, ""
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
def _handle_claude_write(task: str, task_type: str, context: str, file_path: str,
|
|
898
|
+
svc, dcfg: dict, finalize, *, tier: str = "", model: str = "",
|
|
899
|
+
write_paths="") -> str:
|
|
900
|
+
"""Write mode: a Claude worker makes a change the caller specified.
|
|
901
|
+
|
|
902
|
+
The caller names the write set; the worker runs ``claude -p --restricted``
|
|
903
|
+
with Read/Grep/Glob/Edit/Write under Access Guard (services/delegate_write
|
|
904
|
+
has the four fences). C3 then diffs every file the worker touched against
|
|
905
|
+
its pre-image, logs each change to the edit ledger, and returns the diff.
|
|
906
|
+
Never cached. A worker killed at its deadline still reports what it wrote.
|
|
907
|
+
"""
|
|
908
|
+
from services import delegate_write as dw
|
|
909
|
+
|
|
910
|
+
base = {"task_type": task_type, "backend": "claude", "mode": "write"}
|
|
911
|
+
if not dcfg.get("claude_enabled", True):
|
|
912
|
+
return finalize("c3_delegate", base,
|
|
913
|
+
"[delegate:error] Claude not enabled. Set delegate.claude_enabled=true "
|
|
914
|
+
"in .c3/config.json", "disabled")
|
|
915
|
+
globs, problem = dw.parse_write_paths(write_paths)
|
|
916
|
+
if problem:
|
|
917
|
+
return finalize("c3_delegate", base, f"[delegate:error] {problem}", "error")
|
|
918
|
+
# A literal path the guard already refuses would only cost the worker
|
|
919
|
+
# turns and come back as a bare permission error: drop it now and say why.
|
|
920
|
+
guarded: list[str] = []
|
|
921
|
+
for g in list(globs):
|
|
922
|
+
if any(ch in g for ch in "*?["):
|
|
923
|
+
continue
|
|
924
|
+
full = Path(svc.project_path) / g
|
|
925
|
+
denial = access_guard.check(str(full), "write" if full.exists() else "create",
|
|
926
|
+
str(svc.project_path))
|
|
927
|
+
if denial:
|
|
928
|
+
globs.remove(g)
|
|
929
|
+
guarded.append(f"{g} ({denial.kind} rule '{denial.rule}')")
|
|
930
|
+
if not globs:
|
|
931
|
+
return finalize("c3_delegate", base,
|
|
932
|
+
"[delegate:blocked] Access Guard refuses every write path: "
|
|
933
|
+
+ "; ".join(guarded) + ". Make those edits yourself.", "blocked")
|
|
934
|
+
resolved_tier, model_arg, problem = resolve_claude_tier(tier, model, dcfg, write=True)
|
|
935
|
+
if problem:
|
|
936
|
+
return finalize("c3_delegate", base, f"[delegate:error] {problem}", "error")
|
|
937
|
+
base["tier"] = resolved_tier
|
|
938
|
+
breaker = _backend_breaker("claude", dcfg)
|
|
939
|
+
if not breaker.allow():
|
|
940
|
+
return finalize("c3_delegate", base,
|
|
941
|
+
"[delegate:degraded] Claude skipped after repeated failures; retrying in "
|
|
942
|
+
f"~{breaker.cooldown_remaining()}s. Run 'claude --version' to diagnose.",
|
|
943
|
+
"degraded")
|
|
944
|
+
|
|
945
|
+
file_max = max(200, int(dcfg.get("claude_file_max_tokens", 8000) or 8000))
|
|
946
|
+
enriched = context or ""
|
|
947
|
+
packed = _pack_file_context(file_path, svc, file_max_tokens=file_max) if file_path else ""
|
|
948
|
+
if packed:
|
|
949
|
+
enriched = f"{enriched}\n\n{packed}" if enriched else packed
|
|
950
|
+
max_ctx = max(200, int(dcfg.get("claude_max_context_tokens", 24000) or 24000))
|
|
951
|
+
if count_tokens(enriched) > max_ctx:
|
|
952
|
+
enriched = enriched[:max_ctx * 4] + f"\n[context truncated at ~{max_ctx} tokens]"
|
|
953
|
+
|
|
954
|
+
try:
|
|
955
|
+
from cli.tools import _grants
|
|
956
|
+
session_id = _grants.session_id(svc)
|
|
957
|
+
except Exception:
|
|
958
|
+
session_id = ""
|
|
959
|
+
project = str(svc.project_path)
|
|
960
|
+
state = dw.new_state_dir(project, globs, session_id)
|
|
961
|
+
try:
|
|
962
|
+
try:
|
|
963
|
+
settings = worker_settings(project, globs, state)
|
|
964
|
+
except ValueError as exc:
|
|
965
|
+
return finalize("c3_delegate", base,
|
|
966
|
+
f"[delegate:blocked] write mode refused: {exc}. Fix the config "
|
|
967
|
+
"(c3 access list) or make the change yourself.", "blocked")
|
|
968
|
+
timeout, cap_note = _worker_timeout(dcfg)
|
|
969
|
+
effort = claude_effort_for(resolved_tier, dcfg)
|
|
970
|
+
if effort:
|
|
971
|
+
base["effort"] = effort
|
|
972
|
+
thinking_cap = claude_thinking_cap_for(resolved_tier, dcfg)
|
|
973
|
+
if thinking_cap is not None:
|
|
974
|
+
base["thinking_cap"] = thinking_cap
|
|
975
|
+
try:
|
|
976
|
+
budget = float(dcfg.get("claude_max_budget_usd") or 0.0)
|
|
977
|
+
except (TypeError, ValueError):
|
|
978
|
+
budget = 0.0
|
|
979
|
+
prompt = ("WRITE SET (the only paths you may edit or create, relative to the "
|
|
980
|
+
"repository root):\n" + "\n".join(f"- {g}" for g in globs)
|
|
981
|
+
+ f"\n\nTIME: you are stopped after {timeout}s."
|
|
982
|
+
+ f"\n\nTASK FROM THE LEAD AGENT:\n{task}"
|
|
983
|
+
+ f"\n\nCONTEXT:\n{enriched or '(none)'}")
|
|
984
|
+
label = f"claude {resolved_tier} ({model_arg or 'cli-default'})"
|
|
985
|
+
_log_progress(svc, f"[delegate] {label} write mode, {len(globs)} write path(s)...")
|
|
986
|
+
t0 = time.monotonic()
|
|
987
|
+
output, ok, stats = _run_claude(prompt, _CLAUDE_WORKER_RULES, model_arg, timeout=timeout,
|
|
988
|
+
effort=effort, max_budget_usd=budget,
|
|
989
|
+
scout_project=project, settings=settings,
|
|
990
|
+
thinking_cap=thinking_cap, tools=dw.WORKER_TOOLS)
|
|
991
|
+
elapsed = round(time.monotonic() - t0, 1)
|
|
992
|
+
refused = dw.denial_lines(stats.pop("denials", None), project)
|
|
993
|
+
changes = dw.collect_changes(state, project)
|
|
994
|
+
finally:
|
|
995
|
+
shutil.rmtree(state, ignore_errors=True)
|
|
996
|
+
|
|
997
|
+
model_name = stats.pop("model", "") or model_arg or "cli-default"
|
|
998
|
+
added = sum(c["added"] for c in changes)
|
|
999
|
+
removed = sum(c["removed"] for c in changes)
|
|
1000
|
+
meta = {**base, "model": model_name, "elapsed": f"{elapsed}s", **stats,
|
|
1001
|
+
"files_changed": len(changes), "lines_added": added, "lines_removed": removed,
|
|
1002
|
+
"denied": len(refused)}
|
|
1003
|
+
if changes and getattr(svc, "edit_ledger", None):
|
|
1004
|
+
from cli.tools.edit import _log_to_ledger
|
|
1005
|
+
first_line = (task.strip().splitlines() or [""])[0][:100]
|
|
1006
|
+
for c in changes:
|
|
1007
|
+
_log_to_ledger(
|
|
1008
|
+
c["rel"], f"c3_delegate write ({model_name}): {first_line}",
|
|
1009
|
+
["c3_delegate", "claude", resolved_tier], svc,
|
|
1010
|
+
detail={"delegate": {"backend": "claude", "tier": resolved_tier,
|
|
1011
|
+
"model": model_name, "added": c["added"],
|
|
1012
|
+
"removed": c["removed"]},
|
|
1013
|
+
"created": c["change"] == "created"})
|
|
1014
|
+
|
|
1015
|
+
n = len(changes)
|
|
1016
|
+
if ok:
|
|
1017
|
+
breaker.record_success()
|
|
1018
|
+
_delegate_metrics["total_calls"] += 1
|
|
1019
|
+
header = (f"[delegate:write] {label} changed {n} file(s) in {elapsed}s. Review the diff "
|
|
1020
|
+
"and run the tests before relying on it." if n else
|
|
1021
|
+
f"[delegate:write] {label} changed nothing in {elapsed}s.")
|
|
1022
|
+
status, report = "ok", output
|
|
1023
|
+
else:
|
|
1024
|
+
if breaker.record_failure():
|
|
1025
|
+
_notify_backend_degraded(svc, "claude", breaker)
|
|
1026
|
+
header = f"[delegate:write-failed] {output}"
|
|
1027
|
+
if n:
|
|
1028
|
+
header += f"\n{n} file(s) were changed before it stopped; review them:"
|
|
1029
|
+
status, report = "error", ""
|
|
1030
|
+
if cap_note and not ok:
|
|
1031
|
+
header += f" (deadline {cap_note})"
|
|
1032
|
+
if guarded:
|
|
1033
|
+
header += ("\nNot attempted, Access Guard refuses a delegate: " + "; ".join(guarded)
|
|
1034
|
+
+ ". Make those edits yourself.")
|
|
1035
|
+
max_diff = max(2000, int(dcfg.get("claude_write_diff_max_chars", 24000) or 24000))
|
|
1036
|
+
text = dw.render(changes, header=header, report=report, refused=refused,
|
|
1037
|
+
max_diff_chars=max_diff)
|
|
1038
|
+
return finalize("c3_delegate", meta, text, status)
|
|
1039
|
+
|
|
1040
|
+
|
|
811
1041
|
def check_gemini() -> dict:
|
|
812
1042
|
"""Zero-cost health check for Gemini CLI. Returns status dict."""
|
|
813
1043
|
global _gemini_available
|
|
@@ -2116,7 +2346,8 @@ _OUTCOMES = frozenset({"ok", "cached", "error", "timeout", "blocked", "disabled"
|
|
|
2116
2346
|
"unavailable", "degraded"})
|
|
2117
2347
|
_CONFIDENCE = frozenset({"high", "medium", "low"})
|
|
2118
2348
|
_USAGE_KEYS = ("input_tokens", "output_tokens", "cached_tokens", "cache_read_tokens",
|
|
2119
|
-
"cache_write_tokens", "reasoning_tokens", "cost_usd", "turns"
|
|
2349
|
+
"cache_write_tokens", "reasoning_tokens", "cost_usd", "turns",
|
|
2350
|
+
"files_changed", "lines_added", "lines_removed", "denied")
|
|
2120
2351
|
|
|
2121
2352
|
|
|
2122
2353
|
def _delegate_outcome(status) -> str:
|
|
@@ -2224,18 +2455,57 @@ def _ping_finalize(finalize):
|
|
|
2224
2455
|
# Backends that can look things up in the project: claude as a guarded scout,
|
|
2225
2456
|
# codex because its read-only sandbox already runs in the project.
|
|
2226
2457
|
_SCOUT_BACKENDS = ("claude", "codex")
|
|
2458
|
+
_NOT_WRITE_TASKS = ("ping", "available", "codex_check", "gemini_check", "grok_check",
|
|
2459
|
+
"codex_resume")
|
|
2460
|
+
|
|
2461
|
+
|
|
2462
|
+
def _route_write(task: str, task_type: str, context: str, file_path: str, svc, finalize,
|
|
2463
|
+
backend: str, tier: str, model: str, route: dict, write_paths) -> str:
|
|
2464
|
+
"""``write_paths`` given: write mode, which only the claude backend has.
|
|
2465
|
+
|
|
2466
|
+
It never cascades — a write lands on the backend the caller chose or
|
|
2467
|
+
nowhere — and it does not need allow_write_delegation: the worker runs
|
|
2468
|
+
under Access Guard in-band, unlike gemini or grok in write mode.
|
|
2469
|
+
"""
|
|
2470
|
+
dcfg = svc.delegate_config or {}
|
|
2471
|
+
meta = {"task_type": task_type, "backend": backend, "mode": "write"}
|
|
2472
|
+
if not dcfg.get("enabled", True):
|
|
2473
|
+
return finalize("c3_delegate", meta, "[delegate:disabled]", "disabled")
|
|
2474
|
+
if task_type in _NOT_WRITE_TASKS:
|
|
2475
|
+
return finalize("c3_delegate", meta,
|
|
2476
|
+
f"[delegate:error] write_paths does not apply to task_type '{task_type}'.",
|
|
2477
|
+
"error")
|
|
2478
|
+
if backend == "host":
|
|
2479
|
+
provider, mapped = host_backend(svc)
|
|
2480
|
+
if mapped != "claude":
|
|
2481
|
+
return finalize("c3_delegate", meta,
|
|
2482
|
+
f"[delegate:error] write mode runs on the claude backend only; host "
|
|
2483
|
+
f"{provider or 'unknown'} maps to {mapped or 'nothing'}. "
|
|
2484
|
+
"Pass backend='claude' or make the change yourself.", "error")
|
|
2485
|
+
backend = "claude"
|
|
2486
|
+
if backend != "claude":
|
|
2487
|
+
return finalize("c3_delegate", {**meta, "backend": backend},
|
|
2488
|
+
f"[delegate:error] write mode runs on the claude backend only, not "
|
|
2489
|
+
f"'{backend}'.", "error")
|
|
2490
|
+
route["backend"] = "claude"
|
|
2491
|
+
if not model:
|
|
2492
|
+
route["tier"] = normalize_tier(tier, dcfg, claude_default_tier_key(False, write=True))
|
|
2493
|
+
return _handle_claude_write(task, task_type, context, file_path, svc, dcfg, finalize,
|
|
2494
|
+
tier=tier, model=model, write_paths=write_paths)
|
|
2227
2495
|
|
|
2228
2496
|
|
|
2229
2497
|
def handle_delegate(task: str, task_type: str, context: str, file_path: str,
|
|
2230
2498
|
svc, finalize, backend: str = "ollama",
|
|
2231
2499
|
allow_write_delegation: bool = False,
|
|
2232
|
-
tier: str = "", model: str = "", scout: bool = False
|
|
2500
|
+
tier: str = "", model: str = "", scout: bool = False,
|
|
2501
|
+
write_paths: str = "") -> str:
|
|
2233
2502
|
finalize = _telemetry_finalize(finalize, svc, requested_backend=backend,
|
|
2234
2503
|
task_type=task_type)
|
|
2235
2504
|
route = {"backend": backend}
|
|
2236
2505
|
try:
|
|
2237
2506
|
return _route_delegate(task, task_type, context, file_path, svc, finalize, backend,
|
|
2238
|
-
allow_write_delegation, tier, model, scout, route
|
|
2507
|
+
allow_write_delegation, tier, model, scout, route,
|
|
2508
|
+
write_paths=write_paths)
|
|
2239
2509
|
except access_guard.AccessDenied as exc:
|
|
2240
2510
|
# A guard refusal while packing file_path is the answer, not a crash:
|
|
2241
2511
|
# the refusal text goes back as the response (the agent reads the
|
|
@@ -2249,8 +2519,12 @@ def handle_delegate(task: str, task_type: str, context: str, file_path: str,
|
|
|
2249
2519
|
|
|
2250
2520
|
def _route_delegate(task: str, task_type: str, context: str, file_path: str,
|
|
2251
2521
|
svc, finalize, backend: str, allow_write_delegation: bool,
|
|
2252
|
-
tier: str, model: str, scout: bool, route: dict | None = None
|
|
2522
|
+
tier: str, model: str, scout: bool, route: dict | None = None,
|
|
2523
|
+
write_paths: str = "") -> str:
|
|
2253
2524
|
route = route if route is not None else {}
|
|
2525
|
+
if str(write_paths or "").strip():
|
|
2526
|
+
return _route_write(task, task_type, context, file_path, svc, finalize, backend,
|
|
2527
|
+
tier, model, route, write_paths)
|
|
2254
2528
|
if task_type == "ping":
|
|
2255
2529
|
finalize = _ping_finalize(finalize)
|
|
2256
2530
|
task, context, file_path, task_type = PING_TASK, "", "", "ask"
|
|
@@ -127,8 +127,10 @@ def _budget_view(svc, detailed, finalize):
|
|
|
127
127
|
calls = sum(r["calls"] for _k, r in used)
|
|
128
128
|
ok = sum(r["outcomes"].get("ok", 0) + r["outcomes"].get("cached", 0) for _k, r in used)
|
|
129
129
|
cost = sum(r.get("cost_usd") or 0.0 for _k, r in used)
|
|
130
|
+
files_changed = sum(r.get("files_changed") or 0 for _k, r in used)
|
|
130
131
|
by = " | ".join(f"{k}:{r['calls']}" for k, r in used[:4])
|
|
131
|
-
|
|
132
|
+
written = f", {files_changed} file(s) written" if files_changed > 0 else ""
|
|
133
|
+
lines.append(f"[delegate:7d] {calls} calls, {ok} answered, ${cost:.4f} reported{written} ({by})")
|
|
132
134
|
except Exception:
|
|
133
135
|
pass
|
|
134
136
|
|
{code_context_control-2.138.0 → code_context_control-2.139.0}/code_context_control.egg-info/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.139.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
|