code-context-control 2.154.0__tar.gz → 2.155.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.154.0 → code_context_control-2.155.0}/PKG-INFO +1 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/c3.py +1 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_session_open.py +101 -2
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/mcp_server.py +114 -3
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/server.py +57 -35
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/_grants.py +18 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/edit.py +2 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/locks.py +1 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/project.py +18 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/SOURCES.txt +6 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/host.py +13 -3
- {code_context_control-2.154.0 → code_context_control-2.155.0}/pyproject.toml +1 -1
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/agent_locks.py +8 -5
- code_context_control-2.155.0/services/host_handoff.py +320 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/project_manager.py +41 -41
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/session_live.py +16 -4
- code_context_control-2.155.0/services/ui_registry.py +264 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_agent_locks.py +42 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_session_end.py +74 -0
- code_context_control-2.155.0/tests/test_host_handoff.py +165 -0
- code_context_control-2.155.0/tests/test_host_rebind.py +126 -0
- code_context_control-2.155.0/tests/test_project_lease_identity.py +48 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_project_manager.py +56 -0
- code_context_control-2.155.0/tests/test_ui_registry.py +179 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/LICENSE +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/README.md +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/commands/common.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/docs.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/edits.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/access.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/ci.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/delegate.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/index.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/jira.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/sessions.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_agent_model.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_codex_lifecycle.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_read.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_session_end.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_server.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_access.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_sessions.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/progress.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/_edit_report.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/override.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/read.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/search.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/session.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/status.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/api.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/app.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/codex_patch.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/config.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/grok_payload.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/hook_command.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/ide.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/core/web_security.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/config.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/listeners.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/client_tokens.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/access_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/activity_log.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/agent_base.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/agent_downshift.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/agents.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/agents_workflow.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/artifact_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/atomic_json.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/auto_memory.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/background_service.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/delegate_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/delegate_write_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/map_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/builtin_leases.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_act.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_cache.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_expr.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_failures.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_github.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_impact.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_intel.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_runner.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/claude_md.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/codex_integration.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/codex_transcript.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/compressor.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/conversation_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/cred_audit.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/credential_backup.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/credential_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/delegate_agents.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/delegate_hints.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/delegate_write.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/dir_map.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/doc_index.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/edit_blobs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/embedding_index.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/error_reporting.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/file_map.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/file_memory.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/git_context.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/grok_integration.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/grok_transcript.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/host_sessions.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/hub_service.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/index_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/indexer.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/jira_client.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/jira_links.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/lexical_index.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/mask_activation.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/mask_presets.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_graph.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_queue.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/metrics.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/notifications.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ollama_client.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/oracle_service.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/output_filter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/override_costs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/override_grants.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/override_policy.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/override_requests.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/override_wake.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/parser.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/project_runtime.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/protocol.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/proxy_state.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/read_stamps.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/repo_map.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/repo_shape.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/reranker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/retention.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/retrieval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/router.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/runtime.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/scanner.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/session_catalog.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/session_manager.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/session_preloader.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/shell_jobs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/shell_output.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/subprojects.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/task_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/telemetry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/terminal_launch.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/text_index.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/time_tracker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/transcript_index.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/validation_cache.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/vector_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/watcher.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/setup.cfg +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_activity_log_find_last.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_atomic_json.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_builtin_leases.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_builtin_modes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_dag_ownership.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_codex_mcp_transport.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_codex_native.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credential_backup.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_adoption_d4.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_auto.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_claude_d1.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_grok.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_host_d2.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_scout_d3.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_telemetry_d0.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_thinking_cap.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_tuning.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_write.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_delegate_write_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_dir_map_c3.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_eol_atomic.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_outcome.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_report.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_revert.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_stale.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_embedding_index_corrupt_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_embedding_store_safety.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_file_map_c1.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_grok_native.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_grok_compat.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_access_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_builtin_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_hook_migration.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_ide_cmd.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_override_policy_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_override_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_rules_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_sessions_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_large_files_c4.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_map_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_map_telemetry_c0.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_clients.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_jobs_ci.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_override_costs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_notification_kinds.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_loopback.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_override_costs.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_quarantine_sweep.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_read_outside_root.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_retention.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_session_catalog.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_session_live.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_session_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_jobs_s3.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_validate.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_watcher_pruning.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/backend.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/main.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.154.0 → code_context_control-2.155.0}/tui/theme.tcss +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.155.0
|
|
4
4
|
Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
|
|
5
5
|
Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
|
|
|
91
91
|
# Config
|
|
92
92
|
CONFIG_DIR = ".c3"
|
|
93
93
|
CONFIG_FILE = ".c3/config.json"
|
|
94
|
-
__version__ = "2.
|
|
94
|
+
__version__ = "2.155.0"
|
|
95
95
|
|
|
96
96
|
# The PreToolUse matcher for native subagent calls (installer and hub migration).
|
|
97
97
|
AGENT_MATCHER = "Agent|Task"
|
|
@@ -30,6 +30,12 @@ the hub, and it skips a project that already has a live UI port, so a
|
|
|
30
30
|
``C3_NO_UI_AUTOSTART=1`` or
|
|
31
31
|
``.c3/config.json → {"ui": {"autostart_on_session": false}}``.
|
|
32
32
|
|
|
33
|
+
A ``clear`` (or an in-session ``resume``) keeps the MCP server it already
|
|
34
|
+
has, under a host session id that just ended. This hook finds that server
|
|
35
|
+
by the host pid both of them share and hands it the new id
|
|
36
|
+
(``services.host_handoff``, v2.155.0); the server then writes the
|
|
37
|
+
``C3 connected <new id>`` row the desktop sentinel is waiting for.
|
|
38
|
+
|
|
33
39
|
``source: "compact"`` writes NOTHING: a compaction is the same session and
|
|
34
40
|
the same MCP process, and a "Session started" toast on every compaction
|
|
35
41
|
would teach the user to ignore the real ones.
|
|
@@ -48,6 +54,8 @@ from __future__ import annotations
|
|
|
48
54
|
import json
|
|
49
55
|
import os
|
|
50
56
|
import sys
|
|
57
|
+
import time
|
|
58
|
+
import uuid
|
|
51
59
|
from pathlib import Path
|
|
52
60
|
|
|
53
61
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
@@ -56,6 +64,11 @@ from cli._hook_utils import detect_host, find_project, log_hook_error # noqa: E
|
|
|
56
64
|
from cli.hook_session_end import short_id # noqa: E402
|
|
57
65
|
|
|
58
66
|
_SILENT_SOURCES = {"compact"}
|
|
67
|
+
# How long one session's UI launch holds the project against the next. A
|
|
68
|
+
# server lands in the registry only after it binds its port, a few seconds
|
|
69
|
+
# after Popen; this covers that gap with room to spare. After it, the live
|
|
70
|
+
# registry entry (``_ui_running``) is the guard again.
|
|
71
|
+
_LAUNCH_GRACE_S = 90.0
|
|
59
72
|
|
|
60
73
|
|
|
61
74
|
def _ui_autostart_enabled(project: Path) -> bool:
|
|
@@ -96,7 +109,10 @@ def _ui_running(pm, project: Path) -> bool:
|
|
|
96
109
|
"""True when a live UI server is already registered for this project.
|
|
97
110
|
|
|
98
111
|
This is what keeps `resume` / `clear` — both real SessionStart events —
|
|
99
|
-
from stacking a second server on every reconnect.
|
|
112
|
+
from stacking a second server on every reconnect. A registered server
|
|
113
|
+
whose port is quiet but whose pid is running is still "running": it is
|
|
114
|
+
starting up, or busy, and a second one would only be the leak this
|
|
115
|
+
check exists to prevent (2.155.0).
|
|
100
116
|
"""
|
|
101
117
|
target = os.path.normcase(str(project))
|
|
102
118
|
for entry in pm._read_registry():
|
|
@@ -107,8 +123,72 @@ def _ui_running(pm, project: Path) -> bool:
|
|
|
107
123
|
same = os.path.normcase(str(Path(raw).resolve())) == target
|
|
108
124
|
except Exception:
|
|
109
125
|
same = os.path.normcase(raw) == target
|
|
110
|
-
if same
|
|
126
|
+
if not same or not entry.get("port"):
|
|
127
|
+
continue
|
|
128
|
+
if pm._port_alive(entry["port"]):
|
|
129
|
+
return True
|
|
130
|
+
if entry.get("pid") and pm._pid_alive(entry.get("pid")):
|
|
131
|
+
return True
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _launch_lock(project: Path) -> Path:
|
|
136
|
+
return project / ".c3" / "ui_launch.lock"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _claim_launch(project: Path) -> bool:
|
|
140
|
+
"""Atomically claim the right to launch this project's UI server.
|
|
141
|
+
|
|
142
|
+
``_ui_running`` only sees a server once it has registered its port, a
|
|
143
|
+
few seconds after launch. Sessions that open inside that window (an
|
|
144
|
+
agent spawning several at once, or a resume racing a startup) each saw
|
|
145
|
+
no live UI and each launched one, which is how a project ended up with
|
|
146
|
+
two servers. The first claimant creates ``.c3/ui_launch.lock`` with
|
|
147
|
+
O_EXCL; anyone else inside ``_LAUNCH_GRACE_S`` stands down.
|
|
148
|
+
|
|
149
|
+
A lock older than the grace window is stale (the launch died, or the
|
|
150
|
+
server since exited). It is taken over by renaming it to a unique name,
|
|
151
|
+
which only one contender can do, then the create is retried. If the
|
|
152
|
+
lock cannot be handled at all the answer is True, which is the
|
|
153
|
+
behaviour from before this lock existed: a missing UI is worse than a
|
|
154
|
+
rare duplicate.
|
|
155
|
+
"""
|
|
156
|
+
lock = _launch_lock(project)
|
|
157
|
+
try:
|
|
158
|
+
lock.parent.mkdir(parents=True, exist_ok=True)
|
|
159
|
+
except Exception:
|
|
160
|
+
return True
|
|
161
|
+
for _ in range(3):
|
|
162
|
+
try:
|
|
163
|
+
fd = os.open(str(lock), os.O_CREAT | os.O_EXCL | os.O_WRONLY)
|
|
164
|
+
except FileExistsError:
|
|
165
|
+
try:
|
|
166
|
+
age = time.time() - lock.stat().st_mtime
|
|
167
|
+
except FileNotFoundError:
|
|
168
|
+
continue # released between our create and stat; retry
|
|
169
|
+
except Exception:
|
|
170
|
+
return True
|
|
171
|
+
if age < _LAUNCH_GRACE_S:
|
|
172
|
+
return False
|
|
173
|
+
stale = lock.with_name(f"ui_launch.stale-{uuid.uuid4().hex}")
|
|
174
|
+
try:
|
|
175
|
+
os.rename(str(lock), str(stale))
|
|
176
|
+
except FileNotFoundError:
|
|
177
|
+
continue # another contender took it over first
|
|
178
|
+
except Exception:
|
|
179
|
+
return False
|
|
180
|
+
try:
|
|
181
|
+
stale.unlink()
|
|
182
|
+
except Exception:
|
|
183
|
+
pass
|
|
184
|
+
continue
|
|
185
|
+
except Exception:
|
|
111
186
|
return True
|
|
187
|
+
try:
|
|
188
|
+
os.write(fd, f"{os.getpid()} {time.time():.0f}\n".encode("ascii"))
|
|
189
|
+
finally:
|
|
190
|
+
os.close(fd)
|
|
191
|
+
return True
|
|
112
192
|
return False
|
|
113
193
|
|
|
114
194
|
|
|
@@ -136,6 +216,8 @@ def ensure_ui(project: Path, host_session_id: str = "") -> str:
|
|
|
136
216
|
return "unregistered"
|
|
137
217
|
if _ui_running(pm, project):
|
|
138
218
|
return "already-running"
|
|
219
|
+
if not _claim_launch(project):
|
|
220
|
+
return "launch-pending"
|
|
139
221
|
# launch_session copies os.environ into the detached child, which is
|
|
140
222
|
# where cli/server._register_session reads the ownership from.
|
|
141
223
|
os.environ["C3_UI_OWNER"] = "session"
|
|
@@ -150,6 +232,22 @@ def ensure_ui(project: Path, host_session_id: str = "") -> str:
|
|
|
150
232
|
return "error"
|
|
151
233
|
|
|
152
234
|
|
|
235
|
+
def hand_off_runtime(project: Path, host: str, host_sid: str, start_source: str) -> list:
|
|
236
|
+
"""Point the MCP server this host already runs at its new session id.
|
|
237
|
+
|
|
238
|
+
Returns the C3 session ids handed off (usually one, often none: a
|
|
239
|
+
``startup`` has no server yet). Never raises.
|
|
240
|
+
"""
|
|
241
|
+
if not host_sid:
|
|
242
|
+
return []
|
|
243
|
+
try:
|
|
244
|
+
from services.host_handoff import hand_off
|
|
245
|
+
return hand_off(project, host, host_sid, start_source)
|
|
246
|
+
except Exception as exc:
|
|
247
|
+
log_hook_error("hook_session_open", exc)
|
|
248
|
+
return []
|
|
249
|
+
|
|
250
|
+
|
|
153
251
|
def run(payload: dict, project_path: Path | None = None):
|
|
154
252
|
"""Core logic — importable by the dispatcher and tests. Returns None."""
|
|
155
253
|
start_source = str(payload.get("source") or "").strip().lower()
|
|
@@ -178,6 +276,7 @@ def run(payload: dict, project_path: Path | None = None):
|
|
|
178
276
|
kind="session", ref_id=host_sid)
|
|
179
277
|
except Exception:
|
|
180
278
|
pass
|
|
279
|
+
hand_off_runtime(project, host, host_sid, start_source)
|
|
181
280
|
ensure_ui(project, host_sid)
|
|
182
281
|
return None
|
|
183
282
|
|
|
@@ -165,6 +165,93 @@ def _link_host_session(svc, host_sid: str) -> None:
|
|
|
165
165
|
pass
|
|
166
166
|
|
|
167
167
|
|
|
168
|
+
# ── Host handoff (2.155.0): follow a /clear to its new host session id ─────
|
|
169
|
+
# The pid of the IDE / agent CLI above this process (services.host_handoff).
|
|
170
|
+
# Written into every heartbeat; the SessionStart hook matches on it.
|
|
171
|
+
_HOST_PID = 0
|
|
172
|
+
# How often the heartbeat thread looks for a handoff file. The desktop
|
|
173
|
+
# sentinel gives a new session 30 s to produce a `C3 connected` row.
|
|
174
|
+
_HANDOFF_POLL_S = 5
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _rebind_host_session(svc, host_sid: str, start_source: str = "") -> bool:
|
|
178
|
+
"""Adopt ``host_sid`` as this server's host session id. Returns True when
|
|
179
|
+
something changed.
|
|
180
|
+
|
|
181
|
+
Everything that was derived from the old id is redone: the session
|
|
182
|
+
record (what ``_grants.session_id`` and the access guard read), the
|
|
183
|
+
host env var (what a c3_project proxy runtime built later would read),
|
|
184
|
+
the host↔C3 link file, the heartbeat — and the ``C3 connected <id>``
|
|
185
|
+
notification, which is what C3 Desk's "did not connect" sentinel waits
|
|
186
|
+
for after the hook's ``Session started <id>``.
|
|
187
|
+
"""
|
|
188
|
+
host_sid = str(host_sid or "").strip()
|
|
189
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None)
|
|
190
|
+
if not host_sid or not isinstance(session, dict):
|
|
191
|
+
return False
|
|
192
|
+
previous = str(session.get("host_session_id") or "")
|
|
193
|
+
if previous == host_sid:
|
|
194
|
+
return False
|
|
195
|
+
session["host_session_id"] = host_sid
|
|
196
|
+
ide = getattr(svc, "ide_name", "") or _IDE_NAME
|
|
197
|
+
try:
|
|
198
|
+
from core.host import session_env_var
|
|
199
|
+
var = session_env_var(ide)
|
|
200
|
+
if var:
|
|
201
|
+
os.environ[var] = host_sid
|
|
202
|
+
except Exception:
|
|
203
|
+
pass
|
|
204
|
+
try:
|
|
205
|
+
import dataclasses
|
|
206
|
+
base = getattr(svc, "host_context", None) or _HOST
|
|
207
|
+
ctx = dataclasses.replace(base, host_session_id=host_sid)
|
|
208
|
+
svc.host_context = ctx
|
|
209
|
+
if getattr(svc, "session_mgr", None) is not None:
|
|
210
|
+
svc.session_mgr.host_context = ctx
|
|
211
|
+
except Exception:
|
|
212
|
+
pass
|
|
213
|
+
with _host_sid_lock:
|
|
214
|
+
_host_sid_cache["value"] = host_sid
|
|
215
|
+
_host_sid_cache["read_at"] = time.monotonic()
|
|
216
|
+
_host_sid_cache["linked"] = ""
|
|
217
|
+
_link_host_session(svc, host_sid)
|
|
218
|
+
try:
|
|
219
|
+
svc.activity_log.log("session_rebind", {
|
|
220
|
+
"session_id": str(session.get("id") or ""),
|
|
221
|
+
"host_session_id": host_sid,
|
|
222
|
+
"previous_host_session_id": previous,
|
|
223
|
+
"start_source": str(start_source or ""),
|
|
224
|
+
})
|
|
225
|
+
except Exception:
|
|
226
|
+
pass
|
|
227
|
+
try:
|
|
228
|
+
from services import session_live
|
|
229
|
+
session_live.beat(svc.project_path, str(session.get("id") or ""),
|
|
230
|
+
host_session_id=host_sid, ide=ide, host_pid=_HOST_PID)
|
|
231
|
+
except Exception:
|
|
232
|
+
pass
|
|
233
|
+
_notify_mcp_ready(svc)
|
|
234
|
+
return True
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _check_handoff(svc) -> bool:
|
|
238
|
+
"""Consume a pending handoff file for this session, if any. Never raises."""
|
|
239
|
+
try:
|
|
240
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
|
|
241
|
+
c3_id = str(session.get("id") or "")
|
|
242
|
+
if not c3_id:
|
|
243
|
+
return False
|
|
244
|
+
from services import host_handoff
|
|
245
|
+
data = host_handoff.read_handoff(svc.project_path, c3_id)
|
|
246
|
+
if not data:
|
|
247
|
+
return False
|
|
248
|
+
host_handoff.clear_handoff(svc.project_path, c3_id)
|
|
249
|
+
return _rebind_host_session(svc, str(data.get("host_session_id") or ""),
|
|
250
|
+
str(data.get("start_source") or ""))
|
|
251
|
+
except Exception:
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
|
|
168
255
|
def _notify_mcp_ready(svc) -> None:
|
|
169
256
|
"""``kind="mcp"`` / ``C3 connected`` — the runtime is ready to serve (D0b).
|
|
170
257
|
|
|
@@ -341,19 +428,36 @@ async def lifespan(server):
|
|
|
341
428
|
if _live_session_id:
|
|
342
429
|
from services import session_live
|
|
343
430
|
|
|
431
|
+
global _HOST_PID
|
|
432
|
+
try:
|
|
433
|
+
from services.host_handoff import host_process_id
|
|
434
|
+
_HOST_PID = int(host_process_id() or 0)
|
|
435
|
+
except Exception:
|
|
436
|
+
_HOST_PID = 0
|
|
437
|
+
|
|
344
438
|
def _do_beat():
|
|
345
439
|
session_live.beat(services.project_path, _live_session_id,
|
|
346
440
|
host_session_id=_host_session_id(services) or "",
|
|
347
|
-
ide=_IDE_NAME)
|
|
441
|
+
ide=_IDE_NAME, host_pid=_HOST_PID)
|
|
348
442
|
|
|
349
443
|
_do_beat()
|
|
350
444
|
|
|
351
445
|
def _bg_heartbeat():
|
|
352
|
-
|
|
446
|
+
# Wakes every _HANDOFF_POLL_S to look for a handoff (a /clear
|
|
447
|
+
# moved this server to a new host session id), and beats every
|
|
448
|
+
# HEARTBEAT_INTERVAL_S as before.
|
|
449
|
+
last_beat = time.monotonic()
|
|
450
|
+
while not _heartbeat_stop.wait(timeout=_HANDOFF_POLL_S):
|
|
353
451
|
try:
|
|
354
|
-
|
|
452
|
+
_check_handoff(services)
|
|
355
453
|
except Exception:
|
|
356
454
|
pass
|
|
455
|
+
if time.monotonic() - last_beat >= session_live.HEARTBEAT_INTERVAL_S:
|
|
456
|
+
last_beat = time.monotonic()
|
|
457
|
+
try:
|
|
458
|
+
_do_beat()
|
|
459
|
+
except Exception:
|
|
460
|
+
pass
|
|
357
461
|
|
|
358
462
|
threading.Thread(target=_bg_heartbeat, daemon=True,
|
|
359
463
|
name="c3-session-heartbeat").start()
|
|
@@ -423,6 +527,9 @@ async def lifespan(server):
|
|
|
423
527
|
# notification within 30 s, so this must be the LAST thing before the
|
|
424
528
|
# handshake proceeds and must never be skipped on a partial init.
|
|
425
529
|
_notify_mcp_ready(services)
|
|
530
|
+
# A /clear that landed while this process was still starting left its
|
|
531
|
+
# handoff waiting; take it now rather than at the first poll.
|
|
532
|
+
_check_handoff(services)
|
|
426
533
|
|
|
427
534
|
try:
|
|
428
535
|
yield services
|
|
@@ -517,6 +624,10 @@ def _ensure_repo_map_once(rt) -> None:
|
|
|
517
624
|
def _svc(ctx: Context) -> C3Runtime:
|
|
518
625
|
rt = ctx.request_context.lifespan_context
|
|
519
626
|
_ensure_repo_map_once(rt)
|
|
627
|
+
# A tool call right after a /clear must already run under the new host
|
|
628
|
+
# id (grants and leases are keyed by it): one stat per call, before the
|
|
629
|
+
# access guard binds the session.
|
|
630
|
+
_check_handoff(rt)
|
|
520
631
|
access_guard.bind_session(_grants.session_id(rt))
|
|
521
632
|
return rt
|
|
522
633
|
|
|
@@ -63,19 +63,8 @@ _HUB_CONFIG_FILE = _GLOBAL_C3_DIR / "hub_config.json"
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
def _registry_read() -> list:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
with open(_REGISTRY_FILE, encoding="utf-8") as f:
|
|
69
|
-
return json.load(f)
|
|
70
|
-
except Exception:
|
|
71
|
-
pass
|
|
72
|
-
return []
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def _registry_write(entries: list):
|
|
76
|
-
_GLOBAL_C3_DIR.mkdir(parents=True, exist_ok=True)
|
|
77
|
-
with open(_REGISTRY_FILE, "w", encoding="utf-8") as f:
|
|
78
|
-
json.dump(entries, f, indent=2)
|
|
66
|
+
from services import ui_registry
|
|
67
|
+
return ui_registry.read(_REGISTRY_FILE)
|
|
79
68
|
|
|
80
69
|
|
|
81
70
|
def _read_hub_config() -> dict:
|
|
@@ -103,32 +92,54 @@ def _port_alive(port: int) -> bool:
|
|
|
103
92
|
return False
|
|
104
93
|
|
|
105
94
|
|
|
106
|
-
|
|
95
|
+
# Seconds between a running server's re-assertions of its own registry entry
|
|
96
|
+
# (services.ui_registry.ensure). A lost entry — an older hub rewriting the
|
|
97
|
+
# file from a stale snapshot, a crash mid-write — comes back within one tick
|
|
98
|
+
# instead of leaving a server nothing can find, reap or reuse.
|
|
99
|
+
_REGISTRY_REASSERT_S = 60
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _registry_entry(port: int, project_path: str, project_name: str) -> dict:
|
|
103
|
+
# owner says who asked for this server: "session" when an IDE session
|
|
104
|
+
# start launched it (cli/hook_session_open), "user" for `c3 ui`, the
|
|
105
|
+
# hub's Open UI button and the TUI. Only session-owned servers are
|
|
106
|
+
# ever reaped automatically (ProjectManager.sweep_registry).
|
|
107
|
+
return {
|
|
108
|
+
"port": port,
|
|
109
|
+
"project_path": project_path,
|
|
110
|
+
"project_name": project_name,
|
|
111
|
+
"started_at": time.time(),
|
|
112
|
+
"pid": os.getpid(),
|
|
113
|
+
"owner": (os.environ.get("C3_UI_OWNER") or "user").strip().lower(),
|
|
114
|
+
"owner_session": (os.environ.get("C3_UI_OWNER_SESSION") or "").strip(),
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _register_session(port: int, project_path: str, project_name: str) -> dict:
|
|
119
|
+
"""Upsert this server's entry under the registry lock (2.155.0).
|
|
120
|
+
|
|
121
|
+
This used to drop every OTHER entry whose port missed a 0.3 s connect —
|
|
122
|
+
a sibling server busy re-indexing was deregistered by the next one to
|
|
123
|
+
start, and lived on as an orphan. Pruning is the hub sweep's job now,
|
|
124
|
+
and it only drops an entry whose pid is gone as well.
|
|
125
|
+
"""
|
|
126
|
+
from services import ui_registry
|
|
127
|
+
entry = _registry_entry(port, project_path, project_name)
|
|
107
128
|
with _REGISTRY_LOCK:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"port": port,
|
|
117
|
-
"project_path": project_path,
|
|
118
|
-
"project_name": project_name,
|
|
119
|
-
"started_at": time.time(),
|
|
120
|
-
"pid": os.getpid(),
|
|
121
|
-
"owner": (os.environ.get("C3_UI_OWNER") or "user").strip().lower(),
|
|
122
|
-
"owner_session": (os.environ.get("C3_UI_OWNER_SESSION") or "").strip(),
|
|
123
|
-
})
|
|
124
|
-
_registry_write(entries)
|
|
129
|
+
ui_registry.upsert(entry, _REGISTRY_FILE)
|
|
130
|
+
return entry
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _reassert_registration(entry: dict) -> bool:
|
|
134
|
+
from services import ui_registry
|
|
135
|
+
with _REGISTRY_LOCK:
|
|
136
|
+
return ui_registry.ensure(entry, _REGISTRY_FILE)
|
|
125
137
|
|
|
126
138
|
|
|
127
139
|
def _unregister_session(port: int):
|
|
140
|
+
from services import ui_registry
|
|
128
141
|
with _REGISTRY_LOCK:
|
|
129
|
-
|
|
130
|
-
entries = [e for e in entries if e.get("port") != port]
|
|
131
|
-
_registry_write(entries)
|
|
142
|
+
ui_registry.remove_ports([port], _REGISTRY_FILE)
|
|
132
143
|
|
|
133
144
|
|
|
134
145
|
def init_services(project_path: str):
|
|
@@ -4536,8 +4547,19 @@ def run_server(
|
|
|
4536
4547
|
# Fallback chain: custom meta name → folder name → parent/folder for disambiguation
|
|
4537
4548
|
_folder = _resolved.name or _resolved.parent.name or "project"
|
|
4538
4549
|
_proj_name = (_meta.get("name") or "").strip() or _folder
|
|
4539
|
-
_register_session(port, str(_resolved), _proj_name)
|
|
4550
|
+
_entry = _register_session(port, str(_resolved), _proj_name)
|
|
4540
4551
|
atexit.register(_unregister_session, port)
|
|
4552
|
+
|
|
4553
|
+
def _bg_reassert():
|
|
4554
|
+
while True:
|
|
4555
|
+
time.sleep(_REGISTRY_REASSERT_S)
|
|
4556
|
+
try:
|
|
4557
|
+
_reassert_registration(_entry)
|
|
4558
|
+
except Exception:
|
|
4559
|
+
pass
|
|
4560
|
+
|
|
4561
|
+
threading.Thread(target=_bg_reassert, daemon=True,
|
|
4562
|
+
name="c3-ui-registry-reassert").start()
|
|
4541
4563
|
except Exception:
|
|
4542
4564
|
pass
|
|
4543
4565
|
|
|
@@ -51,6 +51,24 @@ def session_id(svc) -> str:
|
|
|
51
51
|
return str(session.get("id", "") or "") or f"pid-{os.getpid()}"
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def agent_id(svc) -> str:
|
|
55
|
+
"""One caller label for explicit locks and implicit edit leases.
|
|
56
|
+
|
|
57
|
+
Runtime host identity belongs to the caller, including c3_project proxies;
|
|
58
|
+
the target project's preferred editor must not override it.
|
|
59
|
+
"""
|
|
60
|
+
from core.host import resolve_host
|
|
61
|
+
from services.agent_locks import agent_id_for
|
|
62
|
+
|
|
63
|
+
provider = getattr(svc, "ide_name", "")
|
|
64
|
+
if not isinstance(provider, str) or not provider.strip():
|
|
65
|
+
session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
|
|
66
|
+
provider = session.get("source_ide", "")
|
|
67
|
+
if not isinstance(provider, str) or not provider.strip():
|
|
68
|
+
provider = resolve_host(str(getattr(svc, "project_path", "") or "")).provider
|
|
69
|
+
return agent_id_for(session_id(svc), provider=provider)
|
|
70
|
+
|
|
71
|
+
|
|
54
72
|
def allow(svc, denial, *, tool: str, op: str, path,
|
|
55
73
|
peek: bool = False) -> str | None:
|
|
56
74
|
"""The `[c3-override:granted]` line when a live grant permits this exact
|
|
@@ -566,7 +566,8 @@ def _write_gate(svc, path: Path, rel: str, file_path: str, op: str,
|
|
|
566
566
|
"holder": holder.get("agent_id", ""),
|
|
567
567
|
"held_for_s": held_for},
|
|
568
568
|
agent_locks.refusal(holder, rel), "lock held")
|
|
569
|
-
agent_locks.lease(str(path), svc.project_path, session_id, intent=intent
|
|
569
|
+
agent_locks.lease(str(path), svc.project_path, session_id, intent=intent,
|
|
570
|
+
agent_id=_grants.agent_id(svc))
|
|
570
571
|
return None
|
|
571
572
|
|
|
572
573
|
|
|
@@ -40,7 +40,7 @@ def handle_locks(action: str, paths: str, intent: str, ttl_s: int,
|
|
|
40
40
|
"""Route c3_locks actions."""
|
|
41
41
|
project = str(svc.project_path)
|
|
42
42
|
session = _session_id(svc)
|
|
43
|
-
agent =
|
|
43
|
+
agent = _grants.agent_id(svc)
|
|
44
44
|
args = {"action": action}
|
|
45
45
|
|
|
46
46
|
cfg = al.config(project)
|
|
@@ -54,6 +54,19 @@ def _runtime_for(path: str):
|
|
|
54
54
|
return shared_cache().get(path)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
class _CallerLabelRuntime:
|
|
58
|
+
"""Use the caller's provider label without changing target session ownership."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, target, caller):
|
|
61
|
+
from cli.tools import _grants
|
|
62
|
+
|
|
63
|
+
self._target = target
|
|
64
|
+
self.ide_name = _grants.agent_id(caller).split(":", 1)[0]
|
|
65
|
+
|
|
66
|
+
def __getattr__(self, name):
|
|
67
|
+
return getattr(self._target, name)
|
|
68
|
+
|
|
69
|
+
|
|
57
70
|
def _is_registered(path: str) -> bool:
|
|
58
71
|
"""True when *path* is in the cross-project registry. Fails closed."""
|
|
59
72
|
try:
|
|
@@ -524,6 +537,11 @@ def handle_project(action, svc, finalize, *, project="", query="", file_path="",
|
|
|
524
537
|
return done(
|
|
525
538
|
f"[c3_project:error] Could not load '{resolved['name']}': {e}", "error")
|
|
526
539
|
|
|
540
|
+
# Label edit leases with the requesting host, without mutating the cached
|
|
541
|
+
# runtime or borrowing the caller's session/grant identity in the target.
|
|
542
|
+
if action == "edit":
|
|
543
|
+
fsvc = _CallerLabelRuntime(fsvc, svc)
|
|
544
|
+
|
|
527
545
|
banner = f"[c3_project:{resolved['name']}] {action}\n"
|
|
528
546
|
try:
|
|
529
547
|
body = _proxy(
|
{code_context_control-2.154.0 → code_context_control-2.155.0}/code_context_control.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.155.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
|
|
@@ -252,6 +252,7 @@ services/file_memory.py
|
|
|
252
252
|
services/git_context.py
|
|
253
253
|
services/grok_integration.py
|
|
254
254
|
services/grok_transcript.py
|
|
255
|
+
services/host_handoff.py
|
|
255
256
|
services/host_sessions.py
|
|
256
257
|
services/hub_service.py
|
|
257
258
|
services/index_store.py
|
|
@@ -314,6 +315,7 @@ services/text_index.py
|
|
|
314
315
|
services/time_tracker.py
|
|
315
316
|
services/tool_classifier.py
|
|
316
317
|
services/transcript_index.py
|
|
318
|
+
services/ui_registry.py
|
|
317
319
|
services/validation_cache.py
|
|
318
320
|
services/vector_store.py
|
|
319
321
|
services/watcher.py
|
|
@@ -430,6 +432,8 @@ tests/test_hook_session_end.py
|
|
|
430
432
|
tests/test_hook_smoke.py
|
|
431
433
|
tests/test_hook_state.py
|
|
432
434
|
tests/test_hook_utf8_stdio.py
|
|
435
|
+
tests/test_host_handoff.py
|
|
436
|
+
tests/test_host_rebind.py
|
|
433
437
|
tests/test_hub_access_routes.py
|
|
434
438
|
tests/test_hub_builtin_routes.py
|
|
435
439
|
tests/test_hub_credentials_route.py
|
|
@@ -509,6 +513,7 @@ tests/test_override_requests.py
|
|
|
509
513
|
tests/test_override_wake.py
|
|
510
514
|
tests/test_permissions.py
|
|
511
515
|
tests/test_pm_api.py
|
|
516
|
+
tests/test_project_lease_identity.py
|
|
512
517
|
tests/test_project_manager.py
|
|
513
518
|
tests/test_project_manager_merge.py
|
|
514
519
|
tests/test_project_tool.py
|
|
@@ -560,6 +565,7 @@ tests/test_token_telemetry.py
|
|
|
560
565
|
tests/test_token_tracking.py
|
|
561
566
|
tests/test_tool_registry.py
|
|
562
567
|
tests/test_ui_jsx_syntax.py
|
|
568
|
+
tests/test_ui_registry.py
|
|
563
569
|
tests/test_upgrade_and_version.py
|
|
564
570
|
tests/test_validate.py
|
|
565
571
|
tests/test_vault_write_guard.py
|
|
@@ -8,6 +8,18 @@ from dataclasses import dataclass
|
|
|
8
8
|
|
|
9
9
|
from core.ide import get_profile, load_ide_config, normalize_ide_name
|
|
10
10
|
|
|
11
|
+
# The environment variable each host puts its session id in. The MCP server
|
|
12
|
+
# reads it once at start; after a /clear it is REWRITTEN in-process by
|
|
13
|
+
# cli/mcp_server._rebind_host_session so that runtimes built later in the same
|
|
14
|
+
# process (the c3_project proxy) inherit the new id — see services.host_handoff.
|
|
15
|
+
SESSION_ENV = {"claude-code": "CLAUDE_CODE_SESSION_ID", "codex": "CODEX_THREAD_ID",
|
|
16
|
+
"grok": "GROK_SESSION_ID"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def session_env_var(provider: str | None) -> str:
|
|
20
|
+
"""The env var carrying ``provider``'s session id, or ``""``."""
|
|
21
|
+
return SESSION_ENV.get(normalize_ide_name(provider or ""), "")
|
|
22
|
+
|
|
11
23
|
|
|
12
24
|
@dataclass(frozen=True)
|
|
13
25
|
class HostContext:
|
|
@@ -35,7 +47,5 @@ def resolve_host(project_path: str = "", explicit_host: str | None = None,
|
|
|
35
47
|
# Grok is never inferred from GROK_SESSION_ID: a grok launched from a Claude
|
|
36
48
|
# Code terminal also inherits CLAUDE_CODE_SESSION_ID, so its MCP entry and
|
|
37
49
|
# hooks name the host explicitly (--host grok) instead.
|
|
38
|
-
|
|
39
|
-
"grok": "GROK_SESSION_ID"}
|
|
40
|
-
session = str(env.get(session_env.get(provider, ""), "") or "").strip()
|
|
50
|
+
session = str(env.get(SESSION_ENV.get(provider, ""), "") or "").strip()
|
|
41
51
|
return HostContext(provider, session)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-context-control"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.155.0"
|
|
8
8
|
description = "Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -170,10 +170,12 @@ def normalize_relpath(filepath, root) -> str:
|
|
|
170
170
|
return rel
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
def agent_id_for(session_id: str) -> str:
|
|
174
|
-
"""
|
|
173
|
+
def agent_id_for(session_id: str, provider: str = "claude-code") -> str:
|
|
174
|
+
"""Label the actual provider; preserve legacy Claude hook callers."""
|
|
175
|
+
from core.ide import normalize_ide_name
|
|
176
|
+
provider = normalize_ide_name(provider)
|
|
175
177
|
sid = (session_id or "").strip()
|
|
176
|
-
return f"
|
|
178
|
+
return f"{provider}:{sid[:8]}" if sid else provider
|
|
177
179
|
|
|
178
180
|
|
|
179
181
|
# ── Engine ──────────────────────────────────────────────────────────────────
|
|
@@ -496,7 +498,8 @@ def check(path, project_path=".", session_id: str = ""):
|
|
|
496
498
|
return None
|
|
497
499
|
|
|
498
500
|
|
|
499
|
-
def lease(path, project_path=".", session_id: str = "", intent: str = ""
|
|
501
|
+
def lease(path, project_path=".", session_id: str = "", intent: str = "",
|
|
502
|
+
agent_id: str = "") -> bool:
|
|
500
503
|
"""Best-effort implicit lease on one file, for c3_edit to call.
|
|
501
504
|
|
|
502
505
|
Implicit rather than explicit by design (spec §14): an explicit
|
|
@@ -512,7 +515,7 @@ def lease(path, project_path=".", session_id: str = "", intent: str = "") -> boo
|
|
|
512
515
|
return False
|
|
513
516
|
text = (intent or "").strip()[:120] or "editing via c3_edit"
|
|
514
517
|
res = store_for(project_path).acquire(
|
|
515
|
-
[path], agent_id=agent_id_for(session_id),
|
|
518
|
+
[path], agent_id=agent_id or agent_id_for(session_id),
|
|
516
519
|
session_id=session_id, intent=text)
|
|
517
520
|
return bool(res.get("granted"))
|
|
518
521
|
except Exception:
|