code-context-control 2.125.0__tar.gz → 2.127.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.125.0/code_context_control.egg-info → code_context_control-2.127.0}/PKG-INFO +1 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/_hook_utils.py +34 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/c3.py +59 -2
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/commands/parser.py +12 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_dispatch.py +12 -3
- code_context_control-2.127.0/cli/hook_session_end.py +103 -0
- code_context_control-2.127.0/cli/hook_session_open.py +97 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_server.py +37 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_access.js +111 -11
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/mcp_server.py +114 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0}/code_context_control.egg-info/SOURCES.txt +9 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/mobile_api.py +231 -4
- {code_context_control-2.125.0 → code_context_control-2.127.0}/pyproject.toml +1 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_runner.py +32 -0
- code_context_control-2.127.0/services/host_sessions.py +95 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/notifications.py +31 -0
- code_context_control-2.127.0/services/override_costs.py +183 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/shell_jobs.py +93 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_codex_compat.py +11 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_dispatch.py +9 -0
- code_context_control-2.127.0/tests/test_hook_session_end.py +291 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_override_routes.py +73 -0
- code_context_control-2.127.0/tests/test_mobile_jobs_ci.py +327 -0
- code_context_control-2.127.0/tests/test_mobile_override_costs.py +252 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mobile_override_routes.py +84 -0
- code_context_control-2.127.0/tests/test_notification_kinds.py +294 -0
- code_context_control-2.127.0/tests/test_override_costs.py +320 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_jobs_s3.py +4 -1
- {code_context_control-2.125.0 → code_context_control-2.127.0}/LICENSE +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/README.md +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/commands/common.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/docs.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/edits.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/access.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/index.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_read.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/progress.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/server.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/override.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/project.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/read.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/search.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/session.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/status.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/api.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/app.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/codex_patch.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/config.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/host.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/ide.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/core/web_security.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/config.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/listeners.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/client_tokens.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/access_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/activity_log.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/agent_base.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/agent_locks.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/agents.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/artifact_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/atomic_json.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/auto_memory.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/background_service.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/map_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_act.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_cache.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_expr.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_failures.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_github.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_impact.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_intel.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/claude_md.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/codex_integration.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/codex_transcript.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/compressor.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/conversation_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/cred_audit.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/credential_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/dir_map.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/doc_index.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/embedding_index.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/error_reporting.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/file_map.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/file_memory.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/git_context.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/hub_service.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/index_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/indexer.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/jira_client.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/jira_links.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/lexical_index.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/mask_activation.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/mask_presets.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_graph.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_queue.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/metrics.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ollama_client.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/oracle_service.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/output_filter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/override_grants.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/override_policy.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/override_requests.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/override_wake.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/parser.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/project_manager.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/project_runtime.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/protocol.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/proxy_state.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/repo_map.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/repo_shape.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/reranker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/retention.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/retrieval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/router.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/runtime.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/scanner.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/session_manager.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/session_preloader.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/shell_output.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/subprojects.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/task_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/telemetry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/text_index.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/time_tracker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/transcript_index.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/validation_cache.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/vector_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/watcher.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/setup.cfg +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_codex_native.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_map_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mobile_clients.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_loopback.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_retention.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_validate.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/backend.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/main.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.125.0 → code_context_control-2.127.0}/tui/theme.tcss +0 -0
{code_context_control-2.125.0/code_context_control.egg-info → code_context_control-2.127.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.127.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
|
|
@@ -500,6 +500,40 @@ def record_json_unlocks(
|
|
|
500
500
|
pass
|
|
501
501
|
|
|
502
502
|
|
|
503
|
+
_PROJECT_WALK_UP_LEVELS = 4
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def find_project(payload: dict, project_path=None) -> Path | None:
|
|
507
|
+
"""The nearest ancestor (≤ 4 levels) of ``project_path`` / ``payload.cwd``
|
|
508
|
+
that owns a ``.c3`` directory, or None.
|
|
509
|
+
|
|
510
|
+
Claude Code runs hooks from the project root, Codex passes ``--project``;
|
|
511
|
+
either way the payload's ``cwd`` may be a subdirectory (a session opened
|
|
512
|
+
in ``src/``). The walk is lexical on purpose — no path canonicalisation
|
|
513
|
+
happens here (see tests/test_access_guard_meta.py).
|
|
514
|
+
"""
|
|
515
|
+
candidates = []
|
|
516
|
+
if project_path:
|
|
517
|
+
candidates.append(Path(str(project_path)))
|
|
518
|
+
cwd = payload.get("cwd") if isinstance(payload, dict) else None
|
|
519
|
+
if cwd:
|
|
520
|
+
candidates.append(Path(str(cwd)))
|
|
521
|
+
if not candidates:
|
|
522
|
+
candidates.append(Path.cwd())
|
|
523
|
+
for base in candidates:
|
|
524
|
+
node = base
|
|
525
|
+
for _ in range(_PROJECT_WALK_UP_LEVELS):
|
|
526
|
+
try:
|
|
527
|
+
if (node / ".c3").is_dir():
|
|
528
|
+
return node
|
|
529
|
+
except OSError:
|
|
530
|
+
break
|
|
531
|
+
if node.parent == node:
|
|
532
|
+
break
|
|
533
|
+
node = node.parent
|
|
534
|
+
return None
|
|
535
|
+
|
|
536
|
+
|
|
503
537
|
def emit_additional_context(text: str, is_gemini: bool) -> None:
|
|
504
538
|
"""Write additionalContext JSON to stdout in the correct format for the IDE."""
|
|
505
539
|
if is_gemini:
|
|
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
|
|
|
92
92
|
# Config
|
|
93
93
|
CONFIG_DIR = ".c3"
|
|
94
94
|
CONFIG_FILE = ".c3/config.json"
|
|
95
|
-
__version__ = "2.
|
|
95
|
+
__version__ = "2.127.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -5558,6 +5558,8 @@ def cmd_install_mcp(args):
|
|
|
5558
5558
|
hook_posttool_cmd = f"{_dispatch_base} posttool"
|
|
5559
5559
|
hook_stop_cmd = f"{_dispatch_base} stop"
|
|
5560
5560
|
hook_prompt_cmd = f"{_dispatch_base} prompt"
|
|
5561
|
+
hook_start_cmd = f"{_dispatch_base} start"
|
|
5562
|
+
hook_end_cmd = f"{_dispatch_base} end"
|
|
5561
5563
|
|
|
5562
5564
|
shell_matcher = "Bash"
|
|
5563
5565
|
read_matcher = "Read"
|
|
@@ -5696,6 +5698,25 @@ def cmd_install_mcp(args):
|
|
|
5696
5698
|
)
|
|
5697
5699
|
settings.setdefault("hooks", {})[prompt_event] = existing_prompt
|
|
5698
5700
|
|
|
5701
|
+
# ── SessionStart / SessionEnd hooks (v2.126.0: session_open /
|
|
5702
|
+
# session_end activity rows + `session` notifications, the join key
|
|
5703
|
+
# a desktop client needs). Same merge discipline: replace only C3's
|
|
5704
|
+
# own dispatcher entries, keep user-added ones. SessionStart's
|
|
5705
|
+
# matcher is the payload `source` (startup|resume|clear|compact);
|
|
5706
|
+
# empty matches all — the hook itself ignores `compact`.
|
|
5707
|
+
for _lifecycle_event, _lifecycle_cmd in (
|
|
5708
|
+
("SessionStart", hook_start_cmd),
|
|
5709
|
+
("SessionEnd", hook_end_cmd),
|
|
5710
|
+
):
|
|
5711
|
+
_kept = [
|
|
5712
|
+
h for h in settings.get("hooks", {}).get(_lifecycle_event, [])
|
|
5713
|
+
if not _is_c3_prompt_hook(h)
|
|
5714
|
+
]
|
|
5715
|
+
_kept.append(
|
|
5716
|
+
{"matcher": "", "hooks": [{"type": "command", "command": _lifecycle_cmd}]}
|
|
5717
|
+
)
|
|
5718
|
+
settings.setdefault("hooks", {})[_lifecycle_event] = _kept
|
|
5719
|
+
|
|
5699
5720
|
# Claude Code only: enable MCP server prompt settings
|
|
5700
5721
|
if profile.name == "claude-code":
|
|
5701
5722
|
settings["enableAllProjectMcpServers"] = True
|
|
@@ -5742,6 +5763,7 @@ def cmd_install_mcp(args):
|
|
|
5742
5763
|
print(f" Hooks ({hook_event}): dispatcher (1 spawn/event) — filter/ghost/read-guard/ledger/unlock/signal via cli/hook_dispatch.py posttool")
|
|
5743
5764
|
print(f" Hooks ({pre_event}): dispatcher — {read_matcher}/{grep_matcher}/{glob_matcher}/{edit_matcher}/{write_matcher} (c3 enforcement)")
|
|
5744
5765
|
print(" Hooks (Stop): dispatcher — session_stats + auto_snapshot + terse_advisor")
|
|
5766
|
+
print(" Hooks (SessionStart/SessionEnd): dispatcher — session_open / session_end rows + session notifications")
|
|
5745
5767
|
if profile.name == "claude-code":
|
|
5746
5768
|
print(" Claude MCP prompt settings enabled for this project")
|
|
5747
5769
|
if perm_tier and profile.name == "claude-code":
|
|
@@ -6946,8 +6968,10 @@ def cmd_override(args):
|
|
|
6946
6968
|
"""
|
|
6947
6969
|
sub = getattr(args, "override_cmd", None)
|
|
6948
6970
|
if not sub:
|
|
6949
|
-
print("Usage: c3 override <policy|grant|list|revoke|check|sweep
|
|
6971
|
+
print("Usage: c3 override <policy|grant|list|revoke|check|sweep|"
|
|
6972
|
+
"requests|approve|deny|costs> ...")
|
|
6950
6973
|
print(" c3 override policy # what is escalatable right now")
|
|
6974
|
+
print(" c3 override costs # which rules keep holding the agent")
|
|
6951
6975
|
return
|
|
6952
6976
|
|
|
6953
6977
|
from services import override_grants as og
|
|
@@ -6976,6 +7000,39 @@ def cmd_override(args):
|
|
|
6976
7000
|
_override_requests(args, project_path)
|
|
6977
7001
|
elif sub in ("approve", "deny"):
|
|
6978
7002
|
_override_decide(args, sub, project_path)
|
|
7003
|
+
elif sub == "costs":
|
|
7004
|
+
_override_costs(args, project_path)
|
|
7005
|
+
|
|
7006
|
+
|
|
7007
|
+
def _override_costs(args, project_path: str) -> None:
|
|
7008
|
+
"""`c3 override costs` — which rules keep holding the agent (§11 T5)."""
|
|
7009
|
+
from services import override_costs as ocost
|
|
7010
|
+
|
|
7011
|
+
days = max(1, int(getattr(args, "days", None) or ocost.DEFAULT_DAYS))
|
|
7012
|
+
everywhere = bool(getattr(args, "all_projects", False))
|
|
7013
|
+
rows = ocost.rule_costs(project_path=None if everywhere else project_path,
|
|
7014
|
+
days=days)
|
|
7015
|
+
print_header(f"Override costs — last {days} day(s)"
|
|
7016
|
+
+ ("" if everywhere else f" · {Path(project_path).name}"))
|
|
7017
|
+
if not rows:
|
|
7018
|
+
print(" (no requests in the window)")
|
|
7019
|
+
return
|
|
7020
|
+
width = max(len(r["rule"]) for r in rows)
|
|
7021
|
+
print(f" {'held':>4} {'ok':>3} {'no':>3} {'exp':>3} {'wait':>4} "
|
|
7022
|
+
f"{'rule':<{width}} suggestion")
|
|
7023
|
+
for r in rows:
|
|
7024
|
+
line = (f" {r['count']:>4} {r['approved']:>3} {r['denied']:>3} "
|
|
7025
|
+
f"{r['expired']:>3} {r['pending']:>4} {r['rule']:<{width}} "
|
|
7026
|
+
f"{r['suggestion']}")
|
|
7027
|
+
if r["count"] >= ocost.NUDGE_THRESHOLD:
|
|
7028
|
+
line += " <- costing you"
|
|
7029
|
+
print(line)
|
|
7030
|
+
if everywhere:
|
|
7031
|
+
print(f" {'':22s} {r['project_path']}")
|
|
7032
|
+
print("\n held = requests filed; ok/no/exp/wait = approved/denied/"
|
|
7033
|
+
"expired/still pending (withdrawn counts in held only).")
|
|
7034
|
+
print(" A rule you keep approving is friction: edit it with `c3 access`. "
|
|
7035
|
+
"A rule you keep denying is working — mute the session instead.")
|
|
6979
7036
|
|
|
6980
7037
|
|
|
6981
7038
|
def _override_requests(args, project_path: str) -> None:
|
|
@@ -779,6 +779,18 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
779
779
|
ov_deny.add_argument("--path", dest="project_path", default=".",
|
|
780
780
|
help="Project directory (default: current)")
|
|
781
781
|
|
|
782
|
+
# Costs: which rules keep asking (spec §11 Threat 5, v2.127.0). A read
|
|
783
|
+
# over the request store — it decides nothing and edits no rule.
|
|
784
|
+
ov_costs = override_subs.add_parser(
|
|
785
|
+
"costs", help="Which rules held the agent most, and how you answered"
|
|
786
|
+
)
|
|
787
|
+
ov_costs.add_argument("--days", type=int, default=7,
|
|
788
|
+
help="Trailing window in days (default 7)")
|
|
789
|
+
ov_costs.add_argument("--all", dest="all_projects", action="store_true",
|
|
790
|
+
help="Every project, not just this one")
|
|
791
|
+
ov_costs.add_argument("--path", dest="project_path", default=".",
|
|
792
|
+
help="Project directory (default: current)")
|
|
793
|
+
|
|
782
794
|
# ── Tool discipline / enforcement mode (v2.66.0) ────────────────────
|
|
783
795
|
# LAYER C: how hard C3 pushes the agent toward c3_* tools. Distinct from
|
|
784
796
|
# `c3 access` (path policy — a security boundary) and from
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Per-event hook dispatcher: ONE process per Claude Code / Gemini hook event.
|
|
3
3
|
|
|
4
|
-
Usage: python hook_dispatch.py <pretool|posttool|stop|prompt>
|
|
4
|
+
Usage: python hook_dispatch.py <pretool|posttool|stop|prompt|start|compact|end>
|
|
5
5
|
|
|
6
6
|
Before v2.42 every hook was registered as its own "cmd /c python <hook>.py"
|
|
7
7
|
subprocess, so a single native Read fired up to three interpreter spawns
|
|
@@ -167,8 +167,17 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
|
|
|
167
167
|
yield "hook_terse_advisor"
|
|
168
168
|
elif event == "prompt":
|
|
169
169
|
yield "hook_prompt_recall"
|
|
170
|
-
elif event in ("start", "compact", "end")
|
|
171
|
-
|
|
170
|
+
elif event in ("start", "compact", "end"):
|
|
171
|
+
# Codex's thread-bound handoff runs first (it may return context on
|
|
172
|
+
# SessionStart); the session bookkeeping below is host-agnostic and
|
|
173
|
+
# returns nothing (v2.126.0: session_open / session_end rows + the
|
|
174
|
+
# `session` notifications a desktop client wakes on).
|
|
175
|
+
if host == HOST_CODEX:
|
|
176
|
+
yield "hook_codex_lifecycle"
|
|
177
|
+
if event == "start":
|
|
178
|
+
yield "hook_session_open"
|
|
179
|
+
elif event == "end":
|
|
180
|
+
yield "hook_session_end"
|
|
172
181
|
|
|
173
182
|
|
|
174
183
|
_RUN_CACHE: dict = {}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""SessionEnd hook: record that a host session ended (D0b, v2.126.0).
|
|
2
|
+
|
|
3
|
+
Claude Code's ``SessionEnd`` event delivers on stdin::
|
|
4
|
+
|
|
5
|
+
{
|
|
6
|
+
"session_id": "<Claude Code UUID>",
|
|
7
|
+
"transcript_path": "...",
|
|
8
|
+
"cwd": "...",
|
|
9
|
+
"hook_event_name": "SessionEnd",
|
|
10
|
+
"reason": "clear" | "logout" | "prompt_input_exit" | "other"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Codex's ``SessionEnd`` carries its thread id in the same ``session_id``
|
|
14
|
+
field; the dispatcher routes both here (``hook_dispatch._routes``, event
|
|
15
|
+
``end``).
|
|
16
|
+
|
|
17
|
+
Why this exists: this repo's activity log held 525 ``session_start`` rows
|
|
18
|
+
and 14 ``session_save`` rows — ``session_save`` is only written when a human
|
|
19
|
+
ends a session from the hub, so for a client the end of a conversation was
|
|
20
|
+
invisible. Two records fix that:
|
|
21
|
+
|
|
22
|
+
- ``{type: "session_end", session_id: <C3 id if known>, host_session_id,
|
|
23
|
+
reason, source}`` appended to ``.c3/activity_log.jsonl``. The C3 id comes
|
|
24
|
+
from the link file the MCP server wrote at session start
|
|
25
|
+
(``services.host_sessions``); it is ``""`` when the server never learned
|
|
26
|
+
the host id.
|
|
27
|
+
- a ``session`` notification (``kind="session"``, ``ref_id=host id``,
|
|
28
|
+
severity ``info``, title ``Session ended <short id>``) in
|
|
29
|
+
``.c3/notifications.jsonl`` — the write that wakes a ``/feed?wait=``
|
|
30
|
+
client.
|
|
31
|
+
|
|
32
|
+
Runs in a short-lived subprocess with a few seconds of budget; every step is
|
|
33
|
+
best-effort and nothing here can fail the session that is already ending.
|
|
34
|
+
"""
|
|
35
|
+
from __future__ import annotations
|
|
36
|
+
|
|
37
|
+
import sys
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
|
|
40
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
41
|
+
|
|
42
|
+
from cli._hook_utils import detect_host, find_project, log_hook_error # noqa: E402
|
|
43
|
+
|
|
44
|
+
SHORT_ID_CHARS = 8
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def short_id(session_id: str) -> str:
|
|
48
|
+
return str(session_id or "")[:SHORT_ID_CHARS] or "?"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def run(payload: dict, project_path: Path | None = None):
|
|
52
|
+
"""Core logic — importable by the dispatcher and tests. Returns None."""
|
|
53
|
+
project = find_project(payload, project_path)
|
|
54
|
+
if project is None:
|
|
55
|
+
return None
|
|
56
|
+
host = detect_host(payload)
|
|
57
|
+
host_sid = str(payload.get("session_id") or "").strip()
|
|
58
|
+
reason = str(payload.get("reason") or "").strip()
|
|
59
|
+
c3_sid = ""
|
|
60
|
+
try:
|
|
61
|
+
from services.host_sessions import linked_c3_session_id
|
|
62
|
+
c3_sid = linked_c3_session_id(project, host, host_sid)
|
|
63
|
+
except Exception:
|
|
64
|
+
c3_sid = ""
|
|
65
|
+
try:
|
|
66
|
+
from services.activity_log import ActivityLog
|
|
67
|
+
ActivityLog(str(project)).log("session_end", {
|
|
68
|
+
"session_id": c3_sid,
|
|
69
|
+
"host_session_id": host_sid,
|
|
70
|
+
"reason": reason,
|
|
71
|
+
"source": host,
|
|
72
|
+
})
|
|
73
|
+
except Exception as exc:
|
|
74
|
+
log_hook_error("hook_session_end", exc)
|
|
75
|
+
try:
|
|
76
|
+
from services.notifications import notify
|
|
77
|
+
notify(project, agent="session", severity="info",
|
|
78
|
+
title=f"Session ended {short_id(host_sid)}",
|
|
79
|
+
message=(f"{host} session {host_sid or '?'} ended"
|
|
80
|
+
+ (f" ({reason})" if reason else "")
|
|
81
|
+
+ (f"; C3 session {c3_sid}" if c3_sid else "")),
|
|
82
|
+
kind="session", ref_id=host_sid)
|
|
83
|
+
except Exception:
|
|
84
|
+
pass
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def main() -> None:
|
|
89
|
+
import json
|
|
90
|
+
try:
|
|
91
|
+
data = json.load(sys.stdin)
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
log_hook_error("hook_session_end", exc)
|
|
94
|
+
sys.exit(0)
|
|
95
|
+
try:
|
|
96
|
+
run(data)
|
|
97
|
+
except Exception as exc:
|
|
98
|
+
log_hook_error("hook_session_end", exc)
|
|
99
|
+
sys.exit(0)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
main()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""SessionStart hook: record that a host session opened (D0b, v2.126.0).
|
|
2
|
+
|
|
3
|
+
Claude Code's ``SessionStart`` event delivers on stdin::
|
|
4
|
+
|
|
5
|
+
{
|
|
6
|
+
"session_id": "<Claude Code UUID>",
|
|
7
|
+
"transcript_path": "...",
|
|
8
|
+
"cwd": "...",
|
|
9
|
+
"hook_event_name": "SessionStart",
|
|
10
|
+
"source": "startup" | "resume" | "clear" | "compact"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Codex's ``SessionStart`` carries its thread id in the same ``session_id``
|
|
14
|
+
field and no ``source``; the dispatcher routes both here (event ``start``).
|
|
15
|
+
|
|
16
|
+
Records:
|
|
17
|
+
|
|
18
|
+
- ``{type: "session_open", host_session_id, source: <host>, start_source}``
|
|
19
|
+
in ``.c3/activity_log.jsonl``. ``source`` is the HOST (``claude`` /
|
|
20
|
+
``codex`` / ``gemini``), matching ``session_end``; the payload's own
|
|
21
|
+
``source`` (startup / resume / clear) is kept as ``start_source``.
|
|
22
|
+
- a ``session`` notification (``kind="session"``, ``ref_id=host id``,
|
|
23
|
+
``info``, title ``Session started <short id>``).
|
|
24
|
+
|
|
25
|
+
``source: "compact"`` writes NOTHING: a compaction is the same session and
|
|
26
|
+
the same MCP process, and a "Session started" toast on every compaction
|
|
27
|
+
would teach the user to ignore the real ones.
|
|
28
|
+
|
|
29
|
+
The MCP server's own ``session_start`` row is untouched — it carries the C3
|
|
30
|
+
id and, when the host put its id in the environment, ``host_session_id``
|
|
31
|
+
too. This hook is what lets a client see the session before the runtime has
|
|
32
|
+
finished starting (~seconds), and it is the row the desktop's "MCP failed to
|
|
33
|
+
connect" sentinel starts its 30 s clock from.
|
|
34
|
+
|
|
35
|
+
Returns None always: SessionStart hook stdout becomes model context, and
|
|
36
|
+
this hook has nothing to tell the model.
|
|
37
|
+
"""
|
|
38
|
+
from __future__ import annotations
|
|
39
|
+
|
|
40
|
+
import sys
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
|
|
43
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
44
|
+
|
|
45
|
+
from cli._hook_utils import detect_host, find_project, log_hook_error # noqa: E402
|
|
46
|
+
from cli.hook_session_end import short_id # noqa: E402
|
|
47
|
+
|
|
48
|
+
_SILENT_SOURCES = {"compact"}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def run(payload: dict, project_path: Path | None = None):
|
|
52
|
+
"""Core logic — importable by the dispatcher and tests. Returns None."""
|
|
53
|
+
start_source = str(payload.get("source") or "").strip().lower()
|
|
54
|
+
if start_source in _SILENT_SOURCES:
|
|
55
|
+
return None
|
|
56
|
+
project = find_project(payload, project_path)
|
|
57
|
+
if project is None:
|
|
58
|
+
return None
|
|
59
|
+
host = detect_host(payload)
|
|
60
|
+
host_sid = str(payload.get("session_id") or "").strip()
|
|
61
|
+
try:
|
|
62
|
+
from services.activity_log import ActivityLog
|
|
63
|
+
ActivityLog(str(project)).log("session_open", {
|
|
64
|
+
"host_session_id": host_sid,
|
|
65
|
+
"source": host,
|
|
66
|
+
"start_source": start_source,
|
|
67
|
+
})
|
|
68
|
+
except Exception as exc:
|
|
69
|
+
log_hook_error("hook_session_open", exc)
|
|
70
|
+
try:
|
|
71
|
+
from services.notifications import notify
|
|
72
|
+
notify(project, agent="session", severity="info",
|
|
73
|
+
title=f"Session started {short_id(host_sid)}",
|
|
74
|
+
message=(f"{host} session {host_sid or '?'} started"
|
|
75
|
+
+ (f" ({start_source})" if start_source else "")),
|
|
76
|
+
kind="session", ref_id=host_sid)
|
|
77
|
+
except Exception:
|
|
78
|
+
pass
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def main() -> None:
|
|
83
|
+
import json
|
|
84
|
+
try:
|
|
85
|
+
data = json.load(sys.stdin)
|
|
86
|
+
except Exception as exc:
|
|
87
|
+
log_hook_error("hook_session_open", exc)
|
|
88
|
+
sys.exit(0)
|
|
89
|
+
try:
|
|
90
|
+
run(data)
|
|
91
|
+
except Exception as exc:
|
|
92
|
+
log_hook_error("hook_session_open", exc)
|
|
93
|
+
sys.exit(0)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
main()
|
|
@@ -3215,6 +3215,43 @@ def api_hub_overrides():
|
|
|
3215
3215
|
"limit": limit})
|
|
3216
3216
|
|
|
3217
3217
|
|
|
3218
|
+
@app.route("/api/hub/overrides/costs", methods=["GET"])
|
|
3219
|
+
def api_hub_override_costs():
|
|
3220
|
+
"""Per-(project, rule) request counts over a trailing window (§11 T5).
|
|
3221
|
+
|
|
3222
|
+
The "this rule is costing you" strip. Query: path (optional — omit for
|
|
3223
|
+
every project in the store; the hub is this machine's own surface and
|
|
3224
|
+
does not filter to a registry), days (1..30, default 7). Response:
|
|
3225
|
+
{days, threshold, rules: [...], count, project} with the row shape of
|
|
3226
|
+
``services.override_costs.FIELDS``; ``threshold`` is the count at which
|
|
3227
|
+
the UI says something, so the strip and the desktop tray agree on it.
|
|
3228
|
+
Registered before the POST-only ``<request_id>`` route so a GET on
|
|
3229
|
+
``costs`` can never fall through to a 405 there.
|
|
3230
|
+
"""
|
|
3231
|
+
from services import override_costs as ocost
|
|
3232
|
+
project_path = ""
|
|
3233
|
+
raw_project = (request.args.get("path") or "").strip()
|
|
3234
|
+
if raw_project:
|
|
3235
|
+
try:
|
|
3236
|
+
project_path = str(_resolve_project_path(raw_project))
|
|
3237
|
+
except ValueError as e:
|
|
3238
|
+
return jsonify({"error": str(e)}), 404
|
|
3239
|
+
try:
|
|
3240
|
+
days = int(request.args.get("days") or ocost.DEFAULT_DAYS)
|
|
3241
|
+
except (TypeError, ValueError):
|
|
3242
|
+
days = ocost.DEFAULT_DAYS
|
|
3243
|
+
days = max(1, min(ocost.MAX_DAYS, days))
|
|
3244
|
+
try:
|
|
3245
|
+
rules = ocost.rule_costs(project_path=project_path or None, days=days)
|
|
3246
|
+
except Exception as exc:
|
|
3247
|
+
return jsonify({"error": str(exc)}), 500
|
|
3248
|
+
for r in rules:
|
|
3249
|
+
r["project_name"] = Path(str(r.get("project_path") or ".")).name
|
|
3250
|
+
return jsonify({"days": days, "threshold": ocost.NUDGE_THRESHOLD,
|
|
3251
|
+
"rules": rules, "count": len(rules),
|
|
3252
|
+
"project": project_path})
|
|
3253
|
+
|
|
3254
|
+
|
|
3218
3255
|
@app.route("/api/hub/overrides/<request_id>", methods=["POST"])
|
|
3219
3256
|
def api_hub_override_decide(request_id):
|
|
3220
3257
|
"""Approve (minting a grant) or deny one request. decided_by='desktop'.
|
{code_context_control-2.125.0 → code_context_control-2.127.0}/cli/hub_ui/components/hub_access.js
RENAMED
|
@@ -185,11 +185,79 @@ function AccRequestCard({ row, busy, onDecide, onTypedApprove, onRuleApprove })
|
|
|
185
185
|
);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// ── "Costing you" — the §11 Threat 5 nudge ─────────────────────────────────
|
|
189
|
+
// One row per rule that held at least `threshold` times in the window. The
|
|
190
|
+
// count is the argument: a rule the user keeps approving is friction, and a
|
|
191
|
+
// rule they keep denying is doing its job against an agent that will not
|
|
192
|
+
// stop asking. Either way the fix is the RULE, not the next card — so the
|
|
193
|
+
// only affordance is "open the rule", which jumps to it in the policy matrix
|
|
194
|
+
// below. The strip never approves anything and never edits policy; it says
|
|
195
|
+
// the number out loud, which is the mitigation the spec asks for.
|
|
196
|
+
function accSamePath(a, b) {
|
|
197
|
+
const norm = (p) => String(p || '').replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();
|
|
198
|
+
return norm(a) === norm(b);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function AccCostStrip({ onOpenRule }) {
|
|
202
|
+
const [data, setData] = useState(null);
|
|
203
|
+
|
|
204
|
+
const load = useCallback(async () => {
|
|
205
|
+
try {
|
|
206
|
+
setData(await api.get('/api/hub/overrides/costs?days=7'));
|
|
207
|
+
} catch { /* keep the last good strip */ }
|
|
208
|
+
}, []);
|
|
209
|
+
|
|
210
|
+
useEffect(() => { load(); }, [load]);
|
|
211
|
+
usePoll(load, 15000);
|
|
212
|
+
|
|
213
|
+
if (!data) return null;
|
|
214
|
+
const threshold = Number(data.threshold) || 3;
|
|
215
|
+
const rows = (data.rules || []).filter(r => (Number(r.count) || 0) >= threshold);
|
|
216
|
+
if (rows.length === 0) return null;
|
|
217
|
+
return (
|
|
218
|
+
<div style={{
|
|
219
|
+
background: T.surface, border: `1px solid ${T.warn}`, borderRadius: 10,
|
|
220
|
+
padding: '10px 14px',
|
|
221
|
+
}}>
|
|
222
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', marginBottom: 4 }}>
|
|
223
|
+
<span style={{ fontSize: 12.5, fontWeight: 700, color: T.warn }}>Costing you</span>
|
|
224
|
+
<span style={{ fontSize: 11, color: T.textDim }}>
|
|
225
|
+
rules that held {threshold}+ times in the last {data.days} days — fix the
|
|
226
|
+
rule, not the next card
|
|
227
|
+
</span>
|
|
228
|
+
</div>
|
|
229
|
+
{rows.map(r => (
|
|
230
|
+
<div key={`${r.project_path}|${r.rule}`} style={{
|
|
231
|
+
display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
|
|
232
|
+
padding: '4px 0', fontSize: 11.5, color: T.textMuted,
|
|
233
|
+
}}>
|
|
234
|
+
<span className="mono" title={r.project_path} style={{
|
|
235
|
+
fontSize: 10.5, padding: '2px 7px', borderRadius: 4,
|
|
236
|
+
background: T.surfaceAlt, color: T.textMuted,
|
|
237
|
+
}}>{r.project_name || r.project_path}</span>
|
|
238
|
+
<span>
|
|
239
|
+
<b className="mono" style={{ color: T.text }}>{r.rule}</b>
|
|
240
|
+
{' '}held {r.count}× this week ({r.approved} approved) — {r.suggestion}
|
|
241
|
+
</span>
|
|
242
|
+
<div style={{ flex: 1 }} />
|
|
243
|
+
<Btn variant="ghost" onClick={() => onOpenRule(r)}
|
|
244
|
+
style={{ padding: '4px 10px' }}>Open rule</Btn>
|
|
245
|
+
</div>
|
|
246
|
+
))}
|
|
247
|
+
</div>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
188
251
|
// ── Read-only per-project policy matrix ────────────────────────────────────
|
|
189
|
-
|
|
252
|
+
// `focus` ({path, rule, seq}) comes from the cost strip's "Open rule": the
|
|
253
|
+
// panel switches to that project, scrolls itself into view and outlines the
|
|
254
|
+
// chip whose glob is the rule. A synthetic rule (discipline / shell) has no
|
|
255
|
+
// chip, so the scroll alone is the answer there.
|
|
256
|
+
function AccRulesPanel({ projects, focus }) {
|
|
190
257
|
const [path, setPath] = useState('');
|
|
191
258
|
const [data, setData] = useState(null);
|
|
192
259
|
const [err, setErr] = useState('');
|
|
260
|
+
const panelRef = useRef(null);
|
|
193
261
|
|
|
194
262
|
const load = useCallback(async (p) => {
|
|
195
263
|
if (!p) { setData(null); setErr(''); return; }
|
|
@@ -199,10 +267,28 @@ function AccRulesPanel({ projects }) {
|
|
|
199
267
|
} catch (e) { setData(null); setErr(apiErr(e)); }
|
|
200
268
|
}, []);
|
|
201
269
|
|
|
270
|
+
// Deliberately keyed on `focus` alone: `projects` is rebuilt by the hub's
|
|
271
|
+
// own poll, and re-running this on every poll would re-scroll the page
|
|
272
|
+
// under the user every few seconds.
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (!focus || !focus.path) return;
|
|
275
|
+
// Prefer the hub's own spelling of the project so the <select> shows it;
|
|
276
|
+
// the store's spelling still loads when the project is not registered.
|
|
277
|
+
const known = (projects || []).find(p => accSamePath(p.path, focus.path));
|
|
278
|
+
const target = known ? known.path : focus.path;
|
|
279
|
+
setPath(target);
|
|
280
|
+
load(target);
|
|
281
|
+
const el = panelRef.current;
|
|
282
|
+
if (el && typeof el.scrollIntoView === 'function') {
|
|
283
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
284
|
+
}
|
|
285
|
+
}, [focus]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
286
|
+
|
|
287
|
+
const hot = focus && focus.rule ? String(focus.rule) : '';
|
|
202
288
|
const scopes = (data && data.rules) || {};
|
|
203
289
|
const layerRows = data && data.policy ? Object.entries(data.policy.layers || {}) : [];
|
|
204
290
|
return (
|
|
205
|
-
<div style={{
|
|
291
|
+
<div ref={panelRef} style={{
|
|
206
292
|
background: T.surface, border: `1px solid ${T.border}`, borderRadius: 10,
|
|
207
293
|
padding: '12px 16px',
|
|
208
294
|
}}>
|
|
@@ -249,14 +335,21 @@ function AccRulesPanel({ projects }) {
|
|
|
249
335
|
<div style={{ fontSize: 11.5, color: T.textDim }}>no rules</div>
|
|
250
336
|
) : (
|
|
251
337
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
252
|
-
{rows.map(([kind, glob], i) =>
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
338
|
+
{rows.map(([kind, glob], i) => {
|
|
339
|
+
const lit = hot && glob === hot;
|
|
340
|
+
return (
|
|
341
|
+
<span key={i} className="mono" style={{
|
|
342
|
+
fontSize: 11, padding: '2px 8px', borderRadius: 4,
|
|
343
|
+
color: ACC_KIND_COLOR(kind),
|
|
344
|
+
background: `${ACC_KIND_COLOR(kind)}18`,
|
|
345
|
+
border: `1px solid ${ACC_KIND_COLOR(kind)}44`,
|
|
346
|
+
outline: lit ? `2px solid ${T.warn}` : 'none',
|
|
347
|
+
outlineOffset: lit ? 2 : 0,
|
|
348
|
+
}} title={lit ? `${kind} — this rule is costing you` : kind}>
|
|
349
|
+
{kind}: {glob}
|
|
350
|
+
</span>
|
|
351
|
+
);
|
|
352
|
+
})}
|
|
260
353
|
</div>
|
|
261
354
|
)}
|
|
262
355
|
{scope === 'builtin' && (sec.disabled || []).length > 0 && (
|
|
@@ -395,6 +488,11 @@ function HubAccess({ projects }) {
|
|
|
395
488
|
const [chip, setChip] = useState('pending');
|
|
396
489
|
const [busyId, setBusyId] = useState('');
|
|
397
490
|
const [confirmSpec, setConfirmSpec] = useState(null);
|
|
491
|
+
// `seq` makes a second click on the same rule re-fire the panel's effect.
|
|
492
|
+
const [ruleFocus, setRuleFocus] = useState(null);
|
|
493
|
+
const openRule = (r) => setRuleFocus({
|
|
494
|
+
path: r.project_path, rule: r.rule, seq: Date.now(),
|
|
495
|
+
});
|
|
398
496
|
|
|
399
497
|
const load = useCallback(async () => {
|
|
400
498
|
try {
|
|
@@ -459,6 +557,8 @@ function HubAccess({ projects }) {
|
|
|
459
557
|
))}
|
|
460
558
|
</div>
|
|
461
559
|
|
|
560
|
+
<AccCostStrip onOpenRule={openRule} />
|
|
561
|
+
|
|
462
562
|
{!loaded ? (
|
|
463
563
|
<div style={{ fontSize: 12, color: T.textDim }}>Loading…</div>
|
|
464
564
|
) : rows.length === 0 ? (
|
|
@@ -479,7 +579,7 @@ function HubAccess({ projects }) {
|
|
|
479
579
|
)}
|
|
480
580
|
|
|
481
581
|
<AccGrantsPanel projects={projects} />
|
|
482
|
-
<AccRulesPanel projects={projects} />
|
|
582
|
+
<AccRulesPanel projects={projects} focus={ruleFocus} />
|
|
483
583
|
{confirmSpec && (
|
|
484
584
|
<CredConfirm spec={confirmSpec} onClose={() => setConfirmSpec(null)} />
|
|
485
585
|
)}
|