code-context-control 2.124.0__tar.gz → 2.126.1__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.124.0/code_context_control.egg-info → code_context_control-2.126.1}/PKG-INFO +2 -2
- {code_context_control-2.124.0 → code_context_control-2.126.1}/README.md +1 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/_hook_utils.py +34 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/c3.py +23 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_dispatch.py +12 -3
- code_context_control-2.126.1/cli/hook_session_end.py +103 -0
- code_context_control-2.126.1/cli/hook_session_open.py +97 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/mcp_server.py +114 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1/code_context_control.egg-info}/PKG-INFO +2 -2
- {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/SOURCES.txt +10 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/config.py +5 -0
- code_context_control-2.126.1/oracle/listeners.py +210 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/oracle_server.py +88 -2
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/oracle_ui.html +9 -3
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_poll.py +8 -3
- code_context_control-2.126.1/oracle/services/client_tokens.py +239 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/mobile_api.py +362 -20
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/app.js +1 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/settings.js +75 -19
- {code_context_control-2.124.0 → code_context_control-2.126.1}/pyproject.toml +1 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_runner.py +32 -0
- code_context_control-2.126.1/services/host_sessions.py +95 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/notifications.py +31 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/shell_jobs.py +93 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_codex_compat.py +11 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_dispatch.py +9 -0
- code_context_control-2.126.1/tests/test_hook_session_end.py +291 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_api.py +85 -1
- code_context_control-2.126.1/tests/test_mobile_clients.py +543 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_extras.py +4 -2
- code_context_control-2.126.1/tests/test_mobile_jobs_ci.py +327 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_override_routes.py +35 -0
- code_context_control-2.126.1/tests/test_notification_kinds.py +294 -0
- code_context_control-2.126.1/tests/test_oracle_loopback.py +269 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_jobs_s3.py +4 -1
- {code_context_control-2.124.0 → code_context_control-2.126.1}/LICENSE +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/_shell_writes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/common.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/parser.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/docs.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/edits.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/access.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/credentials.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/index.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/masking.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/oracle.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/shared.css +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/tools.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/workflow.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_artifact.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_c3read.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_filter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_read.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_server.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/progress.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/server.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/_grants.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/agent.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/ci.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/compress.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/delegate.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edit.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edits.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/federate.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/filter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/impact.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/jira.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/locks.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/memory.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/override.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/project.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/read.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/search.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/session.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/status.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/tasks.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/validate.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/api.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/app.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/access.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/icons.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/shared.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/theme.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui_legacy.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui_nano.html +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/codex_patch.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/config.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/host.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/ide.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/mcp_toml.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/core/web_security.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/local_session.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/activity.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/agents.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/busy.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/core.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/header.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/insights.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/projects.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/access_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/access_telemetry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/activity_log.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agent_base.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agent_locks.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agents.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/artifact_defs.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/artifact_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/atomic_json.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/auto_memory.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/background_service.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/map_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/search_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bitbucket_client.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_act.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_cache.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_expr.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_failures.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_github.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_impact.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_intel.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_workflow.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/circuit_breaker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/claude_md.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/codex_integration.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/codex_transcript.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/compressor.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/context_snapshot.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/conversation_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/cred_audit.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/cred_telemetry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/credential_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/dir_map.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/doc_index.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_tasks.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/edit_ledger.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/embedding_index.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/enforcement_policy.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/error_reporting.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/file_map.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/file_memory.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/git_context.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/hub_service.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/index_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/indexer.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_client.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_cloud.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_data_center.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_links.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/lexical_index.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_activation.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_mirror.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_presets.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_consolidator.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_distiller.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_graph.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_grounder.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_queue.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_scorer.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/metrics.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_bridge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_client.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/oracle_service.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/output_filter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_grants.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_policy.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_requests.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_wake.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/parser.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/project_manager.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/project_runtime.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/protocol.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/proxy_state.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/repo_map.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/repo_shape.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/reranker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retention.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retrieval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retrieval_broker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/router.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/runtime.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/scanner.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_benchmark.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_manager.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_preloader.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/shell_output.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/subprojects.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/task_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/telemetry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/text_index.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/time_tracker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/tool_classifier.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/transcript_index.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/validation_cache.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/vector_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/watcher.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/services/win_subprocess.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/setup.cfg +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_background_service.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_act.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_codex_native.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_env_parser.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_state.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_init_scan.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_client.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_links.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_map_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_system.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_output_filter.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_grants.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_requests.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_wake.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_permissions.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_pm_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_manager.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_related_facts.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_repo_map.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_retention.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_review_digest.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p1.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p2.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p3.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p4.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p5.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_service_durability.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_session_budget.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_output.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subprojects.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_task_store.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_task_tool.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_validate.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_version_sync.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_web_security.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/backend.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/main.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/__init__.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/index_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/init_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/search_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/session_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/stats.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/theme.tcss +0 -0
{code_context_control-2.124.0/code_context_control.egg-info → code_context_control-2.126.1}/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.126.1
|
|
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
|
|
@@ -380,7 +380,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
|
|
|
380
380
|
## Security & privacy
|
|
381
381
|
|
|
382
382
|
- **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
|
|
383
|
-
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires
|
|
383
|
+
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
|
|
384
384
|
- **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
|
|
385
385
|
- **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
|
|
386
386
|
- **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
|
|
@@ -314,7 +314,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
|
|
|
314
314
|
## Security & privacy
|
|
315
315
|
|
|
316
316
|
- **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
|
|
317
|
-
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires
|
|
317
|
+
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
|
|
318
318
|
- **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
|
|
319
319
|
- **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
|
|
320
320
|
- **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
|
|
@@ -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.126.1"
|
|
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":
|
|
@@ -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()
|
|
@@ -100,6 +100,92 @@ def _build_instructions(ide_name: str) -> str:
|
|
|
100
100
|
)
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
# ── Host session id (the join key between hook rows and MCP rows) ──────────
|
|
104
|
+
# The PreToolUse hooks write .c3/enforcement_state.json with `session_id` =
|
|
105
|
+
# the host's id for the session that just called. When the host also put its
|
|
106
|
+
# id in this process's environment (CLAUDE_CODE_SESSION_ID / CODEX_THREAD_ID)
|
|
107
|
+
# the SessionManager already carries it and no file is read. Otherwise the
|
|
108
|
+
# state file is consulted at most once per _HOST_SID_TTL_S — a tool call is
|
|
109
|
+
# far hotter than that, and a per-call read would be a stat+parse on every
|
|
110
|
+
# c3_* invocation for a value that changes once per session.
|
|
111
|
+
_HOST_SID_TTL_S = 5.0
|
|
112
|
+
_host_sid_cache = {"value": "", "read_at": 0.0, "linked": ""}
|
|
113
|
+
_host_sid_lock = threading.Lock()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _host_session_id(svc) -> str:
|
|
117
|
+
"""The host session id for this process, or ``""`` when nobody knows it."""
|
|
118
|
+
try:
|
|
119
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
|
|
120
|
+
env_sid = str(session.get("host_session_id") or "").strip()
|
|
121
|
+
except Exception:
|
|
122
|
+
env_sid = ""
|
|
123
|
+
if env_sid:
|
|
124
|
+
_link_host_session(svc, env_sid)
|
|
125
|
+
return env_sid
|
|
126
|
+
now = time.monotonic()
|
|
127
|
+
with _host_sid_lock:
|
|
128
|
+
if now - _host_sid_cache["read_at"] < _HOST_SID_TTL_S:
|
|
129
|
+
return _host_sid_cache["value"]
|
|
130
|
+
_host_sid_cache["read_at"] = now
|
|
131
|
+
value = ""
|
|
132
|
+
try:
|
|
133
|
+
import json as _json
|
|
134
|
+
|
|
135
|
+
from cli._hook_utils import ENFORCEMENT_STATE_FILE
|
|
136
|
+
state_path = Path(svc.project_path) / ENFORCEMENT_STATE_FILE
|
|
137
|
+
if state_path.is_file():
|
|
138
|
+
data = _json.loads(state_path.read_text(encoding="utf-8"))
|
|
139
|
+
if isinstance(data, dict):
|
|
140
|
+
value = str(data.get("session_id") or "").strip()
|
|
141
|
+
except Exception:
|
|
142
|
+
value = ""
|
|
143
|
+
with _host_sid_lock:
|
|
144
|
+
_host_sid_cache["value"] = value
|
|
145
|
+
if value:
|
|
146
|
+
_link_host_session(svc, value)
|
|
147
|
+
return value
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _link_host_session(svc, host_sid: str) -> None:
|
|
151
|
+
"""Write the host→C3 link file once per distinct host id (services.host_sessions)."""
|
|
152
|
+
with _host_sid_lock:
|
|
153
|
+
if _host_sid_cache["linked"] == host_sid:
|
|
154
|
+
return
|
|
155
|
+
_host_sid_cache["linked"] = host_sid
|
|
156
|
+
try:
|
|
157
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
|
|
158
|
+
c3_id = str(session.get("id") or "")
|
|
159
|
+
if c3_id:
|
|
160
|
+
from services.host_sessions import write_link
|
|
161
|
+
write_link(svc.project_path, getattr(svc, "ide_name", "") or _IDE_NAME, host_sid, c3_id)
|
|
162
|
+
except Exception:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _notify_mcp_ready(svc) -> None:
|
|
167
|
+
"""``kind="mcp"`` / ``C3 connected`` — the runtime is ready to serve (D0b).
|
|
168
|
+
|
|
169
|
+
ref_id is the C3 session id, the same value ``session_start`` carries;
|
|
170
|
+
the host id rides in the message when known. Best-effort: a notification
|
|
171
|
+
failure must never keep the server from serving.
|
|
172
|
+
"""
|
|
173
|
+
try:
|
|
174
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
|
|
175
|
+
c3_id = str(session.get("id") or "")
|
|
176
|
+
host_sid = _host_session_id(svc)
|
|
177
|
+
short = (host_sid or c3_id)[:8] or "?"
|
|
178
|
+
from services.notifications import notify
|
|
179
|
+
notify(svc.project_path, agent="c3", severity="info",
|
|
180
|
+
title=f"C3 connected {short}",
|
|
181
|
+
message=(f"C3 {C3_VERSION} MCP runtime ready for {_IDE_NAME}"
|
|
182
|
+
f" (session {c3_id}"
|
|
183
|
+
+ (f", host {host_sid}" if host_sid else "") + ")"),
|
|
184
|
+
kind="mcp", ref_id=c3_id)
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
|
|
103
189
|
@asynccontextmanager
|
|
104
190
|
async def lifespan(server):
|
|
105
191
|
"""Initialize all services, auto-start session, start file watcher."""
|
|
@@ -223,9 +309,16 @@ async def lifespan(server):
|
|
|
223
309
|
services.auto_memory = AutoMemory(services.memory, services.session_mgr, auto_mem_cfg)
|
|
224
310
|
|
|
225
311
|
if services.session_mgr.current_session:
|
|
312
|
+
# host_session_id (the Claude Code UUID / Codex thread id) joins this
|
|
313
|
+
# row to the hooks' session_open / session_end rows, which only know
|
|
314
|
+
# the host id. Absent when the host did not put its id in the
|
|
315
|
+
# environment; the link file below is written lazily in that case
|
|
316
|
+
# the first time a hook reveals it (see _host_session_id).
|
|
317
|
+
_host_sid = _host_session_id(services)
|
|
226
318
|
services.activity_log.log("session_start", {
|
|
227
319
|
"session_id": services.session_mgr.current_session["id"],
|
|
228
320
|
"source_system": started_session.get("source_system", ""),
|
|
321
|
+
**({"host_session_id": _host_sid} if _host_sid else {}),
|
|
229
322
|
})
|
|
230
323
|
|
|
231
324
|
# Auto-restore latest snapshot if recent (< 30 min).
|
|
@@ -288,6 +381,12 @@ async def lifespan(server):
|
|
|
288
381
|
)
|
|
289
382
|
_t.Thread(target=_bg_validation_sweep, daemon=True, name="c3-validate-sweep").start()
|
|
290
383
|
|
|
384
|
+
# Runtime is ready to serve: say so where a client can hear it. A desktop
|
|
385
|
+
# "MCP failed to connect" sentinel keys on a session_open with no `mcp`
|
|
386
|
+
# notification within 30 s, so this must be the LAST thing before the
|
|
387
|
+
# handshake proceeds and must never be skipped on a partial init.
|
|
388
|
+
_notify_mcp_ready(services)
|
|
389
|
+
|
|
291
390
|
try:
|
|
292
391
|
yield services
|
|
293
392
|
finally:
|
|
@@ -430,8 +529,22 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
|
|
|
430
529
|
call_ok = not _failed(response)
|
|
431
530
|
except Exception:
|
|
432
531
|
call_ok = True
|
|
532
|
+
# Both session ids on every tool_call row (D0b): C3's own id joins the
|
|
533
|
+
# row to session_start / the saved session file, the host id joins it to
|
|
534
|
+
# the hooks' session_open / session_end rows. Either may be absent.
|
|
535
|
+
_ids: dict = {}
|
|
536
|
+
try:
|
|
537
|
+
_c3_sid = str((svc.session_mgr.current_session or {}).get("id") or "")
|
|
538
|
+
if _c3_sid:
|
|
539
|
+
_ids["session_id"] = _c3_sid
|
|
540
|
+
_host_sid = _host_session_id(svc)
|
|
541
|
+
if _host_sid:
|
|
542
|
+
_ids["host_session_id"] = _host_sid
|
|
543
|
+
except Exception:
|
|
544
|
+
pass
|
|
433
545
|
svc.activity_log.log("tool_call", {"tool": tool_name, "args": args,
|
|
434
|
-
"result_summary": summary, "ok": call_ok
|
|
546
|
+
"result_summary": summary, "ok": call_ok,
|
|
547
|
+
**_ids})
|
|
435
548
|
tracker = getattr(svc, "time_tracker", None)
|
|
436
549
|
if tracker is not None:
|
|
437
550
|
try:
|
{code_context_control-2.124.0 → code_context_control-2.126.1/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.126.1
|
|
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
|
|
@@ -380,7 +380,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
|
|
|
380
380
|
## Security & privacy
|
|
381
381
|
|
|
382
382
|
- **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
|
|
383
|
-
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires
|
|
383
|
+
- **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
|
|
384
384
|
- **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
|
|
385
385
|
- **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
|
|
386
386
|
- **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
|
|
@@ -21,6 +21,8 @@ cli/hook_ghost_files.py
|
|
|
21
21
|
cli/hook_pretool_enforce.py
|
|
22
22
|
cli/hook_prompt_recall.py
|
|
23
23
|
cli/hook_read.py
|
|
24
|
+
cli/hook_session_end.py
|
|
25
|
+
cli/hook_session_open.py
|
|
24
26
|
cli/hook_session_stats.py
|
|
25
27
|
cli/hook_terse_advisor.py
|
|
26
28
|
cli/hub_server.py
|
|
@@ -141,6 +143,7 @@ core/mcp_toml.py
|
|
|
141
143
|
core/web_security.py
|
|
142
144
|
oracle/__init__.py
|
|
143
145
|
oracle/config.py
|
|
146
|
+
oracle/listeners.py
|
|
144
147
|
oracle/mcp_oracle.py
|
|
145
148
|
oracle/oracle_server.py
|
|
146
149
|
oracle/oracle_ui.html
|
|
@@ -151,6 +154,7 @@ oracle/services/c3_bridge.py
|
|
|
151
154
|
oracle/services/chat_engine.py
|
|
152
155
|
oracle/services/chat_poll.py
|
|
153
156
|
oracle/services/chat_store.py
|
|
157
|
+
oracle/services/client_tokens.py
|
|
154
158
|
oracle/services/cross_memory.py
|
|
155
159
|
oracle/services/discovery_audit.py
|
|
156
160
|
oracle/services/federated_graph.py
|
|
@@ -229,6 +233,7 @@ services/error_reporting.py
|
|
|
229
233
|
services/file_map.py
|
|
230
234
|
services/file_memory.py
|
|
231
235
|
services/git_context.py
|
|
236
|
+
services/host_sessions.py
|
|
232
237
|
services/hub_service.py
|
|
233
238
|
services/index_store.py
|
|
234
239
|
services/indexer.py
|
|
@@ -370,6 +375,7 @@ tests/test_hook_codex_compat.py
|
|
|
370
375
|
tests/test_hook_dispatch.py
|
|
371
376
|
tests/test_hook_pretool_enforce.py
|
|
372
377
|
tests/test_hook_prompt_recall.py
|
|
378
|
+
tests/test_hook_session_end.py
|
|
373
379
|
tests/test_hook_smoke.py
|
|
374
380
|
tests/test_hook_state.py
|
|
375
381
|
tests/test_hook_utf8_stdio.py
|
|
@@ -410,12 +416,15 @@ tests/test_memory_graph_api.py
|
|
|
410
416
|
tests/test_memory_queue.py
|
|
411
417
|
tests/test_memory_system.py
|
|
412
418
|
tests/test_mobile_api.py
|
|
419
|
+
tests/test_mobile_clients.py
|
|
413
420
|
tests/test_mobile_extras.py
|
|
421
|
+
tests/test_mobile_jobs_ci.py
|
|
414
422
|
tests/test_mobile_override_routes.py
|
|
415
423
|
tests/test_mobile_security_api.py
|
|
416
424
|
tests/test_no_stale_model_pins.py
|
|
417
425
|
tests/test_notification_dedup.py
|
|
418
426
|
tests/test_notification_discipline.py
|
|
427
|
+
tests/test_notification_kinds.py
|
|
419
428
|
tests/test_ollama_credentials.py
|
|
420
429
|
tests/test_oracle_api_auth.py
|
|
421
430
|
tests/test_oracle_apikey_api.py
|
|
@@ -426,6 +435,7 @@ tests/test_oracle_discovery_api.py
|
|
|
426
435
|
tests/test_oracle_discovery_audit.py
|
|
427
436
|
tests/test_oracle_health_probe.py
|
|
428
437
|
tests/test_oracle_local_auth.py
|
|
438
|
+
tests/test_oracle_loopback.py
|
|
429
439
|
tests/test_oracle_ollama_bridge.py
|
|
430
440
|
tests/test_oracle_scanner_cache.py
|
|
431
441
|
tests/test_oracle_security_fixes.py
|
|
@@ -11,6 +11,11 @@ DEFAULTS = {
|
|
|
11
11
|
"port": 3331,
|
|
12
12
|
# ── Discovery API (external LLM tool surface, v2.32.0) ──
|
|
13
13
|
"bind_host": "127.0.0.1", # loopback only by default (was 0.0.0.0)
|
|
14
|
+
# When bind_host is a specific non-loopback address (a Tailscale / LAN
|
|
15
|
+
# IP), ALSO serve the same app on 127.0.0.1 so same-machine clients (the
|
|
16
|
+
# desk tray client, `c3 oracle open`, curl) are not refused. No effect on
|
|
17
|
+
# a loopback or wildcard bind. See oracle/listeners.py.
|
|
18
|
+
"loopback_listener": True,
|
|
14
19
|
"api_enabled": True, # expose /api/discovery/* REST surface
|
|
15
20
|
"api_require_auth": True, # require Bearer token on /api/discovery/*
|
|
16
21
|
"api_max_tier": "action", # cap exposed tools: "read" | "action"
|