code-context-control 2.139.0__tar.gz → 2.140.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.139.0 → code_context_control-2.140.0}/PKG-INFO +1 -1
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/c3.py +9 -2
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/tools.html +1 -1
- code_context_control-2.140.0/cli/hook_agent_model.py +68 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_dispatch.py +11 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_server.py +7 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/mcp_server.py +29 -3
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/status.py +12 -1
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/SOURCES.txt +4 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/config.py +9 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/pyproject.toml +1 -1
- code_context_control-2.140.0/services/agent_downshift.py +220 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/claude_md.py +1 -1
- code_context_control-2.140.0/services/delegate_hints.py +199 -0
- code_context_control-2.140.0/tests/test_delegate_auto.py +362 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/LICENSE +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/README.md +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/commands/common.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/docs.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/edits.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/access.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/index.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_read.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_session_end.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_session_open.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/progress.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/server.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/override.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/project.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/read.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/search.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/session.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/api.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/app.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/codex_patch.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/grok_payload.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/hook_command.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/host.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/ide.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/core/web_security.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/config.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/listeners.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/client_tokens.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/access_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/activity_log.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/agent_base.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/agent_locks.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/agents.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/agents_workflow.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/artifact_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/atomic_json.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/auto_memory.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/background_service.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/delegate_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/delegate_write_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/map_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_act.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_cache.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_expr.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_failures.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_github.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_impact.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_intel.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_runner.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/codex_integration.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/codex_transcript.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/compressor.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/conversation_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/cred_audit.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/credential_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/delegate_agents.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/delegate_write.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/dir_map.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/doc_index.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/embedding_index.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/error_reporting.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/file_map.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/file_memory.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/git_context.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/grok_integration.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/grok_transcript.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/host_sessions.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/hub_service.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/index_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/indexer.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/jira_client.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/jira_links.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/lexical_index.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/mask_activation.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/mask_presets.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_graph.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_queue.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/metrics.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/notifications.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ollama_client.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/oracle_service.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/output_filter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/override_costs.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/override_grants.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/override_policy.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/override_requests.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/override_wake.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/parser.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/project_manager.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/project_runtime.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/protocol.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/proxy_state.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/repo_map.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/repo_shape.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/reranker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/retention.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/retrieval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/router.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/runtime.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/scanner.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/session_live.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/session_manager.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/session_preloader.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/shell_jobs.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/shell_output.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/subprojects.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/task_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/telemetry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/text_index.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/time_tracker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/transcript_index.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/validation_cache.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/vector_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/watcher.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/setup.cfg +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_activity_log_find_last.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_dag_ownership.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_codex_native.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_adoption_d4.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_claude_d1.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_grok.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_host_d2.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_scout_d3.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_telemetry_d0.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_thinking_cap.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_tuning.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_write.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_delegate_write_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_grok_native.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_grok_compat.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_session_end.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_hook_migration.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_override_policy_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_map_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_clients.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_jobs_ci.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_override_costs.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_notification_kinds.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_loopback.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_override_costs.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_read_outside_root.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_retention.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_session_live.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_jobs_s3.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_validate.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_watcher_pruning.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/backend.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/main.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.139.0 → code_context_control-2.140.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.140.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,10 @@ 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.140.0"
|
|
95
|
+
|
|
96
|
+
# The PreToolUse matcher for native subagent calls (installer and hub migration).
|
|
97
|
+
AGENT_MATCHER = "Agent|Task"
|
|
95
98
|
|
|
96
99
|
|
|
97
100
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -5078,7 +5081,7 @@ back to native tools as the task progresses.
|
|
|
5078
5081
|
- **Filter**: `c3_filter(text=...)` — for terminal output >10 lines
|
|
5079
5082
|
- **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
|
|
5080
5083
|
- **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
|
|
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
|
|
5084
|
+
- **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; an `Agent` call with no `model` runs one tier below you (pass `model=` to choose)
|
|
5082
5085
|
- **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).
|
|
5083
5086
|
- **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.
|
|
5084
5087
|
- **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`.
|
|
@@ -5697,6 +5700,10 @@ def cmd_install_mcp(args):
|
|
|
5697
5700
|
shell_matcher,
|
|
5698
5701
|
"run_shell_command",
|
|
5699
5702
|
]
|
|
5703
|
+
# Native subagents (v2.140.0): a blank `model` is filled one tier below
|
|
5704
|
+
# the parent by hook_agent_model — without this matcher PreToolUse
|
|
5705
|
+
# never fires for Agent calls.
|
|
5706
|
+
_pre_matcher_names.append(AGENT_MATCHER)
|
|
5700
5707
|
desired_pre_hooks = [
|
|
5701
5708
|
{"matcher": m, "hooks": [{"type": "command", "command": hook_pretool_cmd}]}
|
|
5702
5709
|
for m in _pre_matcher_names
|
|
@@ -979,7 +979,7 @@ c3_delegate(task=<span class="str">'Rename calc_total to order_total in its defi
|
|
|
979
979
|
<div class="callout callout-info">
|
|
980
980
|
<span class="callout-icon">ℹ️</span>
|
|
981
981
|
<div class="callout-body">
|
|
982
|
-
For multi-step work in Claude Code, <code>c3 install-mcp</code> also writes two subagents to <code>.claude/agents</code>: <code>c3-scout</code> (Haiku, read-only) and <code>c3-worker</code> (Sonnet). They run inside your session, so C3's hooks apply to them. Skip them with <code>--no-agents</code>. <code>c3 delegate-eval</code> measures pass rate and cost per backend and tier on your machine.
|
|
982
|
+
For multi-step work in Claude Code, <code>c3 install-mcp</code> also writes two subagents to <code>.claude/agents</code>: <code>c3-scout</code> (Haiku, read-only) and <code>c3-worker</code> (Sonnet). They run inside your session, so C3's hooks apply to them. Skip them with <code>--no-agents</code>. Any other <code>Agent</code> call that leaves <code>model</code> blank runs one tier below your session (Fable → Opus → Sonnet, never below Sonnet); set <code>delegate.agent_downshift</code> to <code>"off"</code> to keep the parent's model. When your own work looks delegable, a <code>[c3:delegate-hint]</code> line on the tool response names the call to make. <code>c3 delegate-eval</code> measures pass rate and cost per backend and tier on your machine.
|
|
983
983
|
</div>
|
|
984
984
|
</div>
|
|
985
985
|
</div>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""PreToolUse sub-hook: a native subagent with no ``model`` gets one tier below its parent.
|
|
2
|
+
|
|
3
|
+
Routed by cli/hook_dispatch.py for ``Agent`` / ``Task`` on Claude Code only;
|
|
4
|
+
the policy lives in services/agent_downshift.py. Returns
|
|
5
|
+
``hookSpecificOutput.updatedInput`` (the whole tool_input with ``model`` set),
|
|
6
|
+
or None to leave the call as it is. Every decision on a blank call — applied
|
|
7
|
+
or not, and why — is one ``agent_downshift`` telemetry row, so coverage is
|
|
8
|
+
measurable (how many calls fell through as ``parent_unknown``).
|
|
9
|
+
|
|
10
|
+
Opt out per project with ``delegate.agent_downshift: "off"``, or for a shell
|
|
11
|
+
with ``C3_AGENT_DOWNSHIFT=0``. Never raises into the tool call.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
20
|
+
|
|
21
|
+
from cli._hook_utils import find_project, log_hook_error # noqa: E402
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def run(payload: dict, project_path: Path | None = None):
|
|
25
|
+
try:
|
|
26
|
+
return _run(payload, project_path)
|
|
27
|
+
except Exception as exc: # a model choice is never worth a failed tool call
|
|
28
|
+
log_hook_error("hook_agent_model", exc)
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _run(payload: dict, project_path):
|
|
33
|
+
from services import agent_downshift as ad
|
|
34
|
+
|
|
35
|
+
if str(payload.get("tool_name") or "") not in ad.SUBAGENT_TOOLS:
|
|
36
|
+
return None
|
|
37
|
+
tool_input = payload.get("tool_input")
|
|
38
|
+
if not isinstance(tool_input, dict):
|
|
39
|
+
return None
|
|
40
|
+
if str(tool_input.get("model") or "").strip():
|
|
41
|
+
return None # the caller chose
|
|
42
|
+
if os.environ.get("C3_AGENT_DOWNSHIFT", "").strip().lower() in ("0", "off", "false", "no"):
|
|
43
|
+
return None
|
|
44
|
+
project = find_project(payload, project_path)
|
|
45
|
+
if project is None:
|
|
46
|
+
return None
|
|
47
|
+
from core.config import load_delegate_config
|
|
48
|
+
|
|
49
|
+
cfg = load_delegate_config(str(project))
|
|
50
|
+
stype = str(tool_input.get("subagent_type") or "general-purpose")
|
|
51
|
+
if ":" in stype:
|
|
52
|
+
return None # plugin agent: its definition is not ours to second-guess
|
|
53
|
+
if ad.definition_sets_model(stype, project):
|
|
54
|
+
return None
|
|
55
|
+
parent, source = ad.parent_model(payload, project)
|
|
56
|
+
target, reason = ad.resolve(stype, parent, cfg)
|
|
57
|
+
try:
|
|
58
|
+
from services.telemetry import append_telemetry_record
|
|
59
|
+
append_telemetry_record(project, {"tool": "agent_downshift" if target else "agent_downshift_skip",
|
|
60
|
+
"detail": {
|
|
61
|
+
"subagent_type": stype, "parent_model": parent, "parent_source": source,
|
|
62
|
+
"model": target, "reason": reason, "applied": bool(target)}})
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
if not target:
|
|
66
|
+
return None
|
|
67
|
+
return {"hookSpecificOutput": {"hookEventName": "PreToolUse",
|
|
68
|
+
"updatedInput": {**tool_input, "model": target}}}
|
|
@@ -136,6 +136,10 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
|
|
|
136
136
|
yield "hook_access_guard"
|
|
137
137
|
# hook_pretool_enforce self-filters via its _PREREQS table.
|
|
138
138
|
yield "hook_pretool_enforce"
|
|
139
|
+
# A native subagent with no model inherits the parent's; this fills
|
|
140
|
+
# one in (services/agent_downshift.py). Claude Code only.
|
|
141
|
+
if raw_tool in ("Agent", "Task") and host == HOST_CLAUDE:
|
|
142
|
+
yield "hook_agent_model"
|
|
139
143
|
elif event == "posttool":
|
|
140
144
|
# hook_filter is the ONE sub-hook that reads the whole tool payload:
|
|
141
145
|
# it tiktoken-encodes the entire Bash output to measure savings, a
|
|
@@ -402,6 +406,7 @@ def merge_outputs(outputs: list, warnings: list, is_gemini: bool = False,
|
|
|
402
406
|
host = HOST_GEMINI if is_gemini else HOST_CLAUDE
|
|
403
407
|
|
|
404
408
|
deny_hso = None
|
|
409
|
+
updated_input = None
|
|
405
410
|
contexts: list = []
|
|
406
411
|
texts: list = []
|
|
407
412
|
tool_result = None
|
|
@@ -413,6 +418,8 @@ def merge_outputs(outputs: list, warnings: list, is_gemini: bool = False,
|
|
|
413
418
|
if isinstance(hso, dict):
|
|
414
419
|
if deny_hso is None and hso.get("permissionDecision") == "deny":
|
|
415
420
|
deny_hso = hso
|
|
421
|
+
if updated_input is None and isinstance(hso.get("updatedInput"), dict):
|
|
422
|
+
updated_input = hso["updatedInput"]
|
|
416
423
|
nested_ctx = hso.get("additionalContext")
|
|
417
424
|
if nested_ctx and hso.get("permissionDecision") != "deny":
|
|
418
425
|
contexts.append(str(nested_ctx))
|
|
@@ -435,6 +442,10 @@ def merge_outputs(outputs: list, warnings: list, is_gemini: bool = False,
|
|
|
435
442
|
result: dict = {}
|
|
436
443
|
if deny_hso is not None:
|
|
437
444
|
result["hookSpecificOutput"] = deny_hso
|
|
445
|
+
elif updated_input is not None and host == HOST_CLAUDE and event == "pretool":
|
|
446
|
+
# A rewritten tool input (hook_agent_model) — never alongside a deny.
|
|
447
|
+
result["hookSpecificOutput"] = {"hookEventName": "PreToolUse",
|
|
448
|
+
"updatedInput": updated_input}
|
|
438
449
|
if tool_result is not None:
|
|
439
450
|
if is_gemini:
|
|
440
451
|
# Gemini has no tool_result replacement — degrade to context,
|
|
@@ -4516,9 +4516,16 @@ def c3_hook_migrations(cli_dir: Path | None = None) -> list:
|
|
|
4516
4516
|
"command": f"{dispatch} {arg}"}]},
|
|
4517
4517
|
}
|
|
4518
4518
|
|
|
4519
|
+
# v2.140.0: native subagent calls reach the pretool dispatcher, where
|
|
4520
|
+
# hook_agent_model fills a blank model. Same literal as cli.c3.AGENT_MATCHER.
|
|
4521
|
+
agent_entry = {"matcher": "Agent|Task",
|
|
4522
|
+
"hooks": [{"type": "command", "command": f"{dispatch} pretool"}]}
|
|
4523
|
+
|
|
4519
4524
|
return [
|
|
4520
4525
|
{"settings": ".claude/settings.local.json", "event": "PostToolUse",
|
|
4521
4526
|
"present": c3read_present, "entry": c3read_entry},
|
|
4527
|
+
{"settings": ".claude/settings.local.json", "event": "PreToolUse",
|
|
4528
|
+
"present": _has_matcher("Agent|Task"), "entry": agent_entry},
|
|
4522
4529
|
{"settings": ".gemini/settings.json", "event": "AfterTool",
|
|
4523
4530
|
"present": c3read_present, "entry": c3read_entry},
|
|
4524
4531
|
# Claude only — Gemini has no session-lifecycle event to hang these on.
|
|
@@ -25,6 +25,7 @@ from fastmcp import Context, FastMCP
|
|
|
25
25
|
|
|
26
26
|
from core.host import resolve_host
|
|
27
27
|
from core.ide import get_profile
|
|
28
|
+
from services import delegate_hints
|
|
28
29
|
from services.auto_memory import AutoMemory
|
|
29
30
|
from services.context_snapshot import ContextSnapshot
|
|
30
31
|
from services.runtime import C3Runtime, build_runtime, start_runtime, stop_runtime
|
|
@@ -515,6 +516,21 @@ _last_badge_count: int = 0 # delta-based: only show badge when count increases
|
|
|
515
516
|
_finalize_lock = threading.Lock()
|
|
516
517
|
|
|
517
518
|
|
|
519
|
+
def _with_hint(resp, make_hint) -> str:
|
|
520
|
+
"""``resp`` plus a delegation hint line (services/delegate_hints), when the
|
|
521
|
+
call succeeded and a hint is due. A hint is advice: it never fails a call."""
|
|
522
|
+
if not isinstance(resp, str):
|
|
523
|
+
return resp
|
|
524
|
+
try:
|
|
525
|
+
from cli._hook_utils import response_text_failed
|
|
526
|
+
if response_text_failed(resp):
|
|
527
|
+
return resp
|
|
528
|
+
hint = make_hint()
|
|
529
|
+
except Exception:
|
|
530
|
+
return resp
|
|
531
|
+
return f"{resp}\n{hint}" if hint else resp
|
|
532
|
+
|
|
533
|
+
|
|
518
534
|
def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
519
535
|
response: str, summary: str = "",
|
|
520
536
|
response_tokens: int = 0) -> str:
|
|
@@ -668,10 +684,11 @@ async def c3_search(query: str, action: str = "code", top_k: int = 3,
|
|
|
668
684
|
def finalize(name, args, resp, summ, **kw):
|
|
669
685
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
670
686
|
|
|
671
|
-
|
|
687
|
+
resp = await asyncio.to_thread(handle_search, query, action, top_k, max_tokens, svc,
|
|
672
688
|
finalize, maybe_related_facts, prefetch=prefetch,
|
|
673
689
|
scope=scope, ignore_case=ignore_case,
|
|
674
690
|
path=path, lang=lang, kind=kind)
|
|
691
|
+
return _with_hint(resp, lambda: delegate_hints.after_read(svc, ""))
|
|
675
692
|
|
|
676
693
|
|
|
677
694
|
@mcp.tool()
|
|
@@ -746,7 +763,10 @@ async def c3_read(file_path: str, symbols: Any = None, lines: Any = None,
|
|
|
746
763
|
def finalize(name, args, resp, summ, **kw):
|
|
747
764
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
748
765
|
|
|
749
|
-
|
|
766
|
+
resp = await asyncio.to_thread(handle_read, file_path, symbols, lines, include_docstrings, svc, finalize)
|
|
767
|
+
if not (symbols or lines):
|
|
768
|
+
return resp # a map is the cheap way to look; it does not count toward the hint
|
|
769
|
+
return _with_hint(resp, lambda: delegate_hints.after_read(svc, file_path.split(",")[0].strip()))
|
|
750
770
|
|
|
751
771
|
|
|
752
772
|
# c3_compress left the MCP surface in 2.124.0: c3_read(file_path) serves the
|
|
@@ -827,6 +847,10 @@ async def c3_delegate(task: str, task_type: str = "ask", context: str = "",
|
|
|
827
847
|
task.add_done_callback(lambda done: done.exception() if not done.cancelled() else None)
|
|
828
848
|
loop.call_soon_threadsafe(schedule)
|
|
829
849
|
svc._agent_progress_cb = _progress_cb
|
|
850
|
+
try:
|
|
851
|
+
delegate_hints.after_delegate(svc, write=bool(str(write_paths or "").strip()), scout=bool(scout))
|
|
852
|
+
except Exception:
|
|
853
|
+
pass
|
|
830
854
|
try:
|
|
831
855
|
return await asyncio.to_thread(handle_delegate, task, task_type, context,
|
|
832
856
|
file_path, svc, finalize, backend,
|
|
@@ -879,8 +903,10 @@ async def c3_edit(file_path: str, old_string: str = "", new_string: str = "",
|
|
|
879
903
|
def finalize(name, args, resp, summ, **kw):
|
|
880
904
|
return _finalize_response(ctx, name, args, resp, summ, **kw)
|
|
881
905
|
|
|
882
|
-
|
|
906
|
+
resp = await asyncio.to_thread(handle_edit, file_path, old_string, new_string,
|
|
883
907
|
summary, tags, replace_all, svc, finalize, edits)
|
|
908
|
+
return _with_hint(resp, lambda: delegate_hints.after_edit(
|
|
909
|
+
svc, file_path, delegate_hints.edit_chars(new_string, edits)))
|
|
884
910
|
|
|
885
911
|
|
|
886
912
|
@mcp.tool()
|
|
@@ -121,7 +121,18 @@ def _budget_view(svc, detailed, finalize):
|
|
|
121
121
|
# (2.132.0+): how much work went one tier down, where, and what it cost.
|
|
122
122
|
try:
|
|
123
123
|
from services.telemetry import aggregate_tool_telemetry
|
|
124
|
-
|
|
124
|
+
agg7 = aggregate_tool_telemetry(svc.project_path, days=7)
|
|
125
|
+
by_tool = agg7.get("by_tool") or {}
|
|
126
|
+
|
|
127
|
+
def _n(tool: str) -> int:
|
|
128
|
+
return int((by_tool.get(tool) or {}).get("calls") or 0)
|
|
129
|
+
|
|
130
|
+
moved, blank = _n("agent_downshift"), _n("agent_downshift") + _n("agent_downshift_skip")
|
|
131
|
+
hints, followed = _n("delegate_hint"), _n("delegate_hint_followed")
|
|
132
|
+
if blank or hints:
|
|
133
|
+
lines.append(f"[delegate-auto:7d] {moved} of {blank} model-less subagent call(s) moved to a "
|
|
134
|
+
f"lower model, {hints} delegation hint(s) shown, {followed} followed")
|
|
135
|
+
rows = agg7.get("delegate_by_backend") or {}
|
|
125
136
|
used = sorted(((k, r) for k, r in rows.items() if r.get("calls")), key=lambda kv: -kv[1]["calls"])
|
|
126
137
|
if used:
|
|
127
138
|
calls = sum(r["calls"] for _k, r in used)
|
{code_context_control-2.139.0 → code_context_control-2.140.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.140.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
|
|
@@ -8,6 +8,7 @@ cli/c3.py
|
|
|
8
8
|
cli/docs.html
|
|
9
9
|
cli/edits.html
|
|
10
10
|
cli/hook_access_guard.py
|
|
11
|
+
cli/hook_agent_model.py
|
|
11
12
|
cli/hook_artifact.py
|
|
12
13
|
cli/hook_auto_snapshot.py
|
|
13
14
|
cli/hook_c3_signal.py
|
|
@@ -194,6 +195,7 @@ services/access_guard.py
|
|
|
194
195
|
services/access_telemetry.py
|
|
195
196
|
services/activity_log.py
|
|
196
197
|
services/agent_base.py
|
|
198
|
+
services/agent_downshift.py
|
|
197
199
|
services/agent_locks.py
|
|
198
200
|
services/agents.py
|
|
199
201
|
services/agents_workflow.py
|
|
@@ -225,6 +227,7 @@ services/cred_audit.py
|
|
|
225
227
|
services/cred_telemetry.py
|
|
226
228
|
services/credential_store.py
|
|
227
229
|
services/delegate_agents.py
|
|
230
|
+
services/delegate_hints.py
|
|
228
231
|
services/delegate_write.py
|
|
229
232
|
services/dir_map.py
|
|
230
233
|
services/doc_index.py
|
|
@@ -363,6 +366,7 @@ tests/test_credentials_routes.py
|
|
|
363
366
|
tests/test_credentials_tool.py
|
|
364
367
|
tests/test_creds_cli_smoke.py
|
|
365
368
|
tests/test_delegate_adoption_d4.py
|
|
369
|
+
tests/test_delegate_auto.py
|
|
366
370
|
tests/test_delegate_cascade.py
|
|
367
371
|
tests/test_delegate_claude_d1.py
|
|
368
372
|
tests/test_delegate_eval.py
|
|
@@ -316,6 +316,15 @@ DELEGATE_DEFAULTS = {
|
|
|
316
316
|
# (2026-09-14: --effort low changed nothing on Haiku 4.5 — same
|
|
317
317
|
# cost and output tokens over 22 eval cases — so no default)
|
|
318
318
|
"claude_max_budget_usd": 0, # --max-budget-usd per call; 0 = no cap
|
|
319
|
+
# Native Claude Code subagents (docs/delegate-auto.md). An Agent call with no model runs
|
|
320
|
+
# on the parent's model; the PreToolUse hook fills one in.
|
|
321
|
+
"agent_downshift": "one_down", # one_down | off | a fixed alias (haiku/sonnet/opus)
|
|
322
|
+
"agent_downshift_floor": "sonnet", # never below this (Haiku flailed on lookups, missed subtle specs)
|
|
323
|
+
"agent_downshift_skip": ["fork", "Plan"], # subagent types left on the parent's model
|
|
324
|
+
"agent_models": {}, # {subagent_type: alias} explicit per-type choice
|
|
325
|
+
# Delegation hints: one line on a c3_* response when the session's own work looks delegable.
|
|
326
|
+
"hints": True,
|
|
327
|
+
"hint_cooldown_minutes": 45, # per hint kind
|
|
319
328
|
}
|
|
320
329
|
|
|
321
330
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-context-control"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.140.0"
|
|
8
8
|
description = "Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""Give a native Claude Code subagent a model when the caller left it blank.
|
|
2
|
+
|
|
3
|
+
Measured 2026-09-14 over ~/.claude/projects transcripts since 2026-07-01: 963
|
|
4
|
+
of 991 ``Agent`` calls had no ``model``, and on Claude Code 2.1.270 such a call
|
|
5
|
+
runs on the PARENT's model — ``Explore`` included (a probe with a Sonnet parent
|
|
6
|
+
put all of an Explore run on Sonnet). So a Fable or Opus session pays its own
|
|
7
|
+
rate for every search-and-summarise branch it spawns.
|
|
8
|
+
|
|
9
|
+
The same probe proved the lever: a PreToolUse *command* hook that returns
|
|
10
|
+
``hookSpecificOutput.updatedInput`` with ``model`` set changes the model the
|
|
11
|
+
subagent runs on (``opus`` appeared in ``modelUsage`` only with the hook).
|
|
12
|
+
|
|
13
|
+
Policy (``resolve``), all from ``.c3/config.json → delegate``:
|
|
14
|
+
|
|
15
|
+
- ``agent_downshift``: ``"one_down"`` (default) — one tier below the parent,
|
|
16
|
+
Fable → Opus → Sonnet; ``"off"``; or a fixed alias (``"sonnet"``) used only
|
|
17
|
+
when it is below the parent.
|
|
18
|
+
- ``agent_downshift_floor``: ``"sonnet"``. Never below it: on the delegate
|
|
19
|
+
evals Haiku took 28 turns where Sonnet took 8 on a lookup, and missed
|
|
20
|
+
subtle specs Sonnet got right. So a Sonnet parent is left alone.
|
|
21
|
+
- ``agent_downshift_skip``: ``["fork", "Plan"]``. A fork ignores ``model``;
|
|
22
|
+
planning is where the parent's strength is the point.
|
|
23
|
+
- ``agent_models``: ``{subagent_type: alias}`` — an explicit per-type choice,
|
|
24
|
+
applied whenever it is below the parent (or the parent is unknown).
|
|
25
|
+
|
|
26
|
+
Never touched: a call that names a model, and a subagent whose definition
|
|
27
|
+
(``.claude/agents/*.md``, project or user) sets ``model:``. Plugin agents
|
|
28
|
+
(``plugin:name``) are left alone — their definitions are not ours to read.
|
|
29
|
+
|
|
30
|
+
The parent model is not in any hook payload (checked: SessionStart,
|
|
31
|
+
UserPromptSubmit and PreToolUse carry none). It is read from the transcript
|
|
32
|
+
(the last assistant row's ``message.model``), else the last model this project
|
|
33
|
+
saw in the past 14 days, else Claude settings' ``model``; unknown means no
|
|
34
|
+
change.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
import json
|
|
40
|
+
import os
|
|
41
|
+
from datetime import datetime, timedelta, timezone
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
|
|
44
|
+
TIERS = ("haiku", "sonnet", "opus", "fable") # cheapest first
|
|
45
|
+
SUBAGENT_TOOLS = ("Agent", "Task")
|
|
46
|
+
DEFAULT_SKIP = ("fork", "Plan")
|
|
47
|
+
STATE_FILE = "agent_downshift_state.json"
|
|
48
|
+
_STATE_MAX_AGE = timedelta(days=14)
|
|
49
|
+
_TRANSCRIPT_TAIL = 512_000
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def rank(model) -> int | None:
|
|
53
|
+
"""0 haiku … 3 fable, from an alias or a full id; None when not a tier."""
|
|
54
|
+
m = str(model or "").strip().lower()
|
|
55
|
+
for i in range(len(TIERS) - 1, -1, -1):
|
|
56
|
+
if TIERS[i] in m:
|
|
57
|
+
return i
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _alias(value) -> str:
|
|
62
|
+
"""The Agent tool's alias for a tier name or a full model id."""
|
|
63
|
+
r = rank(value)
|
|
64
|
+
return TIERS[r] if r is not None else ""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def resolve(subagent_type: str, parent_model: str, cfg: dict) -> tuple[str, str]:
|
|
68
|
+
"""``(alias_or_empty, reason)`` for one Agent call with no ``model``."""
|
|
69
|
+
mode = str(cfg.get("agent_downshift", "one_down") or "off").strip().lower()
|
|
70
|
+
if mode in ("off", "false", "0", "none", "inherit"):
|
|
71
|
+
return "", "off"
|
|
72
|
+
stype = str(subagent_type or "general-purpose")
|
|
73
|
+
skip = cfg.get("agent_downshift_skip")
|
|
74
|
+
skip = list(DEFAULT_SKIP) if skip is None else [str(s) for s in skip]
|
|
75
|
+
if stype in skip:
|
|
76
|
+
return "", "skipped_type"
|
|
77
|
+
parent = rank(parent_model)
|
|
78
|
+
overrides = cfg.get("agent_models") or {}
|
|
79
|
+
if isinstance(overrides, dict) and stype in overrides:
|
|
80
|
+
target = _alias(overrides[stype])
|
|
81
|
+
if not target:
|
|
82
|
+
return "", "override_inherit"
|
|
83
|
+
if parent is not None and rank(target) >= parent:
|
|
84
|
+
return "", "not_a_downshift"
|
|
85
|
+
return target, "override"
|
|
86
|
+
if parent is None:
|
|
87
|
+
return "", "parent_unknown"
|
|
88
|
+
if mode == "one_down":
|
|
89
|
+
wanted = parent - 1
|
|
90
|
+
else:
|
|
91
|
+
fixed = _alias(mode)
|
|
92
|
+
if not fixed:
|
|
93
|
+
return "", "bad_config"
|
|
94
|
+
wanted = rank(fixed)
|
|
95
|
+
floor = rank(_alias(cfg.get("agent_downshift_floor", "sonnet")) or "sonnet")
|
|
96
|
+
wanted = max(wanted, floor)
|
|
97
|
+
if wanted >= parent:
|
|
98
|
+
return "", "at_floor"
|
|
99
|
+
return TIERS[wanted], mode if mode != "one_down" else "one_down"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ── Parent model ────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def transcript_model(path) -> str:
|
|
106
|
+
"""The model of the latest assistant row in a Claude Code transcript."""
|
|
107
|
+
try:
|
|
108
|
+
p = Path(str(path))
|
|
109
|
+
size = p.stat().st_size
|
|
110
|
+
with open(p, "rb") as fh:
|
|
111
|
+
if size > _TRANSCRIPT_TAIL:
|
|
112
|
+
fh.seek(size - _TRANSCRIPT_TAIL)
|
|
113
|
+
tail = fh.read().decode("utf-8", errors="replace")
|
|
114
|
+
except (OSError, ValueError):
|
|
115
|
+
return ""
|
|
116
|
+
for line in reversed(tail.splitlines()):
|
|
117
|
+
if '"model"' not in line:
|
|
118
|
+
continue
|
|
119
|
+
try:
|
|
120
|
+
row = json.loads(line)
|
|
121
|
+
except ValueError:
|
|
122
|
+
continue
|
|
123
|
+
msg = row.get("message") if isinstance(row, dict) else None
|
|
124
|
+
model = msg.get("model") if isinstance(msg, dict) else None
|
|
125
|
+
if row.get("type") == "assistant" and rank(model) is not None:
|
|
126
|
+
return str(model)
|
|
127
|
+
return ""
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _state_path(project) -> Path:
|
|
131
|
+
return Path(project) / ".c3" / STATE_FILE
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def remember_parent(project, model: str) -> None:
|
|
135
|
+
try:
|
|
136
|
+
path = _state_path(project)
|
|
137
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
138
|
+
tmp = path.with_suffix(f".{os.getpid()}.tmp")
|
|
139
|
+
tmp.write_text(json.dumps({"last_parent_model": model,
|
|
140
|
+
"seen_at": datetime.now(timezone.utc).isoformat()}), encoding="utf-8")
|
|
141
|
+
os.replace(tmp, path)
|
|
142
|
+
except OSError:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _remembered(project) -> str:
|
|
147
|
+
try:
|
|
148
|
+
data = json.loads(_state_path(project).read_text(encoding="utf-8"))
|
|
149
|
+
seen = datetime.fromisoformat(str(data.get("seen_at")))
|
|
150
|
+
if datetime.now(timezone.utc) - seen <= _STATE_MAX_AGE:
|
|
151
|
+
return str(data.get("last_parent_model") or "")
|
|
152
|
+
except (OSError, ValueError, TypeError):
|
|
153
|
+
pass
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _settings_model(project) -> str:
|
|
158
|
+
for p in (Path(project) / ".claude" / "settings.local.json", Path(project) / ".claude" / "settings.json",
|
|
159
|
+
Path.home() / ".claude" / "settings.json"):
|
|
160
|
+
try:
|
|
161
|
+
model = json.loads(p.read_text(encoding="utf-8")).get("model")
|
|
162
|
+
except (OSError, ValueError, AttributeError):
|
|
163
|
+
continue
|
|
164
|
+
if rank(model) is not None:
|
|
165
|
+
return str(model)
|
|
166
|
+
return ""
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def parent_model(payload: dict, project) -> tuple[str, str]:
|
|
170
|
+
"""``(model, source)``: transcript, remembered, settings, or ('', 'unknown')."""
|
|
171
|
+
model = transcript_model(payload.get("transcript_path") or "")
|
|
172
|
+
if model:
|
|
173
|
+
remember_parent(project, model)
|
|
174
|
+
return model, "transcript"
|
|
175
|
+
model = _remembered(project)
|
|
176
|
+
if model:
|
|
177
|
+
return model, "remembered"
|
|
178
|
+
model = _settings_model(project)
|
|
179
|
+
if model:
|
|
180
|
+
return model, "settings"
|
|
181
|
+
return "", "unknown"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# ── Agent definitions ───────────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _frontmatter(text: str) -> dict:
|
|
188
|
+
if not text.startswith("---"):
|
|
189
|
+
return {}
|
|
190
|
+
end = text.find("\n---", 3)
|
|
191
|
+
if end < 0:
|
|
192
|
+
return {}
|
|
193
|
+
out = {}
|
|
194
|
+
for line in text[3:end].splitlines():
|
|
195
|
+
key, sep, value = line.partition(":")
|
|
196
|
+
if sep:
|
|
197
|
+
out[key.strip().lower()] = value.strip().strip("'\"")
|
|
198
|
+
return out
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def definition_sets_model(subagent_type: str, project) -> bool:
|
|
202
|
+
"""True when a project or user agent definition for this type pins a model."""
|
|
203
|
+
name = str(subagent_type or "")
|
|
204
|
+
if not name:
|
|
205
|
+
return False
|
|
206
|
+
for folder in (Path(project) / ".claude" / "agents", Path.home() / ".claude" / "agents"):
|
|
207
|
+
try:
|
|
208
|
+
files = sorted(folder.glob("*.md"))
|
|
209
|
+
except OSError:
|
|
210
|
+
continue
|
|
211
|
+
for f in files:
|
|
212
|
+
try:
|
|
213
|
+
meta = _frontmatter(f.read_text(encoding="utf-8", errors="replace"))
|
|
214
|
+
except OSError:
|
|
215
|
+
continue
|
|
216
|
+
if (meta.get("name") or f.stem) != name:
|
|
217
|
+
continue
|
|
218
|
+
model = meta.get("model", "").strip().lower()
|
|
219
|
+
return bool(model) and model != "inherit"
|
|
220
|
+
return False
|
|
@@ -39,7 +39,7 @@ When falling back, state which c3_* tool was attempted and why it was insufficie
|
|
|
39
39
|
6.5. **SHELL via C3**: `c3_shell(cmd, cwd='', timeout=60)` — for tests, git, build, scripts. Returns structured `{exit_code, stdout, stderr, duration_ms}`. Auto-filters stdout >30 lines; auto-logs git-mutating commands (commit/add/merge/rebase/reset/restore/checkout) to the edit ledger. Best-effort blocks the most catastrophic commands (`rm -rf` of `/`, a top-level system dir, or `$HOME`/`~`; fork bombs; whole-drive wipes) — a guard, not a sandbox; soft-warns on `--force`, `--no-verify`, `reset --hard`. Native Bash remains the fallback for interactive/TTY commands
|
|
40
40
|
7. **VALIDATE**: `c3_validate(file_path)` — after edits or before reporting done. Runs deep type check (pyright/tsc) automatically if installed
|
|
41
41
|
8. **LOG**: `c3_session(action='log')` for decisions. `c3_session(action='snapshot')` before /clear
|
|
42
|
-
9. **DELEGATE** (one tier down, same provider): `c3_delegate(task, task_type, context|file_path)` — default `backend='host'` runs your own provider at `tier='small'` (Claude Code: Haiku; `medium`=Sonnet). Use it for bounded work whose answer is a few lines: summarize a diff or log, explain a function, triage a traceback, draft a docstring or test cases. `scout=true` lets it Read/Grep/Glob the project itself for lookups. `write_paths='a.py,b.py'` hands a change you have already specified to Sonnet: it edits only those paths and returns the diff for you to review and test. Multi-step work in Claude Code: the `c3-scout` (haiku, read-only) and `c3-worker` (sonnet) subagents. `c3_agent(workflow=...)` for multi-model pipelines
|
|
42
|
+
9. **DELEGATE** (one tier down, same provider): `c3_delegate(task, task_type, context|file_path)` — default `backend='host'` runs your own provider at `tier='small'` (Claude Code: Haiku; `medium`=Sonnet). Use it for bounded work whose answer is a few lines: summarize a diff or log, explain a function, triage a traceback, draft a docstring or test cases. `scout=true` lets it Read/Grep/Glob the project itself for lookups. `write_paths='a.py,b.py'` hands a change you have already specified to Sonnet: it edits only those paths and returns the diff for you to review and test. Multi-step work in Claude Code: the `c3-scout` (haiku, read-only) and `c3-worker` (sonnet) subagents; an `Agent` call with no `model` runs one tier below you (Fable→Opus→Sonnet, C3 hook) — pass `model=` to choose. A `[c3:delegate-hint]` line means the work you are doing now is delegable. `c3_agent(workflow=...)` for multi-model pipelines
|
|
43
43
|
9.5. **LOCAL CI** (v2.79.0+): `c3_ci(action='inspect|run|rerun|status|failures|logs|runs')` — run THIS repository's real `.github/workflows/*.yml` on this machine instead of pushing to find out. C3 reads the existing workflow files; it does NOT define a second CI config. `inspect` shows the job DAG and which jobs are runnable on this host; `run` executes in `needs` order and SKIPS (never passes) a job whose dependency failed; `failures` returns `{file,line,message}` instead of raw logs; `rerun` retries only what failed. VERDICTS: `FULL_CI_PASS` means every job ran HERE and passed — the only one that means safe to push. `PARTIAL_PASS` means something did not run (targets another OS, uses an action C3 cannot execute, or you selected a subset) and is NOT a green light. Jobs targeting another OS are refused unless `allow_foreign=true`, which labels the result cross-OS and can never yield FULL_CI_PASS. ENGINES (v2.81.0+): `native` runs jobs matching this host; `act` runs Linux jobs in a real container (real `uses:` actions included) when act+Docker are installed — `c3_ci(action='doctor')` reports what is available. A container run DOES count toward FULL_CI_PASS; a cross-OS one never does. macOS jobs cannot run locally on any engine. Jobs that look like they publish or deploy are refused unless allow_side_effects=true, and C3 never passes secrets to act. See docs/agent-ci.md.
|
|
44
44
|
10. **BITBUCKET** (when configured, v2.30.0+): `c3_bitbucket(action='...')` — for self-hosted enterprise Bitbucket Data Center / Server: PRs, branches, builds, repo admin. Tokens live in the OS keyring (set up via `c3 bitbucket login`, or `login --global` for a home config reusable across projects; account resolution precedence is project → home). Read actions are safe in plan mode; write actions (`merge_pr`, `create_branch`, etc.) are auto-logged to the edit ledger.
|
|
45
45
|
10.5. **JIRA** (when configured, v2.56.0+): `c3_jira(action='...')` — Jira Cloud + Data Center: `search` (raw JQL), `my_issues`, `get_issue`, `list_transitions`, `get_create_metadata`, `search_users`, `list_link_types`, `list_boards`, `list_sprints`, `list_worklogs` reads; `create_issue` / `update_issue` / `comment` / `transition` / `assign` / `link_issues` / `unlink_issues` / `move_to_sprint` / `move_to_backlog` / `add_worklog` / `attach_file` / `delete_issue` (permanent; refuses subtask-bearing issues unless delete_subtasks=true) mutations auto-logged to the edit ledger (identifiers only, never bodies). createmeta reflects the issue type's field configuration, NOT the create screen — if create_issue rejects a listed field ('not on the appropriate screen'), create without it, then set it via `update_issue`. Epic membership: pass `parent=<EPIC-KEY>` to create_issue/update_issue ('none' clears) — C3 maps it per deployment (Cloud `parent` field vs Data Center Epic Link customfield); `link_issues(issue, link_type, target)` creates typed links reading '<issue> <link_type> <target>' (types via `list_link_types`). Sprints: `list_boards` → `list_sprints(board_id)` → `move_to_sprint(issue, sprint_id)`; `attach_file(issue, file_path)` uploads a local file as evidence. Tokens in the OS keyring (`c3 jira login`, or `login --global` for cross-project reuse; the jira config section resolves project → home wholesale from one file — never field-merged). Read actions are safe in plan mode.
|