code-context-control 2.91.0__tar.gz → 2.92.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.91.0/code_context_control.egg-info → code_context_control-2.92.0}/PKG-INFO +1 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/c3.py +257 -49
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/oracle.html +2 -2
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_pretool_enforce.py +148 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_server.py +43 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/topbar.js +4 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0/code_context_control.egg-info}/PKG-INFO +1 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/code_context_control.egg-info/SOURCES.txt +3 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/oracle_server.py +15 -2
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/oracle_ui.html +31 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/local_session.py +72 -8
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/send.js +6 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/core.js +39 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/header.js +13 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/pyproject.toml +1 -1
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/claude_md.py +38 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/enforcement_policy.py +9 -3
- code_context_control-2.92.0/services/repo_shape.py +129 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_pretool_enforce.py +123 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_oracle_service_routes.py +56 -0
- code_context_control-2.92.0/tests/test_init_clear_preserves_user_content.py +236 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_session_bootstrap.py +69 -0
- code_context_control-2.92.0/tests/test_repo_shape.py +204 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/LICENSE +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/README.md +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/commands/common.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/commands/parser.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/docs.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/edits.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/access.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/credentials.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/index.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_read.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/hub_credentials.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/mcp_server.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/progress.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/server.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/override.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/project.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/read.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/search.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/session.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/status.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/api.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/app.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/access.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/credentials.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/core/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/core/config.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/core/ide.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/core/web_security.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/config.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/mobile_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/access_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/activity_log.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/agent_base.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/agent_locks.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/agents.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/artifact_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/auto_memory.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/background_service.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_act.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_cache.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_expr.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_failures.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_github.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_impact.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_intel.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_runner.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/compressor.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/conversation_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/credential_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/doc_index.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/embedding_index.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/error_reporting.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/file_memory.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/git_context.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/hub_service.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/indexer.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/jira_client.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/jira_links.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/mask_activation.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/mask_presets.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_graph.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_queue.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/metrics.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/notifications.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ollama_client.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/oracle_service.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/output_filter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/override_grants.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/override_policy.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/override_requests.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/override_wake.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/parser.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/project_manager.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/project_runtime.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/protocol.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/proxy_state.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/repo_map.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/retention.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/router.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/runtime.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/scanner.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/session_manager.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/session_preloader.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/subprojects.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/task_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/telemetry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/text_index.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/time_tracker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/transcript_index.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/validation_cache.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/vector_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/watcher.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/setup.cfg +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_builtin_optout.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_guard_meta.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_credential_login_kind.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_credential_ui_parity.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_override_grants.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_override_requests.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_retention.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_validate.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/backend.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/main.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.91.0 → code_context_control-2.92.0}/tui/theme.tcss +0 -0
{code_context_control-2.91.0/code_context_control.egg-info → code_context_control-2.92.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.92.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
|
|
@@ -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.92.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -845,7 +845,8 @@ def _prompt_memory_llm(project_path: str) -> None:
|
|
|
845
845
|
+ ("cloud + local fallback." if section["cloud_enabled"] else "local only (private)."))
|
|
846
846
|
|
|
847
847
|
|
|
848
|
-
def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct"
|
|
848
|
+
def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct",
|
|
849
|
+
shape=None) -> tuple[str, bool]:
|
|
849
850
|
"""Run guided post-init setup steps for Git and MCP."""
|
|
850
851
|
chosen_ide = _select_init_ide(ide_name or "auto")
|
|
851
852
|
save_config({"ide": chosen_ide}, project_path)
|
|
@@ -916,7 +917,7 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
|
|
|
916
917
|
)
|
|
917
918
|
include_wildcard = bool(wildcard_choice and wildcard_choice.startswith("Yes"))
|
|
918
919
|
|
|
919
|
-
chosen_enforcement = _prompt_enforcement(chosen_tier)
|
|
920
|
+
chosen_enforcement = _prompt_enforcement(chosen_tier, shape=shape)
|
|
920
921
|
|
|
921
922
|
_run_install_mcp(project_path, chosen_ide, mcp_mode=mcp_mode,
|
|
922
923
|
permissions=chosen_tier, include_mcp_wildcard=include_wildcard,
|
|
@@ -924,9 +925,70 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
|
|
|
924
925
|
return chosen_ide, True
|
|
925
926
|
|
|
926
927
|
|
|
927
|
-
def
|
|
928
|
+
def _assess_repo_shape(project_path: str):
|
|
929
|
+
"""Measure the project (services.repo_shape). None when it cannot be measured."""
|
|
930
|
+
try:
|
|
931
|
+
from services import repo_shape
|
|
932
|
+
return repo_shape.assess(project_path)
|
|
933
|
+
except Exception:
|
|
934
|
+
_log.debug("repo shape assessment failed", exc_info=True)
|
|
935
|
+
return None
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
def _apply_repo_shape_default(project_path: str, explicit_enforcement: str | None = None,
|
|
939
|
+
shape=None) -> None:
|
|
940
|
+
"""Say what kind of project this is, and default a prose one to ``advisory``.
|
|
941
|
+
|
|
942
|
+
Field report 2026-08-22: a 636-file project, ~95% Markdown and .docx,
|
|
943
|
+
where every symbol-aware C3 tool had nothing to act on and strict
|
|
944
|
+
discipline was paid on every turn until C3 was uninstalled. The shape
|
|
945
|
+
is printed for every project; the default is written only for the prose
|
|
946
|
+
kind, only over a tier-derived or unset mode (never over ``c3 enforce``
|
|
947
|
+
or ``--enforcement``), with provenance ``set_by: repo-shape`` so
|
|
948
|
+
``c3 enforce`` shows where it came from, and with the way back printed.
|
|
949
|
+
"""
|
|
950
|
+
try:
|
|
951
|
+
from services import enforcement_policy as ep
|
|
952
|
+
from services import repo_shape
|
|
953
|
+
except Exception:
|
|
954
|
+
return
|
|
955
|
+
if shape is None:
|
|
956
|
+
shape = _assess_repo_shape(project_path)
|
|
957
|
+
if shape is None or shape.kind == repo_shape.KIND_EMPTY:
|
|
958
|
+
return
|
|
959
|
+
print(f"\n Repo shape: {shape.describe()}")
|
|
960
|
+
mode = repo_shape.recommended_mode(shape)
|
|
961
|
+
if not mode:
|
|
962
|
+
return
|
|
963
|
+
if explicit_enforcement:
|
|
964
|
+
print(f" Prose-heavy, but --enforcement {explicit_enforcement} was given — leaving it as set.")
|
|
965
|
+
return
|
|
966
|
+
current = ep.resolve(project_path)
|
|
967
|
+
if current.set_by == ep.SET_BY_USER:
|
|
968
|
+
print(f" Prose-heavy; tool discipline stays '{current.mode}' (your choice).")
|
|
969
|
+
return
|
|
970
|
+
if current.mode == mode:
|
|
971
|
+
print(f" Prose-heavy; tool discipline is already '{mode}'.")
|
|
972
|
+
return
|
|
973
|
+
try:
|
|
974
|
+
result = ep.set_mode(mode, project_path, set_by=ep.SET_BY_SHAPE, scope="project")
|
|
975
|
+
except ValueError:
|
|
976
|
+
return
|
|
977
|
+
if result.get("deferred"):
|
|
978
|
+
return
|
|
979
|
+
print(" [!] This is a documentation project: C3's symbol-aware tools (compress/read/impact/")
|
|
980
|
+
print(f" validate/CI) have little to act on here, so tool discipline is set to '{mode}' —")
|
|
981
|
+
print(" native Edit/Write are allowed with a nudge and the edit ledger still records them.")
|
|
982
|
+
print(" `c3 enforce strict` restores the hard block; `c3 enforce` shows the setting.")
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
def _prompt_enforcement(chosen_tier: str | None, shape=None) -> str | None:
|
|
928
986
|
"""Step 5/5 — tool discipline. Returns an explicit mode, or None to derive.
|
|
929
987
|
|
|
988
|
+
``shape`` (services.repo_shape.RepoShape) moves the suggested default to
|
|
989
|
+
``advisory`` for a documentation project and says why, so the user is
|
|
990
|
+
not asked to guess what C3's symbol tools will do with 600 Markdown files.
|
|
991
|
+
|
|
930
992
|
Asked separately from the permission tier because it answers a genuinely
|
|
931
993
|
different question: the tier controls what the IDE will let the agent call,
|
|
932
994
|
this controls how hard C3's own hook pushes it toward c3_* tools. Users hit
|
|
@@ -938,8 +1000,18 @@ def _prompt_enforcement(chosen_tier: str | None) -> str | None:
|
|
|
938
1000
|
return None
|
|
939
1001
|
|
|
940
1002
|
default_mode = ep.derive_from_tier(chosen_tier) if chosen_tier else ep.MODE_ADVISORY
|
|
1003
|
+
suggested_by = "Your permission tier suggests"
|
|
1004
|
+
try:
|
|
1005
|
+
from services import repo_shape
|
|
1006
|
+
shape_mode = repo_shape.recommended_mode(shape) if shape is not None else None
|
|
1007
|
+
except Exception:
|
|
1008
|
+
shape_mode = None
|
|
1009
|
+
if shape_mode:
|
|
1010
|
+
default_mode = shape_mode
|
|
1011
|
+
suggested_by = ("This is a documentation project — C3's symbol tools have "
|
|
1012
|
+
"little to act on here. Suggested")
|
|
941
1013
|
print()
|
|
942
|
-
print(f" (
|
|
1014
|
+
print(f" ({suggested_by}: {default_mode})")
|
|
943
1015
|
choice = _prompt_choice(
|
|
944
1016
|
"Step 5/5 — Tool discipline: how hard should C3 push toward c3_* tools?",
|
|
945
1017
|
[
|
|
@@ -1085,6 +1157,7 @@ def cmd_init(args):
|
|
|
1085
1157
|
if not c3_dir.exists() or not (c3_dir / "config.json").exists():
|
|
1086
1158
|
print_header(f"Initializing C3 for: {project_path}")
|
|
1087
1159
|
_do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
|
|
1160
|
+
shape = _assess_repo_shape(project_path)
|
|
1088
1161
|
try:
|
|
1089
1162
|
from services.project_manager import ProjectManager
|
|
1090
1163
|
ProjectManager().add_project(project_path)
|
|
@@ -1101,7 +1174,11 @@ def cmd_init(args):
|
|
|
1101
1174
|
enforcement=getattr(args, "enforcement", None),
|
|
1102
1175
|
)
|
|
1103
1176
|
else:
|
|
1104
|
-
_prompt_init_steps(project_path, requested_ide,
|
|
1177
|
+
_prompt_init_steps(project_path, requested_ide,
|
|
1178
|
+
default_mode=getattr(args, "mcp_mode", "direct"), shape=shape)
|
|
1179
|
+
_apply_repo_shape_default(project_path,
|
|
1180
|
+
explicit_enforcement=getattr(args, "enforcement", None),
|
|
1181
|
+
shape=shape)
|
|
1105
1182
|
# Detect Codex CLI availability
|
|
1106
1183
|
try:
|
|
1107
1184
|
from cli.tools.delegate import check_codex
|
|
@@ -1285,11 +1362,7 @@ def cmd_init(args):
|
|
|
1285
1362
|
if c3_dir.exists():
|
|
1286
1363
|
shutil.rmtree(c3_dir)
|
|
1287
1364
|
print(" Deleted .c3/")
|
|
1288
|
-
|
|
1289
|
-
p = Path(project_path) / filename
|
|
1290
|
-
if p.exists():
|
|
1291
|
-
p.unlink()
|
|
1292
|
-
print(f" Deleted {filename}")
|
|
1365
|
+
_remove_c3_instruction_docs(project_path)
|
|
1293
1366
|
print("\n[OK] C3 project files removed.")
|
|
1294
1367
|
return
|
|
1295
1368
|
|
|
@@ -1361,9 +1434,10 @@ def cmd_init(args):
|
|
|
1361
1434
|
|
|
1362
1435
|
elif selected.startswith("Wipe"):
|
|
1363
1436
|
confirm = input(
|
|
1364
|
-
"\n WARNING: This will permanently delete .c3
|
|
1365
|
-
"
|
|
1366
|
-
"
|
|
1437
|
+
"\n WARNING: This will permanently delete .c3/, remove C3's managed\n"
|
|
1438
|
+
" block from CLAUDE.md / AGENTS.md / GEMINI.md (a file is deleted only\n"
|
|
1439
|
+
" when nothing else is in it), and remove C3 MCP configurations from\n"
|
|
1440
|
+
" your IDE. Type 'yes' to confirm: "
|
|
1367
1441
|
).strip().lower()
|
|
1368
1442
|
if confirm != "yes":
|
|
1369
1443
|
print(" Wipe cancelled.")
|
|
@@ -1375,11 +1449,7 @@ def cmd_init(args):
|
|
|
1375
1449
|
shutil.rmtree(c3_dir)
|
|
1376
1450
|
print(" Deleted .c3/")
|
|
1377
1451
|
|
|
1378
|
-
|
|
1379
|
-
p = Path(project_path) / filename
|
|
1380
|
-
if p.exists():
|
|
1381
|
-
p.unlink()
|
|
1382
|
-
print(f" Deleted {filename}")
|
|
1452
|
+
_remove_c3_instruction_docs(project_path)
|
|
1383
1453
|
|
|
1384
1454
|
print("\n[OK] C3 project files removed.")
|
|
1385
1455
|
|
|
@@ -4555,6 +4625,115 @@ def _ensure_global_session_fallbacks(server_script: str, c3_mcp_exe: str | None
|
|
|
4555
4625
|
print(f"Warning: Could not update {antigravity_path} (global fallback skipped)")
|
|
4556
4626
|
|
|
4557
4627
|
|
|
4628
|
+
# Every hook script C3 has ever registered in a settings file — the v2.42+
|
|
4629
|
+
# dispatcher plus the pre-v2.42 per-hook scripts — so uninstall recognises an
|
|
4630
|
+
# entry written by any C3 version. A user hook is anything not naming one.
|
|
4631
|
+
_C3_HOOK_SCRIPTS = (
|
|
4632
|
+
"hook_dispatch.py",
|
|
4633
|
+
"hook_access_guard.py", "hook_artifact.py", "hook_auto_snapshot.py",
|
|
4634
|
+
"hook_c3_signal.py", "hook_c3read.py", "hook_edit_ledger.py",
|
|
4635
|
+
"hook_edit_unlock.py", "hook_filter.py", "hook_ghost_files.py",
|
|
4636
|
+
"hook_pretool_enforce.py", "hook_prompt_recall.py", "hook_read.py",
|
|
4637
|
+
"hook_session_stats.py", "hook_terse_advisor.py",
|
|
4638
|
+
)
|
|
4639
|
+
|
|
4640
|
+
|
|
4641
|
+
def _is_c3_hook_command(command) -> bool:
|
|
4642
|
+
return any(script in str(command or "") for script in _C3_HOOK_SCRIPTS)
|
|
4643
|
+
|
|
4644
|
+
|
|
4645
|
+
def _is_c3_permission(rule) -> bool:
|
|
4646
|
+
"""``mcp__c3__<tool>``, ``mcp__c3__*``, or the bare ``mcp__c3`` server grant."""
|
|
4647
|
+
r = str(rule or "").strip()
|
|
4648
|
+
return r == "mcp__c3" or r.startswith("mcp__c3__")
|
|
4649
|
+
|
|
4650
|
+
|
|
4651
|
+
def _c3_references_in_settings(settings: dict) -> list:
|
|
4652
|
+
"""Every C3-owned entry present in a settings dict: hook commands (named
|
|
4653
|
+
by event) and permission rules. Used to decide whether there is anything
|
|
4654
|
+
to remove and, after writing, to check that it was actually removed."""
|
|
4655
|
+
refs: list = []
|
|
4656
|
+
hooks = settings.get("hooks")
|
|
4657
|
+
if isinstance(hooks, dict):
|
|
4658
|
+
for event, groups in hooks.items():
|
|
4659
|
+
for group in groups or []:
|
|
4660
|
+
if not isinstance(group, dict):
|
|
4661
|
+
continue
|
|
4662
|
+
for hk in group.get("hooks") or []:
|
|
4663
|
+
if isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")):
|
|
4664
|
+
refs.append(f"hooks.{event}")
|
|
4665
|
+
perms = settings.get("permissions")
|
|
4666
|
+
if isinstance(perms, dict):
|
|
4667
|
+
for key in ("allow", "deny", "ask"):
|
|
4668
|
+
for rule in perms.get(key) or []:
|
|
4669
|
+
if _is_c3_permission(rule):
|
|
4670
|
+
refs.append(f"permissions.{key}:{rule}")
|
|
4671
|
+
if "c3" in (settings.get("enabledMcpjsonServers") or []):
|
|
4672
|
+
refs.append("enabledMcpjsonServers:c3")
|
|
4673
|
+
return refs
|
|
4674
|
+
|
|
4675
|
+
|
|
4676
|
+
def _strip_c3_from_settings(settings: dict) -> dict:
|
|
4677
|
+
"""Remove every C3-owned entry from a Claude Code settings dict (in place,
|
|
4678
|
+
and returned). Touches ONLY what C3 wrote: hook entries whose command runs
|
|
4679
|
+
a C3 hook script — any event, any matcher; the previous cleanup looked at
|
|
4680
|
+
three PostToolUse matchers from the pre-v2.42 layout and nothing else, so
|
|
4681
|
+
PreToolUse/Stop/UserPromptSubmit and the whole ``permissions.allow`` list
|
|
4682
|
+
survived an "uninstall" — plus ``mcp__c3__*`` permission rules and the
|
|
4683
|
+
``c3`` MCP-server enablement. User hooks, user permission rules and every
|
|
4684
|
+
other key are left exactly as found; containers emptied by the removal
|
|
4685
|
+
are dropped so a file C3 created alone ends up empty (and the caller
|
|
4686
|
+
deletes it) rather than as ``{"hooks": {}}``.
|
|
4687
|
+
"""
|
|
4688
|
+
hooks = settings.get("hooks")
|
|
4689
|
+
if isinstance(hooks, dict):
|
|
4690
|
+
for event in list(hooks.keys()):
|
|
4691
|
+
kept_groups = []
|
|
4692
|
+
for group in hooks.get(event) or []:
|
|
4693
|
+
if not isinstance(group, dict):
|
|
4694
|
+
kept_groups.append(group)
|
|
4695
|
+
continue
|
|
4696
|
+
entries = group.get("hooks") or []
|
|
4697
|
+
if not any(isinstance(hk, dict) and _is_c3_hook_command(hk.get("command"))
|
|
4698
|
+
for hk in entries):
|
|
4699
|
+
kept_groups.append(group) # not ours — untouched
|
|
4700
|
+
continue
|
|
4701
|
+
kept = [hk for hk in entries
|
|
4702
|
+
if not (isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")))]
|
|
4703
|
+
if kept:
|
|
4704
|
+
group = dict(group)
|
|
4705
|
+
group["hooks"] = kept
|
|
4706
|
+
kept_groups.append(group)
|
|
4707
|
+
if kept_groups:
|
|
4708
|
+
hooks[event] = kept_groups
|
|
4709
|
+
else:
|
|
4710
|
+
del hooks[event]
|
|
4711
|
+
if not hooks:
|
|
4712
|
+
del settings["hooks"]
|
|
4713
|
+
|
|
4714
|
+
perms = settings.get("permissions")
|
|
4715
|
+
if isinstance(perms, dict):
|
|
4716
|
+
for key in ("allow", "deny", "ask"):
|
|
4717
|
+
rules = perms.get(key)
|
|
4718
|
+
if isinstance(rules, list) and any(_is_c3_permission(r) for r in rules):
|
|
4719
|
+
kept_rules = [r for r in rules if not _is_c3_permission(r)]
|
|
4720
|
+
if kept_rules:
|
|
4721
|
+
perms[key] = kept_rules
|
|
4722
|
+
else:
|
|
4723
|
+
del perms[key]
|
|
4724
|
+
if not perms:
|
|
4725
|
+
del settings["permissions"]
|
|
4726
|
+
|
|
4727
|
+
enabled = settings.get("enabledMcpjsonServers")
|
|
4728
|
+
if isinstance(enabled, list) and "c3" in enabled:
|
|
4729
|
+
enabled = [s for s in enabled if s != "c3"]
|
|
4730
|
+
if enabled:
|
|
4731
|
+
settings["enabledMcpjsonServers"] = enabled
|
|
4732
|
+
else:
|
|
4733
|
+
del settings["enabledMcpjsonServers"]
|
|
4734
|
+
return settings
|
|
4735
|
+
|
|
4736
|
+
|
|
4558
4737
|
def _uninstall_mcp_all(project_path: str, include_global: bool = True):
|
|
4559
4738
|
"""Remove C3 MCP server configurations from all supported IDEs.
|
|
4560
4739
|
|
|
@@ -4658,37 +4837,28 @@ def _uninstall_mcp_all(project_path: str, include_global: bool = True):
|
|
|
4658
4837
|
with open(settings_path, 'r', encoding="utf-8") as f:
|
|
4659
4838
|
settings = json.load(f)
|
|
4660
4839
|
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
c3_hook_files = {"hook_filter.py", "hook_read.py", "hook_c3read.py", "hook_dispatch.py"}
|
|
4665
|
-
for h in hooks:
|
|
4666
|
-
if h.get("matcher") in ("Bash", "Read", "mcp__c3__c3_read"):
|
|
4667
|
-
h["hooks"] = [hook for hook in h.get("hooks", [])
|
|
4668
|
-
if not any(f in hook.get("command", "") for f in c3_hook_files)]
|
|
4669
|
-
if h["hooks"]:
|
|
4670
|
-
new_hooks.append(h)
|
|
4671
|
-
else:
|
|
4672
|
-
new_hooks.append(h)
|
|
4673
|
-
|
|
4674
|
-
if new_hooks:
|
|
4675
|
-
settings["hooks"]["PostToolUse"] = new_hooks
|
|
4676
|
-
elif "hooks" in settings and "PostToolUse" in settings["hooks"]:
|
|
4677
|
-
del settings["hooks"]["PostToolUse"]
|
|
4678
|
-
if not settings["hooks"]:
|
|
4679
|
-
del settings["hooks"]
|
|
4680
|
-
|
|
4681
|
-
# Remove enabled server
|
|
4682
|
-
if "enabledMcpjsonServers" in settings and "c3" in settings["enabledMcpjsonServers"]:
|
|
4683
|
-
settings["enabledMcpjsonServers"].remove("c3")
|
|
4684
|
-
|
|
4685
|
-
if not settings:
|
|
4686
|
-
settings_path.unlink()
|
|
4687
|
-
print(f" Deleted empty {settings_path}")
|
|
4840
|
+
before = _c3_references_in_settings(settings)
|
|
4841
|
+
if not before:
|
|
4842
|
+
print(f" No C3 entries in {settings_path}")
|
|
4688
4843
|
else:
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4844
|
+
settings = _strip_c3_from_settings(settings)
|
|
4845
|
+
if not settings:
|
|
4846
|
+
settings_path.unlink()
|
|
4847
|
+
print(f" Deleted empty {settings_path}")
|
|
4848
|
+
else:
|
|
4849
|
+
with open(settings_path, 'w', encoding="utf-8") as f:
|
|
4850
|
+
json.dump(settings, f, indent=2)
|
|
4851
|
+
# Postcondition: re-read what is on disk and report
|
|
4852
|
+
# what is true, not what was attempted.
|
|
4853
|
+
with open(settings_path, 'r', encoding="utf-8") as f:
|
|
4854
|
+
remaining = _c3_references_in_settings(json.load(f))
|
|
4855
|
+
if remaining:
|
|
4856
|
+
shown = ", ".join(remaining[:5]) + (" ..." if len(remaining) > 5 else "")
|
|
4857
|
+
print(f" [!] C3 entries remain in {settings_path} "
|
|
4858
|
+
f"({len(remaining)}): {shown}")
|
|
4859
|
+
else:
|
|
4860
|
+
print(f" Removed C3 hooks/settings from {settings_path} "
|
|
4861
|
+
f"({len(before)} entries)")
|
|
4692
4862
|
except Exception as e:
|
|
4693
4863
|
print(f" Warning: Could not update {settings_path}: {e}")
|
|
4694
4864
|
|
|
@@ -4872,6 +5042,44 @@ def _instruction_documents_for_project() -> list[tuple[str, str]]:
|
|
|
4872
5042
|
]
|
|
4873
5043
|
|
|
4874
5044
|
|
|
5045
|
+
def _remove_c3_instruction_docs(project_path: str) -> None:
|
|
5046
|
+
"""Take C3's managed block OUT of every instruction doc it ever wrote.
|
|
5047
|
+
|
|
5048
|
+
Uninstall counterpart of ``_sync_project_instruction_docs``. Before
|
|
5049
|
+
v2.92 this was a bare ``unlink()`` of CLAUDE.md / AGENTS.md / GEMINI.md —
|
|
5050
|
+
which, in a project whose CLAUDE.md also carried another tool's managed
|
|
5051
|
+
block (``<!-- YEP:BEGIN -->``) or the user's own notes, destroyed content
|
|
5052
|
+
C3 never owned, with no warning and no way back unless git had it.
|
|
5053
|
+
Same rule every regeneration path already follows: C3 owns its slice,
|
|
5054
|
+
everything outside the markers is preserved. A file is deleted only when
|
|
5055
|
+
the block was all there was.
|
|
5056
|
+
"""
|
|
5057
|
+
from services.claude_md import strip_c3_block
|
|
5058
|
+
|
|
5059
|
+
for filename, _ in _instruction_documents_for_project():
|
|
5060
|
+
p = Path(project_path) / filename
|
|
5061
|
+
if not p.exists():
|
|
5062
|
+
continue
|
|
5063
|
+
try:
|
|
5064
|
+
existing = p.read_text(encoding="utf-8", errors="replace")
|
|
5065
|
+
except OSError as exc:
|
|
5066
|
+
print(f" Warning: Could not read {filename}: {exc}")
|
|
5067
|
+
continue
|
|
5068
|
+
remainder = strip_c3_block(existing)
|
|
5069
|
+
if remainder is None:
|
|
5070
|
+
print(f" Kept {filename} (no C3 block in it — not ours to delete)")
|
|
5071
|
+
elif remainder.strip():
|
|
5072
|
+
try:
|
|
5073
|
+
p.write_text(remainder, encoding="utf-8")
|
|
5074
|
+
except OSError as exc:
|
|
5075
|
+
print(f" Warning: Could not update {filename}: {exc}")
|
|
5076
|
+
continue
|
|
5077
|
+
print(f" Removed C3 block from {filename} (kept the rest of the file)")
|
|
5078
|
+
else:
|
|
5079
|
+
p.unlink()
|
|
5080
|
+
print(f" Deleted {filename}")
|
|
5081
|
+
|
|
5082
|
+
|
|
4875
5083
|
_LEGACY_INSTRUCTION_DOCS = ("GEMINI.md",) # Gemini CLI profile removed in v2.52
|
|
4876
5084
|
|
|
4877
5085
|
|
|
@@ -330,10 +330,10 @@ curl -X POST \
|
|
|
330
330
|
<tr><td><code>c3 oracle serve --install</code></td> <td>Register the Oracle as a login/startup service — no terminal window — and start it now. Windows: Task Scheduler (Run-key fallback); macOS: launchd; Linux: systemd user unit</td></tr>
|
|
331
331
|
<tr><td><code>c3 oracle serve --uninstall</code></td> <td>Remove the startup registration (a running Oracle keeps running)</td></tr>
|
|
332
332
|
<tr><td><code>c3 oracle serve --status</code></td> <td>Installed? Running? Port, bind host, URL, and the launcher log path</td></tr>
|
|
333
|
-
<tr><td><code>c3 oracle open</code></td> <td>Sign in to a running dashboard via a single-use URL</td></tr>
|
|
333
|
+
<tr><td><code>c3 oracle open</code></td> <td>Sign in to a running dashboard via a single-use URL (the hub's <strong>Open Oracle</strong> button does the same thing)</td></tr>
|
|
334
334
|
</tbody>
|
|
335
335
|
</table>
|
|
336
|
-
<p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">The Hub exposes the same controls under <strong>Settings → Oracle service</strong> (Install / Uninstall / Start / Stop / Open). Starting the Oracle from there also fills in the Hub's <em>Oracle URL</em> when it is empty, so the Open Oracle button appears in the top bar
|
|
336
|
+
<p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">The Hub exposes the same controls under <strong>Settings → Oracle service</strong> (Install / Uninstall / Start / Stop / Open). Starting the Oracle from there also fills in the Hub's <em>Oracle URL</em> when it is empty, so the Open Oracle button appears in the top bar. That button opens a <strong>signed-in</strong> dashboard: it redeems the Oracle's owner-only bootstrap key for you. Reaching the dashboard by pasting its URL instead leaves it read-only — the page renders and the header looks healthy, but chat, Save and Test Ollama answer <code>401 unauthorized</code>.</p>
|
|
337
337
|
</section>
|
|
338
338
|
|
|
339
339
|
<hr class="divider">
|
|
@@ -35,6 +35,7 @@ advisory path instead of granting stale unlocks.
|
|
|
35
35
|
Supports both Claude Code and Gemini CLI via _hook_utils.
|
|
36
36
|
"""
|
|
37
37
|
import json
|
|
38
|
+
import re
|
|
38
39
|
import sys
|
|
39
40
|
from datetime import datetime, timezone
|
|
40
41
|
from pathlib import Path
|
|
@@ -361,6 +362,131 @@ def _vault_denial(tool_name: str, tool_input: dict) -> dict | None:
|
|
|
361
362
|
return None
|
|
362
363
|
|
|
363
364
|
|
|
365
|
+
def _outside_project(base: Path, tool_input: dict) -> bool:
|
|
366
|
+
"""True when the call targets a path outside the project root.
|
|
367
|
+
|
|
368
|
+
Tool discipline exists to keep THIS project's edit ledger complete and
|
|
369
|
+
its index warm. A scratch file in /tmp or a file in some other checkout
|
|
370
|
+
has no ledger here, so a block buys nothing and costs a workaround, and
|
|
371
|
+
a hint is noise (ISSUE-2 of the 2026-08 field report). Relative paths
|
|
372
|
+
resolve against the project root, which is also the hook's cwd. A path
|
|
373
|
+
that cannot be resolved counts as inside — the existing behaviour.
|
|
374
|
+
"""
|
|
375
|
+
raw = str(tool_input.get("file_path") or tool_input.get("notebook_path")
|
|
376
|
+
or tool_input.get("path") or "")
|
|
377
|
+
if not raw:
|
|
378
|
+
return False
|
|
379
|
+
try:
|
|
380
|
+
target = Path(raw)
|
|
381
|
+
if not target.is_absolute():
|
|
382
|
+
target = base / target
|
|
383
|
+
# canonical_key: resolved, forward-slash, casefolded — the one path
|
|
384
|
+
# identity the unlock map and Access Guard already agree on.
|
|
385
|
+
target_key = canonical_key(target)
|
|
386
|
+
root_key = canonical_key(base).rstrip("/")
|
|
387
|
+
except (OSError, RuntimeError, ValueError):
|
|
388
|
+
return False
|
|
389
|
+
return not (target_key == root_key or target_key.startswith(root_key + "/"))
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# ── Sub-agent tool grants ──────────────────────────────────────────────────
|
|
393
|
+
# Claude Code sends `agent_type` (plus `agent_id` inside a sub-agent) with
|
|
394
|
+
# every hook payload. A sub-agent whose definition lists `tools:` gets ONLY
|
|
395
|
+
# those tools; if none of them reaches the c3 MCP server, the agent has no
|
|
396
|
+
# c3_edit to be redirected to, and a strict deny just pushes the write onto
|
|
397
|
+
# a shell heredoc that the ledger never sees (field report 2026-08-22,
|
|
398
|
+
# ISSUE-1: four self-reports in one session). For that agent only, the
|
|
399
|
+
# block degrades to the advisory nudge. An agent with no `tools:` line
|
|
400
|
+
# inherits every tool and stays strict; an agent we cannot find stays strict
|
|
401
|
+
# but the deny names the fix.
|
|
402
|
+
|
|
403
|
+
_C3_GRANT_PREFIXES = ("mcp__c3__", "c3_")
|
|
404
|
+
_C3_GRANT_EXACT = frozenset({"*", "mcp__*", "mcp__c3"})
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _agent_definition(base: Path, agent_type: str) -> Path | None:
|
|
408
|
+
"""The agent file for ``agent_type``: project ``.claude/agents`` first,
|
|
409
|
+
then the user's. Plugin-scoped or path-like names are not looked up."""
|
|
410
|
+
name = str(agent_type or "").strip()
|
|
411
|
+
if not name or any(ch in name for ch in r"/\:") or name.startswith("."):
|
|
412
|
+
return None
|
|
413
|
+
roots = [base / ".claude" / "agents"]
|
|
414
|
+
try:
|
|
415
|
+
roots.append(Path.home() / ".claude" / "agents")
|
|
416
|
+
except Exception:
|
|
417
|
+
pass
|
|
418
|
+
for root in roots:
|
|
419
|
+
if not root.is_dir():
|
|
420
|
+
continue
|
|
421
|
+
direct = root / f"{name}.md"
|
|
422
|
+
if direct.is_file():
|
|
423
|
+
return direct
|
|
424
|
+
nested = next((p for p in root.rglob(f"{name}.md") if p.is_file()), None)
|
|
425
|
+
if nested is not None:
|
|
426
|
+
return nested
|
|
427
|
+
return None
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def _frontmatter_tools(text: str) -> list | None:
|
|
431
|
+
"""The ``tools:`` grant from an agent file's YAML frontmatter.
|
|
432
|
+
|
|
433
|
+
``None`` when there is no frontmatter or no ``tools:`` key — the agent
|
|
434
|
+
inherits every tool. Handles the inline form (``tools: Read, Write`` or
|
|
435
|
+
``tools: [Read, Write]``) and the list form (``- Read`` lines).
|
|
436
|
+
"""
|
|
437
|
+
lines = text.splitlines()
|
|
438
|
+
if not lines or lines[0].strip() != "---":
|
|
439
|
+
return None
|
|
440
|
+
body = []
|
|
441
|
+
for line in lines[1:]:
|
|
442
|
+
if line.strip() == "---":
|
|
443
|
+
break
|
|
444
|
+
body.append(line)
|
|
445
|
+
for i, line in enumerate(body):
|
|
446
|
+
m = re.match(r"^tools\s*:\s*(.*)$", line)
|
|
447
|
+
if not m:
|
|
448
|
+
continue
|
|
449
|
+
rest = m.group(1).strip()
|
|
450
|
+
if rest and rest not in ("|", ">"):
|
|
451
|
+
rest = rest.strip("[]")
|
|
452
|
+
return [t.strip().strip("'\"") for t in rest.split(",") if t.strip()]
|
|
453
|
+
tools = []
|
|
454
|
+
for nxt in body[i + 1:]:
|
|
455
|
+
lm = re.match(r"^\s+-\s*(.*)$", nxt)
|
|
456
|
+
if not lm:
|
|
457
|
+
break
|
|
458
|
+
tools.append(lm.group(1).strip().strip("'\""))
|
|
459
|
+
return tools
|
|
460
|
+
return None
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def _grant_reaches_c3(tools: list) -> bool:
|
|
464
|
+
for t in tools:
|
|
465
|
+
t = str(t).strip()
|
|
466
|
+
if t in _C3_GRANT_EXACT or t.startswith(_C3_GRANT_PREFIXES):
|
|
467
|
+
return True
|
|
468
|
+
return False
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _agent_cannot_comply(payload: dict, base: Path) -> str | None:
|
|
472
|
+
"""A one-line reason when the calling agent provably has no c3 tool to
|
|
473
|
+
use instead, else None (keep strict). Any failure → None."""
|
|
474
|
+
agent_type = str(payload.get("agent_type") or "").strip()
|
|
475
|
+
if not agent_type:
|
|
476
|
+
return None
|
|
477
|
+
try:
|
|
478
|
+
definition = _agent_definition(base, agent_type)
|
|
479
|
+
if definition is None:
|
|
480
|
+
return None
|
|
481
|
+
tools = _frontmatter_tools(definition.read_text(encoding="utf-8", errors="replace"))
|
|
482
|
+
except Exception:
|
|
483
|
+
return None
|
|
484
|
+
if tools is None or _grant_reaches_c3(tools):
|
|
485
|
+
return None
|
|
486
|
+
return (f"agent '{agent_type}' ({definition.name}) lists tools: with no "
|
|
487
|
+
f"mcp__c3__* entry, so it has no c3_edit to use")
|
|
488
|
+
|
|
489
|
+
|
|
364
490
|
def _override_allows(base: Path, tool_name: str, tool_input: dict,
|
|
365
491
|
session_id: str) -> str | None:
|
|
366
492
|
"""A live discipline grant for this exact write, or None (spec §5).
|
|
@@ -401,6 +527,11 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
401
527
|
if vault:
|
|
402
528
|
return vault
|
|
403
529
|
|
|
530
|
+
# Scope: this hook governs the project's own files. Anything outside the
|
|
531
|
+
# root passes through in every mode — nothing here to keep a ledger of.
|
|
532
|
+
if _outside_project(base, tool_input):
|
|
533
|
+
return None
|
|
534
|
+
|
|
404
535
|
policy = _resolve_policy(base)
|
|
405
536
|
mode = getattr(policy, "mode", None) or "strict"
|
|
406
537
|
ttl_s = getattr(policy, "signal_ttl_s", _SIGNAL_MAX_AGE_SECS)
|
|
@@ -444,6 +575,16 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
444
575
|
granted = _override_allows(base, tool_name, tool_input, session_id)
|
|
445
576
|
if granted:
|
|
446
577
|
return _with_warnings({"additionalContext": granted}, policy)
|
|
578
|
+
cannot = _agent_cannot_comply(payload, base)
|
|
579
|
+
if cannot:
|
|
580
|
+
return _with_warnings({
|
|
581
|
+
"additionalContext": (
|
|
582
|
+
f"[c3:hint] Native `{tool_name}` allowed: {cannot}. The edit "
|
|
583
|
+
f"ledger still records this write. To keep strict discipline "
|
|
584
|
+
f"for this agent, add `mcp__c3__c3_edit` (or `mcp__c3`) to its "
|
|
585
|
+
f"tools: list, or drop the tools: line so it inherits every tool."
|
|
586
|
+
)
|
|
587
|
+
}, policy)
|
|
447
588
|
_record_block(tool_name, tool_input, session_id, base)
|
|
448
589
|
reason = (
|
|
449
590
|
f"[c3:enforce] Native `{tool_name}` is blocked to preserve the edit "
|
|
@@ -451,6 +592,13 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
|
|
|
451
592
|
f"If this is getting in your way, the user can run "
|
|
452
593
|
f"`c3 enforce advisory`."
|
|
453
594
|
)
|
|
595
|
+
agent_type = str(payload.get("agent_type") or "").strip()
|
|
596
|
+
if agent_type:
|
|
597
|
+
reason += (
|
|
598
|
+
f" Running as agent '{agent_type}': if its tools: grant has no "
|
|
599
|
+
f"mcp__c3__* entry it cannot follow this — add `mcp__c3__c3_edit` "
|
|
600
|
+
f"to the grant, or drop the tools: line so it inherits every tool."
|
|
601
|
+
)
|
|
454
602
|
return {
|
|
455
603
|
"hookSpecificOutput": {
|
|
456
604
|
"hookEventName": "PreToolUse",
|
|
@@ -25,7 +25,7 @@ import urllib.request
|
|
|
25
25
|
import webbrowser
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
|
|
28
|
-
from flask import Flask, jsonify, request, send_from_directory
|
|
28
|
+
from flask import Flask, jsonify, redirect, request, send_from_directory
|
|
29
29
|
|
|
30
30
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
31
31
|
|
|
@@ -3464,6 +3464,48 @@ def api_oracle_service_stop():
|
|
|
3464
3464
|
return jsonify(_oracle_service().stop())
|
|
3465
3465
|
|
|
3466
3466
|
|
|
3467
|
+
@app.route("/api/oracle/open")
|
|
3468
|
+
def api_oracle_open():
|
|
3469
|
+
"""Redirect the browser to a *signed-in* Oracle dashboard.
|
|
3470
|
+
|
|
3471
|
+
Plain ``GET /`` on the Oracle is read-only by design (#31): the session
|
|
3472
|
+
cookie is only issued in exchange for a single-use bootstrap code, and the
|
|
3473
|
+
owner-only ``bootstrap.key`` is what proves the caller is the same OS user
|
|
3474
|
+
as the server. Since the Oracle became a login service nothing redeems
|
|
3475
|
+
that key for the browser, so the top-bar link landed on a dashboard where
|
|
3476
|
+
every read looked healthy and every write — chat, Save settings, Test
|
|
3477
|
+
Ollama — answered ``401 unauthorized``.
|
|
3478
|
+
|
|
3479
|
+
The hub runs as the owning user, so it can redeem the key on the browser's
|
|
3480
|
+
behalf. It reaches no further than ``c3 oracle open`` already does. Any
|
|
3481
|
+
failure falls back to the plain URL, i.e. the previous behavior.
|
|
3482
|
+
"""
|
|
3483
|
+
base = (_read_hub_config().get("oracle_url") or "").strip().rstrip("/")
|
|
3484
|
+
if not base:
|
|
3485
|
+
base = _oracle_service().url()
|
|
3486
|
+
try:
|
|
3487
|
+
from oracle.config import ORACLE_DIR
|
|
3488
|
+
from oracle.services import local_session
|
|
3489
|
+
key = local_session.read_bootstrap_key(ORACLE_DIR)
|
|
3490
|
+
except Exception:
|
|
3491
|
+
key = ""
|
|
3492
|
+
if not key:
|
|
3493
|
+
return redirect(base) # Oracle not running, or key not published yet
|
|
3494
|
+
try:
|
|
3495
|
+
req = urllib.request.Request(
|
|
3496
|
+
f"{base}/api/session/bootstrap",
|
|
3497
|
+
data=json.dumps({"key": key}).encode("utf-8"),
|
|
3498
|
+
headers={"Content-Type": "application/json"},
|
|
3499
|
+
method="POST",
|
|
3500
|
+
)
|
|
3501
|
+
with urllib.request.urlopen(req, timeout=10) as r:
|
|
3502
|
+
payload = json.loads(r.read().decode("utf-8"))
|
|
3503
|
+
return redirect(payload.get("url") or base)
|
|
3504
|
+
except Exception as e:
|
|
3505
|
+
logging.getLogger("c3.hub").warning("oracle sign-in mint failed: %s", e)
|
|
3506
|
+
return redirect(base)
|
|
3507
|
+
|
|
3508
|
+
|
|
3467
3509
|
# ─── Routes: sessions ────────────────────────────────────────────────────────
|
|
3468
3510
|
|
|
3469
3511
|
@app.route("/api/sessions/start", methods=["POST"])
|