code-context-control 2.115.0__tar.gz → 2.118.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.115.0 → code_context_control-2.118.0}/PKG-INFO +1 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/c3.py +134 -33
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/commands/parser.py +21 -4
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/credentials.html +31 -10
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_server.py +79 -7
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_access.js +140 -5
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_credentials.js +13 -5
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/mcp_server.py +11 -5
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/server.py +13 -9
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/access.js +51 -7
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/credentials.js +13 -5
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/PKG-INFO +1 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/mobile_api.py +57 -7
- {code_context_control-2.115.0 → code_context_control-2.118.0}/pyproject.toml +1 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/access_guard.py +198 -73
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/claude_md.py +1 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/credential_store.py +155 -36
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/override_grants.py +224 -35
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/override_policy.py +84 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/override_requests.py +113 -21
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/session_benchmark.py +31 -8
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_builtin_optout.py +17 -4
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_guard_meta.py +7 -1
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_builtin_modes.py +91 -5
- code_context_control-2.118.0/tests/test_credential_login_kind.py +365 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_credential_ui_parity.py +40 -4
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_override_routes.py +116 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_override_grants.py +168 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_override_requests.py +89 -0
- code_context_control-2.115.0/tests/test_credential_login_kind.py +0 -191
- {code_context_control-2.115.0 → code_context_control-2.118.0}/LICENSE +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/README.md +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/_shell_writes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/commands/common.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/docs.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/edits.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/access.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/bitbucket.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/getting-started.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/index.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/masking.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/oracle.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/shared.css +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/tools.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/guide/workflow.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_access_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_artifact.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_dispatch.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_prompt_recall.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_read.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/app.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/add_project.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/config_editor.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_health.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_panel.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_tasks.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/drill_views.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/global_search.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_ci.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_locks.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/hub_tokens.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/mcp_manager.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/modals.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/project_card.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/project_tree.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/session_drawer.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/settings_modal.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/sidebar.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/summary_bar.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/task_board.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/toasts.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/components/topbar.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui/state.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/hub_ui.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/progress.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/_grants.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/artifacts.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/ci.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/edit_verify.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/federate.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/jira.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/locks.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/override.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/project.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/read.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/search.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/session.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/shell_job.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/shell_nudge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/shell_parsers.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/shell_render.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/status.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/tasks.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/api.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/app.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/enforcement.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/jira.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/components/tasks.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/pm_shared.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/SOURCES.txt +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/core/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/core/config.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/core/ide.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/core/mcp_toml.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/core/web_security.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/config.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/mcp_oracle.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/oracle_ui.html +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/activity_reporter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/api_auth.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/chat_poll.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/discovery_audit.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/local_session.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/tool_executor.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/services/tool_registry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/activity.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/agents.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/app.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/busy.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/conversations.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/input.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/markdown.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/send.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/stream_renderer.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/chat/toolbar.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/core.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/crossgraph.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/header.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/insights.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/projects.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/qrcode.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/settings.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/suggestions.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/oracle/ui/theme_tabs.js +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/access_telemetry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/activity_log.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/agent_base.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/agent_locks.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/agents.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/artifact_defs.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/artifact_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/auto_memory.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/background_service.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/search_eval.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bench/shell_eval.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bitbucket_client.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_act.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_cache.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_expr.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_failures.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_github.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_impact.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_intel.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_runner.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ci_workflow.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/circuit_breaker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/compressor.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/conversation_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/cred_audit.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/cred_telemetry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/doc_index.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/embedding_index.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/enforcement_policy.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/error_reporting.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/file_memory.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/git_context.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/hub_service.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/index_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/indexer.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/jira_client.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/jira_cloud.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/jira_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/jira_data_center.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/jira_links.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/lexical_index.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/mask_activation.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/mask_mirror.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/mask_presets.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_distiller.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_graph.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_queue.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/metrics.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/notifications.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ollama_bridge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ollama_client.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/ollama_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/oracle_service.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/output_filter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/override_wake.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/parser.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/project_manager.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/project_runtime.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/protocol.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/proxy_state.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/repo_map.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/repo_shape.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/reranker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/retention.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/retrieval.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/router.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/runtime.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/scanner.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/session_manager.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/session_preloader.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/shell_jobs.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/shell_output.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/subprojects.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/task_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/telemetry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/text_index.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/time_tracker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/transcript_index.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/validation_cache.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/vector_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/watcher.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/services/win_subprocess.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/setup.cfg +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_guard_shell_project.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_guard_surfaces.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_access_guard_wiring.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_activity_reporter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_agent_locks.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_antigravity_transition.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_artifact_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_artifact_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_background_service.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_bitbucket_config_fallback.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_chat_poll.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_act.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_cache.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_expr.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_impact.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_intel.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_runner.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ci_workflow.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_circuit_breaker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_claude_md_merge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_claude_md_updater.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_compressor_large_file.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_confirm_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_confirm_guard_wiring.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_cooccurrence_bounds.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_cred_audit.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_cred_telemetry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_credential_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_credentials_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_credentials_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_creds_cli_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_delegate_cascade.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_delegate_version_probe.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_edit_ledger_deadline.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_edit_ledger_hook.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_edit_locking.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_edit_verify.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_embedding_index_deadlock.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_enforcement_policy.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_enforcement_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_env_parser.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_filter_backoff.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ghost_generation.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_git_branch_awareness.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_access_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_codex_compat.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_dispatch.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_pretool_enforce.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_prompt_recall.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_state.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hook_utf8_stdio.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_credentials_route.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_credentials_routes_write.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_enforcement_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_inspect_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_locks_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_oracle_service_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_hub_subproject_links.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ide_workflow_adaptation.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_index_cap_not_hardcoded.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_init_clear_preserves_user_content.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_init_scan.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_install_mcp_entrypoint.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_cli_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_client.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_config_fallback.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_links.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_jira_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_lazy_store_init.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mask_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mask_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mask_surfaces.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mcp_host_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mcp_memory_timeout.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mcp_toml.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_memory_distiller.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_memory_queue.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mobile_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mobile_extras.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mobile_override_routes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_mobile_security_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_no_stale_model_pins.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_notification_dedup.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ollama_credentials.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_api_auth.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_apikey_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_c3_bridge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_chat_engine.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_chat_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_discovery_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_discovery_audit.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_health_probe.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_local_auth.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_ollama_bridge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_scanner_cache.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_security_fixes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_session_bootstrap.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_subproject_awareness.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_oracle_ui_bundle.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_override_grants_mcp.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_override_wake.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_pm_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_project_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_read_coercion.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_read_edit_parity.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_related_facts.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_repo_map.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_repo_shape.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_response_boilerplate.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_retention.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_review_digest.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_eval.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p1.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p2.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p2b.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p3.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p4.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_search_p5.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_service_durability.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_budget_s1.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_creds.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_eval.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_jobs_s3.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_nudge_s4.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_output.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_parsers_s2.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_robustness.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_telemetry_s0.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_write_ledger.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_shell_writes.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subproject_clear_scope.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subproject_depth_consumers.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subproject_exclusion.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subproject_federation.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subproject_linkage_api.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_subprojects.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_task_store.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_task_tool.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_time_tracker.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_token_telemetry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_token_tracking.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_tool_registry.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_ui_jsx_syntax.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_upgrade_and_version.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_validate.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_vault_write_guard.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_version_sync.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_web_security.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/backend.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/main.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.115.0 → code_context_control-2.118.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.118.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.118.0"
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -6338,7 +6338,16 @@ def _creds_entry_line(name: str, entry: dict) -> str:
|
|
|
6338
6338
|
return " ".join(parts)
|
|
6339
6339
|
|
|
6340
6340
|
|
|
6341
|
-
|
|
6341
|
+
#: Fields prompted with getpass instead of input(). This list was missing
|
|
6342
|
+
#: `password` and `totp_secret` from v2.90.0 to v2.118.0, so
|
|
6343
|
+
#: `c3 creds set X --type login` echoed the password to the terminal — both
|
|
6344
|
+
#: JS UIs masked it and nothing asserted the CLI. tests/test_creds_cli.py now
|
|
6345
|
+
#: derives the expected set from _SCHEMAS, so a future kind cannot reopen it.
|
|
6346
|
+
_CREDS_HIDDEN_FIELDS = {"number", "cvc", "ssn", "password", "private_key",
|
|
6347
|
+
"passphrase", "totp_secret"}
|
|
6348
|
+
#: A private key is pasted as many lines; getpass reads one. Read these until
|
|
6349
|
+
#: a blank line instead of silently storing the first line of a PEM.
|
|
6350
|
+
_CREDS_MULTILINE_FIELDS = {"private_key"}
|
|
6342
6351
|
|
|
6343
6352
|
|
|
6344
6353
|
def _creds_prompt_structured(name: str, ctype: str) -> str:
|
|
@@ -6355,7 +6364,16 @@ def _creds_prompt_structured(name: str, ctype: str) -> str:
|
|
|
6355
6364
|
fields: dict = {}
|
|
6356
6365
|
for fname in list(required) + list(optional):
|
|
6357
6366
|
tag = "" if fname in required else " (optional)"
|
|
6358
|
-
if fname in
|
|
6367
|
+
if fname in _CREDS_MULTILINE_FIELDS:
|
|
6368
|
+
print(f" {fname}{tag} — paste it, then a blank line:")
|
|
6369
|
+
lines = []
|
|
6370
|
+
while True:
|
|
6371
|
+
line = input()
|
|
6372
|
+
if not line.strip():
|
|
6373
|
+
break
|
|
6374
|
+
lines.append(line)
|
|
6375
|
+
raw = "\n".join(lines)
|
|
6376
|
+
elif fname in _CREDS_HIDDEN_FIELDS:
|
|
6359
6377
|
raw = getpass.getpass(f" {fname}{tag}: ")
|
|
6360
6378
|
else:
|
|
6361
6379
|
raw = input(f" {fname}{tag}: ")
|
|
@@ -7031,12 +7049,14 @@ def _override_requests(args, project_path: str) -> None:
|
|
|
7031
7049
|
def _override_decide(args, decision: str, project_path: str) -> None:
|
|
7032
7050
|
from services import override_requests as orq
|
|
7033
7051
|
|
|
7052
|
+
mode = getattr(args, "mode", None) or orq.MODE_ONCE
|
|
7034
7053
|
try:
|
|
7035
7054
|
row = orq.decide(getattr(args, "request_id", ""), decision,
|
|
7036
7055
|
uses=getattr(args, "uses", None),
|
|
7037
7056
|
ttl_s=getattr(args, "ttl_s", None),
|
|
7038
7057
|
note=getattr(args, "note", "") or "",
|
|
7039
|
-
decided_by="cli",
|
|
7058
|
+
decided_by="cli", mode=mode,
|
|
7059
|
+
mute=bool(getattr(args, "mute", False)),
|
|
7040
7060
|
confirm=getattr(args, "confirm", None))
|
|
7041
7061
|
except orq.OverrideError as exc:
|
|
7042
7062
|
print(f" {exc}")
|
|
@@ -7046,15 +7066,29 @@ def _override_decide(args, decision: str, project_path: str) -> None:
|
|
|
7046
7066
|
return
|
|
7047
7067
|
|
|
7048
7068
|
if decision == "deny":
|
|
7049
|
-
|
|
7069
|
+
muted = " This session will not be asked again." \
|
|
7070
|
+
if row.get("muted") else ""
|
|
7071
|
+
print(f" Denied {row['id']}. The block stands.{muted}")
|
|
7050
7072
|
return
|
|
7051
7073
|
print_header("Override approved")
|
|
7052
7074
|
print(f" Request : {row['id']} Grant: {row.get('grant_id', '?')}")
|
|
7053
7075
|
print(f" Allows : {row['tool']} {row['op']} on {row['path']}")
|
|
7054
7076
|
print(f" Session : {row['session_id']}")
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7077
|
+
# The reach line is the whole point of printing anything here: a session
|
|
7078
|
+
# or rule grant is a standing capability, and saying "one retry" for one
|
|
7079
|
+
# would be a lie the user acts on.
|
|
7080
|
+
print(f"\n The rule {row['rule']} is still in force.")
|
|
7081
|
+
if mode == orq.MODE_RULE:
|
|
7082
|
+
print(" This grant covers EVERY path that rule matches, for any tool")
|
|
7083
|
+
print(" in the same op class, in that session — until it expires or")
|
|
7084
|
+
print(" the session stops using it. `c3 override list` shows it;")
|
|
7085
|
+
print(" `c3 override revoke <grant_id>` ends it.")
|
|
7086
|
+
elif mode == orq.MODE_SESSION:
|
|
7087
|
+
print(" Unlimited retries of this exact call, in that session, on")
|
|
7088
|
+
print(" that exact path, until the grant expires.")
|
|
7089
|
+
else:
|
|
7090
|
+
print(" One retry of this exact call, in that session, on that exact")
|
|
7091
|
+
print(" path — nothing else.")
|
|
7058
7092
|
|
|
7059
7093
|
|
|
7060
7094
|
def _override_show(policy, project_path: str, opol) -> None:
|
|
@@ -7074,6 +7108,14 @@ def _override_show(policy, project_path: str, opol) -> None:
|
|
|
7074
7108
|
f"{opol.HARD_MAX_TTL_S}s)")
|
|
7075
7109
|
print(f" uses : {policy.default_uses} "
|
|
7076
7110
|
f"(session grants: {'allowed' if policy.allow_session_grants else 'off'})")
|
|
7111
|
+
if policy.allow_rule_grants:
|
|
7112
|
+
print(f" rule grants : allowed — <= {policy.rule_grant_ttl_s}s "
|
|
7113
|
+
f"(hard ceiling {opol.HARD_MAX_RULE_TTL_S}s), idle cap "
|
|
7114
|
+
f"{policy.rule_grant_idle_s}s")
|
|
7115
|
+
print(" one approval covers every path the rule "
|
|
7116
|
+
"matches")
|
|
7117
|
+
else:
|
|
7118
|
+
print(" rule grants : off")
|
|
7077
7119
|
print(f" request TTL : {policy.request_ttl_s}s")
|
|
7078
7120
|
print(f" rate : {policy.max_pending_per_session} pending/session, "
|
|
7079
7121
|
f"{policy.max_requests_per_hour}/hour")
|
|
@@ -7185,11 +7227,22 @@ def _override_list(args, project_path: str, og) -> None:
|
|
|
7185
7227
|
if not grants:
|
|
7186
7228
|
print(" (none)")
|
|
7187
7229
|
for g in grants:
|
|
7188
|
-
|
|
7189
|
-
|
|
7230
|
+
wide = g.get("scope") == og.SCOPE_RULE
|
|
7231
|
+
left = ("unlimited use" if g.get("uses_remaining") is None
|
|
7232
|
+
else f"{g.get('uses_remaining', 0)} use(s) left")
|
|
7233
|
+
# A rule grant's path_key is where it was MINTED, not what it covers.
|
|
7234
|
+
# Printing it in the same column as a call grant's target would read
|
|
7235
|
+
# as a much smaller capability than it is.
|
|
7236
|
+
reach = (f"any path matching {g.get('rule', '?')}" if wide
|
|
7237
|
+
else g.get("path_key", "?"))
|
|
7238
|
+
print(f" {g.get('id', '?'):18s} [{'rule' if wide else 'call'}] "
|
|
7239
|
+
f"{g.get('tool', '?')} {g.get('op', '?')} {reach}")
|
|
7190
7240
|
print(f" {'':18s} rule {g.get('rule', '?')} · session "
|
|
7191
7241
|
f"{g.get('session_id', '?')} · expires {g.get('expires_at', '?')}"
|
|
7192
|
-
f" · {
|
|
7242
|
+
f" · {left}"
|
|
7243
|
+
+ (f" · idle cap {g.get('idle_s')}s" if g.get("idle_s") else ""))
|
|
7244
|
+
if wide:
|
|
7245
|
+
print(f" {'':18s} minted from {g.get('path_key', '?')}")
|
|
7193
7246
|
tail = int(getattr(args, "audit", 0) or 0)
|
|
7194
7247
|
if tail:
|
|
7195
7248
|
print("\n Audit (.c3/overrides.jsonl):")
|
|
@@ -7212,8 +7265,10 @@ def _override_check(args, policy, project_path: str, og, opol) -> None:
|
|
|
7212
7265
|
layer=gate, rule=rule, tool=tool, op=op,
|
|
7213
7266
|
path=getattr(args, "target", ""))
|
|
7214
7267
|
if hit:
|
|
7215
|
-
|
|
7216
|
-
|
|
7268
|
+
left = ("unlimited use" if hit.get("uses_remaining") is None
|
|
7269
|
+
else f"{hit['uses_remaining']} use(s) left")
|
|
7270
|
+
print(f" Allowed by {hit['id']} ({hit.get('scope', 'call')} scope) "
|
|
7271
|
+
f"— {left}, expires {hit['expires_at']}.")
|
|
7217
7272
|
print(" (`check` never consumes a use.)")
|
|
7218
7273
|
else:
|
|
7219
7274
|
print(" Denied — no live grant matches this exact "
|
|
@@ -7392,19 +7447,30 @@ def _access_cmd_list(args, project_path: str) -> None:
|
|
|
7392
7447
|
print(" [warn] access section invalid — scope fails closed "
|
|
7393
7448
|
"(deny-all); fix config.json 'access' by hand")
|
|
7394
7449
|
if scope == "builtin":
|
|
7450
|
+
# Which SCOPE set each live mode. Printing a project-set opt-out
|
|
7451
|
+
# as if it were machine-wide (or the reverse) is the exact
|
|
7452
|
+
# confusion the realm split exists to prevent.
|
|
7453
|
+
realms = sec.get("mode_realms") or {}
|
|
7454
|
+
|
|
7455
|
+
def _where(glob):
|
|
7456
|
+
r = realms.get(access_guard._norm_builtin(glob), "")
|
|
7457
|
+
return f" [{r}]" if r else ""
|
|
7458
|
+
|
|
7395
7459
|
off = sec.get("disabled") or []
|
|
7396
7460
|
if off:
|
|
7397
7461
|
print(" DISABLED by you (not enforced):")
|
|
7398
7462
|
for glob in off:
|
|
7399
|
-
print(f" {'off':<10} {glob}")
|
|
7400
|
-
print(" re-enable: c3 access builtin enable <glob>"
|
|
7463
|
+
print(f" {'off':<10} {glob}{_where(glob)}")
|
|
7464
|
+
print(" re-enable: c3 access builtin enable <glob> "
|
|
7465
|
+
"[--project]")
|
|
7401
7466
|
moded = {g: m for g, m in (sec.get("modes") or {}).items()
|
|
7402
7467
|
if m not in ("default", "allow")}
|
|
7403
7468
|
if moded:
|
|
7404
7469
|
print(" MODE set by you (departs from the shipped default):")
|
|
7405
7470
|
for glob, m in sorted(moded.items()):
|
|
7406
|
-
print(f" {m:<10} {glob}")
|
|
7407
|
-
print(" reset: c3 access builtin mode <glob> default"
|
|
7471
|
+
print(f" {m:<10} {glob}{_where(glob)}")
|
|
7472
|
+
print(" reset: c3 access builtin mode <glob> default "
|
|
7473
|
+
"[--project]")
|
|
7408
7474
|
can = [g for g in (sec.get("disableable") or [])
|
|
7409
7475
|
if access_guard._norm_builtin(g) not in set(off)
|
|
7410
7476
|
and access_guard._norm_builtin(g) not in moded]
|
|
@@ -7414,6 +7480,8 @@ def _access_cmd_list(args, project_path: str) -> None:
|
|
|
7414
7480
|
print(" disable: c3 access builtin disable <glob> · "
|
|
7415
7481
|
"granular: c3 access builtin mode <glob> "
|
|
7416
7482
|
"{deny,confirm,allow}")
|
|
7483
|
+
print(" add --project to scope it to this project only "
|
|
7484
|
+
"(attested under its own keyring realm)")
|
|
7417
7485
|
if sec.get("absolute"):
|
|
7418
7486
|
print(" absolute (credential vault, cannot be disabled): "
|
|
7419
7487
|
+ ", ".join(sec["absolute"]))
|
|
@@ -7430,7 +7498,8 @@ def _access_cmd_list(args, project_path: str) -> None:
|
|
|
7430
7498
|
|
|
7431
7499
|
|
|
7432
7500
|
def _access_cmd_builtin(args, project_path: str) -> None:
|
|
7433
|
-
"""Switch a Tier-1 builtin off or back on. Human-only;
|
|
7501
|
+
"""Switch a Tier-1 builtin off or back on. Human-only; global scope by
|
|
7502
|
+
default, this project only with --project (v2.118.0).
|
|
7434
7503
|
|
|
7435
7504
|
Disabling asks for typed confirmation unless --yes: these guards are what
|
|
7436
7505
|
stop an agent rewriting its own hooks, settings or git history, and the
|
|
@@ -7452,8 +7521,11 @@ def _access_cmd_builtin(args, project_path: str) -> None:
|
|
|
7452
7521
|
return
|
|
7453
7522
|
|
|
7454
7523
|
disabling = action == "disable"
|
|
7524
|
+
scope = "project" if getattr(args, "project_scope", False) else "global"
|
|
7455
7525
|
if disabling and not getattr(args, "yes", False):
|
|
7456
|
-
|
|
7526
|
+
where = (f"in THIS project only ({project_path})" if scope == "project"
|
|
7527
|
+
else "on EVERY project on this machine")
|
|
7528
|
+
print(f"About to STOP enforcing the builtin guard on: {glob} {where}")
|
|
7457
7529
|
print(" While off, any agent with C3 tools can write those paths.")
|
|
7458
7530
|
if glob.endswith("settings*.json") or ".claude" in glob:
|
|
7459
7531
|
print(" This is the file that configures the agent itself — hooks,")
|
|
@@ -7464,23 +7536,29 @@ def _access_cmd_builtin(args, project_path: str) -> None:
|
|
|
7464
7536
|
return
|
|
7465
7537
|
|
|
7466
7538
|
try:
|
|
7467
|
-
result = access_guard.set_builtin_disabled(glob, disabling
|
|
7539
|
+
result = access_guard.set_builtin_disabled(glob, disabling, scope,
|
|
7540
|
+
project_path)
|
|
7468
7541
|
except ValueError as exc:
|
|
7469
7542
|
print(f"[error] {exc}")
|
|
7470
7543
|
return
|
|
7471
7544
|
|
|
7472
|
-
_access_audit(f"builtin_{action}", result["glob"], "builtin",
|
|
7473
|
-
project_path)
|
|
7545
|
+
_access_audit(f"builtin_{action}", result["glob"], "builtin",
|
|
7546
|
+
result["scope"], project_path)
|
|
7474
7547
|
if not result["changed"]:
|
|
7475
7548
|
state = "already disabled" if disabling else "already enforced"
|
|
7476
|
-
print(f"[=] {result['glob']} — {state}")
|
|
7549
|
+
print(f"[=] {result['glob']} — {state} ({result['scope']} scope)")
|
|
7477
7550
|
return
|
|
7551
|
+
flag = " --project" if result["scope"] == "project" else ""
|
|
7478
7552
|
if disabling:
|
|
7479
|
-
print(f"[OK] Builtin '{result['glob']}' DISABLED
|
|
7553
|
+
print(f"[OK] Builtin '{result['glob']}' DISABLED "
|
|
7554
|
+
f"({result['scope']} scope).")
|
|
7480
7555
|
print(" Re-enable with: c3 access builtin enable "
|
|
7481
|
-
f"{result['glob']}")
|
|
7556
|
+
f"{result['glob']}{flag}")
|
|
7557
|
+
if result["glob"].endswith(".env*"):
|
|
7558
|
+
print(_ENV_VAULT_HINT)
|
|
7482
7559
|
else:
|
|
7483
|
-
print(f"[OK] Builtin '{result['glob']}' re-enforced
|
|
7560
|
+
print(f"[OK] Builtin '{result['glob']}' re-enforced "
|
|
7561
|
+
f"({result['scope']} scope).")
|
|
7484
7562
|
if not result["attested"]:
|
|
7485
7563
|
print(" [warn] keyring attestation could not be cleared; the "
|
|
7486
7564
|
"builtin is enforced anyway (config entry removed).")
|
|
@@ -7496,8 +7574,18 @@ _BUILTIN_MODE_HELP = {
|
|
|
7496
7574
|
}
|
|
7497
7575
|
|
|
7498
7576
|
|
|
7577
|
+
#: Shown whenever someone loosens the `.env` guard. `.env` is the one Tier-1
|
|
7578
|
+
#: builtin whose whole content is secrets, and C3 already has a place to put
|
|
7579
|
+
#: them that the agent cannot read. Advisory — never a refusal.
|
|
7580
|
+
_ENV_VAULT_HINT = (
|
|
7581
|
+
" [note] .env values are better held in the vault: "
|
|
7582
|
+
"`c3_credentials import_env` reads the file server-side, so the agent\n"
|
|
7583
|
+
" gets names, lengths and fingerprints and never a value."
|
|
7584
|
+
)
|
|
7585
|
+
|
|
7586
|
+
|
|
7499
7587
|
def _access_cmd_builtin_mode(args, glob: str, project_path: str) -> None:
|
|
7500
|
-
"""`c3 access builtin mode <glob> <mode
|
|
7588
|
+
"""`c3 access builtin mode <glob> <mode> [--project]` — granular control.
|
|
7501
7589
|
|
|
7502
7590
|
`deny` and `default` never prompt (tightening / reset). `confirm` and
|
|
7503
7591
|
`allow` weaken the guard, so they get the same typed-glob beat of
|
|
@@ -7506,10 +7594,13 @@ def _access_cmd_builtin_mode(args, glob: str, project_path: str) -> None:
|
|
|
7506
7594
|
from services import access_guard
|
|
7507
7595
|
|
|
7508
7596
|
mode = getattr(args, "mode", None)
|
|
7597
|
+
scope = "project" if getattr(args, "project_scope", False) else "global"
|
|
7598
|
+
where = (f"in THIS project only ({project_path})" if scope == "project"
|
|
7599
|
+
else "on EVERY project on this machine")
|
|
7509
7600
|
if mode in ("confirm", "allow") and not getattr(args, "yes", False):
|
|
7510
7601
|
widening = ("STOP enforcing" if mode == "allow"
|
|
7511
7602
|
else "PAUSE (not block) and ask you to approve")
|
|
7512
|
-
print(f"About to make the builtin guard on {glob} {widening}.")
|
|
7603
|
+
print(f"About to make the builtin guard on {glob} {widening} {where}.")
|
|
7513
7604
|
if mode == "allow":
|
|
7514
7605
|
print(" While off, any agent with C3 tools can touch those paths.")
|
|
7515
7606
|
else:
|
|
@@ -7524,20 +7615,30 @@ def _access_cmd_builtin_mode(args, glob: str, project_path: str) -> None:
|
|
|
7524
7615
|
return
|
|
7525
7616
|
|
|
7526
7617
|
try:
|
|
7527
|
-
result = access_guard.set_builtin_mode(glob, mode)
|
|
7618
|
+
result = access_guard.set_builtin_mode(glob, mode, scope, project_path)
|
|
7528
7619
|
except ValueError as exc:
|
|
7529
7620
|
print(f"[error] {exc}")
|
|
7530
7621
|
return
|
|
7531
7622
|
|
|
7532
7623
|
_access_audit(f"builtin_mode_{result['mode']}", result["glob"],
|
|
7533
|
-
"builtin", "
|
|
7624
|
+
"builtin", result["scope"], project_path)
|
|
7534
7625
|
if not result["changed"]:
|
|
7535
|
-
print(f"[=] {result['glob']} — already {result['mode']}"
|
|
7626
|
+
print(f"[=] {result['glob']} — already {result['mode']} "
|
|
7627
|
+
f"({result['scope']} scope)")
|
|
7536
7628
|
return
|
|
7537
7629
|
print(f"[OK] Builtin '{result['glob']}' mode = {result['mode']} "
|
|
7538
|
-
f"(
|
|
7630
|
+
f"({result['scope']} scope): {_BUILTIN_MODE_HELP[result['mode']]}.")
|
|
7631
|
+
if result["scope"] == "project":
|
|
7632
|
+
print(" Bound to this project's keyring realm — a clone of this "
|
|
7633
|
+
"repo carries the config\n but not the attestation, so the "
|
|
7634
|
+
"builtin stays enforced there.")
|
|
7539
7635
|
if result["mode"] != "default":
|
|
7540
|
-
|
|
7636
|
+
flag = " --project" if result["scope"] == "project" else ""
|
|
7637
|
+
print(f" Reset with: c3 access builtin mode {result['glob']} "
|
|
7638
|
+
f"default{flag}")
|
|
7639
|
+
if result["glob"].endswith(".env*") and result["mode"] in ("allow",
|
|
7640
|
+
"confirm"):
|
|
7641
|
+
print(_ENV_VAULT_HINT)
|
|
7541
7642
|
if not result["attested"]:
|
|
7542
7643
|
print(" [warn] keyring attestation could not be cleared; the "
|
|
7543
7644
|
"default is enforced anyway (config entry removed).")
|
|
@@ -735,10 +735,18 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
735
735
|
help="Seconds until the grant expires (clamped to override.max_ttl_s)")
|
|
736
736
|
ov_approve.add_argument("--uses", type=int, default=None,
|
|
737
737
|
help="Uses allowed (default 1)")
|
|
738
|
+
ov_approve.add_argument(
|
|
739
|
+
"--mode", choices=("once", "session", "rule"), default="once",
|
|
740
|
+
help="once (default) | session: unlimited uses on THIS call until the "
|
|
741
|
+
"grant expires (needs override.allow_session_grants and "
|
|
742
|
+
"--confirm session) | rule: every path the rule matches, any "
|
|
743
|
+
"tool in the same op class (needs override.allow_rule_grants "
|
|
744
|
+
"and the rule glob in --confirm)")
|
|
738
745
|
ov_approve.add_argument("--note", default="",
|
|
739
746
|
help="Note recorded with the decision")
|
|
740
747
|
ov_approve.add_argument("--confirm", default=None,
|
|
741
|
-
help="Required for deny/builtin rules
|
|
748
|
+
help="Required for deny/builtin rules and for --mode rule: "
|
|
749
|
+
"retype the rule glob by hand ('session' for --mode session)")
|
|
742
750
|
ov_approve.add_argument("--path", dest="project_path", default=".",
|
|
743
751
|
help="Project directory (default: current)")
|
|
744
752
|
|
|
@@ -746,6 +754,8 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
746
754
|
ov_deny.add_argument("request_id", help="Request id (ovr_…)")
|
|
747
755
|
ov_deny.add_argument("--note", default="",
|
|
748
756
|
help="Note the agent will see with the refusal")
|
|
757
|
+
ov_deny.add_argument("--mute", action="store_true",
|
|
758
|
+
help="Also stop this session asking the same thing again")
|
|
749
759
|
ov_deny.add_argument("--path", dest="project_path", default=".",
|
|
750
760
|
help="Project directory (default: current)")
|
|
751
761
|
|
|
@@ -830,10 +840,12 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
830
840
|
# ── Builtin opt-out (two-key) ───────────────────────────────────────
|
|
831
841
|
# Builtins are on by default. Switching one off needs a config entry AND
|
|
832
842
|
# a keyring attestation, so an agent that writes config.json alone still
|
|
833
|
-
# cannot loosen the guard.
|
|
834
|
-
#
|
|
843
|
+
# cannot loosen the guard. Since v2.118.0 the pair may be written at
|
|
844
|
+
# PROJECT scope too, because the attestation is realm-bound: a cloned
|
|
845
|
+
# repo carries the config half and changes nothing. The credential-vault
|
|
846
|
+
# builtins are never disableable at any scope.
|
|
835
847
|
ac_builtin = access_subs.add_parser(
|
|
836
|
-
"builtin", help="Disable or re-enable a built-in guard (
|
|
848
|
+
"builtin", help="Disable or re-enable a built-in guard (needs confirmation)")
|
|
837
849
|
builtin_subs = ac_builtin.add_subparsers(dest="builtin_cmd")
|
|
838
850
|
for _name, _help in (("disable", "Stop enforcing a built-in guard"),
|
|
839
851
|
("enable", "Re-enforce a built-in guard")):
|
|
@@ -841,6 +853,8 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
841
853
|
_p.add_argument("glob", help="One of: **/.env*, **/.c3/**, **/.claude/settings*.json, **/.git/**")
|
|
842
854
|
_p.add_argument("--path", dest="project_path", default=".",
|
|
843
855
|
help="Project directory used for the audit log (default: current)")
|
|
856
|
+
_p.add_argument("--project", dest="project_scope", action="store_true",
|
|
857
|
+
help="This project only (default: every project on this machine)")
|
|
844
858
|
if _name == "disable":
|
|
845
859
|
_p.add_argument("--yes", action="store_true",
|
|
846
860
|
help="Skip the typed confirmation (scripts/CI)")
|
|
@@ -857,6 +871,9 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
857
871
|
"approval; allow = off (two-key); default = shipped behaviour")
|
|
858
872
|
bm.add_argument("--path", dest="project_path", default=".",
|
|
859
873
|
help="Project directory used for the audit log (default: current)")
|
|
874
|
+
bm.add_argument("--project", dest="project_scope", action="store_true",
|
|
875
|
+
help="Set the mode for THIS project only, attested under "
|
|
876
|
+
"its own keyring realm (default: every project)")
|
|
860
877
|
bm.add_argument("--yes", action="store_true",
|
|
861
878
|
help="Skip the typed confirmation (scripts/CI)")
|
|
862
879
|
|
|
@@ -308,8 +308,9 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
|
|
|
308
308
|
<code>card</code> (cardholder, number, expiry, optional cvc/billing_zip — Luhn-checked),
|
|
309
309
|
<code>address</code> (street1, city, state, zip, optional recipient/street2/country/phone),
|
|
310
310
|
<code>identity</code> (full_name, optional dob/ssn/phone/email) and
|
|
311
|
-
<code>login</code> (site_id,
|
|
312
|
-
v2.90.0).
|
|
311
|
+
<code>login</code> (site_id, canonical_target, username, optional
|
|
312
|
+
password/private_key/passphrase/totp_secret — v2.90.0, generalized v2.118.0).
|
|
313
|
+
The payload is stored as one
|
|
313
314
|
canonical JSON object through the same keyring / encrypted-sidecar path as any other value.</p>
|
|
314
315
|
|
|
315
316
|
<p>They are <strong>inject-only by construction</strong>, which is stricter than a normal secret:</p>
|
|
@@ -323,9 +324,10 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
|
|
|
323
324
|
<li><strong>The registry shows a projection, not the data.</strong> Lists and the UI display
|
|
324
325
|
<code>visa ••••4242</code> for a card (brand + last4, deliberately <em>not</em> expiry),
|
|
325
326
|
city/state for an address, the name for an identity, and
|
|
326
|
-
<code>github · https://github.com · 2FA</code>
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
<code>github · https://github.com · 2FA</code> or
|
|
328
|
+
<code>build01 · ssh://build01.lan:22 · key</code> for a login — site, target and
|
|
329
|
+
2FA/key booleans, with the <em>username withheld on purpose</em>, because username +
|
|
330
|
+
target is half the credential. Field <em>names</em> are public;
|
|
329
331
|
field <em>values</em> never transit any HTTP response — a sweep test enforces this.</li>
|
|
330
332
|
<li><strong>Echoes redact per field</strong> to <code>[cred:NAME.field]</code>. Caveat: the
|
|
331
333
|
redactor only tracks values of 4+ characters, so a 3-digit CVC or 2-letter state that a
|
|
@@ -346,15 +348,34 @@ c3_shell(cmd=<span class="str">'terraform apply'</span>, env_creds=<span class="
|
|
|
346
348
|
|
|
347
349
|
<p><strong><code>login</code> is storage only, and that is a design constraint, not a
|
|
348
350
|
gap.</strong> C3 has no browser surface and must not grow one: a login runner in which the
|
|
349
|
-
<em>agent</em> picks the destination
|
|
351
|
+
<em>agent</em> picks the destination turns page-content prompt injection into credential
|
|
350
352
|
exfiltration, and a check written into a script that already holds the plaintext in its own
|
|
351
353
|
environment is not a boundary — the script can simply not call it. That is what
|
|
352
|
-
<code>
|
|
354
|
+
<code>canonical_target</code> is for: stored normalized
|
|
353
355
|
(<code>scheme://host[:port]</code>, no path/query/fragment/userinfo, host lowercased), so a
|
|
354
356
|
separate <em>out-of-process</em> runner that the agent does not author can pin a credential to
|
|
355
|
-
exactly one
|
|
356
|
-
deliberately not shipped in this package. <code>totp_secret</code> must be
|
|
357
|
-
malformed seed produces wrong codes that look exactly like a wrong password.</p>
|
|
357
|
+
exactly one destination and check where it is actually about to authenticate before typing.
|
|
358
|
+
That runner is deliberately not shipped in this package. <code>totp_secret</code> must be
|
|
359
|
+
base32 — a malformed seed produces wrong codes that look exactly like a wrong password.</p>
|
|
360
|
+
|
|
361
|
+
<p><strong>Not just websites (v2.118.0).</strong> A <code>login</code> holds any target with
|
|
362
|
+
one unambiguous destination: <code>ssh://build01.lan:22</code>,
|
|
363
|
+
<code>postgres://db.internal:5432</code>, <code>rdp://jump.corp</code>,
|
|
364
|
+
<code>smb://files.lan</code>. The scheme comes from an allowlist (https, ssh, sftp, ftps,
|
|
365
|
+
rdp, smb, vnc, winrm, ldaps, imaps, smtps, amqps, postgres, mysql, mariadb, mssql, mongodb,
|
|
366
|
+
redis); <strong>cleartext schemes are refused by name</strong> and told which TLS variant to
|
|
367
|
+
use instead, for the same reason http:// always was. A server login may carry a
|
|
368
|
+
<code>private_key</code> (PEM/OpenSSH, checked, with its own size allowance and an optional
|
|
369
|
+
<code>passphrase</code>) instead of a password — one of the two is required, because a login
|
|
370
|
+
with neither is not a credential.</p>
|
|
371
|
+
|
|
372
|
+
<p>The origin-pinning property is <em>preserved, not weakened</em>:
|
|
373
|
+
<code>canonical_origin</code> is still a valid field name and still reads back — but
|
|
374
|
+
<strong>only when the target is https</strong>. A browser broker that pins a credential by
|
|
375
|
+
asking for <code>canonical_origin</code> gets nothing for an <code>ssh://</code> entry and
|
|
376
|
+
fails closed, rather than being handed a string it cannot compare to a top-level frame.
|
|
377
|
+
Entries stored before v2.118.0 need no migration: the old field name is accepted on input
|
|
378
|
+
and resolves on read.</p>
|
|
358
379
|
</section>
|
|
359
380
|
|
|
360
381
|
<hr class="divider">
|
|
@@ -3111,7 +3111,7 @@ def _hub_override_row(row: dict) -> dict:
|
|
|
3111
3111
|
quoted under the untrusted-input label, never as markup.
|
|
3112
3112
|
"""
|
|
3113
3113
|
out = {k: row.get(k) for k in _OVERRIDE_ROW_FIELDS}
|
|
3114
|
-
for extra in ("grant_id", "grant_mode", "muted"):
|
|
3114
|
+
for extra in ("grant_id", "grant_mode", "grant_scope", "muted"):
|
|
3115
3115
|
if row.get(extra) is not None:
|
|
3116
3116
|
out[extra] = row.get(extra)
|
|
3117
3117
|
return out
|
|
@@ -3160,6 +3160,7 @@ def api_hub_overrides():
|
|
|
3160
3160
|
whether the layer is still escalatable and which typed challenge (if any)
|
|
3161
3161
|
an approval demands.
|
|
3162
3162
|
"""
|
|
3163
|
+
from services import override_grants as orq_grants
|
|
3163
3164
|
from services import override_policy as opol
|
|
3164
3165
|
from services import override_requests as orq
|
|
3165
3166
|
project_path = ""
|
|
@@ -3199,6 +3200,12 @@ def api_hub_overrides():
|
|
|
3199
3200
|
if policy is not None else False
|
|
3200
3201
|
entry["allow_session_grants"] = bool(policy.allow_session_grants) \
|
|
3201
3202
|
if policy is not None else False
|
|
3203
|
+
# A rule grant is only offerable when policy allows it AND the rule is
|
|
3204
|
+
# a real glob — the synthetic discipline/shell tokens have no path set
|
|
3205
|
+
# to widen along, so the card must not show a button that would 400.
|
|
3206
|
+
entry["allow_rule_grants"] = bool(
|
|
3207
|
+
policy is not None and policy.allow_rule_grants
|
|
3208
|
+
and orq_grants.rule_is_globbable(row.get("rule", "")))
|
|
3202
3209
|
entry["project_name"] = Path(proj).name
|
|
3203
3210
|
out.append(entry)
|
|
3204
3211
|
return jsonify({"requests": out, "count": len(out),
|
|
@@ -3234,12 +3241,18 @@ def api_hub_override_decide(request_id):
|
|
|
3234
3241
|
|
|
3235
3242
|
rule_class = str(row.get("rule_class") or "")
|
|
3236
3243
|
confirm = data.get("confirm")
|
|
3237
|
-
|
|
3238
|
-
|
|
3244
|
+
# A rule-scoped approval demands the glob retyped on EVERY layer, not just
|
|
3245
|
+
# the two that already do — it is a standing capability, so the layers
|
|
3246
|
+
# that are one-tap for `once` are deliberately not one-tap for `rule`.
|
|
3247
|
+
needs_glob = (rule_class in opol.TYPED_CONFIRM_LAYERS
|
|
3248
|
+
or mode == orq.MODE_RULE)
|
|
3249
|
+
if (decision == orq.DECISION_APPROVE and needs_glob
|
|
3239
3250
|
and confirm != row.get("rule")):
|
|
3240
3251
|
return jsonify({
|
|
3241
|
-
"error":
|
|
3242
|
-
|
|
3252
|
+
"error": ("a rule-scoped approval needs the rule glob retyped by "
|
|
3253
|
+
"hand" if mode == orq.MODE_RULE else
|
|
3254
|
+
f"approving an {rule_class} request needs the rule "
|
|
3255
|
+
"glob retyped by hand"),
|
|
3243
3256
|
"needs_confirmation": True,
|
|
3244
3257
|
"confirm_with": row.get("rule"),
|
|
3245
3258
|
}), 400
|
|
@@ -3261,14 +3274,73 @@ def api_hub_override_decide(request_id):
|
|
|
3261
3274
|
except Exception as exc:
|
|
3262
3275
|
return jsonify({"error": str(exc)}), 500
|
|
3263
3276
|
|
|
3264
|
-
_hub_override_audit(decision, result,
|
|
3265
|
-
confirmed=rule_class in opol.TYPED_CONFIRM_LAYERS,
|
|
3277
|
+
_hub_override_audit(decision, result, confirmed=needs_glob,
|
|
3266
3278
|
detail_extra={"mode": mode,
|
|
3267
3279
|
"grant_id": result.get("grant_id", "")})
|
|
3268
3280
|
return jsonify({"request": _hub_override_row(result),
|
|
3269
3281
|
"decision": decision})
|
|
3270
3282
|
|
|
3271
3283
|
|
|
3284
|
+
#: Grant fields the hub may render. `path_key` is a canon identity, not a
|
|
3285
|
+
#: display string, but a rule grant's whole point is that it is NOT bound to
|
|
3286
|
+
#: that one path — so the card leads with the rule and shows the path only as
|
|
3287
|
+
#: "minted from", which is what the user was looking at when they approved.
|
|
3288
|
+
_GRANT_ROW_FIELDS = (
|
|
3289
|
+
"id", "request_id", "session_id", "scope", "layer", "rule", "tool", "op",
|
|
3290
|
+
"path_key", "expires_at", "uses_remaining", "idle_s", "granted_at",
|
|
3291
|
+
"granted_by", "last_used_at",
|
|
3292
|
+
)
|
|
3293
|
+
|
|
3294
|
+
|
|
3295
|
+
@app.route("/api/hub/grants", methods=["GET"])
|
|
3296
|
+
def api_hub_grants():
|
|
3297
|
+
"""Live grants for one project — the standing capabilities, visible.
|
|
3298
|
+
|
|
3299
|
+
A rule-scoped grant can authorise many calls over hours, so it must be
|
|
3300
|
+
inspectable and killable from the same screen that minted it. Without
|
|
3301
|
+
this the only evidence a grant exists is a line in the agent's own
|
|
3302
|
+
transcript, which is the wrong place to police it from.
|
|
3303
|
+
"""
|
|
3304
|
+
from services import override_grants as og
|
|
3305
|
+
raw = (request.args.get("path") or "").strip()
|
|
3306
|
+
if not raw:
|
|
3307
|
+
return jsonify({"error": "path is required"}), 400
|
|
3308
|
+
try:
|
|
3309
|
+
resolved = _resolve_project_path(raw)
|
|
3310
|
+
except ValueError as e:
|
|
3311
|
+
return jsonify({"error": str(e)}), 404
|
|
3312
|
+
session_id = (request.args.get("session") or "").strip()
|
|
3313
|
+
try:
|
|
3314
|
+
grants = og.active(str(resolved), session_id=session_id)
|
|
3315
|
+
except Exception as exc:
|
|
3316
|
+
return jsonify({"error": str(exc)}), 500
|
|
3317
|
+
out = [{k: g.get(k) for k in _GRANT_ROW_FIELDS} for g in grants]
|
|
3318
|
+
return jsonify({"path": str(resolved), "grants": out, "count": len(out)})
|
|
3319
|
+
|
|
3320
|
+
|
|
3321
|
+
@app.route("/api/hub/grants/<grant_id>", methods=["DELETE"])
|
|
3322
|
+
def api_hub_grant_revoke(grant_id):
|
|
3323
|
+
"""Revoke one live grant. Human surface; ledger-logged like a decision."""
|
|
3324
|
+
from services import override_grants as og
|
|
3325
|
+
raw = (request.args.get("path") or "").strip()
|
|
3326
|
+
if not raw:
|
|
3327
|
+
return jsonify({"error": "path is required"}), 400
|
|
3328
|
+
try:
|
|
3329
|
+
resolved = _resolve_project_path(raw)
|
|
3330
|
+
except ValueError as e:
|
|
3331
|
+
return jsonify({"error": str(e)}), 404
|
|
3332
|
+
try:
|
|
3333
|
+
gone = og.revoke(str(resolved), grant_id=str(grant_id))
|
|
3334
|
+
except Exception as exc:
|
|
3335
|
+
return jsonify({"error": str(exc)}), 500
|
|
3336
|
+
if not gone:
|
|
3337
|
+
return jsonify({"error": "unknown or already-expired grant"}), 404
|
|
3338
|
+
_hub_override_audit("grant_revoke",
|
|
3339
|
+
{"id": "", "project_path": str(resolved), "rule": ""},
|
|
3340
|
+
detail_extra={"grant_id": str(grant_id)})
|
|
3341
|
+
return jsonify({"revoked": str(grant_id)})
|
|
3342
|
+
|
|
3343
|
+
|
|
3272
3344
|
@app.route("/api/hub/access", methods=["GET"])
|
|
3273
3345
|
def api_hub_access():
|
|
3274
3346
|
"""Effective Access Guard rules + override policy for one project.
|